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