github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/provider/ec2/local_test.go (about) 1 // Copyright 2011, 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package ec2_test 5 6 import ( 7 "fmt" 8 "regexp" 9 "sort" 10 "strings" 11 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 "launchpad.net/goamz/aws" 15 amzec2 "launchpad.net/goamz/ec2" 16 "launchpad.net/goamz/ec2/ec2test" 17 "launchpad.net/goamz/s3" 18 "launchpad.net/goamz/s3/s3test" 19 gc "launchpad.net/gocheck" 20 "launchpad.net/goyaml" 21 22 "github.com/juju/juju/constraints" 23 "github.com/juju/juju/environs" 24 "github.com/juju/juju/environs/bootstrap" 25 "github.com/juju/juju/environs/config" 26 "github.com/juju/juju/environs/configstore" 27 "github.com/juju/juju/environs/imagemetadata" 28 "github.com/juju/juju/environs/jujutest" 29 "github.com/juju/juju/environs/simplestreams" 30 envtesting "github.com/juju/juju/environs/testing" 31 "github.com/juju/juju/environs/tools" 32 "github.com/juju/juju/instance" 33 "github.com/juju/juju/juju/arch" 34 "github.com/juju/juju/juju/testing" 35 "github.com/juju/juju/provider/ec2" 36 coretesting "github.com/juju/juju/testing" 37 "github.com/juju/juju/utils/ssh" 38 "github.com/juju/juju/version" 39 ) 40 41 type ProviderSuite struct { 42 coretesting.BaseSuite 43 } 44 45 var _ = gc.Suite(&ProviderSuite{}) 46 47 func (t *ProviderSuite) assertGetImageMetadataSources(c *gc.C, stream, officialSourcePath string) { 48 // Make an env configured with the stream. 49 envAttrs := localConfigAttrs 50 if stream != "" { 51 envAttrs = envAttrs.Merge(coretesting.Attrs{ 52 "image-stream": stream, 53 }) 54 } 55 cfg, err := config.New(config.NoDefaults, envAttrs) 56 c.Assert(err, gc.IsNil) 57 env, err := environs.Prepare(cfg, coretesting.Context(c), configstore.NewMem()) 58 c.Assert(err, gc.IsNil) 59 c.Assert(env, gc.NotNil) 60 61 sources, err := imagemetadata.GetMetadataSources(env) 62 c.Assert(err, gc.IsNil) 63 c.Assert(len(sources), gc.Equals, 2) 64 var urls = make([]string, len(sources)) 65 for i, source := range sources { 66 url, err := source.URL("") 67 c.Assert(err, gc.IsNil) 68 urls[i] = url 69 } 70 // The control bucket URL contains the bucket name. 71 c.Check(strings.Contains(urls[0], ec2.ControlBucketName(env)+"/images"), jc.IsTrue) 72 c.Assert(urls[1], gc.Equals, fmt.Sprintf("http://cloud-images.ubuntu.com/%s/", officialSourcePath)) 73 } 74 75 func (t *ProviderSuite) TestGetImageMetadataSources(c *gc.C) { 76 t.assertGetImageMetadataSources(c, "", "releases") 77 t.assertGetImageMetadataSources(c, "released", "releases") 78 t.assertGetImageMetadataSources(c, "daily", "daily") 79 } 80 81 var localConfigAttrs = coretesting.FakeConfig().Merge(coretesting.Attrs{ 82 "name": "sample", 83 "type": "ec2", 84 "region": "test", 85 "control-bucket": "test-bucket", 86 "access-key": "x", 87 "secret-key": "x", 88 "agent-version": version.Current.Number.String(), 89 }) 90 91 func registerLocalTests() { 92 // N.B. Make sure the region we use here 93 // has entries in the images/query txt files. 94 aws.Regions["test"] = aws.Region{ 95 Name: "test", 96 } 97 98 gc.Suite(&localServerSuite{}) 99 gc.Suite(&localLiveSuite{}) 100 gc.Suite(&localNonUSEastSuite{}) 101 } 102 103 // localLiveSuite runs tests from LiveTests using a fake 104 // EC2 server that runs within the test process itself. 105 type localLiveSuite struct { 106 LiveTests 107 srv localServer 108 restoreEC2Patching func() 109 } 110 111 func (t *localLiveSuite) SetUpSuite(c *gc.C) { 112 t.TestConfig = localConfigAttrs 113 t.restoreEC2Patching = patchEC2ForTesting() 114 t.srv.startServer(c) 115 t.LiveTests.SetUpSuite(c) 116 } 117 118 func (t *localLiveSuite) TearDownSuite(c *gc.C) { 119 t.LiveTests.TearDownSuite(c) 120 t.srv.stopServer(c) 121 t.restoreEC2Patching() 122 } 123 124 // localServer represents a fake EC2 server running within 125 // the test process itself. 126 type localServer struct { 127 ec2srv *ec2test.Server 128 s3srv *s3test.Server 129 config *s3test.Config 130 } 131 132 func (srv *localServer) startServer(c *gc.C) { 133 var err error 134 srv.ec2srv, err = ec2test.NewServer() 135 if err != nil { 136 c.Fatalf("cannot start ec2 test server: %v", err) 137 } 138 srv.s3srv, err = s3test.NewServer(srv.config) 139 if err != nil { 140 c.Fatalf("cannot start s3 test server: %v", err) 141 } 142 aws.Regions["test"] = aws.Region{ 143 Name: "test", 144 EC2Endpoint: srv.ec2srv.URL(), 145 S3Endpoint: srv.s3srv.URL(), 146 S3LocationConstraint: true, 147 } 148 s3inst := s3.New(aws.Auth{}, aws.Regions["test"]) 149 storage := ec2.BucketStorage(s3inst.Bucket("juju-dist")) 150 envtesting.UploadFakeTools(c, storage) 151 srv.addSpice(c) 152 153 zones := make([]amzec2.AvailabilityZoneInfo, 3) 154 zones[0].Region = "test" 155 zones[0].Name = "test-available" 156 zones[0].State = "available" 157 zones[1].Region = "test" 158 zones[1].Name = "test-impaired" 159 zones[1].State = "impaired" 160 zones[2].Region = "test" 161 zones[2].Name = "test-unavailable" 162 zones[2].State = "unavailable" 163 srv.ec2srv.SetAvailabilityZones(zones) 164 } 165 166 // addSpice adds some "spice" to the local server 167 // by adding state that may cause tests to fail. 168 func (srv *localServer) addSpice(c *gc.C) { 169 states := []amzec2.InstanceState{ 170 ec2test.ShuttingDown, 171 ec2test.Terminated, 172 ec2test.Stopped, 173 } 174 for _, state := range states { 175 srv.ec2srv.NewInstances(1, "m1.small", "ami-a7f539ce", state, nil) 176 } 177 } 178 179 func (srv *localServer) stopServer(c *gc.C) { 180 srv.ec2srv.Quit() 181 srv.s3srv.Quit() 182 // Clear out the region because the server address is 183 // no longer valid. 184 delete(aws.Regions, "test") 185 } 186 187 // localServerSuite contains tests that run against a fake EC2 server 188 // running within the test process itself. These tests can test things that 189 // would be unreasonably slow or expensive to test on a live Amazon server. 190 // It starts a new local ec2test server for each test. The server is 191 // accessed by using the "test" region, which is changed to point to the 192 // network address of the local server. 193 type localServerSuite struct { 194 coretesting.BaseSuite 195 jujutest.Tests 196 srv localServer 197 restoreEC2Patching func() 198 } 199 200 func (t *localServerSuite) SetUpSuite(c *gc.C) { 201 t.TestConfig = localConfigAttrs 202 t.restoreEC2Patching = patchEC2ForTesting() 203 t.BaseSuite.SetUpSuite(c) 204 } 205 206 func (t *localServerSuite) TearDownSuite(c *gc.C) { 207 t.BaseSuite.TearDownSuite(c) 208 t.restoreEC2Patching() 209 } 210 211 func (t *localServerSuite) SetUpTest(c *gc.C) { 212 t.BaseSuite.SetUpTest(c) 213 t.srv.startServer(c) 214 t.Tests.SetUpTest(c) 215 t.PatchValue(&version.Current, version.Binary{ 216 Number: version.Current.Number, 217 Series: coretesting.FakeDefaultSeries, 218 Arch: arch.AMD64, 219 }) 220 } 221 222 func (t *localServerSuite) TearDownTest(c *gc.C) { 223 t.Tests.TearDownTest(c) 224 t.srv.stopServer(c) 225 t.BaseSuite.TearDownTest(c) 226 } 227 228 func (t *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) { 229 env := t.Prepare(c) 230 envtesting.UploadFakeTools(c, env.Storage()) 231 err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) 232 c.Assert(err, gc.IsNil) 233 234 // check that the state holds the id of the bootstrap machine. 235 bootstrapState, err := bootstrap.LoadState(env.Storage()) 236 c.Assert(err, gc.IsNil) 237 c.Assert(bootstrapState.StateInstances, gc.HasLen, 1) 238 239 insts, err := env.AllInstances() 240 c.Assert(err, gc.IsNil) 241 c.Assert(insts, gc.HasLen, 1) 242 c.Check(insts[0].Id(), gc.Equals, bootstrapState.StateInstances[0]) 243 244 // check that the user data is configured to start zookeeper 245 // and the machine and provisioning agents. 246 // check that the user data is configured to only configure 247 // authorized SSH keys and set the log output; everything 248 // else happens after the machine is brought up. 249 inst := t.srv.ec2srv.Instance(string(insts[0].Id())) 250 c.Assert(inst, gc.NotNil) 251 addresses, err := insts[0].Addresses() 252 c.Assert(err, gc.IsNil) 253 c.Assert(addresses, gc.Not(gc.HasLen), 0) 254 userData, err := utils.Gunzip(inst.UserData) 255 c.Assert(err, gc.IsNil) 256 c.Logf("first instance: UserData: %q", userData) 257 var userDataMap map[interface{}]interface{} 258 err = goyaml.Unmarshal(userData, &userDataMap) 259 c.Assert(err, gc.IsNil) 260 c.Assert(userDataMap, jc.DeepEquals, map[interface{}]interface{}{ 261 "output": map[interface{}]interface{}{ 262 "all": "| tee -a /var/log/cloud-init-output.log", 263 }, 264 "ssh_authorized_keys": splitAuthKeys(env.Config().AuthorizedKeys()), 265 "runcmd": []interface{}{ 266 "set -xe", 267 "install -D -m 644 /dev/null '/var/lib/juju/nonce.txt'", 268 "printf '%s\\n' 'user-admin:bootstrap' > '/var/lib/juju/nonce.txt'", 269 }, 270 }) 271 272 // check that a new instance will be started with a machine agent 273 inst1, hc := testing.AssertStartInstance(c, env, "1") 274 c.Check(*hc.Arch, gc.Equals, "amd64") 275 c.Check(*hc.Mem, gc.Equals, uint64(1740)) 276 c.Check(*hc.CpuCores, gc.Equals, uint64(1)) 277 c.Assert(*hc.CpuPower, gc.Equals, uint64(100)) 278 inst = t.srv.ec2srv.Instance(string(inst1.Id())) 279 c.Assert(inst, gc.NotNil) 280 userData, err = utils.Gunzip(inst.UserData) 281 c.Assert(err, gc.IsNil) 282 c.Logf("second instance: UserData: %q", userData) 283 userDataMap = nil 284 err = goyaml.Unmarshal(userData, &userDataMap) 285 c.Assert(err, gc.IsNil) 286 CheckPackage(c, userDataMap, "git", true) 287 CheckPackage(c, userDataMap, "mongodb-server", false) 288 CheckScripts(c, userDataMap, "jujud bootstrap-state", false) 289 CheckScripts(c, userDataMap, "/var/lib/juju/agents/machine-1/agent.conf", true) 290 // TODO check for provisioning agent 291 292 err = env.Destroy() 293 c.Assert(err, gc.IsNil) 294 295 _, err = bootstrap.LoadState(env.Storage()) 296 c.Assert(err, gc.NotNil) 297 } 298 299 // splitAuthKeys splits the given authorized keys 300 // into the form expected to be found in the 301 // user data. 302 func splitAuthKeys(keys string) []interface{} { 303 slines := strings.FieldsFunc(keys, func(r rune) bool { 304 return r == '\n' 305 }) 306 var lines []interface{} 307 for _, line := range slines { 308 lines = append(lines, ssh.EnsureJujuComment(strings.TrimSpace(line))) 309 } 310 return lines 311 } 312 313 func (t *localServerSuite) TestInstanceStatus(c *gc.C) { 314 env := t.Prepare(c) 315 envtesting.UploadFakeTools(c, env.Storage()) 316 err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) 317 c.Assert(err, gc.IsNil) 318 t.srv.ec2srv.SetInitialInstanceState(ec2test.Terminated) 319 inst, _ := testing.AssertStartInstance(c, env, "1") 320 c.Assert(err, gc.IsNil) 321 c.Assert(inst.Status(), gc.Equals, "terminated") 322 } 323 324 func (t *localServerSuite) TestStartInstanceHardwareCharacteristics(c *gc.C) { 325 env := t.Prepare(c) 326 envtesting.UploadFakeTools(c, env.Storage()) 327 err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) 328 c.Assert(err, gc.IsNil) 329 _, hc := testing.AssertStartInstance(c, env, "1") 330 c.Check(*hc.Arch, gc.Equals, "amd64") 331 c.Check(*hc.Mem, gc.Equals, uint64(1740)) 332 c.Check(*hc.CpuCores, gc.Equals, uint64(1)) 333 c.Assert(*hc.CpuPower, gc.Equals, uint64(100)) 334 } 335 336 func (t *localServerSuite) TestStartInstanceAvailZone(c *gc.C) { 337 inst, err := t.testStartInstanceAvailZone(c, "test-available") 338 c.Assert(err, gc.IsNil) 339 c.Assert(ec2.InstanceEC2(inst).AvailZone, gc.Equals, "test-available") 340 } 341 342 func (t *localServerSuite) TestStartInstanceAvailZoneImpaired(c *gc.C) { 343 _, err := t.testStartInstanceAvailZone(c, "test-impaired") 344 c.Assert(err, gc.ErrorMatches, `availability zone "test-impaired" is impaired`) 345 } 346 347 func (t *localServerSuite) TestStartInstanceAvailZoneUnknown(c *gc.C) { 348 _, err := t.testStartInstanceAvailZone(c, "test-unknown") 349 c.Assert(err, gc.ErrorMatches, `invalid availability zone "test-unknown"`) 350 } 351 352 func (t *localServerSuite) testStartInstanceAvailZone(c *gc.C, zone string) (instance.Instance, error) { 353 env := t.Prepare(c) 354 envtesting.UploadFakeTools(c, env.Storage()) 355 err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) 356 c.Assert(err, gc.IsNil) 357 358 params := environs.StartInstanceParams{Placement: "zone=" + zone} 359 inst, _, _, err := testing.StartInstanceWithParams(env, "1", params, nil) 360 return inst, err 361 } 362 363 func (t *localServerSuite) TestGetAvailabilityZones(c *gc.C) { 364 var resultZones []amzec2.AvailabilityZoneInfo 365 var resultErr error 366 t.PatchValue(ec2.EC2AvailabilityZones, func(e *amzec2.EC2, f *amzec2.Filter) (*amzec2.AvailabilityZonesResp, error) { 367 resp := &amzec2.AvailabilityZonesResp{ 368 Zones: append([]amzec2.AvailabilityZoneInfo{}, resultZones...), 369 } 370 return resp, resultErr 371 }) 372 env := t.Prepare(c) 373 374 resultErr = fmt.Errorf("failed to get availability zones") 375 zones, err := ec2.GetAvailabilityZones(env) 376 c.Assert(err, gc.Equals, resultErr) 377 c.Assert(zones, gc.IsNil) 378 379 resultErr = nil 380 resultZones = make([]amzec2.AvailabilityZoneInfo, 1) 381 resultZones[0].Name = "whatever" 382 zones, err = ec2.GetAvailabilityZones(env) 383 c.Assert(err, gc.IsNil) 384 c.Assert(zones, gc.HasLen, 1) 385 c.Assert(zones[0].Name, gc.Equals, "whatever") 386 387 // A successful result is cached, currently for the lifetime 388 // of the Environ. This will change if/when we have long-lived 389 // Environs to cut down repeated IaaS requests. 390 resultErr = fmt.Errorf("failed to get availability zones") 391 resultZones[0].Name = "andever" 392 zones, err = ec2.GetAvailabilityZones(env) 393 c.Assert(err, gc.IsNil) 394 c.Assert(zones, gc.HasLen, 1) 395 c.Assert(zones[0].Name, gc.Equals, "whatever") 396 } 397 398 func (t *localServerSuite) TestAddresses(c *gc.C) { 399 env := t.Prepare(c) 400 envtesting.UploadFakeTools(c, env.Storage()) 401 err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) 402 c.Assert(err, gc.IsNil) 403 inst, _ := testing.AssertStartInstance(c, env, "1") 404 c.Assert(err, gc.IsNil) 405 addrs, err := inst.Addresses() 406 c.Assert(err, gc.IsNil) 407 // Expected values use Address type but really contain a regexp for 408 // the value rather than a valid ip or hostname. 409 expected := []instance.Address{{ 410 Value: "*.testing.invalid", 411 Type: instance.HostName, 412 NetworkScope: instance.NetworkPublic, 413 }, { 414 Value: "*.internal.invalid", 415 Type: instance.HostName, 416 NetworkScope: instance.NetworkCloudLocal, 417 }, { 418 Value: "8.0.0.*", 419 Type: instance.Ipv4Address, 420 NetworkScope: instance.NetworkPublic, 421 }, { 422 Value: "127.0.0.*", 423 Type: instance.Ipv4Address, 424 NetworkScope: instance.NetworkCloudLocal, 425 }} 426 c.Assert(addrs, gc.HasLen, len(expected)) 427 for i, addr := range addrs { 428 c.Check(addr.Value, gc.Matches, expected[i].Value) 429 c.Check(addr.Type, gc.Equals, expected[i].Type) 430 c.Check(addr.NetworkScope, gc.Equals, expected[i].NetworkScope) 431 } 432 } 433 434 func (t *localServerSuite) TestConstraintsValidatorUnsupported(c *gc.C) { 435 env := t.Prepare(c) 436 validator, err := env.ConstraintsValidator() 437 c.Assert(err, gc.IsNil) 438 cons := constraints.MustParse("arch=amd64 tags=foo") 439 unsupported, err := validator.Validate(cons) 440 c.Assert(err, gc.IsNil) 441 c.Assert(unsupported, gc.DeepEquals, []string{"tags"}) 442 } 443 444 func (t *localServerSuite) TestConstraintsValidatorVocab(c *gc.C) { 445 env := t.Prepare(c) 446 validator, err := env.ConstraintsValidator() 447 c.Assert(err, gc.IsNil) 448 cons := constraints.MustParse("arch=ppc64") 449 _, err = validator.Validate(cons) 450 c.Assert(err, gc.ErrorMatches, "invalid constraint value: arch=ppc64\nvalid values are:.*") 451 cons = constraints.MustParse("instance-type=foo") 452 _, err = validator.Validate(cons) 453 c.Assert(err, gc.ErrorMatches, "invalid constraint value: instance-type=foo\nvalid values are:.*") 454 } 455 456 func (t *localServerSuite) TestConstraintsMerge(c *gc.C) { 457 env := t.Prepare(c) 458 validator, err := env.ConstraintsValidator() 459 c.Assert(err, gc.IsNil) 460 consA := constraints.MustParse("arch=amd64 mem=1G cpu-power=10 cpu-cores=2 tags=bar") 461 consB := constraints.MustParse("arch=i386 instance-type=m1.small") 462 cons, err := validator.Merge(consA, consB) 463 c.Assert(err, gc.IsNil) 464 c.Assert(cons, gc.DeepEquals, constraints.MustParse("arch=i386 instance-type=m1.small tags=bar")) 465 } 466 467 func (t *localServerSuite) TestPrecheckInstanceValidInstanceType(c *gc.C) { 468 env := t.Prepare(c) 469 cons := constraints.MustParse("instance-type=m1.small root-disk=1G") 470 placement := "" 471 err := env.PrecheckInstance("precise", cons, placement) 472 c.Assert(err, gc.IsNil) 473 } 474 475 func (t *localServerSuite) TestPrecheckInstanceInvalidInstanceType(c *gc.C) { 476 env := t.Prepare(c) 477 cons := constraints.MustParse("instance-type=m1.invalid") 478 placement := "" 479 err := env.PrecheckInstance("precise", cons, placement) 480 c.Assert(err, gc.ErrorMatches, `invalid AWS instance type "m1.invalid" specified`) 481 } 482 483 func (t *localServerSuite) TestPrecheckInstanceUnsupportedArch(c *gc.C) { 484 env := t.Prepare(c) 485 cons := constraints.MustParse("instance-type=cc1.4xlarge arch=i386") 486 placement := "" 487 err := env.PrecheckInstance("precise", cons, placement) 488 c.Assert(err, gc.ErrorMatches, `invalid AWS instance type "cc1.4xlarge" and arch "i386" specified`) 489 } 490 491 func (t *localServerSuite) TestPrecheckInstanceAvailZone(c *gc.C) { 492 env := t.Prepare(c) 493 placement := "zone=test-available" 494 err := env.PrecheckInstance("precise", constraints.Value{}, placement) 495 c.Assert(err, gc.IsNil) 496 } 497 498 func (t *localServerSuite) TestPrecheckInstanceAvailZoneUnavailable(c *gc.C) { 499 env := t.Prepare(c) 500 placement := "zone=test-unavailable" 501 err := env.PrecheckInstance("precise", constraints.Value{}, placement) 502 c.Assert(err, gc.IsNil) 503 } 504 505 func (t *localServerSuite) TestPrecheckInstanceAvailZoneUnknown(c *gc.C) { 506 env := t.Prepare(c) 507 placement := "zone=test-unknown" 508 err := env.PrecheckInstance("precise", constraints.Value{}, placement) 509 c.Assert(err, gc.ErrorMatches, `invalid availability zone "test-unknown"`) 510 } 511 512 func (t *localServerSuite) TestValidateImageMetadata(c *gc.C) { 513 env := t.Prepare(c) 514 params, err := env.(simplestreams.MetadataValidator).MetadataLookupParams("test") 515 c.Assert(err, gc.IsNil) 516 params.Series = "precise" 517 params.Endpoint = "https://ec2.endpoint.com" 518 params.Sources, err = imagemetadata.GetMetadataSources(env) 519 c.Assert(err, gc.IsNil) 520 image_ids, _, err := imagemetadata.ValidateImageMetadata(params) 521 c.Assert(err, gc.IsNil) 522 sort.Strings(image_ids) 523 c.Assert(image_ids, gc.DeepEquals, []string{"ami-00000033", "ami-00000034", "ami-00000035"}) 524 } 525 526 func (t *localServerSuite) TestGetToolsMetadataSources(c *gc.C) { 527 env := t.Prepare(c) 528 sources, err := tools.GetMetadataSources(env) 529 c.Assert(err, gc.IsNil) 530 c.Assert(len(sources), gc.Equals, 1) 531 url, err := sources[0].URL("") 532 // The control bucket URL contains the bucket name. 533 c.Assert(strings.Contains(url, ec2.ControlBucketName(env)+"/tools"), jc.IsTrue) 534 } 535 536 func (t *localServerSuite) TestSupportedArchitectures(c *gc.C) { 537 env := t.Prepare(c) 538 a, err := env.SupportedArchitectures() 539 c.Assert(err, gc.IsNil) 540 c.Assert(a, jc.SameContents, []string{"amd64", "i386"}) 541 } 542 543 func (t *localServerSuite) TestSupportNetworks(c *gc.C) { 544 env := t.Prepare(c) 545 c.Assert(env.SupportNetworks(), jc.IsFalse) 546 } 547 548 // localNonUSEastSuite is similar to localServerSuite but the S3 mock server 549 // behaves as if it is not in the us-east region. 550 type localNonUSEastSuite struct { 551 coretesting.BaseSuite 552 restoreEC2Patching func() 553 srv localServer 554 env environs.Environ 555 } 556 557 func (t *localNonUSEastSuite) SetUpSuite(c *gc.C) { 558 t.BaseSuite.SetUpSuite(c) 559 t.restoreEC2Patching = patchEC2ForTesting() 560 } 561 562 func (t *localNonUSEastSuite) TearDownSuite(c *gc.C) { 563 t.restoreEC2Patching() 564 t.BaseSuite.TearDownSuite(c) 565 } 566 567 func (t *localNonUSEastSuite) SetUpTest(c *gc.C) { 568 t.BaseSuite.SetUpTest(c) 569 t.srv.config = &s3test.Config{ 570 Send409Conflict: true, 571 } 572 t.srv.startServer(c) 573 574 cfg, err := config.New(config.NoDefaults, localConfigAttrs) 575 c.Assert(err, gc.IsNil) 576 env, err := environs.Prepare(cfg, coretesting.Context(c), configstore.NewMem()) 577 c.Assert(err, gc.IsNil) 578 t.env = env 579 } 580 581 func (t *localNonUSEastSuite) TearDownTest(c *gc.C) { 582 t.srv.stopServer(c) 583 t.BaseSuite.TearDownTest(c) 584 } 585 586 func patchEC2ForTesting() func() { 587 ec2.UseTestImageData(ec2.TestImagesData) 588 ec2.UseTestInstanceTypeData(ec2.TestInstanceTypeCosts) 589 ec2.UseTestRegionData(ec2.TestRegions) 590 restoreTimeouts := envtesting.PatchAttemptStrategies(ec2.ShortAttempt, ec2.StorageAttempt) 591 restoreFinishBootstrap := envtesting.DisableFinishBootstrap() 592 return func() { 593 restoreFinishBootstrap() 594 restoreTimeouts() 595 ec2.UseTestImageData(nil) 596 ec2.UseTestInstanceTypeData(nil) 597 ec2.UseTestRegionData(nil) 598 } 599 } 600 601 // If match is true, CheckScripts checks that at least one script started 602 // by the cloudinit data matches the given regexp pattern, otherwise it 603 // checks that no script matches. It's exported so it can be used by tests 604 // defined in ec2_test. 605 func CheckScripts(c *gc.C, userDataMap map[interface{}]interface{}, pattern string, match bool) { 606 scripts0 := userDataMap["runcmd"] 607 if scripts0 == nil { 608 c.Errorf("cloudinit has no entry for runcmd") 609 return 610 } 611 scripts := scripts0.([]interface{}) 612 re := regexp.MustCompile(pattern) 613 found := false 614 for _, s0 := range scripts { 615 s := s0.(string) 616 if re.MatchString(s) { 617 found = true 618 } 619 } 620 switch { 621 case match && !found: 622 c.Errorf("script %q not found in %q", pattern, scripts) 623 case !match && found: 624 c.Errorf("script %q found but not expected in %q", pattern, scripts) 625 } 626 } 627 628 // CheckPackage checks that the cloudinit will or won't install the given 629 // package, depending on the value of match. It's exported so it can be 630 // used by tests defined outside the ec2 package. 631 func CheckPackage(c *gc.C, userDataMap map[interface{}]interface{}, pkg string, match bool) { 632 pkgs0 := userDataMap["packages"] 633 if pkgs0 == nil { 634 if match { 635 c.Errorf("cloudinit has no entry for packages") 636 } 637 return 638 } 639 640 pkgs := pkgs0.([]interface{}) 641 642 found := false 643 for _, p0 := range pkgs { 644 p := p0.(string) 645 if p == pkg { 646 found = true 647 } 648 } 649 switch { 650 case match && !found: 651 c.Errorf("package %q not found in %v", pkg, pkgs) 652 case !match && found: 653 c.Errorf("%q found but not expected in %v", pkg, pkgs) 654 } 655 }