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