github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/maas/environ_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package maas_test 5 6 import ( 7 stdtesting "testing" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "launchpad.net/gomaasapi" 12 13 "github.com/juju/juju/environs/config" 14 envtesting "github.com/juju/juju/environs/testing" 15 "github.com/juju/juju/feature" 16 "github.com/juju/juju/provider/maas" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 type environSuite struct { 21 coretesting.BaseSuite 22 envtesting.ToolsFixture 23 testMAASObject *gomaasapi.TestMAASObject 24 restoreTimeouts func() 25 } 26 27 var _ = gc.Suite(&environSuite{}) 28 29 func TestMAAS(t *stdtesting.T) { 30 gc.TestingT(t) 31 } 32 33 // TDOO: jam 2013-12-06 This is copied from the providerSuite which is in a 34 // whitebox package maas. Either move that into a whitebox test so it can be 35 // shared, or into a 'testing' package so we can use it here. 36 func (s *environSuite) SetUpSuite(c *gc.C) { 37 s.restoreTimeouts = envtesting.PatchAttemptStrategies(maas.ShortAttempt) 38 s.BaseSuite.SetUpSuite(c) 39 TestMAASObject := gomaasapi.NewTestMAAS("1.0") 40 s.testMAASObject = TestMAASObject 41 } 42 43 func (s *environSuite) SetUpTest(c *gc.C) { 44 s.BaseSuite.SetUpTest(c) 45 s.ToolsFixture.SetUpTest(c) 46 s.SetFeatureFlags(feature.AddressAllocation) 47 } 48 49 func (s *environSuite) TearDownTest(c *gc.C) { 50 s.testMAASObject.TestServer.Clear() 51 s.ToolsFixture.TearDownTest(c) 52 s.BaseSuite.TearDownTest(c) 53 } 54 55 func (s *environSuite) TearDownSuite(c *gc.C) { 56 s.testMAASObject.Close() 57 s.restoreTimeouts() 58 s.BaseSuite.TearDownSuite(c) 59 } 60 61 func getSimpleTestConfig(c *gc.C, extraAttrs coretesting.Attrs) *config.Config { 62 attrs := coretesting.FakeConfig() 63 attrs["type"] = "maas" 64 attrs["maas-server"] = "http://maas.testing.invalid" 65 attrs["maas-oauth"] = "a:b:c" 66 for k, v := range extraAttrs { 67 attrs[k] = v 68 } 69 cfg, err := config.New(config.NoDefaults, attrs) 70 c.Assert(err, jc.ErrorIsNil) 71 return cfg 72 } 73 74 func (*environSuite) TestSetConfigValidatesFirst(c *gc.C) { 75 // SetConfig() validates the config change and disallows, for example, 76 // changes in the environment name. 77 oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "old-name"}) 78 newCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "new-name"}) 79 env, err := maas.NewEnviron(oldCfg) 80 c.Assert(err, jc.ErrorIsNil) 81 82 // SetConfig() fails, even though both the old and the new config are 83 // individually valid. 84 err = env.SetConfig(newCfg) 85 c.Assert(err, gc.NotNil) 86 c.Check(err, gc.ErrorMatches, ".*cannot change name.*") 87 88 // The old config is still in place. The new config never took effect. 89 c.Check(env.Config().Name(), gc.Equals, "old-name") 90 } 91 92 func (*environSuite) TestSetConfigRefusesChangingAgentName(c *gc.C) { 93 oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-one"}) 94 newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-two"}) 95 env, err := maas.NewEnviron(oldCfg) 96 c.Assert(err, jc.ErrorIsNil) 97 98 // SetConfig() fails, even though both the old and the new config are 99 // individually valid. 100 err = env.SetConfig(newCfgTwo) 101 c.Assert(err, gc.NotNil) 102 c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*") 103 104 // The old config is still in place. The new config never took effect. 105 c.Check(maas.MAASAgentName(env), gc.Equals, "agent-one") 106 107 // It also refuses to set it to the empty string: 108 err = env.SetConfig(getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})) 109 c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*") 110 111 // And to nil 112 err = env.SetConfig(getSimpleTestConfig(c, nil)) 113 c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*") 114 } 115 116 func (*environSuite) TestSetConfigAllowsEmptyFromNilAgentName(c *gc.C) { 117 // bug #1256179 is that when using an older version of Juju (<1.16.2) 118 // we didn't include maas-agent-name in the database, so it was 'nil' 119 // in the OldConfig. However, when setting an environment, we would set 120 // it to "" (because maasEnvironConfig.Validate ensures it is a 'valid' 121 // string). We can't create that from NewEnviron or newConfig because 122 // both of them Validate the contents. 'cmd/juju/environment 123 // SetEnvironmentCommand' instead uses conn.State.EnvironConfig() which 124 // just reads the content of the database into a map, so we just create 125 // the map ourselves. 126 127 // Even though we use 'nil' here, it actually stores it as "" because 128 // 1.16.2 already validates the value 129 baseCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""}) 130 c.Check(baseCfg.UnknownAttrs()["maas-agent-name"], gc.Equals, "") 131 env, err := maas.NewEnviron(baseCfg) 132 c.Assert(err, jc.ErrorIsNil) 133 provider := env.Provider() 134 135 attrs := coretesting.FakeConfig() 136 // These are attrs we need to make it a valid Config, but would usually 137 // be set by other infrastructure 138 attrs["type"] = "maas" 139 nilCfg, err := config.New(config.NoDefaults, attrs) 140 c.Assert(err, jc.ErrorIsNil) 141 validatedConfig, err := provider.Validate(baseCfg, nilCfg) 142 c.Assert(err, jc.ErrorIsNil) 143 c.Check(validatedConfig.UnknownAttrs()["maas-agent-name"], gc.Equals, "") 144 // However, you can't set it to an actual value if you haven't been using a value 145 valueCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-name"}) 146 _, err = provider.Validate(valueCfg, nilCfg) 147 c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*") 148 } 149 150 func (*environSuite) TestSetConfigAllowsChangingNilAgentNameToEmptyString(c *gc.C) { 151 oldCfg := getSimpleTestConfig(c, nil) 152 newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""}) 153 env, err := maas.NewEnviron(oldCfg) 154 c.Assert(err, jc.ErrorIsNil) 155 156 err = env.SetConfig(newCfgTwo) 157 c.Assert(err, jc.ErrorIsNil) 158 c.Check(maas.MAASAgentName(env), gc.Equals, "") 159 } 160 161 func (*environSuite) TestSetConfigUpdatesConfig(c *gc.C) { 162 origAttrs := coretesting.Attrs{ 163 "server-name": "http://maas2.testing.invalid", 164 "maas-oauth": "a:b:c", 165 "admin-secret": "secret", 166 } 167 cfg := getSimpleTestConfig(c, origAttrs) 168 env, err := maas.NewEnviron(cfg) 169 c.Check(err, jc.ErrorIsNil) 170 c.Check(env.Config().Name(), gc.Equals, "testenv") 171 172 anotherServer := "http://maas.testing.invalid" 173 anotherOauth := "c:d:e" 174 anotherSecret := "secret2" 175 newAttrs := coretesting.Attrs{ 176 "server-name": anotherServer, 177 "maas-oauth": anotherOauth, 178 "admin-secret": anotherSecret, 179 } 180 cfg2 := getSimpleTestConfig(c, newAttrs) 181 errSetConfig := env.SetConfig(cfg2) 182 c.Check(errSetConfig, gc.IsNil) 183 c.Check(env.Config().Name(), gc.Equals, "testenv") 184 authClient, _ := gomaasapi.NewAuthenticatedClient(anotherServer, anotherOauth, maas.APIVersion) 185 maasClient := gomaasapi.NewMAAS(*authClient) 186 MAASServer := maas.GetMAASClient(env) 187 c.Check(MAASServer, gc.DeepEquals, maasClient) 188 } 189 190 func (*environSuite) TestNewEnvironSetsConfig(c *gc.C) { 191 cfg := getSimpleTestConfig(c, nil) 192 193 env, err := maas.NewEnviron(cfg) 194 195 c.Check(err, jc.ErrorIsNil) 196 c.Check(env.Config().Name(), gc.Equals, "testenv") 197 } 198 199 var expectedCloudinitConfig = []string{ 200 "set -xe", 201 "mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'", 202 } 203 204 var expectedCloudinitConfigWithBridge = []string{ 205 "set -xe", 206 "mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'", 207 "\n# In case we already created the bridge, don't do it again.\ngrep -q \"iface juju-br0 inet dhcp\" && exit 0\n\n# Discover primary interface at run-time using the default route (if set)\nPRIMARY_IFACE=$(ip route list exact 0/0 | egrep -o 'dev [^ ]+' | cut -b5-)\n\n# If $PRIMARY_IFACE is empty, there's nothing to do.\n[ -z \"$PRIMARY_IFACE\" ] && exit 0\n\n# Change the config to make $PRIMARY_IFACE manual instead of DHCP,\n# then create the bridge and enslave $PRIMARY_IFACE into it.\ngrep -q \"iface ${PRIMARY_IFACE} inet dhcp\" /etc/network/interfaces && \\\nsed -i \"s/iface ${PRIMARY_IFACE} inet dhcp//\" /etc/network/interfaces && \\\ncat >> /etc/network/interfaces << EOF\n\n# Primary interface (defining the default route)\niface ${PRIMARY_IFACE} inet manual\n\n# Bridge to use for LXC/KVM containers\nauto juju-br0\niface juju-br0 inet dhcp\n bridge_ports ${PRIMARY_IFACE}\nEOF\n\n# Make the primary interface not auto-starting.\ngrep -q \"auto ${PRIMARY_IFACE}\" /etc/network/interfaces && \\\nsed -i \"s/auto ${PRIMARY_IFACE}//\" /etc/network/interfaces\n\n# Stop $PRIMARY_IFACE and start the bridge instead.\nifdown -v ${PRIMARY_IFACE} ; ifup -v juju-br0\n\n# Finally, remove the route using $PRIMARY_IFACE (if any) so it won't\n# clash with the same automatically added route for juju-br0 (except\n# for the device name).\nip route flush dev $PRIMARY_IFACE scope link proto kernel || true\n", 208 } 209 210 func (*environSuite) TestNewCloudinitConfigWithFeatureFlag(c *gc.C) { 211 cfg := getSimpleTestConfig(c, nil) 212 env, err := maas.NewEnviron(cfg) 213 c.Assert(err, jc.ErrorIsNil) 214 cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal") 215 c.Assert(err, jc.ErrorIsNil) 216 c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue) 217 c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig) 218 } 219 220 func (s *environSuite) TestNewCloudinitConfigNoFeatureFlag(c *gc.C) { 221 cfg := getSimpleTestConfig(c, nil) 222 env, err := maas.NewEnviron(cfg) 223 c.Assert(err, jc.ErrorIsNil) 224 testCase := func(expectedConfig []string) { 225 cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal") 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue) 228 c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedConfig) 229 } 230 // First test the default case (address allocation feature flag on). 231 testCase(expectedCloudinitConfig) 232 233 // Now test with the flag off. 234 s.SetFeatureFlags() // clear the flags. 235 testCase(expectedCloudinitConfigWithBridge) 236 } 237 238 func (*environSuite) TestNewCloudinitConfigWithDisabledNetworkManagement(c *gc.C) { 239 attrs := coretesting.Attrs{ 240 "disable-network-management": true, 241 } 242 cfg := getSimpleTestConfig(c, attrs) 243 env, err := maas.NewEnviron(cfg) 244 c.Assert(err, jc.ErrorIsNil) 245 cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal") 246 c.Assert(err, jc.ErrorIsNil) 247 c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue) 248 c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig) 249 }