github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/environs/jujutest/livetests.go (about) 1 // Copyright 2011, 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package jujutest 5 6 import ( 7 "fmt" 8 "path/filepath" 9 "time" 10 11 "github.com/juju/errors" 12 gitjujutesting "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils" 15 "github.com/juju/utils/arch" 16 "github.com/juju/utils/series" 17 "github.com/juju/version" 18 gc "gopkg.in/check.v1" 19 "gopkg.in/juju/charmrepo.v2-unstable" 20 21 "github.com/juju/juju/api" 22 "github.com/juju/juju/cloud" 23 "github.com/juju/juju/cloudconfig/instancecfg" 24 "github.com/juju/juju/constraints" 25 "github.com/juju/juju/environs" 26 "github.com/juju/juju/environs/bootstrap" 27 "github.com/juju/juju/environs/config" 28 "github.com/juju/juju/environs/filestorage" 29 sstesting "github.com/juju/juju/environs/simplestreams/testing" 30 "github.com/juju/juju/environs/storage" 31 "github.com/juju/juju/environs/sync" 32 envtesting "github.com/juju/juju/environs/testing" 33 envtools "github.com/juju/juju/environs/tools" 34 envtoolstesting "github.com/juju/juju/environs/tools/testing" 35 "github.com/juju/juju/instance" 36 "github.com/juju/juju/juju" 37 jujutesting "github.com/juju/juju/juju/testing" 38 "github.com/juju/juju/jujuclient" 39 "github.com/juju/juju/jujuclient/jujuclienttesting" 40 "github.com/juju/juju/network" 41 "github.com/juju/juju/provider/dummy" 42 "github.com/juju/juju/state" 43 statetesting "github.com/juju/juju/state/testing" 44 "github.com/juju/juju/testcharms" 45 coretesting "github.com/juju/juju/testing" 46 coretools "github.com/juju/juju/tools" 47 jujuversion "github.com/juju/juju/version" 48 ) 49 50 // LiveTests contains tests that are designed to run against a live server 51 // (e.g. Amazon EC2). The Environ is opened once only for all the tests 52 // in the suite, stored in Env, and Destroyed after the suite has completed. 53 type LiveTests struct { 54 gitjujutesting.CleanupSuite 55 56 envtesting.ToolsFixture 57 sstesting.TestDataSuite 58 59 // TestConfig contains the configuration attributes for opening an environment. 60 TestConfig coretesting.Attrs 61 62 // Credential contains the credential for preparing an environment for 63 // bootstrapping. If this is unset, empty credentials will be used. 64 Credential cloud.Credential 65 66 // CloudRegion contains the cloud region name to create resources in. 67 CloudRegion string 68 69 // CloudEndpoint contains the cloud API endpoint to communicate with. 70 CloudEndpoint string 71 72 // Attempt holds a strategy for waiting until the environment 73 // becomes logically consistent. 74 Attempt utils.AttemptStrategy 75 76 // CanOpenState should be true if the testing environment allows 77 // the state to be opened after bootstrapping. 78 CanOpenState bool 79 80 // HasProvisioner should be true if the environment has 81 // a provisioning agent. 82 HasProvisioner bool 83 84 // Env holds the currently opened environment. 85 // This is set by PrepareOnce and BootstrapOnce. 86 Env environs.Environ 87 88 // ControllerStore holds the controller related informtion 89 // such as controllers, accounts, etc., used when preparing 90 // the environment. This is initialized by SetUpSuite. 91 ControllerStore jujuclient.ClientStore 92 93 prepared bool 94 bootstrapped bool 95 toolsStorage storage.Storage 96 } 97 98 func (t *LiveTests) SetUpSuite(c *gc.C) { 99 t.CleanupSuite.SetUpSuite(c) 100 t.TestDataSuite.SetUpSuite(c) 101 t.ControllerStore = jujuclienttesting.NewMemStore() 102 t.PatchValue(&juju.JujuPublicKey, sstesting.SignedMetadataPublicKey) 103 } 104 105 func (t *LiveTests) SetUpTest(c *gc.C) { 106 t.CleanupSuite.SetUpTest(c) 107 t.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber) 108 storageDir := c.MkDir() 109 baseUrlPath := filepath.Join(storageDir, "tools") 110 t.DefaultBaseURL = utils.MakeFileURL(baseUrlPath) 111 t.ToolsFixture.SetUpTest(c) 112 stor, err := filestorage.NewFileStorageWriter(storageDir) 113 c.Assert(err, jc.ErrorIsNil) 114 t.UploadFakeTools(c, stor, "released", "released") 115 t.toolsStorage = stor 116 t.CleanupSuite.PatchValue(&envtools.BundleTools, envtoolstesting.GetMockBundleTools(c)) 117 } 118 119 func (t *LiveTests) TearDownSuite(c *gc.C) { 120 t.Destroy(c) 121 t.TestDataSuite.TearDownSuite(c) 122 t.CleanupSuite.TearDownSuite(c) 123 } 124 125 func (t *LiveTests) TearDownTest(c *gc.C) { 126 t.ToolsFixture.TearDownTest(c) 127 t.CleanupSuite.TearDownTest(c) 128 } 129 130 // PrepareOnce ensures that the environment is 131 // available and prepared. It sets t.Env appropriately. 132 func (t *LiveTests) PrepareOnce(c *gc.C) { 133 if t.prepared { 134 return 135 } 136 args := t.prepareForBootstrapParams(c) 137 e, err := environs.Prepare(envtesting.BootstrapContext(c), t.ControllerStore, args) 138 c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig)) 139 c.Assert(e, gc.NotNil) 140 t.Env = e 141 t.prepared = true 142 } 143 144 func (t *LiveTests) prepareForBootstrapParams(c *gc.C) environs.PrepareParams { 145 credential := t.Credential 146 if credential.AuthType() == "" { 147 credential = cloud.NewEmptyCredential() 148 } 149 return environs.PrepareParams{ 150 BaseConfig: t.TestConfig, 151 Credential: credential, 152 CloudEndpoint: t.CloudEndpoint, 153 CloudRegion: t.CloudRegion, 154 ControllerName: t.TestConfig["name"].(string), 155 CloudName: t.TestConfig["type"].(string), 156 } 157 } 158 159 func (t *LiveTests) BootstrapOnce(c *gc.C) { 160 if t.bootstrapped { 161 return 162 } 163 t.PrepareOnce(c) 164 // We only build and upload tools if there will be a state agent that 165 // we could connect to (actual live tests, rather than local-only) 166 cons := constraints.MustParse("mem=2G") 167 if t.CanOpenState { 168 _, err := sync.Upload(t.toolsStorage, "released", nil, series.LatestLts()) 169 c.Assert(err, jc.ErrorIsNil) 170 } 171 err := bootstrap.Bootstrap(envtesting.BootstrapContext(c), t.Env, bootstrap.BootstrapParams{ 172 BootstrapConstraints: cons, 173 ModelConstraints: cons, 174 }) 175 c.Assert(err, jc.ErrorIsNil) 176 t.bootstrapped = true 177 } 178 179 func (t *LiveTests) Destroy(c *gc.C) { 180 if t.Env == nil { 181 return 182 } 183 err := environs.Destroy(t.Env.Config().Name(), t.Env, t.ControllerStore) 184 c.Assert(err, jc.ErrorIsNil) 185 t.bootstrapped = false 186 t.prepared = false 187 t.Env = nil 188 } 189 190 func (t *LiveTests) TestPrechecker(c *gc.C) { 191 // Providers may implement Prechecker. If they do, then they should 192 // return nil for empty constraints (excluding the null provider). 193 prechecker, ok := t.Env.(state.Prechecker) 194 if !ok { 195 return 196 } 197 const placement = "" 198 err := prechecker.PrecheckInstance("precise", constraints.Value{}, placement) 199 c.Assert(err, jc.ErrorIsNil) 200 } 201 202 // TestStartStop is similar to Tests.TestStartStop except 203 // that it does not assume a pristine environment. 204 func (t *LiveTests) TestStartStop(c *gc.C) { 205 t.BootstrapOnce(c) 206 207 inst, _ := jujutesting.AssertStartInstance(c, t.Env, "0") 208 c.Assert(inst, gc.NotNil) 209 id0 := inst.Id() 210 211 insts, err := t.Env.Instances([]instance.Id{id0, id0}) 212 c.Assert(err, jc.ErrorIsNil) 213 c.Assert(insts, gc.HasLen, 2) 214 c.Assert(insts[0].Id(), gc.Equals, id0) 215 c.Assert(insts[1].Id(), gc.Equals, id0) 216 217 // Asserting on the return of AllInstances makes the test fragile, 218 // as even comparing the before and after start values can be thrown 219 // off if other instances have been created or destroyed in the same 220 // time frame. Instead, just check the instance we created exists. 221 insts, err = t.Env.AllInstances() 222 c.Assert(err, jc.ErrorIsNil) 223 found := false 224 for _, inst := range insts { 225 if inst.Id() == id0 { 226 c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts)) 227 found = true 228 } 229 } 230 c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts)) 231 232 addresses, err := jujutesting.WaitInstanceAddresses(t.Env, inst.Id()) 233 c.Assert(err, jc.ErrorIsNil) 234 c.Assert(addresses, gc.Not(gc.HasLen), 0) 235 236 insts, err = t.Env.Instances([]instance.Id{id0, ""}) 237 c.Assert(err, gc.Equals, environs.ErrPartialInstances) 238 c.Assert(insts, gc.HasLen, 2) 239 c.Check(insts[0].Id(), gc.Equals, id0) 240 c.Check(insts[1], gc.IsNil) 241 242 err = t.Env.StopInstances(inst.Id()) 243 c.Assert(err, jc.ErrorIsNil) 244 245 // The machine may not be marked as shutting down 246 // immediately. Repeat a few times to ensure we get the error. 247 for a := t.Attempt.Start(); a.Next(); { 248 insts, err = t.Env.Instances([]instance.Id{id0}) 249 if err != nil { 250 break 251 } 252 } 253 c.Assert(err, gc.Equals, environs.ErrNoInstances) 254 c.Assert(insts, gc.HasLen, 0) 255 } 256 257 func (t *LiveTests) TestPorts(c *gc.C) { 258 t.BootstrapOnce(c) 259 260 inst1, _ := jujutesting.AssertStartInstance(c, t.Env, "1") 261 c.Assert(inst1, gc.NotNil) 262 defer t.Env.StopInstances(inst1.Id()) 263 ports, err := inst1.Ports("1") 264 c.Assert(err, jc.ErrorIsNil) 265 c.Assert(ports, gc.HasLen, 0) 266 267 inst2, _ := jujutesting.AssertStartInstance(c, t.Env, "2") 268 c.Assert(inst2, gc.NotNil) 269 ports, err = inst2.Ports("2") 270 c.Assert(err, jc.ErrorIsNil) 271 c.Assert(ports, gc.HasLen, 0) 272 defer t.Env.StopInstances(inst2.Id()) 273 274 // Open some ports and check they're there. 275 err = inst1.OpenPorts("1", []network.PortRange{{67, 67, "udp"}, {45, 45, "tcp"}, {80, 100, "tcp"}}) 276 c.Assert(err, jc.ErrorIsNil) 277 ports, err = inst1.Ports("1") 278 c.Assert(err, jc.ErrorIsNil) 279 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {80, 100, "tcp"}, {67, 67, "udp"}}) 280 ports, err = inst2.Ports("2") 281 c.Assert(err, jc.ErrorIsNil) 282 c.Assert(ports, gc.HasLen, 0) 283 284 err = inst2.OpenPorts("2", []network.PortRange{{89, 89, "tcp"}, {45, 45, "tcp"}, {20, 30, "tcp"}}) 285 c.Assert(err, jc.ErrorIsNil) 286 287 // Check there's no crosstalk to another machine 288 ports, err = inst2.Ports("2") 289 c.Assert(err, jc.ErrorIsNil) 290 c.Assert(ports, gc.DeepEquals, []network.PortRange{{20, 30, "tcp"}, {45, 45, "tcp"}, {89, 89, "tcp"}}) 291 ports, err = inst1.Ports("1") 292 c.Assert(err, jc.ErrorIsNil) 293 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {80, 100, "tcp"}, {67, 67, "udp"}}) 294 295 // Check that opening the same port again is ok. 296 oldPorts, err := inst2.Ports("2") 297 c.Assert(err, jc.ErrorIsNil) 298 err = inst2.OpenPorts("2", []network.PortRange{{45, 45, "tcp"}}) 299 c.Assert(err, jc.ErrorIsNil) 300 err = inst2.OpenPorts("2", []network.PortRange{{20, 30, "tcp"}}) 301 c.Assert(err, jc.ErrorIsNil) 302 ports, err = inst2.Ports("2") 303 c.Assert(err, jc.ErrorIsNil) 304 c.Assert(ports, gc.DeepEquals, oldPorts) 305 306 // Check that opening the same port again and another port is ok. 307 err = inst2.OpenPorts("2", []network.PortRange{{45, 45, "tcp"}, {99, 99, "tcp"}}) 308 c.Assert(err, jc.ErrorIsNil) 309 ports, err = inst2.Ports("2") 310 c.Assert(err, jc.ErrorIsNil) 311 c.Assert(ports, gc.DeepEquals, []network.PortRange{{20, 30, "tcp"}, {45, 45, "tcp"}, {89, 89, "tcp"}, {99, 99, "tcp"}}) 312 313 err = inst2.ClosePorts("2", []network.PortRange{{45, 45, "tcp"}, {99, 99, "tcp"}, {20, 30, "tcp"}}) 314 c.Assert(err, jc.ErrorIsNil) 315 316 // Check that we can close ports and that there's no crosstalk. 317 ports, err = inst2.Ports("2") 318 c.Assert(err, jc.ErrorIsNil) 319 c.Assert(ports, gc.DeepEquals, []network.PortRange{{89, 89, "tcp"}}) 320 ports, err = inst1.Ports("1") 321 c.Assert(err, jc.ErrorIsNil) 322 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {80, 100, "tcp"}, {67, 67, "udp"}}) 323 324 // Check that we can close multiple ports. 325 err = inst1.ClosePorts("1", []network.PortRange{{45, 45, "tcp"}, {67, 67, "udp"}, {80, 100, "tcp"}}) 326 c.Assert(err, jc.ErrorIsNil) 327 ports, err = inst1.Ports("1") 328 c.Assert(ports, gc.HasLen, 0) 329 330 // Check that we can close ports that aren't there. 331 err = inst2.ClosePorts("2", []network.PortRange{{111, 111, "tcp"}, {222, 222, "udp"}, {600, 700, "tcp"}}) 332 c.Assert(err, jc.ErrorIsNil) 333 ports, err = inst2.Ports("2") 334 c.Assert(ports, gc.DeepEquals, []network.PortRange{{89, 89, "tcp"}}) 335 336 // Check errors when acting on environment. 337 err = t.Env.OpenPorts([]network.PortRange{{80, 80, "tcp"}}) 338 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on model`) 339 340 err = t.Env.ClosePorts([]network.PortRange{{80, 80, "tcp"}}) 341 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on model`) 342 343 _, err = t.Env.Ports() 344 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ports from model`) 345 } 346 347 func (t *LiveTests) TestGlobalPorts(c *gc.C) { 348 t.BootstrapOnce(c) 349 350 // Change configuration. 351 oldConfig := t.Env.Config() 352 defer func() { 353 err := t.Env.SetConfig(oldConfig) 354 c.Assert(err, jc.ErrorIsNil) 355 }() 356 357 attrs := t.Env.Config().AllAttrs() 358 attrs["firewall-mode"] = config.FwGlobal 359 newConfig, err := t.Env.Config().Apply(attrs) 360 c.Assert(err, jc.ErrorIsNil) 361 err = t.Env.SetConfig(newConfig) 362 c.Assert(err, jc.ErrorIsNil) 363 364 // Create instances and check open ports on both instances. 365 inst1, _ := jujutesting.AssertStartInstance(c, t.Env, "1") 366 defer t.Env.StopInstances(inst1.Id()) 367 ports, err := t.Env.Ports() 368 c.Assert(err, jc.ErrorIsNil) 369 c.Assert(ports, gc.HasLen, 0) 370 371 inst2, _ := jujutesting.AssertStartInstance(c, t.Env, "2") 372 ports, err = t.Env.Ports() 373 c.Assert(err, jc.ErrorIsNil) 374 c.Assert(ports, gc.HasLen, 0) 375 defer t.Env.StopInstances(inst2.Id()) 376 377 err = t.Env.OpenPorts([]network.PortRange{{67, 67, "udp"}, {45, 45, "tcp"}, {89, 89, "tcp"}, {99, 99, "tcp"}, {100, 110, "tcp"}}) 378 c.Assert(err, jc.ErrorIsNil) 379 380 ports, err = t.Env.Ports() 381 c.Assert(err, jc.ErrorIsNil) 382 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {89, 89, "tcp"}, {99, 99, "tcp"}, {100, 110, "tcp"}, {67, 67, "udp"}}) 383 384 // Check closing some ports. 385 err = t.Env.ClosePorts([]network.PortRange{{99, 99, "tcp"}, {67, 67, "udp"}}) 386 c.Assert(err, jc.ErrorIsNil) 387 388 ports, err = t.Env.Ports() 389 c.Assert(err, jc.ErrorIsNil) 390 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {89, 89, "tcp"}, {100, 110, "tcp"}}) 391 392 // Check that we can close ports that aren't there. 393 err = t.Env.ClosePorts([]network.PortRange{{111, 111, "tcp"}, {222, 222, "udp"}, {2000, 2500, "tcp"}}) 394 c.Assert(err, jc.ErrorIsNil) 395 396 ports, err = t.Env.Ports() 397 c.Assert(err, jc.ErrorIsNil) 398 c.Assert(ports, gc.DeepEquals, []network.PortRange{{45, 45, "tcp"}, {89, 89, "tcp"}, {100, 110, "tcp"}}) 399 400 // Check errors when acting on instances. 401 err = inst1.OpenPorts("1", []network.PortRange{{80, 80, "tcp"}}) 402 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`) 403 404 err = inst1.ClosePorts("1", []network.PortRange{{80, 80, "tcp"}}) 405 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`) 406 407 _, err = inst1.Ports("1") 408 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ports from instance`) 409 } 410 411 func (t *LiveTests) TestBootstrapMultiple(c *gc.C) { 412 // bootstrap.Bootstrap no longer raises errors if the environment is 413 // already up, this has been moved into the bootstrap command. 414 t.BootstrapOnce(c) 415 416 c.Logf("destroy env") 417 env := t.Env 418 t.Destroy(c) 419 err := env.Destroy() // Again, should work fine and do nothing. 420 c.Assert(err, jc.ErrorIsNil) 421 422 // check that we can bootstrap after destroy 423 t.BootstrapOnce(c) 424 } 425 426 func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) { 427 if !t.CanOpenState || !t.HasProvisioner { 428 c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner)) 429 } 430 t.BootstrapOnce(c) 431 432 // TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts. 433 434 c.Logf("opening state") 435 st := t.Env.(jujutesting.GetStater).GetStateInAPIServer() 436 437 env, err := st.Model() 438 c.Assert(err, jc.ErrorIsNil) 439 owner := env.Owner() 440 441 c.Logf("opening API connection") 442 apiInfo, err := environs.APIInfo(t.Env) 443 c.Assert(err, jc.ErrorIsNil) 444 apiInfo.Tag = owner 445 apiInfo.Password = t.Env.Config().AdminSecret() 446 apiState, err := api.Open(apiInfo, api.DefaultDialOpts()) 447 c.Assert(err, jc.ErrorIsNil) 448 defer apiState.Close() 449 450 // Check that the agent version has made it through the 451 // bootstrap process (it's optional in the config.Config) 452 cfg, err := st.ModelConfig() 453 c.Assert(err, jc.ErrorIsNil) 454 agentVersion, ok := cfg.AgentVersion() 455 c.Check(ok, jc.IsTrue) 456 c.Check(agentVersion, gc.Equals, jujuversion.Current) 457 458 // Check that the constraints have been set in the environment. 459 cons, err := st.ModelConstraints() 460 c.Assert(err, jc.ErrorIsNil) 461 c.Assert(cons.String(), gc.Equals, "mem=2048M") 462 463 // Wait for machine agent to come up on the bootstrap 464 // machine and find the deployed series from that. 465 m0, err := st.Machine("0") 466 c.Assert(err, jc.ErrorIsNil) 467 468 instId0, err := m0.InstanceId() 469 c.Assert(err, jc.ErrorIsNil) 470 471 // Check that the API connection is working. 472 status, err := apiState.Client().Status(nil) 473 c.Assert(err, jc.ErrorIsNil) 474 c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0)) 475 476 mw0 := newMachineToolWaiter(m0) 477 defer mw0.Stop() 478 479 // If the series has not been specified, we expect the most recent Ubuntu LTS release to be used. 480 expectedVersion := version.Binary{ 481 Number: jujuversion.Current, 482 Arch: arch.HostArch(), 483 Series: series.LatestLts(), 484 } 485 486 mtools0 := waitAgentTools(c, mw0, expectedVersion) 487 488 // Create a new service and deploy a unit of it. 489 c.Logf("deploying service") 490 repoDir := c.MkDir() 491 url := testcharms.Repo.ClonedURL(repoDir, mtools0.Version.Series, "dummy") 492 sch, err := jujutesting.PutCharm(st, url, &charmrepo.LocalRepository{Path: repoDir}, false) 493 c.Assert(err, jc.ErrorIsNil) 494 svc, err := st.AddService(state.AddServiceArgs{Name: "dummy", Owner: owner.String(), Charm: sch}) 495 c.Assert(err, jc.ErrorIsNil) 496 units, err := juju.AddUnits(st, svc, 1, nil) 497 c.Assert(err, jc.ErrorIsNil) 498 unit := units[0] 499 500 // Wait for the unit's machine and associated agent to come up 501 // and announce itself. 502 mid1, err := unit.AssignedMachineId() 503 c.Assert(err, jc.ErrorIsNil) 504 m1, err := st.Machine(mid1) 505 c.Assert(err, jc.ErrorIsNil) 506 mw1 := newMachineToolWaiter(m1) 507 defer mw1.Stop() 508 waitAgentTools(c, mw1, mtools0.Version) 509 510 err = m1.Refresh() 511 c.Assert(err, jc.ErrorIsNil) 512 instId1, err := m1.InstanceId() 513 c.Assert(err, jc.ErrorIsNil) 514 uw := newUnitToolWaiter(unit) 515 defer uw.Stop() 516 utools := waitAgentTools(c, uw, expectedVersion) 517 518 // Check that we can upgrade the environment. 519 newVersion := utools.Version 520 newVersion.Patch++ 521 t.checkUpgrade(c, st, newVersion, mw0, mw1, uw) 522 523 // BUG(niemeyer): Logic below is very much wrong. Must be: 524 // 525 // 1. EnsureDying on the unit and EnsureDying on the machine 526 // 2. Unit dies by itself 527 // 3. Machine removes dead unit 528 // 4. Machine dies by itself 529 // 5. Provisioner removes dead machine 530 // 531 532 // Now remove the unit and its assigned machine and 533 // check that the PA removes it. 534 c.Logf("removing unit") 535 err = unit.Destroy() 536 c.Assert(err, jc.ErrorIsNil) 537 538 // Wait until unit is dead 539 uwatch := unit.Watch() 540 defer uwatch.Stop() 541 for unit.Life() != state.Dead { 542 c.Logf("waiting for unit change") 543 <-uwatch.Changes() 544 err := unit.Refresh() 545 c.Logf("refreshed; err %v", err) 546 if errors.IsNotFound(err) { 547 c.Logf("unit has been removed") 548 break 549 } 550 c.Assert(err, jc.ErrorIsNil) 551 } 552 for { 553 c.Logf("destroying machine") 554 err := m1.Destroy() 555 if err == nil { 556 break 557 } 558 c.Assert(err, gc.FitsTypeOf, &state.HasAssignedUnitsError{}) 559 time.Sleep(5 * time.Second) 560 err = m1.Refresh() 561 if errors.IsNotFound(err) { 562 break 563 } 564 c.Assert(err, jc.ErrorIsNil) 565 } 566 c.Logf("waiting for instance to be removed") 567 t.assertStopInstance(c, t.Env, instId1) 568 } 569 570 type tooler interface { 571 Life() state.Life 572 AgentTools() (*coretools.Tools, error) 573 Refresh() error 574 String() string 575 } 576 577 type watcher interface { 578 Stop() error 579 Err() error 580 } 581 582 type toolsWaiter struct { 583 lastTools *coretools.Tools 584 // changes is a chan of struct{} so that it can 585 // be used with different kinds of entity watcher. 586 changes chan struct{} 587 watcher watcher 588 tooler tooler 589 } 590 591 func newMachineToolWaiter(m *state.Machine) *toolsWaiter { 592 w := m.Watch() 593 waiter := &toolsWaiter{ 594 changes: make(chan struct{}, 1), 595 watcher: w, 596 tooler: m, 597 } 598 go func() { 599 for _ = range w.Changes() { 600 waiter.changes <- struct{}{} 601 } 602 close(waiter.changes) 603 }() 604 return waiter 605 } 606 607 func newUnitToolWaiter(u *state.Unit) *toolsWaiter { 608 w := u.Watch() 609 waiter := &toolsWaiter{ 610 changes: make(chan struct{}, 1), 611 watcher: w, 612 tooler: u, 613 } 614 go func() { 615 for _ = range w.Changes() { 616 waiter.changes <- struct{}{} 617 } 618 close(waiter.changes) 619 }() 620 return waiter 621 } 622 623 func (w *toolsWaiter) Stop() error { 624 return w.watcher.Stop() 625 } 626 627 // NextTools returns the next changed tools, waiting 628 // until the tools are actually set. 629 func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) { 630 for _ = range w.changes { 631 err := w.tooler.Refresh() 632 if err != nil { 633 return nil, fmt.Errorf("cannot refresh: %v", err) 634 } 635 if w.tooler.Life() == state.Dead { 636 return nil, fmt.Errorf("object is dead") 637 } 638 tools, err := w.tooler.AgentTools() 639 if errors.IsNotFound(err) { 640 c.Logf("tools not yet set") 641 continue 642 } 643 if err != nil { 644 return nil, err 645 } 646 changed := w.lastTools == nil || *tools != *w.lastTools 647 w.lastTools = tools 648 if changed { 649 return tools, nil 650 } 651 c.Logf("found same tools") 652 } 653 return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err()) 654 } 655 656 // waitAgentTools waits for the given agent 657 // to start and returns the tools that it is running. 658 func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools { 659 c.Logf("waiting for %v to signal agent version", w.tooler.String()) 660 tools, err := w.NextTools(c) 661 c.Assert(err, jc.ErrorIsNil) 662 c.Check(tools.Version, gc.Equals, expect) 663 return tools 664 } 665 666 // checkUpgrade sets the environment agent version and checks that 667 // all the provided watchers upgrade to the requested version. 668 func (t *LiveTests) checkUpgrade(c *gc.C, st *state.State, newVersion version.Binary, waiters ...*toolsWaiter) { 669 c.Logf("putting testing version of juju tools") 670 upgradeTools, err := sync.Upload(t.toolsStorage, "released", &newVersion.Number, newVersion.Series) 671 c.Assert(err, jc.ErrorIsNil) 672 // sync.Upload always returns tools for the series on which the tests are running. 673 // We are only interested in checking the version.Number below so need to fake the 674 // upgraded tools series to match that of newVersion. 675 upgradeTools.Version.Series = newVersion.Series 676 677 // Check that the put version really is the version we expect. 678 c.Assert(upgradeTools.Version, gc.Equals, newVersion) 679 err = statetesting.SetAgentVersion(st, newVersion.Number) 680 c.Assert(err, jc.ErrorIsNil) 681 682 for i, w := range waiters { 683 c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String()) 684 685 waitAgentTools(c, w, newVersion) 686 c.Logf("upgrade %d successful", i) 687 } 688 } 689 690 var waitAgent = utils.AttemptStrategy{ 691 Total: 30 * time.Second, 692 Delay: 1 * time.Second, 693 } 694 695 func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) { 696 var err error 697 for a := waitAgent.Start(); a.Next(); { 698 _, err = t.Env.Instances([]instance.Id{instId}) 699 if err == nil { 700 continue 701 } 702 if err == environs.ErrNoInstances { 703 return 704 } 705 c.Logf("error from Instances: %v", err) 706 } 707 c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total) 708 } 709 710 // Check that we get a consistent error when asking for an instance without 711 // a valid machine config. 712 func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) { 713 machineId := "4" 714 stateInfo := jujutesting.FakeStateInfo(machineId) 715 apiInfo := jujutesting.FakeAPIInfo(machineId) 716 instanceConfig, err := instancecfg.NewInstanceConfig(machineId, "", "released", "quantal", "", true, stateInfo, apiInfo) 717 c.Assert(err, jc.ErrorIsNil) 718 719 t.PrepareOnce(c) 720 possibleTools := coretools.List(envtesting.AssertUploadFakeToolsVersions( 721 c, t.toolsStorage, "released", "released", version.MustParseBinary("5.4.5-trusty-amd64"), 722 )) 723 params := environs.StartInstanceParams{ 724 Tools: possibleTools, 725 InstanceConfig: instanceConfig, 726 } 727 err = jujutesting.SetImageMetadata( 728 t.Env, 729 possibleTools.AllSeries(), 730 possibleTools.Arches(), 731 ¶ms.ImageMetadata, 732 ) 733 c.Check(err, jc.ErrorIsNil) 734 result, err := t.Env.StartInstance(params) 735 if result != nil && result.Instance != nil { 736 err := t.Env.StopInstances(result.Instance.Id()) 737 c.Check(err, jc.ErrorIsNil) 738 } 739 c.Assert(result, gc.IsNil) 740 c.Assert(err, gc.ErrorMatches, ".*missing machine nonce") 741 } 742 743 func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) { 744 if !t.HasProvisioner { 745 c.Skip("HasProvisioner is false; cannot test deployment") 746 } 747 748 current := version.Binary{ 749 Number: jujuversion.Current, 750 Arch: arch.HostArch(), 751 Series: series.HostSeries(), 752 } 753 other := current 754 other.Series = "quantal" 755 if current == other { 756 other.Series = "precise" 757 } 758 759 dummyCfg := dummy.SampleConfig().Merge(coretesting.Attrs{ 760 "controller": false, 761 "name": "dummy storage", 762 }) 763 args := t.prepareForBootstrapParams(c) 764 args.BaseConfig = dummyCfg 765 dummyenv, err := environs.Prepare(envtesting.BootstrapContext(c), 766 jujuclienttesting.NewMemStore(), 767 args, 768 ) 769 c.Assert(err, jc.ErrorIsNil) 770 defer dummyenv.Destroy() 771 772 t.Destroy(c) 773 774 attrs := t.TestConfig.Merge(coretesting.Attrs{ 775 "name": "livetests", 776 "default-series": other.Series, 777 }) 778 args.BaseConfig = attrs 779 env, err := environs.Prepare(envtesting.BootstrapContext(c), 780 t.ControllerStore, 781 args) 782 c.Assert(err, jc.ErrorIsNil) 783 defer environs.Destroy("livetests", env, t.ControllerStore) 784 785 err = bootstrap.Bootstrap(envtesting.BootstrapContext(c), env, bootstrap.BootstrapParams{}) 786 c.Assert(err, jc.ErrorIsNil) 787 788 st := t.Env.(jujutesting.GetStater).GetStateInAPIServer() 789 // Wait for machine agent to come up on the bootstrap 790 // machine and ensure it deployed the proper series. 791 m0, err := st.Machine("0") 792 c.Assert(err, jc.ErrorIsNil) 793 mw0 := newMachineToolWaiter(m0) 794 defer mw0.Stop() 795 796 waitAgentTools(c, mw0, other) 797 }