A new config attribute availability-sets-enabled
is defined, which controls the mode in which the
Azure environment operates. If true (the default),
availability set support is enabled and instances
will be grouped by service. The attribute cannot
be changed after the environment is prepared.
If the availability-sets-enabled is true, unit
placement is prohibited. This is necessary to
avoid various issues such as incorrectly load-
balancing ports across heterogenous services, and
makes it possible to unambiguously determine
which Cloud Service to assign units to for high
availability.
Affected files (+83, -2 lines):
A [revision details]
M provider/azure/config.go
M provider/azure/config_test.go
M provider/azure/environ.go
M provider/azure/environ_test.go
M provider/azure/environprovider.go
type azureEnviron struct {
common.NopPrechecker
- common.DoesSupportUnitPlacement
// Except where indicated otherwise, all fields in this object should
// only be accessed using a lock or a snapshot.
@@ -897,3 +896,11 @@
Endpoint: string(gwacl.GetEndpoint(ecfg.location())),
}, nil
}
+
+// SupportsUnitPlacement is specified in the state.EnvironCapability
interface.
+func (env *azureEnviron) SupportsUnitPlacement() error {
+ if env.getSnapshot().ecfg.availabilitySetsEnabled() {
+ return fmt.Errorf("unit placement is not permitted with
availability-sets-enabled")
+ }
+ return nil
+}
Index: provider/azure/environ_test.go
=== modified file 'provider/azure/environ_test.go'
--- provider/azure/environ_test.go 2014-03-18 01:25:52 +0000
+++ provider/azure/environ_test.go 2014-03-20 04:44:57 +0000
@@ -1285,3 +1285,18 @@
c.Assert(len(sources), gc.Equals, 1)
assertSourceContents(c, sources[0], "filename", data)
}
+
+func (s *environSuite) TestCheckUnitAssignment(c *gc.C) {
+ // If availability-sets-enabled is true, then placement is disabled.
+ attrs := makeAzureConfigMap(c)
+ attrs["availability-sets-enabled"] = true
+ env := environs.Environ(makeEnvironWithConfig(c, attrs))
+ err := env.SupportsUnitPlacement()
+ c.Assert(err, gc.ErrorMatches, "unit placement is not permitted with
availability-sets-enabled")
+
+ // If the user disables availability sets, they can do what they want.
+ attrs["availability-sets-enabled"] = false
+ env = environs.Environ(makeEnvironWithConfig(c, attrs))
+ err = env.SupportsUnitPlacement()
+ c.Assert(err, gc.IsNil)
+}
// Prepare is specified in the EnvironProvider interface.
func (prov azureEnvironProvider) Prepare(ctx environs.BootstrapContext,
cfg *config.Config) (environs.Environ, error) {
- // TODO prepare environment as necessary
+ // Set availability-sets-enabled to true
+ // by default, unless the user set a value.
+ if _, ok := cfg.AllAttrs()["availability-sets-enabled"]; !ok {
+ var err error
+ cfg, err = cfg.Apply(map[string]interface{}{"availability-sets-enabled":
true})
+ if err != nil {
+ return nil, err
+ }
+ }
return prov.Open(cfg)
}
Reviewers: mp+211863_ code.launchpad. net,
Message:
Please take a look.
Description: sets-enabled config
provider/azure: availability-
A new config attribute availability- sets-enabled
is defined, which controls the mode in which the
Azure environment operates. If true (the default),
availability set support is enabled and instances
will be grouped by service. The attribute cannot
be changed after the environment is prepared.
If the availability- sets-enabled is true, unit
placement is prohibited. This is necessary to
avoid various issues such as incorrectly load-
balancing ports across heterogenous services, and
makes it possible to unambiguously determine
which Cloud Service to assign units to for high
availability.
https:/ /code.launchpad .net/~axwalk/ juju-core/ azure-mode- nounitplacement /+merge/ 211863
Requires: /code.launchpad .net/~axwalk/ juju-core/ state-environca pability/ +merge/ 211749
https:/
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/77950045/
Affected files (+83, -2 lines): azure/config. go azure/config_ test.go azure/environ. go azure/environ_ test.go azure/environpr ovider. go
A [revision details]
M provider/
M provider/
M provider/
M provider/
M provider/
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>
Index: provider/ azure/config. go azure/config. go' azure/config. go 2014-03-10 20:22:44 +0000 azure/config. go 2014-03-20 04:44:57 +0000 certificate" : schema.String(), account- name": schema.String(), image-name" : schema.String(), sets-enabled" : schema.Bool(), certificate" : "", certificate- path": "", image-name" : "", sets-enabled is set to Omit (equivalent sets-enabled" : schema.Omit,
=== modified file 'provider/
--- provider/
+++ provider/
@@ -18,12 +18,16 @@
"management-
"storage-
"force-
+ "availability-
}
var configDefaults = schema.Defaults{
"location": "",
"management-
"management-
"force-
+ // availability-
+ // to false) for backwards compatibility.
+ "availability-
}
type azureEnvironConfig struct { "force- image-name" ].(string)
@@ -51,6 +55,11 @@
return cfg.attrs[
}
+func (cfg *azureEnvironCo nfig) availabilitySet sEnabled( ) bool { "availability- sets-enabled" ].(bool) vider) newConfig(cfg *config.Config) onfig, error) {
+ enabled, _ := cfg.attrs[
+ return enabled
+}
+
func (prov azureEnvironPro
(*azureEnvironC
validCfg, err := prov.Validate(cfg, nil)
if err != nil {
@@ -71,6 +80,13 @@
return nil, err
}
+ // User cannot change availability- sets-enabled after environment is AllAttrs( )["availability -sets-enabled" ] != )["availability -sets-enabled" ] { sets-enabled" ) nownAttrs( configFields, configDefaults)
prepared.
+ if oldCfg != nil {
+ if oldCfg.
cfg.AllAttrs(
+ return nil, fmt.Errorf("cannot change availability-
+ }
+ }
+
validated, err := cfg.ValidateUnk
if err != nil {
return nil, err
Index: provider/ azure/config_ test.go azure/config_ test.go' azure/config_ test.go 2014-02-12 04:54:19 +0000 azure/config_ test.go 2014-03-20 04:44:57 +0000
=== modified file 'provider/
--- provider/
+++ provider/
@@ -7,6 +7,7 @@
"io/ioutil"
"strings"
+ jc "github. com/juju/ testing/ checkers" net/gocheck"
gc "launchpad.
"launchpad. net/juju- core/environs/ config" Validate( cfg, nil) ySetsEnabledDef ault(c *gc.C) { Map(c) sets-enabled isn't specified, it's set to true. availability- sets-enabled" ] = userValue New(config. UseDefaults, attrs) vider{} .Prepare( testing. Context( c), cfg) azureEnv. ecfg.availabili tySetsEnabled( ), checker) ySetsEnabledImm utable( c *gc.C) { New(config. UseDefaults, makeAzureConfig Map(c)) vider{} .Prepare( testing. Context( c), cfg) ).Apply( map[string] interface{ }{"availability -sets-enabled" : sets-enabled" )
@@ -202,3 +203,35 @@
_, err = provider.
c.Assert(err, gc.IsNil)
}
+
+func (*configSuite) TestAvailabilit
+ userValues := []interface{}{nil, false, true}
+ for _, userValue := range userValues {
+ attrs := makeAzureConfig
+ // If availability-
+ checker := jc.IsTrue
+ if userValue, ok := userValue.(bool); ok {
+ attrs["
+ if !userValue {
+ checker = jc.IsFalse
+ }
+ }
+ cfg, err := config.
+ c.Assert(err, gc.IsNil)
+ env, err := azureEnvironPro
+ c.Assert(err, gc.IsNil)
+ azureEnv := env.(*azureEnviron)
+ c.Assert(
+ }
+}
+
+func (*configSuite) TestAvailabilit
+ cfg, err := config.
+ c.Assert(err, gc.IsNil)
+ env, err := azureEnvironPro
+ c.Assert(err, gc.IsNil)
+ cfg, err =
env.Config(
false})
+ c.Assert(err, gc.IsNil)
+ err = env.SetConfig(cfg)
+ c.Assert(err, gc.ErrorMatches, "cannot change availability-
+}
Index: provider/ azure/environ. go azure/environ. go' azure/environ. go 2014-03-20 03:27:26 +0000 azure/environ. go 2014-03-20 04:44:57 +0000
=== modified file 'provider/
--- provider/
+++ provider/
@@ -52,7 +52,6 @@
type azureEnviron struct { NopPrechecker DoesSupportUnit Placement
common.
- common.
// Except where indicated otherwise, all fields in this object should gwacl.GetEndpoi nt(ecfg. location( ))), cement is specified in the state.EnvironCa pability cement( ) error { ().ecfg. availabilitySet sEnabled( ) { sets-enabled" )
// only be accessed using a lock or a snapshot.
@@ -897,3 +896,11 @@
Endpoint: string(
}, nil
}
+
+// SupportsUnitPla
interface.
+func (env *azureEnviron) SupportsUnitPla
+ if env.getSnapshot
+ return fmt.Errorf("unit placement is not permitted with
availability-
+ }
+ return nil
+}
Index: provider/ azure/environ_ test.go azure/environ_ test.go' azure/environ_ test.go 2014-03-18 01:25:52 +0000 azure/environ_ test.go 2014-03-20 04:44:57 +0000 len(sources) , gc.Equals, 1) Contents( c, sources[0], "filename", data) signment( c *gc.C) { sets-enabled is true, then placement is disabled. Map(c) availability- sets-enabled" ] = true Environ( makeEnvironWith Config( c, attrs)) tPlacement( ) sets-enabled" ) availability- sets-enabled" ] = false Environ( makeEnvironWith Config( c, attrs)) tPlacement( )
=== modified file 'provider/
--- provider/
+++ provider/
@@ -1285,3 +1285,18 @@
c.Assert(
assertSource
}
+
+func (s *environSuite) TestCheckUnitAs
+ // If availability-
+ attrs := makeAzureConfig
+ attrs["
+ env := environs.
+ err := env.SupportsUni
+ c.Assert(err, gc.ErrorMatches, "unit placement is not permitted with
availability-
+
+ // If the user disables availability sets, they can do what they want.
+ attrs["
+ env = environs.
+ err = env.SupportsUni
+ c.Assert(err, gc.IsNil)
+}
Index: provider/ azure/environpr ovider. go azure/environpr ovider. go' azure/environpr ovider. go 2014-03-05 19:41:34 +0000 azure/environpr ovider. go 2014-03-20 04:44:57 +0000
=== modified file 'provider/
--- provider/
+++ provider/
@@ -43,7 +43,15 @@
// Prepare is specified in the EnvironProvider interface. vider) Prepare(ctx environs. BootstrapContex t, sets-enabled to true )["availability -sets-enabled" ]; !ok { map[string] interface{ }{"availability -sets-enabled" :
func (prov azureEnvironPro
cfg *config.Config) (environs.Environ, error) {
- // TODO prepare environment as necessary
+ // Set availability-
+ // by default, unless the user set a value.
+ if _, ok := cfg.AllAttrs(
+ var err error
+ cfg, err = cfg.Apply(
true})
+ if err != nil {
+ return nil, err
+ }
+ }
return prov.Open(cfg)
}