launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/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, 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(bootstrapContext(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.(environs.Prechecker) 163 if !ok { 164 return 165 } 166 167 const series = "precise" 168 var cons constraints.Value 169 c.Check(prechecker.PrecheckInstance(series, cons), gc.IsNil) 170 171 err := prechecker.PrecheckContainer(series, instance.LXC) 172 // If err is nil, that is fine, some providers support containers. 173 if err != nil { 174 // But for ones that don't, they should have a standard error format. 175 c.Check(err, gc.ErrorMatches, ".*provider does not support .*containers") 176 c.Check(err, jc.Satisfies, environs.IsContainersUnsupportedError) 177 } 178 } 179 180 // TestStartStop is similar to Tests.TestStartStop except 181 // that it does not assume a pristine environment. 182 func (t *LiveTests) TestStartStop(c *gc.C) { 183 t.PrepareOnce(c) 184 envtesting.UploadFakeTools(c, t.Env.Storage()) 185 186 inst, _ := testing.AssertStartInstance(c, t.Env, "0") 187 c.Assert(inst, gc.NotNil) 188 id0 := inst.Id() 189 190 insts, err := t.Env.Instances([]instance.Id{id0, id0}) 191 c.Assert(err, gc.IsNil) 192 c.Assert(insts, gc.HasLen, 2) 193 c.Assert(insts[0].Id(), gc.Equals, id0) 194 c.Assert(insts[1].Id(), gc.Equals, id0) 195 196 // Asserting on the return of AllInstances makes the test fragile, 197 // as even comparing the before and after start values can be thrown 198 // off if other instances have been created or destroyed in the same 199 // time frame. Instead, just check the instance we created exists. 200 insts, err = t.Env.AllInstances() 201 c.Assert(err, gc.IsNil) 202 found := false 203 for _, inst := range insts { 204 if inst.Id() == id0 { 205 c.Assert(found, gc.Equals, false, gc.Commentf("%v", insts)) 206 found = true 207 } 208 } 209 c.Assert(found, gc.Equals, true, gc.Commentf("expected %v in %v", inst, insts)) 210 211 dns, err := inst.WaitDNSName() 212 c.Assert(err, gc.IsNil) 213 c.Assert(dns, gc.Not(gc.Equals), "") 214 215 insts, err = t.Env.Instances([]instance.Id{id0, ""}) 216 c.Assert(err, gc.Equals, environs.ErrPartialInstances) 217 c.Assert(insts, gc.HasLen, 2) 218 c.Check(insts[0].Id(), gc.Equals, id0) 219 c.Check(insts[1], gc.IsNil) 220 221 err = t.Env.StopInstances([]instance.Instance{inst}) 222 c.Assert(err, gc.IsNil) 223 224 // The machine may not be marked as shutting down 225 // immediately. Repeat a few times to ensure we get the error. 226 for a := t.Attempt.Start(); a.Next(); { 227 insts, err = t.Env.Instances([]instance.Id{id0}) 228 if err != nil { 229 break 230 } 231 } 232 c.Assert(err, gc.Equals, environs.ErrNoInstances) 233 c.Assert(insts, gc.HasLen, 0) 234 } 235 236 func (t *LiveTests) TestPorts(c *gc.C) { 237 t.PrepareOnce(c) 238 envtesting.UploadFakeTools(c, t.Env.Storage()) 239 240 inst1, _ := testing.AssertStartInstance(c, t.Env, "1") 241 c.Assert(inst1, gc.NotNil) 242 defer t.Env.StopInstances([]instance.Instance{inst1}) 243 ports, err := inst1.Ports("1") 244 c.Assert(err, gc.IsNil) 245 c.Assert(ports, gc.HasLen, 0) 246 247 inst2, _ := testing.AssertStartInstance(c, t.Env, "2") 248 c.Assert(inst2, gc.NotNil) 249 ports, err = inst2.Ports("2") 250 c.Assert(err, gc.IsNil) 251 c.Assert(ports, gc.HasLen, 0) 252 defer t.Env.StopInstances([]instance.Instance{inst2}) 253 254 // Open some ports and check they're there. 255 err = inst1.OpenPorts("1", []instance.Port{{"udp", 67}, {"tcp", 45}}) 256 c.Assert(err, gc.IsNil) 257 ports, err = inst1.Ports("1") 258 c.Assert(err, gc.IsNil) 259 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 260 ports, err = inst2.Ports("2") 261 c.Assert(err, gc.IsNil) 262 c.Assert(ports, gc.HasLen, 0) 263 264 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 89}, {"tcp", 45}}) 265 c.Assert(err, gc.IsNil) 266 267 // Check there's no crosstalk to another machine 268 ports, err = inst2.Ports("2") 269 c.Assert(err, gc.IsNil) 270 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 271 ports, err = inst1.Ports("1") 272 c.Assert(err, gc.IsNil) 273 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 274 275 // Check that opening the same port again is ok. 276 oldPorts, err := inst2.Ports("2") 277 c.Assert(err, gc.IsNil) 278 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}}) 279 c.Assert(err, gc.IsNil) 280 ports, err = inst2.Ports("2") 281 c.Assert(err, gc.IsNil) 282 c.Assert(ports, gc.DeepEquals, oldPorts) 283 284 // Check that opening the same port again and another port is ok. 285 err = inst2.OpenPorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}}) 286 c.Assert(err, gc.IsNil) 287 ports, err = inst2.Ports("2") 288 c.Assert(err, gc.IsNil) 289 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}}) 290 291 err = inst2.ClosePorts("2", []instance.Port{{"tcp", 45}, {"tcp", 99}}) 292 c.Assert(err, gc.IsNil) 293 294 // Check that we can close ports and that there's no crosstalk. 295 ports, err = inst2.Ports("2") 296 c.Assert(err, gc.IsNil) 297 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}}) 298 ports, err = inst1.Ports("1") 299 c.Assert(err, gc.IsNil) 300 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"udp", 67}}) 301 302 // Check that we can close multiple ports. 303 err = inst1.ClosePorts("1", []instance.Port{{"tcp", 45}, {"udp", 67}}) 304 c.Assert(err, gc.IsNil) 305 ports, err = inst1.Ports("1") 306 c.Assert(ports, gc.HasLen, 0) 307 308 // Check that we can close ports that aren't there. 309 err = inst2.ClosePorts("2", []instance.Port{{"tcp", 111}, {"udp", 222}}) 310 c.Assert(err, gc.IsNil) 311 ports, err = inst2.Ports("2") 312 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 89}}) 313 314 // Check errors when acting on environment. 315 err = t.Env.OpenPorts([]instance.Port{{"tcp", 80}}) 316 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for opening ports on environment`) 317 318 err = t.Env.ClosePorts([]instance.Port{{"tcp", 80}}) 319 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for closing ports on environment`) 320 321 _, err = t.Env.Ports() 322 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "instance" for retrieving ports from environment`) 323 } 324 325 func (t *LiveTests) TestGlobalPorts(c *gc.C) { 326 t.PrepareOnce(c) 327 envtesting.UploadFakeTools(c, t.Env.Storage()) 328 329 // Change configuration. 330 oldConfig := t.Env.Config() 331 defer func() { 332 err := t.Env.SetConfig(oldConfig) 333 c.Assert(err, gc.IsNil) 334 }() 335 336 attrs := t.Env.Config().AllAttrs() 337 attrs["firewall-mode"] = "global" 338 newConfig, err := t.Env.Config().Apply(attrs) 339 c.Assert(err, gc.IsNil) 340 err = t.Env.SetConfig(newConfig) 341 c.Assert(err, gc.IsNil) 342 343 // Create instances and check open ports on both instances. 344 inst1, _ := testing.AssertStartInstance(c, t.Env, "1") 345 defer t.Env.StopInstances([]instance.Instance{inst1}) 346 ports, err := t.Env.Ports() 347 c.Assert(err, gc.IsNil) 348 c.Assert(ports, gc.HasLen, 0) 349 350 inst2, _ := testing.AssertStartInstance(c, t.Env, "2") 351 ports, err = t.Env.Ports() 352 c.Assert(err, gc.IsNil) 353 c.Assert(ports, gc.HasLen, 0) 354 defer t.Env.StopInstances([]instance.Instance{inst2}) 355 356 err = t.Env.OpenPorts([]instance.Port{{"udp", 67}, {"tcp", 45}, {"tcp", 89}, {"tcp", 99}}) 357 c.Assert(err, gc.IsNil) 358 359 ports, err = t.Env.Ports() 360 c.Assert(err, gc.IsNil) 361 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}, {"tcp", 99}, {"udp", 67}}) 362 363 // Check closing some ports. 364 err = t.Env.ClosePorts([]instance.Port{{"tcp", 99}, {"udp", 67}}) 365 c.Assert(err, gc.IsNil) 366 367 ports, err = t.Env.Ports() 368 c.Assert(err, gc.IsNil) 369 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 370 371 // Check that we can close ports that aren't there. 372 err = t.Env.ClosePorts([]instance.Port{{"tcp", 111}, {"udp", 222}}) 373 c.Assert(err, gc.IsNil) 374 375 ports, err = t.Env.Ports() 376 c.Assert(err, gc.IsNil) 377 c.Assert(ports, gc.DeepEquals, []instance.Port{{"tcp", 45}, {"tcp", 89}}) 378 379 // Check errors when acting on instances. 380 err = inst1.OpenPorts("1", []instance.Port{{"tcp", 80}}) 381 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for opening ports on instance`) 382 383 err = inst1.ClosePorts("1", []instance.Port{{"tcp", 80}}) 384 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for closing ports on instance`) 385 386 _, err = inst1.Ports("1") 387 c.Assert(err, gc.ErrorMatches, `invalid firewall mode "global" for retrieving ports from instance`) 388 } 389 390 func (t *LiveTests) TestBootstrapMultiple(c *gc.C) { 391 // bootstrap.Bootstrap no longer raises errors if the environment is 392 // already up, this has been moved into the bootstrap command. 393 t.BootstrapOnce(c) 394 395 err := common.EnsureNotBootstrapped(t.Env) 396 c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") 397 398 c.Logf("destroy env") 399 env := t.Env 400 t.Destroy(c) 401 env.Destroy() // Again, should work fine and do nothing. 402 403 // check that we can bootstrap after destroy 404 t.BootstrapOnce(c) 405 } 406 407 func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) { 408 if !t.CanOpenState || !t.HasProvisioner { 409 c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner)) 410 } 411 t.BootstrapOnce(c) 412 413 // TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts. 414 415 c.Logf("opening connection") 416 conn, err := juju.NewConn(t.Env) 417 c.Assert(err, gc.IsNil) 418 defer conn.Close() 419 420 c.Logf("opening API connection") 421 apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts()) 422 c.Assert(err, gc.IsNil) 423 defer conn.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 := conn.State.EnvironConfig() 428 c.Assert(err, gc.IsNil) 429 agentVersion, ok := cfg.AgentVersion() 430 c.Check(ok, gc.Equals, true) 431 c.Check(agentVersion, gc.Equals, version.Current.Number) 432 433 // Check that the constraints have been set in the environment. 434 cons, err := conn.State.EnvironConstraints() 435 c.Assert(err, gc.IsNil) 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 := conn.State.Machine("0") 441 c.Assert(err, gc.IsNil) 442 443 instId0, err := m0.InstanceId() 444 c.Assert(err, gc.IsNil) 445 446 // Check that the API connection is working. 447 status, err := apiConn.State.Client().Status(nil) 448 c.Assert(err, gc.IsNil) 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.DefaultSeries 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 := coretesting.Charms.ClonedURL(repoDir, mtools0.Version.Series, "dummy") 464 sch, err := conn.PutCharm(url, &charm.LocalRepository{repoDir}, false) 465 c.Assert(err, gc.IsNil) 466 svc, err := conn.State.AddService("dummy", "user-admin", sch) 467 c.Assert(err, gc.IsNil) 468 units, err := juju.AddUnits(conn.State, svc, 1, "") 469 c.Assert(err, gc.IsNil) 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, gc.IsNil) 476 m1, err := conn.State.Machine(mid1) 477 c.Assert(err, gc.IsNil) 478 mw1 := newMachineToolWaiter(m1) 479 defer mw1.Stop() 480 waitAgentTools(c, mw1, mtools0.Version) 481 482 err = m1.Refresh() 483 c.Assert(err, gc.IsNil) 484 instId1, err := m1.InstanceId() 485 c.Assert(err, gc.IsNil) 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, conn, 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, gc.IsNil) 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.IsNotFoundError(err) { 519 c.Logf("unit has been removed") 520 break 521 } 522 c.Assert(err, gc.IsNil) 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.IsNotFoundError(err) { 534 break 535 } 536 c.Assert(err, gc.IsNil) 537 } 538 c.Logf("waiting for instance to be removed") 539 t.assertStopInstance(c, conn.Environ, instId1) 540 } 541 542 func (t *LiveTests) TestBootstrapVerifyStorage(c *gc.C) { 543 // Bootstrap automatically verifies that storage is writable. 544 t.BootstrapOnce(c) 545 environ := t.Env 546 stor := environ.Storage() 547 reader, err := storage.Get(stor, "bootstrap-verify") 548 c.Assert(err, gc.IsNil) 549 defer reader.Close() 550 contents, err := ioutil.ReadAll(reader) 551 c.Assert(err, gc.IsNil) 552 c.Check(string(contents), gc.Equals, 553 "juju-core storage writing verified: ok\n") 554 } 555 556 func restoreBootstrapVerificationFile(c *gc.C, stor storage.Storage) { 557 content := "juju-core storage writing verified: ok\n" 558 contentReader := strings.NewReader(content) 559 err := stor.Put("bootstrap-verify", contentReader, 560 int64(len(content))) 561 c.Assert(err, gc.IsNil) 562 } 563 564 func (t *LiveTests) TestCheckEnvironmentOnConnect(c *gc.C) { 565 // When new connection is established to a bootstraped environment, 566 // it is checked that we are running against a juju-core environment. 567 if !t.CanOpenState { 568 c.Skip("CanOpenState is false; cannot open state connection") 569 } 570 t.BootstrapOnce(c) 571 572 conn, err := juju.NewConn(t.Env) 573 c.Assert(err, gc.IsNil) 574 conn.Close() 575 576 apiConn, err := juju.NewAPIConn(t.Env, api.DefaultDialOpts()) 577 c.Assert(err, gc.IsNil) 578 apiConn.Close() 579 } 580 581 func (t *LiveTests) TestCheckEnvironmentOnConnectNoVerificationFile(c *gc.C) { 582 // When new connection is established to a bootstraped environment, 583 // it is checked that we are running against a juju-core environment. 584 // 585 // Absence of a verification file means it is a juju-core environment 586 // with an older version, which is fine. 587 if !t.CanOpenState { 588 c.Skip("CanOpenState is false; cannot open state connection") 589 } 590 t.BootstrapOnce(c) 591 environ := t.Env 592 stor := environ.Storage() 593 err := stor.Remove("bootstrap-verify") 594 c.Assert(err, gc.IsNil) 595 defer restoreBootstrapVerificationFile(c, stor) 596 597 conn, err := juju.NewConn(t.Env) 598 c.Assert(err, gc.IsNil) 599 conn.Close() 600 } 601 602 func (t *LiveTests) TestCheckEnvironmentOnConnectBadVerificationFile(c *gc.C) { 603 // When new connection is established to a bootstraped environment, 604 // it is checked that we are running against a juju-core environment. 605 // 606 // If the verification file has unexpected content, it is not 607 // a juju-core environment (likely to a Python juju environment). 608 if !t.CanOpenState { 609 c.Skip("CanOpenState is false; cannot open state connection") 610 } 611 t.BootstrapOnce(c) 612 environ := t.Env 613 stor := environ.Storage() 614 615 // Finally, replace the content with an arbitrary string. 616 badVerificationContent := "bootstrap storage verification" 617 reader := strings.NewReader(badVerificationContent) 618 err := stor.Put( 619 "bootstrap-verify", 620 reader, 621 int64(len(badVerificationContent))) 622 c.Assert(err, gc.IsNil) 623 defer restoreBootstrapVerificationFile(c, stor) 624 625 // Running NewConn() should fail. 626 _, err = juju.NewConn(t.Env) 627 c.Assert(err, gc.Equals, environs.InvalidEnvironmentError) 628 } 629 630 type tooler interface { 631 Life() state.Life 632 AgentTools() (*coretools.Tools, error) 633 Refresh() error 634 String() string 635 } 636 637 type watcher interface { 638 Stop() error 639 Err() error 640 } 641 642 type toolsWaiter struct { 643 lastTools *coretools.Tools 644 // changes is a chan of struct{} so that it can 645 // be used with different kinds of entity watcher. 646 changes chan struct{} 647 watcher watcher 648 tooler tooler 649 } 650 651 func newMachineToolWaiter(m *state.Machine) *toolsWaiter { 652 w := m.Watch() 653 waiter := &toolsWaiter{ 654 changes: make(chan struct{}, 1), 655 watcher: w, 656 tooler: m, 657 } 658 go func() { 659 for _ = range w.Changes() { 660 waiter.changes <- struct{}{} 661 } 662 close(waiter.changes) 663 }() 664 return waiter 665 } 666 667 func newUnitToolWaiter(u *state.Unit) *toolsWaiter { 668 w := u.Watch() 669 waiter := &toolsWaiter{ 670 changes: make(chan struct{}, 1), 671 watcher: w, 672 tooler: u, 673 } 674 go func() { 675 for _ = range w.Changes() { 676 waiter.changes <- struct{}{} 677 } 678 close(waiter.changes) 679 }() 680 return waiter 681 } 682 683 func (w *toolsWaiter) Stop() error { 684 return w.watcher.Stop() 685 } 686 687 // NextTools returns the next changed tools, waiting 688 // until the tools are actually set. 689 func (w *toolsWaiter) NextTools(c *gc.C) (*coretools.Tools, error) { 690 for _ = range w.changes { 691 err := w.tooler.Refresh() 692 if err != nil { 693 return nil, fmt.Errorf("cannot refresh: %v", err) 694 } 695 if w.tooler.Life() == state.Dead { 696 return nil, fmt.Errorf("object is dead") 697 } 698 tools, err := w.tooler.AgentTools() 699 if errors.IsNotFoundError(err) { 700 c.Logf("tools not yet set") 701 continue 702 } 703 if err != nil { 704 return nil, err 705 } 706 changed := w.lastTools == nil || *tools != *w.lastTools 707 w.lastTools = tools 708 if changed { 709 return tools, nil 710 } 711 c.Logf("found same tools") 712 } 713 return nil, fmt.Errorf("watcher closed prematurely: %v", w.watcher.Err()) 714 } 715 716 // waitAgentTools waits for the given agent 717 // to start and returns the tools that it is running. 718 func waitAgentTools(c *gc.C, w *toolsWaiter, expect version.Binary) *coretools.Tools { 719 c.Logf("waiting for %v to signal agent version", w.tooler.String()) 720 tools, err := w.NextTools(c) 721 c.Assert(err, gc.IsNil) 722 c.Check(tools.Version, gc.Equals, expect) 723 return tools 724 } 725 726 // checkUpgrade sets the environment agent version and checks that 727 // all the provided watchers upgrade to the requested version. 728 func (t *LiveTests) checkUpgrade(c *gc.C, conn *juju.Conn, newVersion version.Binary, waiters ...*toolsWaiter) { 729 c.Logf("putting testing version of juju tools") 730 upgradeTools, err := sync.Upload(t.Env.Storage(), &newVersion.Number, newVersion.Series) 731 c.Assert(err, gc.IsNil) 732 // sync.Upload always returns tools for the series on which the tests are running. 733 // We are only interested in checking the version.Number below so need to fake the 734 // upgraded tools series to match that of newVersion. 735 upgradeTools.Version.Series = newVersion.Series 736 737 // Check that the put version really is the version we expect. 738 c.Assert(upgradeTools.Version, gc.Equals, newVersion) 739 err = statetesting.SetAgentVersion(conn.State, newVersion.Number) 740 c.Assert(err, gc.IsNil) 741 742 for i, w := range waiters { 743 c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String()) 744 745 waitAgentTools(c, w, newVersion) 746 c.Logf("upgrade %d successful", i) 747 } 748 } 749 750 var waitAgent = utils.AttemptStrategy{ 751 Total: 30 * time.Second, 752 Delay: 1 * time.Second, 753 } 754 755 func (t *LiveTests) assertStartInstance(c *gc.C, m *state.Machine) { 756 // Wait for machine to get an instance id. 757 for a := waitAgent.Start(); a.Next(); { 758 err := m.Refresh() 759 c.Assert(err, gc.IsNil) 760 instId, err := m.InstanceId() 761 if err != nil { 762 c.Assert(err, jc.Satisfies, state.IsNotProvisionedError) 763 continue 764 } 765 _, err = t.Env.Instances([]instance.Id{instId}) 766 c.Assert(err, gc.IsNil) 767 return 768 } 769 c.Fatalf("provisioner failed to start machine after %v", waitAgent.Total) 770 } 771 772 func (t *LiveTests) assertStopInstance(c *gc.C, env environs.Environ, instId instance.Id) { 773 var err error 774 for a := waitAgent.Start(); a.Next(); { 775 _, err = t.Env.Instances([]instance.Id{instId}) 776 if err == nil { 777 continue 778 } 779 if err == environs.ErrNoInstances { 780 return 781 } 782 c.Logf("error from Instances: %v", err) 783 } 784 c.Fatalf("provisioner failed to stop machine after %v", waitAgent.Total) 785 } 786 787 // assertInstanceId asserts that the machine has an instance id 788 // that matches that of the given instance. If the instance is nil, 789 // It asserts that the instance id is unset. 790 func assertInstanceId(c *gc.C, m *state.Machine, inst instance.Instance) { 791 var wantId, gotId instance.Id 792 var err error 793 if inst != nil { 794 wantId = inst.Id() 795 } 796 for a := waitAgent.Start(); a.Next(); { 797 err := m.Refresh() 798 c.Assert(err, gc.IsNil) 799 gotId, err = m.InstanceId() 800 if err != nil { 801 c.Assert(err, jc.Satisfies, state.IsNotProvisionedError) 802 if inst == nil { 803 return 804 } 805 continue 806 } 807 break 808 } 809 c.Assert(err, gc.IsNil) 810 c.Assert(gotId, gc.Equals, wantId) 811 } 812 813 // TODO check that binary data works ok? 814 var contents = []byte("hello\n") 815 var contents2 = []byte("goodbye\n\n") 816 817 func (t *LiveTests) TestFile(c *gc.C) { 818 t.PrepareOnce(c) 819 name := fmt.Sprint("testfile", time.Now().UnixNano()) 820 stor := t.Env.Storage() 821 822 checkFileDoesNotExist(c, stor, name, t.Attempt) 823 checkPutFile(c, stor, name, contents) 824 checkFileHasContents(c, stor, name, contents, t.Attempt) 825 checkPutFile(c, stor, name, contents2) // check that we can overwrite the file 826 checkFileHasContents(c, stor, name, contents2, t.Attempt) 827 828 // check that the listed contents include the 829 // expected name. 830 found := false 831 var names []string 832 attempt: 833 for a := t.Attempt.Start(); a.Next(); { 834 var err error 835 names, err = stor.List("") 836 c.Assert(err, gc.IsNil) 837 for _, lname := range names { 838 if lname == name { 839 found = true 840 break attempt 841 } 842 } 843 } 844 if !found { 845 c.Errorf("file name %q not found in file list %q", name, names) 846 } 847 err := stor.Remove(name) 848 c.Check(err, gc.IsNil) 849 checkFileDoesNotExist(c, stor, name, t.Attempt) 850 // removing a file that does not exist should not be an error. 851 err = stor.Remove(name) 852 c.Check(err, gc.IsNil) 853 854 // RemoveAll deletes all files from storage. 855 checkPutFile(c, stor, "file-1.txt", contents) 856 checkPutFile(c, stor, "file-2.txt", contents) 857 err = stor.RemoveAll() 858 c.Check(err, gc.IsNil) 859 checkFileDoesNotExist(c, stor, "file-1.txt", t.Attempt) 860 checkFileDoesNotExist(c, stor, "file-2.txt", t.Attempt) 861 } 862 863 // Check that we get a consistent error when asking for an instance without 864 // a valid machine config. 865 func (t *LiveTests) TestStartInstanceWithEmptyNonceFails(c *gc.C) { 866 machineId := "4" 867 stateInfo := testing.FakeStateInfo(machineId) 868 apiInfo := testing.FakeAPIInfo(machineId) 869 machineConfig := environs.NewMachineConfig(machineId, "", stateInfo, apiInfo) 870 871 t.PrepareOnce(c) 872 possibleTools := envtesting.AssertUploadFakeToolsVersions(c, t.Env.Storage(), version.MustParseBinary("5.4.5-precise-amd64")) 873 inst, _, err := t.Env.StartInstance(constraints.Value{}, possibleTools, machineConfig) 874 if inst != nil { 875 err := t.Env.StopInstances([]instance.Instance{inst}) 876 c.Check(err, gc.IsNil) 877 } 878 c.Assert(inst, gc.IsNil) 879 c.Assert(err, gc.ErrorMatches, ".*missing machine nonce") 880 } 881 882 func (t *LiveTests) TestBootstrapWithDefaultSeries(c *gc.C) { 883 if !t.HasProvisioner { 884 c.Skip("HasProvisioner is false; cannot test deployment") 885 } 886 887 current := version.Current 888 other := current 889 other.Series = "quantal" 890 if current == other { 891 other.Series = "precise" 892 } 893 894 dummyCfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge(coretesting.Attrs{ 895 "state-server": false, 896 "name": "dummy storage", 897 })) 898 dummyenv, err := environs.Prepare(dummyCfg, configstore.NewMem()) 899 c.Assert(err, gc.IsNil) 900 defer dummyenv.Destroy() 901 902 t.Destroy(c) 903 904 attrs := t.TestConfig.Merge(coretesting.Attrs{"default-series": other.Series}) 905 cfg, err := config.New(config.NoDefaults, attrs) 906 c.Assert(err, gc.IsNil) 907 env, err := environs.Prepare(cfg, t.ConfigStore) 908 c.Assert(err, gc.IsNil) 909 defer environs.Destroy(env, t.ConfigStore) 910 911 currentName := envtools.StorageName(current) 912 otherName := envtools.StorageName(other) 913 envStorage := env.Storage() 914 dummyStorage := dummyenv.Storage() 915 916 defer envStorage.Remove(otherName) 917 918 _, err = sync.Upload(dummyStorage, ¤t.Number) 919 c.Assert(err, gc.IsNil) 920 921 // This will only work while cross-compiling across releases is safe, 922 // which depends on external elements. Tends to be safe for the last 923 // few releases, but we may have to refactor some day. 924 err = storageCopy(dummyStorage, currentName, envStorage, otherName) 925 c.Assert(err, gc.IsNil) 926 927 err = bootstrap.Bootstrap(bootstrapContext(c), env, constraints.Value{}) 928 c.Assert(err, gc.IsNil) 929 930 conn, err := juju.NewConn(env) 931 c.Assert(err, gc.IsNil) 932 defer conn.Close() 933 934 // Wait for machine agent to come up on the bootstrap 935 // machine and ensure it deployed the proper series. 936 m0, err := conn.State.Machine("0") 937 c.Assert(err, gc.IsNil) 938 mw0 := newMachineToolWaiter(m0) 939 defer mw0.Stop() 940 941 waitAgentTools(c, mw0, other) 942 } 943 944 func storageCopy(source storage.Storage, sourcePath string, target storage.Storage, targetPath string) error { 945 rc, err := storage.Get(source, sourcePath) 946 if err != nil { 947 return err 948 } 949 var buf bytes.Buffer 950 _, err = io.Copy(&buf, rc) 951 rc.Close() 952 if err != nil { 953 return err 954 } 955 return target.Put(targetPath, &buf, int64(buf.Len())) 956 }