github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/provider/local/environ_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package local_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 "time" 13 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/agent" 18 "github.com/juju/juju/cloudconfig/cloudinit" 19 "github.com/juju/juju/cloudconfig/instancecfg" 20 "github.com/juju/juju/constraints" 21 "github.com/juju/juju/container" 22 "github.com/juju/juju/container/lxc" 23 containertesting "github.com/juju/juju/container/testing" 24 "github.com/juju/juju/environs" 25 "github.com/juju/juju/environs/config" 26 "github.com/juju/juju/environs/jujutest" 27 envtesting "github.com/juju/juju/environs/testing" 28 "github.com/juju/juju/environs/tools" 29 "github.com/juju/juju/instance" 30 "github.com/juju/juju/juju/arch" 31 "github.com/juju/juju/juju/osenv" 32 "github.com/juju/juju/mongo" 33 "github.com/juju/juju/provider/local" 34 "github.com/juju/juju/service/common" 35 svctesting "github.com/juju/juju/service/common/testing" 36 "github.com/juju/juju/state/multiwatcher" 37 coretools "github.com/juju/juju/tools" 38 "github.com/juju/juju/version" 39 ) 40 41 const echoCommandScript = "#!/bin/sh\necho $0 \"$@\" >> $0.args" 42 43 type environSuite struct { 44 baseProviderSuite 45 envtesting.ToolsFixture 46 } 47 48 var _ = gc.Suite(&environSuite{}) 49 50 func (s *environSuite) SetUpTest(c *gc.C) { 51 s.baseProviderSuite.SetUpTest(c) 52 s.ToolsFixture.SetUpTest(c) 53 } 54 55 func (s *environSuite) TearDownTest(c *gc.C) { 56 s.ToolsFixture.TearDownTest(c) 57 s.baseProviderSuite.TearDownTest(c) 58 } 59 60 func (*environSuite) TestOpenFailsWithProtectedDirectories(c *gc.C) { 61 testConfig := minimalConfig(c) 62 testConfig, err := testConfig.Apply(map[string]interface{}{ 63 "root-dir": "/usr/lib/juju", 64 }) 65 c.Assert(err, jc.ErrorIsNil) 66 67 environ, err := local.Provider.Open(testConfig) 68 c.Assert(err, gc.ErrorMatches, "failure setting config: mkdir .* permission denied") 69 c.Assert(environ, gc.IsNil) 70 } 71 72 func (s *environSuite) TestName(c *gc.C) { 73 testConfig := minimalConfig(c) 74 environ, err := local.Provider.Open(testConfig) 75 c.Assert(err, jc.ErrorIsNil) 76 c.Assert(environ.Config().Name(), gc.Equals, "test") 77 } 78 79 func (s *environSuite) TestGetToolsMetadataSources(c *gc.C) { 80 testConfig := minimalConfig(c) 81 environ, err := local.Provider.Open(testConfig) 82 c.Assert(err, jc.ErrorIsNil) 83 sources, err := tools.GetMetadataSources(environ) 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(sources, gc.HasLen, 0) 86 } 87 88 func (*environSuite) TestSupportedArchitectures(c *gc.C) { 89 testConfig := minimalConfig(c) 90 environ, err := local.Provider.Open(testConfig) 91 c.Assert(err, jc.ErrorIsNil) 92 arches, err := environ.SupportedArchitectures() 93 c.Assert(err, jc.ErrorIsNil) 94 for _, a := range arches { 95 c.Assert(arch.IsSupportedArch(a), jc.IsTrue) 96 } 97 } 98 99 func (*environSuite) TestSupportsNetworking(c *gc.C) { 100 testConfig := minimalConfig(c) 101 environ, err := local.Provider.Open(testConfig) 102 c.Assert(err, jc.ErrorIsNil) 103 _, ok := environs.SupportsNetworking(environ) 104 c.Assert(ok, jc.IsFalse) 105 } 106 107 type localJujuTestSuite struct { 108 baseProviderSuite 109 jujutest.Tests 110 testPath string 111 fakesudo string 112 svcData *svctesting.FakeServiceData 113 } 114 115 func (s *localJujuTestSuite) SetUpTest(c *gc.C) { 116 s.baseProviderSuite.SetUpTest(c) 117 // Construct the directories first. 118 err := local.CreateDirs(c, minimalConfig(c)) 119 c.Assert(err, jc.ErrorIsNil) 120 s.testPath = c.MkDir() 121 s.fakesudo = filepath.Join(s.testPath, "sudo") 122 s.PatchEnvPathPrepend(s.testPath) 123 s.PatchValue(&lxc.TemplateLockDir, c.MkDir()) 124 s.PatchValue(&lxc.TemplateStopTimeout, 500*time.Millisecond) 125 126 // Write a fake "sudo" which records its args to sudo.args. 127 err = ioutil.WriteFile(s.fakesudo, []byte(echoCommandScript), 0755) 128 c.Assert(err, jc.ErrorIsNil) 129 130 // Add in an admin secret 131 s.Tests.TestConfig["admin-secret"] = "sekrit" 132 s.PatchValue(local.CheckIfRoot, func() bool { return false }) 133 s.Tests.SetUpTest(c) 134 135 s.PatchValue(local.ExecuteCloudConfig, func(environs.BootstrapContext, *instancecfg.InstanceConfig, cloudinit.CloudConfig) error { 136 return nil 137 }) 138 139 s.svcData = svctesting.NewFakeServiceData() 140 local.PatchServices(s.PatchValue, s.svcData) 141 } 142 143 func (s *localJujuTestSuite) TearDownTest(c *gc.C) { 144 s.Tests.TearDownTest(c) 145 s.baseProviderSuite.TearDownTest(c) 146 } 147 148 func (s *localJujuTestSuite) MakeTool(c *gc.C, name, script string) { 149 path := filepath.Join(s.testPath, name) 150 script = "#!/bin/bash\n" + script 151 err := ioutil.WriteFile(path, []byte(script), 0755) 152 c.Assert(err, jc.ErrorIsNil) 153 } 154 155 func (s *localJujuTestSuite) StoppedStatus(c *gc.C) { 156 s.MakeTool(c, "status", `echo "some-service stop/waiting"`) 157 } 158 159 func (s *localJujuTestSuite) RunningStatus(c *gc.C) { 160 s.MakeTool(c, "status", `echo "some-service start/running, process 123"`) 161 } 162 163 var _ = gc.Suite(&localJujuTestSuite{ 164 Tests: jujutest.Tests{ 165 TestConfig: minimalConfigValues(), 166 }, 167 }) 168 169 func (s *localJujuTestSuite) TestStartStop(c *gc.C) { 170 c.Skip("StartInstance not implemented yet.") 171 } 172 173 func (s *localJujuTestSuite) testBootstrap(c *gc.C, cfg *config.Config) environs.Environ { 174 ctx := envtesting.BootstrapContext(c) 175 environ, err := local.Provider.PrepareForBootstrap(ctx, cfg) 176 c.Assert(err, jc.ErrorIsNil) 177 availableTools := coretools.List{&coretools.Tools{ 178 Version: version.Current, 179 URL: "http://testing.invalid/tools.tar.gz", 180 }} 181 _, _, finalizer, err := environ.Bootstrap(ctx, environs.BootstrapParams{ 182 AvailableTools: availableTools, 183 }) 184 c.Assert(err, jc.ErrorIsNil) 185 icfg, err := instancecfg.NewBootstrapInstanceConfig(constraints.Value{}, "quantal") 186 c.Assert(err, jc.ErrorIsNil) 187 icfg.Tools = availableTools[0] 188 err = finalizer(ctx, icfg) 189 c.Assert(err, jc.ErrorIsNil) 190 return environ 191 } 192 193 func (s *localJujuTestSuite) TestBootstrap(c *gc.C) { 194 195 minCfg := minimalConfig(c) 196 197 mockFinish := func(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig, cloudcfg cloudinit.CloudConfig) error { 198 199 envCfgAttrs := minCfg.AllAttrs() 200 if val, ok := envCfgAttrs["enable-os-refresh-update"]; !ok { 201 c.Check(cloudcfg.SystemUpdate(), jc.IsFalse) 202 } else { 203 c.Check(cloudcfg.SystemUpdate(), gc.Equals, val) 204 } 205 206 if val, ok := envCfgAttrs["enable-os-upgrade"]; !ok { 207 c.Check(cloudcfg.SystemUpgrade(), jc.IsFalse) 208 } else { 209 c.Check(cloudcfg.SystemUpgrade(), gc.Equals, val) 210 } 211 212 c.Assert(icfg.AgentEnvironment, gc.Not(gc.IsNil)) 213 c.Assert(icfg.AgentEnvironment[agent.LxcBridge], gc.Not(gc.Equals), "") 214 // local does not allow machine-0 to host units 215 c.Assert(icfg.Jobs, gc.DeepEquals, []multiwatcher.MachineJob{multiwatcher.JobManageEnviron}) 216 return nil 217 } 218 s.PatchValue(local.ExecuteCloudConfig, mockFinish) 219 220 // Test that defaults are correct. 221 s.testBootstrap(c, minCfg) 222 223 // Test that overrides work. 224 minCfg, err := minCfg.Apply(map[string]interface{}{ 225 "enable-os-refresh-update": true, 226 "enable-os-upgrade": true, 227 }) 228 c.Assert(err, jc.ErrorIsNil) 229 s.testBootstrap(c, minCfg) 230 } 231 232 func (s *localJujuTestSuite) TestDestroy(c *gc.C) { 233 env := s.testBootstrap(c, minimalConfig(c)) 234 err := env.Destroy() 235 // Succeeds because there's no "agents" directory, 236 // so destroy will just return without attempting 237 // sudo or anything. 238 c.Assert(err, jc.ErrorIsNil) 239 c.Assert(s.fakesudo+".args", jc.DoesNotExist) 240 } 241 242 func (s *localJujuTestSuite) makeAgentsDir(c *gc.C, env environs.Environ) { 243 rootDir := env.Config().AllAttrs()["root-dir"].(string) 244 agentsDir := filepath.Join(rootDir, "agents") 245 err := os.Mkdir(agentsDir, 0755) 246 c.Assert(err, jc.ErrorIsNil) 247 } 248 249 func (s *localJujuTestSuite) TestDestroyCallSudo(c *gc.C) { 250 env := s.testBootstrap(c, minimalConfig(c)) 251 s.makeAgentsDir(c, env) 252 err := env.Destroy() 253 c.Assert(err, jc.ErrorIsNil) 254 data, err := ioutil.ReadFile(s.fakesudo + ".args") 255 c.Assert(err, jc.ErrorIsNil) 256 expected := []string{ 257 s.fakesudo, 258 "env", 259 "JUJU_HOME=" + osenv.JujuHome(), 260 os.Args[0], 261 "destroy-environment", 262 "-y", 263 "--force", 264 env.Config().Name(), 265 } 266 c.Assert(string(data), gc.Equals, strings.Join(expected, " ")+"\n") 267 } 268 269 type installable interface { 270 Install() error 271 Installed() (bool, error) 272 } 273 274 func (s *localJujuTestSuite) makeFakeInitScripts(c *gc.C, env environs.Environ) (installable, installable) { 275 s.MakeTool(c, "start", `echo "some-service start/running, process 123"`) 276 namespace := env.Config().AllAttrs()["namespace"].(string) 277 278 // Mongo first... 279 mongoName := mongo.ServiceName(namespace) 280 mongoConf := common.Conf{ 281 Desc: "fake mongo", 282 ExecStart: "echo FAKE", 283 } 284 mongoService := local.NewService(mongoName, mongoConf, s.svcData) 285 s.svcData.SetStatus(mongoName, "installed") 286 installed, err := mongoService.Installed() 287 c.Assert(err, jc.ErrorIsNil) 288 c.Check(installed, jc.IsTrue) 289 290 // ...then the machine agent 291 agentName := fmt.Sprintf("juju-agent-%s", namespace) 292 agentConf := common.Conf{ 293 Desc: "fake agent", 294 ExecStart: "echo FAKE", 295 } 296 agentService := local.NewService(agentName, agentConf, s.svcData) 297 s.svcData.SetStatus(agentName, "installed") 298 installed, err = agentService.Installed() 299 c.Assert(err, jc.ErrorIsNil) 300 c.Check(installed, jc.IsTrue) 301 302 return mongoService, agentService 303 } 304 305 func (s *localJujuTestSuite) TestDestroyRemovesInitServices(c *gc.C) { 306 env := s.testBootstrap(c, minimalConfig(c)) 307 s.makeAgentsDir(c, env) 308 mongoService, agentService := s.makeFakeInitScripts(c, env) 309 s.PatchValue(local.CheckIfRoot, func() bool { return true }) 310 311 err := env.Destroy() 312 c.Assert(err, jc.ErrorIsNil) 313 314 installed, err := mongoService.Installed() 315 c.Assert(err, jc.ErrorIsNil) 316 c.Check(installed, jc.IsFalse) 317 installed, err = agentService.Installed() 318 c.Assert(err, jc.ErrorIsNil) 319 c.Check(installed, jc.IsFalse) 320 } 321 322 func (s *localJujuTestSuite) TestDestroyRemovesContainers(c *gc.C) { 323 env := s.testBootstrap(c, minimalConfig(c)) 324 s.makeAgentsDir(c, env) 325 s.PatchValue(local.CheckIfRoot, func() bool { return true }) 326 327 namespace := env.Config().AllAttrs()["namespace"].(string) 328 manager, err := lxc.NewContainerManager(container.ManagerConfig{ 329 container.ConfigName: namespace, 330 container.ConfigLogDir: "logdir", 331 "use-clone": "false", 332 }, nil) 333 c.Assert(err, jc.ErrorIsNil) 334 335 machine1 := containertesting.CreateContainer(c, manager, "1") 336 337 err = env.Destroy() 338 c.Assert(err, jc.ErrorIsNil) 339 340 container := s.ContainerFactory.New(string(machine1.Id())) 341 c.Assert(container.IsConstructed(), jc.IsFalse) 342 } 343 344 func (s *localJujuTestSuite) TestBootstrapRemoveLeftovers(c *gc.C) { 345 cfg := minimalConfig(c) 346 rootDir := cfg.AllAttrs()["root-dir"].(string) 347 348 // Create a dir inside local/log that should be removed by Bootstrap. 349 logThings := filepath.Join(rootDir, "log", "things") 350 err := os.MkdirAll(logThings, 0755) 351 c.Assert(err, jc.ErrorIsNil) 352 353 // Create a cloud-init-output.log in root-dir that should be 354 // removed/truncated by Bootstrap. 355 cloudInitOutputLog := filepath.Join(rootDir, "cloud-init-output.log") 356 err = ioutil.WriteFile(cloudInitOutputLog, []byte("ohai"), 0644) 357 c.Assert(err, jc.ErrorIsNil) 358 359 s.testBootstrap(c, cfg) 360 c.Assert(logThings, jc.DoesNotExist) 361 c.Assert(cloudInitOutputLog, jc.DoesNotExist) 362 c.Assert(filepath.Join(rootDir, "log"), jc.IsSymlink) 363 } 364 365 func (s *localJujuTestSuite) TestConstraintsValidator(c *gc.C) { 366 ctx := envtesting.BootstrapContext(c) 367 env, err := local.Provider.PrepareForBootstrap(ctx, minimalConfig(c)) 368 c.Assert(err, jc.ErrorIsNil) 369 validator, err := env.ConstraintsValidator() 370 c.Assert(err, jc.ErrorIsNil) 371 hostArch := arch.HostArch() 372 cons := constraints.MustParse(fmt.Sprintf("arch=%s instance-type=foo tags=bar cpu-power=10 cpu-cores=2", hostArch)) 373 unsupported, err := validator.Validate(cons) 374 c.Assert(err, jc.ErrorIsNil) 375 c.Assert(unsupported, jc.SameContents, []string{"cpu-cores", "cpu-power", "instance-type", "tags"}) 376 } 377 378 func (s *localJujuTestSuite) TestConstraintsValidatorVocab(c *gc.C) { 379 env := s.Prepare(c) 380 validator, err := env.ConstraintsValidator() 381 c.Assert(err, jc.ErrorIsNil) 382 383 hostArch := arch.HostArch() 384 var invalidArch string 385 for _, a := range arch.AllSupportedArches { 386 if a != hostArch { 387 invalidArch = a 388 break 389 } 390 } 391 cons := constraints.MustParse(fmt.Sprintf("arch=%s", invalidArch)) 392 _, err = validator.Validate(cons) 393 c.Assert(err, gc.ErrorMatches, "invalid constraint value: arch="+invalidArch+"\nvalid values are:.*") 394 } 395 396 func (s *localJujuTestSuite) TestStateServerInstances(c *gc.C) { 397 env := s.testBootstrap(c, minimalConfig(c)) 398 399 instances, err := env.StateServerInstances() 400 c.Assert(err, gc.Equals, environs.ErrNotBootstrapped) 401 c.Assert(instances, gc.HasLen, 0) 402 403 s.makeAgentsDir(c, env) 404 instances, err = env.StateServerInstances() 405 c.Assert(err, jc.ErrorIsNil) 406 c.Assert(instances, gc.DeepEquals, []instance.Id{"localhost"}) 407 }