github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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 "bytes" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "strings" 12 "time" 13 14 gc "launchpad.net/gocheck" 15 16 "launchpad.net/juju-core/charm" 17 "launchpad.net/juju-core/constraints" 18 "launchpad.net/juju-core/environs" 19 "launchpad.net/juju-core/environs/bootstrap" 20 "launchpad.net/juju-core/environs/config" 21 "launchpad.net/juju-core/environs/configstore" 22 "launchpad.net/juju-core/environs/storage" 23 "launchpad.net/juju-core/environs/sync" 24 envtesting "launchpad.net/juju-core/environs/testing" 25 envtools "launchpad.net/juju-core/environs/tools" 26 "launchpad.net/juju-core/errors" 27 "launchpad.net/juju-core/instance" 28 "launchpad.net/juju-core/juju" 29 "launchpad.net/juju-core/juju/testing" 30 "launchpad.net/juju-core/provider/common" 31 "launchpad.net/juju-core/provider/dummy" 32 "launchpad.net/juju-core/state" 33 "launchpad.net/juju-core/state/api" 34 statetesting "launchpad.net/juju-core/state/testing" 35 coretesting "launchpad.net/juju-core/testing" 36 jc "launchpad.net/juju-core/testing/checkers" 37 "launchpad.net/juju-core/testing/testbase" 38 coretools "launchpad.net/juju-core/tools" 39 "launchpad.net/juju-core/utils" 40 "launchpad.net/juju-core/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 testbase.LoggingSuite 48 envtesting.ToolsFixture 49 50 // TestConfig contains the configuration attributes for opening an environment. 51 TestConfig coretesting.Attrs 52 53 // Attempt holds a strategy for waiting until the environment 54 // becomes logically consistent. 55 Attempt utils.AttemptStrategy 56 57 // CanOpenState should be true if the testing environment allows 58 // the state to be opened after bootstrapping. 59 CanOpenState bool 60 61 // HasProvisioner should be true if the environment has 62 // a provisioning agent. 63 HasProvisioner bool 64 65 // Env holds the currently opened environment. 66 // This is set by PrepareOnce and BootstrapOnce. 67 Env environs.Environ 68 69 // ConfigStore holds the configuration storage 70 // used when preparing the environment. 71 // This is initialized by SetUpSuite. 72 ConfigStore configstore.Storage 73 74 prepared bool 75 bootstrapped bool 76 } 77 78 func (t *LiveTests) SetUpSuite(c *gc.C) { 79 t.LoggingSuite.SetUpSuite(c) 80 t.ConfigStore = configstore.NewMem() 81 } 82 83 func (t *LiveTests) SetUpTest(c *gc.C) { 84 t.LoggingSuite.SetUpTest(c) 85 t.ToolsFixture.SetUpTest(c) 86 } 87 88 func publicAttrs(e environs.Environ) map[string]interface{} { 89 cfg := e.Config() 90 secrets, err := e.Provider().SecretAttrs(cfg) 91 if err != nil { 92 panic(err) 93 } 94 attrs := cfg.AllAttrs() 95 for attr := range secrets { 96 delete(attrs, attr) 97 } 98 return attrs 99 } 100 101 func (t *LiveTests) TearDownSuite(c *gc.C) { 102 if t.Env != nil { 103 t.Destroy(c) 104 } 105 t.LoggingSuite.TearDownSuite(c) 106 } 107 108 func (t *LiveTests) TearDownTest(c *gc.C) { 109 t.ToolsFixture.TearDownTest(c) 110 t.LoggingSuite.TearDownTest(c) 111 } 112 113 // PrepareOnce ensures that the environment is 114 // available and prepared. It sets t.Env appropriately. 115 func (t *LiveTests) PrepareOnce(c *gc.C) { 116 if t.prepared { 117 return 118 } 119 cfg, err := config.New(config.NoDefaults, t.TestConfig) 120 c.Assert(err, gc.IsNil) 121 e, err := environs.Prepare(cfg, coretesting.Context(c), t.ConfigStore) 122 c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig)) 123 c.Assert(e, gc.NotNil) 124 t.Env = e 125 t.prepared = true 126 } 127 128 func (t *LiveTests) BootstrapOnce(c *gc.C) { 129 if t.bootstrapped { 130 return 131 } 132 t.PrepareOnce(c) 133 // We only build and upload tools if there will be a state agent that 134 // we could connect to (actual live tests, rather than local-only) 135 cons := constraints.MustParse("mem=2G") 136 if t.CanOpenState { 137 _, err := sync.Upload(t.Env.Storage(), nil, config.DefaultSeries) 138 c.Assert(err, gc.IsNil) 139 } 140 envtesting.UploadFakeTools(c, t.Env.Storage()) 141 err := common.EnsureNotBootstrapped(t.Env) 142 c.Assert(err, gc.IsNil) 143 err = bootstrap.Bootstrap(coretesting.Context(c), t.Env, cons) 144 c.Assert(err, gc.IsNil) 145 t.bootstrapped = true 146 } 147 148 func (t *LiveTests) Destroy(c *gc.C) { 149 if t.Env == nil { 150 return 151 } 152 err := environs.Destroy(t.Env, t.ConfigStore) 153 c.Assert(err, gc.IsNil) 154 t.bootstrapped = false 155 t.prepared = false 156 t.Env = nil 157 } 158 159 func (t *LiveTests) TestPrechecker(c *gc.C) { 160 // Providers may implement Prechecker. If they do, then they should 161 // return nil for empty constraints (excluding the null provider). 162 prechecker, ok := t.Env.(state.Prechecker) 163 if !ok { 164 return 165 } 166 err := prechecker.PrecheckInstance("precise", constraints.Value{}) 167 c.Assert(err, gc.IsNil) 168 } 169 170 // TestStartStop is similar to Tests.TestStartStop except 171 // that it does not assume a pristine environment. 172 func (t *LiveTests) TestStartStop(c *gc.C) { 173 t.PrepareOnce(c) 174 envtesting.UploadFakeTools(c, t.Env.Storage()) 175 176 inst, _ := testing.AssertStartInstance(c, t.Env, "0") 177 c.Assert(inst, gc.NotNil) 178 id0 := inst.Id() 179 180 insts, err := t.Env.Instances([]instance.Id{id0, id0}) 181 c.Assert(err, gc.IsNil) 182 c.Assert(insts, gc.HasLen, 2) 183 c.Assert(insts[0].Id(), gc.Equals, id0) 184 c.Assert(insts[1].Id(), gc.Equals, id0) 185 186 // Asserting on the return of AllInstances makes the test fragile, 187 // as even comparing the before and after start values can be thrown 188 // off if other instances have been created or destroyed in the same 189 // time frame. Instead, just check the instance we created exists. 190 insts, err = t.Env.AllInstances() 191 c.Assert(err, gc.IsNil) 192 found := false 193 for _, inst := range insts { 194 if inst.Id() == id0 { 195 c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts)) 196 found = true 197 } 198 } 199 c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts)) 200 201 dns, err := inst.WaitDNSName() 202 c.Assert(err, gc.IsNil) 203 c.Assert(dns, gc.Not(gc.Equals), "") 204 205 insts, err = t.Env.Instances([]instance.Id{id0, ""}) 206 c.Assert(err, gc.Equals, environs.ErrPartialInstances) 207 c.Assert(insts, gc.HasLen, 2) 208 c.Check(insts[0].Id(), gc.Equals, id0) 209 c.Check(insts[1], gc.IsNil) 210 211 err = t.Env.StopInstances([]instance.Instance{inst}) 212 c.Assert(err, gc.IsNil) 213 214 // The machine may not be marked as shutting down 215 // immediately. Repeat a few times to ensure we get the error. 216 for a := t.Attempt.Start(); a.Next(); { 217 insts, err = t.Env.Instances([]instance.Id{id0}) 218 if err != nil { 219 break 220 } 221 } 222 c.Assert(err, gc.Equals, environs.ErrNoInstances) 223 c.Assert(insts, gc.HasLen, 0) 224 } 225 226 func (t *LiveTests) TestPorts(c *gc.C) { 227 t.PrepareOnce(c) 228 envtesting.UploadFakeTools(c, t.Env.Storage()) 229 230 inst1, _ := testing.AssertStartInstance(c, t.Env, "1") 231 c.Assert(inst1, gc.NotNil) 232 defer t.Env.StopInstances([]instance.Instance{inst1}) 233 ports, err := inst1.Ports("1") 234 c.Assert(err, gc.IsNil) 235 c.Assert(ports, gc.HasLen, 0) 236 237 inst2, _ := testing.AssertStartInstance(c, t.Env, "2") 238 c.Assert(inst2, gc.NotNil) 239 ports, err = inst2.Ports("2") 240 c.Assert(err, gc.IsNil) 241 c.Assert(ports, gc.HasLen, 0) 242 defer t.Env.StopInstances([]instance.Instance{inst2}) 243 244 // Open some ports and check they're there. 245 err = inst1.OpenPorts("1", []instance.Port{{"udp", 67}, {"tcp", 45}}) 246 c.Assert(err, gc.IsNil) 247 ports, err = inst1.Ports("1") 248 c.Assert(err, gc.IsNil) 249 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 250 ports, err = inst2.Ports("2") 251 c.Assert(err, gc.IsNil) 252 c.Assert(ports, gc.HasLen, 0) 253 254 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 89}, {"tcp", 45}}) 255 c.Assert(err, gc.IsNil) 256 257 // Check there's no crosstalk to another machine 258 ports, err = inst2.Ports("2") 259 c.Assert(err, gc.IsNil) 260 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 261 ports, err = inst1.Ports("1") 262 c.Assert(err, gc.IsNil) 263 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 264 265 // Check that opening the same port again is ok. 266 oldPorts, err := inst2.Ports("2") 267 c.Assert(err, gc.IsNil) 268 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}}) 269 c.Assert(err, gc.IsNil) 270 ports, err = inst2.Ports("2") 271 c.Assert(err, gc.IsNil) 272 c.Assert(ports, gc.DeepEquals, oldPorts) 273 274 // Check that opening the same port again and another port is ok. 275 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}}) 276 c.Assert(err, gc.IsNil) 277 ports, err = inst2.Ports("2") 278 c.Assert(err, gc.IsNil) 279 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}}) 280 281 err = inst2.ClosePorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}}) 282 c.Assert(err, gc.IsNil) 283 284 // Check that we can close ports and that there's no crosstalk. 285 ports, err = inst2.Ports("2") 286 c.Assert(err, gc.IsNil) 287 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}}) 288 ports, err = inst1.Ports("1") 289 c.Assert(err, gc.IsNil) 290 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 291 292 // Check that we can close multiple ports. 293 err = inst1.ClosePorts("1", []instance.Port{{"tcp", 45}, {"udp", 67}}) 294 c.Assert(err, gc.IsNil) 295 ports, err = inst1.Ports("1") 296 c.Assert(ports, gc.HasLen, 0) 297 298 // Check that we can close ports that aren't there. 299 err = inst2.ClosePorts("2", []instance.Port{{"tcp", 111}, {"udp", 222}}) 300 c.Assert(err, gc.IsNil) 301 ports, err = inst2.Ports("2") 302 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}}) 303 304 // Check errors when acting on environment. 305 err = t.Env.OpenPorts([]instance.Port{{"tcp", 80}}) 306 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on environment`) 307 308 err = t.Env.ClosePorts([]instance.Port{{"tcp", 80}}) 309 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on environment`) 310 311 _, err = t.Env.Ports() 312 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ports from environment`) 313 } 314 315 func (t *LiveTests) TestGlobalPorts(c *gc.C) { 316 t.PrepareOnce(c) 317 envtesting.UploadFakeTools(c, t.Env.Storage()) 318 319 // Change configuration. 320 oldConfig := t.Env.Config() 321 defer func() { 322 err := t.Env.SetConfig(oldConfig) 323 c.Assert(err, gc.IsNil) 324 }() 325 326 attrs := t.Env.Config().AllAttrs() 327 attrs["firewall-mode"] = "global" 328 newConfig, err := t.Env.Config().Apply(attrs) 329 c.Assert(err, gc.IsNil) 330 err = t.Env.SetConfig(newConfig) 331 c.Assert(err, gc.IsNil) 332 333 // Create instances and check open ports on both instances. 334 inst1, _ := testing.AssertStartInstance(c, t.Env, "1") 335 defer t.Env.StopInstances([]instance.Instance{inst1}) 336 ports, err := t.Env.Ports() 337 c.Assert(err, gc.IsNil) 338 c.Assert(ports, gc.HasLen, 0) 339 340 inst2, _ := testing.AssertStartInstance(c, t.Env, "2") 341 ports, err = t.Env.Ports() 342 c.Assert(err, gc.IsNil) 343 c.Assert(ports, gc.HasLen, 0) 344 defer t.Env.StopInstances([]instance.Instance{inst2}) 345 346 err = t.Env.OpenPorts([]instance.Port{{"udp", 67}, {"tcp", 45}, {"tcp", 89}, {"tcp", 99}}) 347 c.Assert(err, gc.IsNil) 348 349 ports, err = t.Env.Ports() 350 c.Assert(err, gc.IsNil) 351 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}, {"udp", 67}}) 352 353 // Check closing some ports. 354 err = t.Env.ClosePorts([]instance.Port{{"tcp", 99}, {"udp", 67}}) 355 c.Assert(err, gc.IsNil) 356 357 ports, err = t.Env.Ports() 358 c.Assert(err, gc.IsNil) 359 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 360 361 // Check that we can close ports that aren't there. 362 err = t.Env.ClosePorts([]instance.Port{{"tcp", 111}, {"udp", 222}}) 363 c.Assert(err, gc.IsNil) 364 365 ports, err = t.Env.Ports() 366 c.Assert(err, gc.IsNil) 367 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 368 369 // Check errors when acting on instances. 370 err = inst1.OpenPorts("1", []instance.Port{{"tcp", 80}}) 371 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`) 372 373 err = inst1.ClosePorts("1", []instance.Port{{"tcp", 80}}) 374 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`) 375 376 _, err = inst1.Ports("1") 377 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ports from instance`) 378 } 379 380 func (t *LiveTests) TestBootstrapMultiple(c *gc.C) { 381 // bootstrap.Bootstrap no longer raises errors if the environment is 382 // already up, this has been moved into the bootstrap command. 383 t.BootstrapOnce(c) 384 385 err := common.EnsureNotBootstrapped(t.Env) 386 c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") 387 388 c.Logf("destroy env") 389 env := t.Env 390 t.Destroy(c) 391 env.Destroy() // Again, should work fine and do nothing. 392 393 // check that we can bootstrap after destroy 394 t.BootstrapOnce(c) 395 } 396 397 func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) { 398 if !t.CanOpenState || !t.HasProvisioner { 399 c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner)) 400 } 401 t.BootstrapOnce(c) 402 403 // TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts. 404 405 c.Logf("opening connection") 406 conn, err := juju.NewConn(t.Env) 407 c.Assert(err, gc.IsNil) 408 defer conn.Close() 409 410 c.Logf("opening API connection") 411 apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts()) 412 c.Assert(err, gc.IsNil) 413 defer conn.Close() 414 415 // Check that the agent version has made it through the 416 // bootstrap process (it's optional in the config.Config) 417 cfg, err := conn.State.EnvironConfig() 418 c.Assert(err, gc.IsNil) 419 agentVersion, ok := cfg.AgentVersion() 420 c.Check(ok, gc.Equals, true) 421 c.Check(agentVersion, gc.Equals, version.Current.Number) 422 423 // Check that the constraints have been set in the environment. 424 cons, err := conn.State.EnvironConstraints() 425 c.Assert(err, gc.IsNil) 426 c.Assert(cons.String(), gc.Equals, "mem=2048M") 427 428 // Wait for machine agent to come up on the bootstrap 429 // machine and find the deployed series from that. 430 m0, err := conn.State.Machine("0") 431 c.Assert(err, gc.IsNil) 432 433 instId0, err := m0.InstanceId() 434 c.Assert(err, gc.IsNil) 435 436 // Check that the API connection is working. 437 status, err := apiConn.State.Client().Status(nil) 438 c.Assert(err, gc.IsNil) 439 c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0)) 440 441 mw0 := newMachineToolWaiter(m0) 442 defer mw0.Stop() 443 444 // If the series has not been specified, we expect the most recent Ubuntu LTS release to be used. 445 expectedVersion := version.Current 446 expectedVersion.Series = config.DefaultSeries 447 448 mtools0 := waitAgentTools(c, mw0, expectedVersion) 449 450 // Create a new service and deploy a unit of it. 451 c.Logf("deploying service") 452 repoDir := c.MkDir() 453 url := coretesting.Charms.ClonedURL(repoDir, mtools0.Version.Series, "dummy") 454 sch, err := conn.PutCharm(url, &charm.LocalRepository{repoDir}, false) 455 c.Assert(err, gc.IsNil) 456 svc, err := conn.State.AddService("dummy", "user-admin", sch) 457 c.Assert(err, gc.IsNil) 458 units, err := juju.AddUnits(conn.State, svc, 1, "") 459 c.Assert(err, gc.IsNil) 460 unit := units[0] 461 462 // Wait for the unit's machine and associated agent to come up 463 // and announce itself. 464 mid1, err := unit.AssignedMachineId() 465 c.Assert(err, gc.IsNil) 466 m1, err := conn.State.Machine(mid1) 467 c.Assert(err, gc.IsNil) 468 mw1 := newMachineToolWaiter(m1) 469 defer mw1.Stop() 470 waitAgentTools(c, mw1, mtools0.Version) 471 472 err = m1.Refresh() 473 c.Assert(err, gc.IsNil) 474 instId1, err := m1.InstanceId() 475 c.Assert(err, gc.IsNil) 476 uw := newUnitToolWaiter(unit) 477 defer uw.Stop() 478 utools := waitAgentTools(c, uw, expectedVersion) 479 480 // Check that we can upgrade the environment. 481 newVersion := utools.Version 482 newVersion.Patch++ 483 t.checkUpgrade(c, conn, newVersion, mw0, mw1, uw) 484 485 // BUG(niemeyer): Logic below is very much wrong. Must be: 486 // 487 // 1. EnsureDying on the unit and EnsureDying on the machine 488 // 2. Unit dies by itself 489 // 3. Machine removes dead unit 490 // 4. Machine dies by itself 491 // 5. Provisioner removes dead machine 492 // 493 494 // Now remove the unit and its assigned machine and 495 // check that the PA removes it. 496 c.Logf("removing unit") 497 err = unit.Destroy() 498 c.Assert(err, gc.IsNil) 499 500 // Wait until unit is dead 501 uwatch := unit.Watch() 502 defer uwatch.Stop() 503 for unit.Life() != state.Dead { 504 c.Logf("waiting for unit change") 505 <-uwatch.Changes() 506 err := unit.Refresh() 507 c.Logf("refreshed; err %v", err) 508 if errors.IsNotFoundError(err) { 509 c.Logf("unit has been removed") 510 break 511 } 512 c.Assert(err, gc.IsNil) 513 } 514 for { 515 c.Logf("destroying machine") 516 err := m1.Destroy() 517 if err == nil { 518 break 519 } 520 c.Assert(err, gc.FitsTypeOf, &state.HasAssignedUnitsError{}) 521 time.Sleep(5 * time.Second) 522 err = m1.Refresh() 523 if errors.IsNotFoundError(err) { 524 break 525 } 526 c.Assert(err, gc.IsNil) 527 } 528 c.Logf("waiting for instance to be removed") 529 t.assertStopInstance(c, conn.Environ, instId1) 530 } 531 532 func (t *LiveTests) TestBootstrapVerifyStorage(c *gc.C) { 533 // Bootstrap automatically verifies that storage is writable. 534 t.BootstrapOnce(c) 535 environ := t.Env 536 stor := environ.Storage() 537 reader, err := storage.Get(stor, "bootstrap-verify") 538 c.Assert(err, gc.IsNil) 539 defer reader.Close() 540 contents, err := ioutil.ReadAll(reader) 541 c.Assert(err, gc.IsNil) 542 c.Check(string(contents), gc.Equals, 543 "juju-core storage writing verified: ok\n") 544 } 545 546 func restoreBootstrapVerificationFile(c *gc.C, stor storage.Storage) { 547 content := "juju-core storage writing verified: ok\n" 548 contentReader := strings.NewReader(content) 549 err := stor.Put("bootstrap-verify", contentReader, 550 int64(len(content))) 551 c.Assert(err, gc.IsNil) 552 } 553 554 func (t *LiveTests) TestCheckEnvironmentOnConnect(c *gc.C) { 555 // When new connection is established to a bootstraped environment, 556 // it is checked that we are running against a juju-core environment. 557 if !t.CanOpenState { 558 c.Skip("CanOpenState is false; cannot open state connection") 559 } 560 t.BootstrapOnce(c) 561 562 conn, err := juju.NewConn(t.Env) 563 c.Assert(err, gc.IsNil) 564 conn.Close() 565 566 apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts()) 567 c.Assert(err, gc.IsNil) 568 apiConn.Close() 569 } 570 571 func (t *LiveTests) TestCheckEnvironmentOnConnectNoVerificationFile(c *gc.C) { 572 // When new connection is established to a bootstraped environment, 573 // it is checked that we are running against a juju-core environment. 574 // 575 // Absence of a verification file means it is a juju-core environment 576 // with an older version, which is fine. 577 if !t.CanOpenState { 578 c.Skip("CanOpenState is false; cannot open state connection") 579 } 580 t.BootstrapOnce(c) 581 environ := t.Env 582 stor := environ.Storage() 583 err := stor.Remove("bootstrap-verify") 584 c.Assert(err, gc.IsNil) 585 defer restoreBootstrapVerificationFile(c, stor) 586 587 conn, err := juju.NewConn(t.Env) 588 c.Assert(err, gc.IsNil) 589 conn.Close() 590 } 591 592 func (t *LiveTests) TestCheckEnvironmentOnConnectBadVerificationFile(c *gc.C) { 593 // When new connection is established to a bootstraped environment, 594 // it is checked that we are running against a juju-core environment. 595 // 596 // If the verification file has unexpected content, it is not 597 // a juju-core environment (likely to a Python juju environment). 598 if !t.CanOpenState { 599 c.Skip("CanOpenState is false; cannot open state connection") 600 } 601 t.BootstrapOnce(c) 602 environ := t.Env 603 stor := environ.Storage() 604 605 // Finally, replace the content with an arbitrary string. 606 badVerificationContent := "bootstrap storage verification" 607 reader := strings.NewReader(badVerificationContent) 608 err := stor.Put( 609 "bootstrap-verify", 610 reader, 611 int64(len(badVerificationContent))) 612 c.Assert(err, gc.IsNil) 613 defer restoreBootstrapVerificationFile(c, stor) 614 615 // Running NewConn() should fail. 616 _, err = juju.NewConn(t.Env) 617 c.Assert(err, gc.Equals, environs.InvalidEnvironmentError) 618 } 619 620 type tooler interface { 621 Life() state.Life 622 AgentTools() (*coretools.Tools, error) 623 Refresh() error 624 String() string 625 } 626 627 type watcher interface { 628 Stop() error 629 Err() error 630 } 631 632 type toolsWaiter struct { 633 lastTools *coretools.Tools 634 // changes is a chan of struct{} so that it can 635 // be used with different kinds of entity watcher. 636 changes chan struct{} 637 watcher watcher 638 tooler tooler 639 } 640 641 func newMachineToolWaiter(m *state.Machine) *toolsWaiter { 642 w := m.Watch() 643 waiter := &toolsWaiter{ 644 changes: make(chan struct{}, 1), 645 watcher: w, 646 tooler: m, 647 } 648 go func() { 649 for _ = range w.Changes() { 650 waiter.changes <- struct{}{} 651 } 652 close(waiter.changes) 653 }() 654 return waiter 655 } 656 657 func newUnitToolWaiter(u *state.Unit) *toolsWaiter { 658 w := u.Watch() 659 waiter := &toolsWaiter{ 660 changes: make(chan struct{}, 1), 661 watcher: w, 662 tooler: u, 663 } 664 go func() { 665 for _ = range w.Changes() { 666 waiter.changes <- struct{}{} 667 } 668 close(waiter.changes) 669 }() 670 return waiter 671 } 672 673 func (w *toolsWaiter) Stop() error { 674 return w.watcher.Stop() 675 } 676 677 // NextTools returns the next changed tools, waiting 678 // until the tools are actually set. 679 func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) { 680 for _ = range w.changes { 681 err := w.tooler.Refresh() 682 if err != nil { 683 return nil, fmt.Errorf("cannot refresh: %v", err) 684 } 685 if w.tooler.Life() == state.Dead { 686 return nil, fmt.Errorf("object is dead") 687 } 688 tools, err := w.tooler.AgentTools() 689 if errors.IsNotFoundError(err) { 690 c.Logf("tools not yet set") 691 continue 692 } 693 if err != nil { 694 return nil, err 695 } 696 changed := w.lastTools == nil || *tools != *w.lastTools 697 w.lastTools = tools 698 if changed { 699 return tools, nil 700 } 701 c.Logf("found same tools") 702 } 703 return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err()) 704 } 705 706 // waitAgentTools waits for the given agent 707 // to start and returns the tools that it is running. 708 func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools { 709 c.Logf("waiting for %v to signal agent version", w.tooler.String()) 710 tools, err := w.NextTools(c) 711 c.Assert(err, gc.IsNil) 712 c.Check(tools.Version, gc.Equals, expect) 713 return tools 714 } 715 716 // checkUpgrade sets the environment agent version and checks that 717 // all the provided watchers upgrade to the requested version. 718 func (t *LiveTests) checkUpgrade(c *gc.C, conn *juju.Conn, newVersion version.Binary, waiters ...*toolsWaiter) { 719 c.Logf("putting testing version of juju tools") 720 upgradeTools, err := sync.Upload(t.Env.Storage(), &newVersion.Number, newVersion.Series) 721 c.Assert(err, gc.IsNil) 722 // sync.Upload always returns tools for the series on which the tests are running. 723 // We are only interested in checking the version.Number below so need to fake the 724 // upgraded tools series to match that of newVersion. 725 upgradeTools.Version.Series = newVersion.Series 726 727 // Check that the put version really is the version we expect. 728 c.Assert(upgradeTools.Version, gc.Equals, newVersion) 729 err = statetesting.SetAgentVersion(conn.State, newVersion.Number) 730 c.Assert(err, gc.IsNil) 731 732 for i, w := range waiters { 733 c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String()) 734 735 waitAgentTools(c, w, newVersion) 736 c.Logf("upgrade %d successful", i) 737 } 738 } 739 740 var waitAgent = utils.AttemptStrategy{ 741 Total: 30 * time.Second, 742 Delay: 1 * time.Second, 743 } 744 745 func (t *LiveTests) assertStartInstance(c *gc.C, m *state.Machine) { 746 // Wait for machine to get an instance id. 747 for a := waitAgent.Start(); a.Next(); { 748 err := m.Refresh() 749 c.Assert(err, gc.IsNil) 750 instId, err := m.InstanceId() 751 if err != nil { 752 c.Assert(err, jc.Satisfies, state.IsNotProvisionedError) 753 continue 754 } 755 _, err = t.Env.Instances([]instance.Id{instId}) 756 c.Assert(err, gc.IsNil) 757 return 758 } 759 c.Fatalf("provisioner failed to start machine after %v", waitAgent.Total) 760 } 761 762 func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) { 763 var err error 764 for a := waitAgent.Start(); a.Next(); { 765 _, err = t.Env.Instances([]instance.Id{instId}) 766 if err == nil { 767 continue 768 } 769 if err == environs.ErrNoInstances { 770 return 771 } 772 c.Logf("error from Instances: %v", err) 773 } 774 c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total) 775 } 776 777 // assertInstanceId asserts that the machine has an instance id 778 // that matches that of the given instance. If the instance is nil, 779 // It asserts that the instance id is unset. 780 func assertInstanceId(c *gc.C, m *state.Machine, inst instance.Instance) { 781 var wantId, gotId instance.Id 782 var err error 783 if inst != nil { 784 wantId = inst.Id() 785 } 786 for a := waitAgent.Start(); a.Next(); { 787 err := m.Refresh() 788 c.Assert(err, gc.IsNil) 789 gotId, err = m.InstanceId() 790 if err != nil { 791 c.Assert(err, jc.Satisfies, state.IsNotProvisionedError) 792 if inst == nil { 793 return 794 } 795 continue 796 } 797 break 798 } 799 c.Assert(err, gc.IsNil) 800 c.Assert(gotId, gc.Equals, wantId) 801 } 802 803 // TODO check that binary data works ok? 804 var contents = []byte("hello\n") 805 var contents2 = []byte("goodbye\n\n") 806 807 func (t *LiveTests) TestFile(c *gc.C) { 808 t.PrepareOnce(c) 809 name := fmt.Sprint("testfile", time.Now().UnixNano()) 810 stor := t.Env.Storage() 811 812 checkFileDoesNotExist(c, stor, name, t.Attempt) 813 checkPutFile(c, stor, name, contents) 814 checkFileHasContents(c, stor, name, contents, t.Attempt) 815 checkPutFile(c, stor, name, contents2) // check that we can overwrite the file 816 checkFileHasContents(c, stor, name, contents2, t.Attempt) 817 818 // check that the listed contents include the 819 // expected name. 820 found := false 821 var names []string 822 attempt: 823 for a := t.Attempt.Start(); a.Next(); { 824 var err error 825 names, err = stor.List("") 826 c.Assert(err, gc.IsNil) 827 for _, lname := range names { 828 if lname == name { 829 found = true 830 break attempt 831 } 832 } 833 } 834 if !found { 835 c.Errorf("file name %q not found in file list %q", name, names) 836 } 837 err := stor.Remove(name) 838 c.Check(err, gc.IsNil) 839 checkFileDoesNotExist(c, stor, name, t.Attempt) 840 // removing a file that does not exist should not be an error. 841 err = stor.Remove(name) 842 c.Check(err, gc.IsNil) 843 844 // RemoveAll deletes all files from storage. 845 checkPutFile(c, stor, "file-1.txt", contents) 846 checkPutFile(c, stor, "file-2.txt", contents) 847 err = stor.RemoveAll() 848 c.Check(err, gc.IsNil) 849 checkFileDoesNotExist(c, stor, "file-1.txt", t.Attempt) 850 checkFileDoesNotExist(c, stor, "file-2.txt", t.Attempt) 851 } 852 853 // Check that we get a consistent error when asking for an instance without 854 // a valid machine config. 855 func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) { 856 machineId := "4" 857 stateInfo := testing.FakeStateInfo(machineId) 858 apiInfo := testing.FakeAPIInfo(machineId) 859 machineConfig := environs.NewMachineConfig(machineId, "", "", stateInfo, apiInfo) 860 861 t.PrepareOnce(c) 862 possibleTools := envtesting.AssertUploadFakeToolsVersions(c, t.Env.Storage(), version.MustParseBinary("5.4.5-precise-amd64")) 863 inst, _, err := t.Env.StartInstance(constraints.Value{}, possibleTools, machineConfig) 864 if inst != nil { 865 err := t.Env.StopInstances([]instance.Instance{inst}) 866 c.Check(err, gc.IsNil) 867 } 868 c.Assert(inst, gc.IsNil) 869 c.Assert(err, gc.ErrorMatches, ".*missing machine nonce") 870 } 871 872 func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) { 873 if !t.HasProvisioner { 874 c.Skip("HasProvisioner is false; cannot test deployment") 875 } 876 877 current := version.Current 878 other := current 879 other.Series = "quantal" 880 if current == other { 881 other.Series = "precise" 882 } 883 884 dummyCfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(coretesting.Attrs{ 885 "state-server": false, 886 "name": "dummy storage", 887 })) 888 dummyenv, err := environs.Prepare(dummyCfg, coretesting.Context(c), configstore.NewMem()) 889 c.Assert(err, gc.IsNil) 890 defer dummyenv.Destroy() 891 892 t.Destroy(c) 893 894 attrs := t.TestConfig.Merge(coretesting.Attrs{"default-series": other.Series}) 895 cfg, err := config.New(config.NoDefaults, attrs) 896 c.Assert(err, gc.IsNil) 897 env, err := environs.Prepare(cfg, coretesting.Context(c), t.ConfigStore) 898 c.Assert(err, gc.IsNil) 899 defer environs.Destroy(env, t.ConfigStore) 900 901 currentName := envtools.StorageName(current) 902 otherName := envtools.StorageName(other) 903 envStorage := env.Storage() 904 dummyStorage := dummyenv.Storage() 905 906 defer envStorage.Remove(otherName) 907 908 _, err = sync.Upload(dummyStorage, ¤t.Number) 909 c.Assert(err, gc.IsNil) 910 911 // This will only work while cross-compiling across releases is safe, 912 // which depends on external elements. Tends to be safe for the last 913 // few releases, but we may have to refactor some day. 914 err = storageCopy(dummyStorage, currentName, envStorage, otherName) 915 c.Assert(err, gc.IsNil) 916 917 err = bootstrap.Bootstrap(coretesting.Context(c), env, constraints.Value{}) 918 c.Assert(err, gc.IsNil) 919 920 conn, err := juju.NewConn(env) 921 c.Assert(err, gc.IsNil) 922 defer conn.Close() 923 924 // Wait for machine agent to come up on the bootstrap 925 // machine and ensure it deployed the proper series. 926 m0, err := conn.State.Machine("0") 927 c.Assert(err, gc.IsNil) 928 mw0 := newMachineToolWaiter(m0) 929 defer mw0.Stop() 930 931 waitAgentTools(c, mw0, other) 932 } 933 934 func storageCopy(source storage.Storage, sourcePath string, target storage.Storage, targetPath string) error { 935 rc, err := storage.Get(source, sourcePath) 936 if err != nil { 937 return err 938 } 939 var buf bytes.Buffer 940 _, err = io.Copy(&buf, rc) 941 rc.Close() 942 if err != nil { 943 return err 944 } 945 return target.Put(targetPath, &buf, int64(buf.Len())) 946 }