1
// Copyright 2012, 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
19
jujuerrors "github.com/juju/errors"
20
gitjujutesting "github.com/juju/testing"
21
jc "github.com/juju/testing/checkers"
22
"github.com/juju/utils"
23
"github.com/juju/utils/arch"
24
"github.com/juju/utils/series"
25
"github.com/juju/utils/ssh"
26
"github.com/juju/version"
27
gc "gopkg.in/check.v1"
28
"gopkg.in/goose.v1/client"
29
"gopkg.in/goose.v1/identity"
30
"gopkg.in/goose.v1/nova"
31
"gopkg.in/goose.v1/testservices/hook"
32
"gopkg.in/goose.v1/testservices/identityservice"
33
"gopkg.in/goose.v1/testservices/novaservice"
34
"gopkg.in/goose.v1/testservices/openstackservice"
36
"github.com/juju/juju/cloud"
37
"github.com/juju/juju/cloudconfig/instancecfg"
38
"github.com/juju/juju/constraints"
39
"github.com/juju/juju/environs"
40
"github.com/juju/juju/environs/bootstrap"
41
"github.com/juju/juju/environs/config"
42
"github.com/juju/juju/environs/filestorage"
43
"github.com/juju/juju/environs/imagemetadata"
44
imagetesting "github.com/juju/juju/environs/imagemetadata/testing"
45
"github.com/juju/juju/environs/jujutest"
46
"github.com/juju/juju/environs/simplestreams"
47
sstesting "github.com/juju/juju/environs/simplestreams/testing"
48
"github.com/juju/juju/environs/storage"
49
envtesting "github.com/juju/juju/environs/testing"
50
"github.com/juju/juju/environs/tools"
51
"github.com/juju/juju/instance"
52
"github.com/juju/juju/juju/keys"
53
"github.com/juju/juju/juju/testing"
54
"github.com/juju/juju/jujuclient/jujuclienttesting"
55
"github.com/juju/juju/network"
56
"github.com/juju/juju/provider/common"
57
"github.com/juju/juju/provider/openstack"
58
"github.com/juju/juju/status"
59
coretesting "github.com/juju/juju/testing"
60
jujuversion "github.com/juju/juju/version"
63
type ProviderSuite struct {
64
restoreTimeouts func()
67
var _ = gc.Suite(&ProviderSuite{})
68
var _ = gc.Suite(&localHTTPSServerSuite{})
69
var _ = gc.Suite(&noSwiftSuite{})
71
func (s *ProviderSuite) SetUpTest(c *gc.C) {
72
s.restoreTimeouts = envtesting.PatchAttemptStrategies(openstack.ShortAttempt, openstack.StorageAttempt)
75
func (s *ProviderSuite) TearDownTest(c *gc.C) {
79
// Register tests to run against a test Openstack instance (service doubles).
80
func registerLocalTests() {
81
cred := &identity.Credentials{
84
Region: "some-region",
85
TenantName: "some tenant",
87
config := makeTestConfig(cred)
88
config["agent-version"] = coretesting.FakeVersionNumber.String()
89
config["authorized-keys"] = "fakekey"
90
gc.Suite(&localLiveSuite{
93
LiveTests: jujutest.LiveTests{
98
gc.Suite(&localServerSuite{
100
Tests: jujutest.Tests{
106
// localServer is used to spin up a local Openstack service double.
107
type localServer struct {
108
Server *httptest.Server
110
oldHandler http.Handler
111
Nova *novaservice.Nova
112
restoreTimeouts func()
116
type newOpenstackFunc func(*http.ServeMux, *identity.Credentials, identity.AuthMode) *novaservice.Nova
118
func (s *localServer) start(
119
c *gc.C, cred *identity.Credentials, newOpenstackFunc newOpenstackFunc,
121
// Set up the HTTP server.
123
s.Server = httptest.NewTLSServer(nil)
125
s.Server = httptest.NewServer(nil)
127
c.Assert(s.Server, gc.NotNil)
128
s.oldHandler = s.Server.Config.Handler
129
s.Mux = http.NewServeMux()
130
s.Server.Config.Handler = s.Mux
131
cred.URL = s.Server.URL
132
c.Logf("Started service at: %v", s.Server.URL)
133
s.Nova = newOpenstackFunc(s.Mux, cred, identity.AuthUserPass)
134
s.restoreTimeouts = envtesting.PatchAttemptStrategies(openstack.ShortAttempt, openstack.StorageAttempt)
135
s.Nova.SetAvailabilityZones(
136
nova.AvailabilityZone{Name: "test-unavailable"},
137
nova.AvailabilityZone{
138
Name: "test-available",
139
State: nova.AvailabilityZoneState{
146
func (s *localServer) stop() {
148
s.Server.Config.Handler = s.oldHandler
153
// localLiveSuite runs tests from LiveTests using an Openstack service double.
154
type localLiveSuite struct {
155
coretesting.BaseSuite
160
func overrideCinderProvider(c *gc.C, s *gitjujutesting.CleanupSuite) {
161
s.PatchValue(openstack.NewOpenstackStorage, func(*openstack.Environ) (openstack.OpenstackStorage, error) {
162
return &mockAdapter{}, nil
166
func (s *localLiveSuite) SetUpSuite(c *gc.C) {
167
s.BaseSuite.SetUpSuite(c)
169
c.Logf("Running live tests using openstack service test double")
170
s.srv.start(c, s.cred, newFullOpenstackService)
172
// Set credentials to use when bootstrapping. Must be done after
173
// starting server to get the auth URL.
174
s.Credential = makeCredential(s.cred)
175
s.CloudEndpoint = s.cred.URL
176
s.CloudRegion = s.cred.Region
178
s.LiveTests.SetUpSuite(c)
179
openstack.UseTestImageData(openstack.ImageMetadataStorage(s.Env), s.cred)
180
restoreFinishBootstrap := envtesting.DisableFinishBootstrap()
181
s.AddCleanup(func(*gc.C) { restoreFinishBootstrap() })
182
overrideCinderProvider(c, &s.CleanupSuite)
185
func (s *localLiveSuite) TearDownSuite(c *gc.C) {
186
openstack.RemoveTestImageData(openstack.ImageMetadataStorage(s.Env))
187
s.LiveTests.TearDownSuite(c)
189
s.BaseSuite.TearDownSuite(c)
192
func (s *localLiveSuite) SetUpTest(c *gc.C) {
193
s.BaseSuite.SetUpTest(c)
194
s.LiveTests.SetUpTest(c)
195
imagetesting.PatchOfficialDataSources(&s.CleanupSuite, "")
198
func (s *localLiveSuite) TearDownTest(c *gc.C) {
199
s.LiveTests.TearDownTest(c)
200
s.BaseSuite.TearDownTest(c)
203
// localServerSuite contains tests that run against an Openstack service double.
204
// These tests can test things that would be unreasonably slow or expensive
205
// to test on a live Openstack server. The service double is started and stopped for
207
type localServerSuite struct {
208
coretesting.BaseSuite
210
cred *identity.Credentials
213
toolsMetadataStorage storage.Storage
214
imageMetadataStorage storage.Storage
217
func (s *localServerSuite) SetUpSuite(c *gc.C) {
218
s.BaseSuite.SetUpSuite(c)
219
restoreFinishBootstrap := envtesting.DisableFinishBootstrap()
220
s.AddCleanup(func(*gc.C) { restoreFinishBootstrap() })
221
overrideCinderProvider(c, &s.CleanupSuite)
222
c.Logf("Running local tests")
225
func (s *localServerSuite) SetUpTest(c *gc.C) {
226
s.BaseSuite.SetUpTest(c)
227
s.srv.start(c, s.cred, newFullOpenstackService)
229
// Set credentials to use when bootstrapping. Must be done after
230
// starting server to get the auth URL.
231
s.Credential = makeCredential(s.cred)
232
s.CloudEndpoint = s.cred.URL
233
s.CloudRegion = s.cred.Region
235
cl := client.NewClient(s.cred, identity.AuthUserPass, nil)
236
err := cl.Authenticate()
237
c.Assert(err, jc.ErrorIsNil)
238
containerURL, err := cl.MakeServiceURL("object-store", nil)
239
c.Assert(err, jc.ErrorIsNil)
240
s.TestConfig = s.TestConfig.Merge(coretesting.Attrs{
241
"agent-metadata-url": containerURL + "/juju-dist-test/tools",
242
"image-metadata-url": containerURL + "/juju-dist-test",
243
"auth-url": s.cred.URL,
245
s.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber)
247
// For testing, we create a storage instance to which is uploaded tools and image metadata.
249
s.toolsMetadataStorage = openstack.MetadataStorage(s.env)
250
// Put some fake metadata in place so that tests that are simply
251
// starting instances without any need to check if those instances
252
// are running can find the metadata.
253
envtesting.UploadFakeTools(c, s.toolsMetadataStorage, s.env.Config().AgentStream(), s.env.Config().AgentStream())
254
s.imageMetadataStorage = openstack.ImageMetadataStorage(s.env)
255
openstack.UseTestImageData(s.imageMetadataStorage, s.cred)
258
func (s *localServerSuite) TearDownTest(c *gc.C) {
259
if s.imageMetadataStorage != nil {
260
openstack.RemoveTestImageData(s.imageMetadataStorage)
262
if s.toolsMetadataStorage != nil {
263
envtesting.RemoveFakeToolsMetadata(c, s.toolsMetadataStorage)
265
s.Tests.TearDownTest(c)
267
s.BaseSuite.TearDownTest(c)
270
func (s *localServerSuite) openEnviron(c *gc.C, attrs coretesting.Attrs) environs.Environ {
271
cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(attrs))
272
c.Assert(err, jc.ErrorIsNil)
273
env, err := environs.New(environs.OpenParams{
274
Cloud: s.CloudSpec(),
277
c.Assert(err, jc.ErrorIsNil)
281
func (s *localServerSuite) TestBootstrap(c *gc.C) {
282
// Tests uses Prepare, so destroy first.
283
err := environs.Destroy(s.env.Config().Name(), s.env, s.ControllerStore)
284
c.Assert(err, jc.ErrorIsNil)
285
s.Tests.TestBootstrap(c)
288
func (s *localServerSuite) TestStartStop(c *gc.C) {
289
// Tests uses Prepare, so destroy first.
290
err := environs.Destroy(s.env.Config().Name(), s.env, s.ControllerStore)
291
c.Assert(err, jc.ErrorIsNil)
292
s.Tests.TestStartStop(c)
295
// If the bootstrap node is configured to require a public IP address,
296
// bootstrapping fails if an address cannot be allocated.
297
func (s *localServerSuite) TestBootstrapFailsWhenPublicIPError(c *gc.C) {
298
coretesting.SkipIfPPC64EL(c, "lp:1425242")
300
cleanup := s.srv.Nova.RegisterControlPoint(
302
func(sc hook.ServiceControl, args ...interface{}) error {
303
return fmt.Errorf("failed on purpose")
308
err := environs.Destroy(s.env.Config().Name(), s.env, s.ControllerStore)
309
c.Assert(err, jc.ErrorIsNil)
311
env := s.openEnviron(c, coretesting.Attrs{"use-floating-ip": true})
312
err = bootstrapEnv(c, env)
313
c.Assert(err, gc.ErrorMatches, "(.|\n)*cannot allocate a public IP as needed(.|\n)*")
316
func (s *localServerSuite) TestAddressesWithPublicIP(c *gc.C) {
317
// Floating IP address is 10.0.0.1
318
bootstrapFinished := false
319
s.PatchValue(&common.FinishBootstrap, func(
320
ctx environs.BootstrapContext,
322
env environs.Environ,
323
inst instance.Instance,
324
instanceConfig *instancecfg.InstanceConfig,
325
_ environs.BootstrapDialOpts,
327
addr, err := inst.Addresses()
328
c.Assert(err, jc.ErrorIsNil)
329
c.Assert(addr, jc.SameContents, []network.Address{
330
{Value: "10.0.0.1", Type: "ipv4", Scope: "public"},
331
{Value: "127.0.0.1", Type: "ipv4", Scope: "local-machine"},
332
{Value: "::face::000f", Type: "hostname", Scope: ""},
333
{Value: "127.10.0.1", Type: "ipv4", Scope: "public"},
334
{Value: "::dead:beef:f00d", Type: "ipv6", Scope: "public"},
336
bootstrapFinished = true
340
env := s.openEnviron(c, coretesting.Attrs{"use-floating-ip": true})
341
err := bootstrapEnv(c, env)
342
c.Assert(err, jc.ErrorIsNil)
343
c.Assert(bootstrapFinished, jc.IsTrue)
346
func (s *localServerSuite) TestAddressesWithoutPublicIP(c *gc.C) {
347
bootstrapFinished := false
348
s.PatchValue(&common.FinishBootstrap, func(
349
ctx environs.BootstrapContext,
351
env environs.Environ,
352
inst instance.Instance,
353
instanceConfig *instancecfg.InstanceConfig,
354
_ environs.BootstrapDialOpts,
356
addr, err := inst.Addresses()
357
c.Assert(err, jc.ErrorIsNil)
358
c.Assert(addr, jc.SameContents, []network.Address{
359
{Value: "127.0.0.1", Type: "ipv4", Scope: "local-machine"},
360
{Value: "::face::000f", Type: "hostname", Scope: ""},
361
{Value: "127.10.0.1", Type: "ipv4", Scope: "public"},
362
{Value: "::dead:beef:f00d", Type: "ipv6", Scope: "public"},
364
bootstrapFinished = true
368
env := s.openEnviron(c, coretesting.Attrs{"use-floating-ip": false})
369
err := bootstrapEnv(c, env)
370
c.Assert(err, jc.ErrorIsNil)
371
c.Assert(bootstrapFinished, jc.IsTrue)
374
// If the environment is configured not to require a public IP address for nodes,
375
// bootstrapping and starting an instance should occur without any attempt to
376
// allocate a public address.
377
func (s *localServerSuite) TestStartInstanceWithoutPublicIP(c *gc.C) {
378
cleanup := s.srv.Nova.RegisterControlPoint(
380
func(sc hook.ServiceControl, args ...interface{}) error {
381
return fmt.Errorf("add floating IP should not have been called")
385
cleanup = s.srv.Nova.RegisterControlPoint(
386
"addServerFloatingIP",
387
func(sc hook.ServiceControl, args ...interface{}) error {
388
return fmt.Errorf("add server floating IP should not have been called")
393
err := environs.Destroy(s.env.Config().Name(), s.env, s.ControllerStore)
394
c.Assert(err, jc.ErrorIsNil)
396
s.TestConfig["use-floating-ip"] = false
398
err = bootstrapEnv(c, env)
399
c.Assert(err, jc.ErrorIsNil)
400
inst, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, "100")
401
err = env.StopInstances(inst.Id())
402
c.Assert(err, jc.ErrorIsNil)
405
func (s *localServerSuite) TestStartInstanceHardwareCharacteristics(c *gc.C) {
406
// Ensure amd64 tools are available, to ensure an amd64 image.
407
amd64Version := version.Binary{
408
Number: jujuversion.Current,
411
for _, series := range series.SupportedSeries() {
412
amd64Version.Series = series
413
envtesting.AssertUploadFakeToolsVersions(
414
c, s.toolsMetadataStorage, s.env.Config().AgentStream(), s.env.Config().AgentStream(), amd64Version)
417
err := environs.Destroy(s.env.Config().Name(), s.env, s.ControllerStore)
418
c.Assert(err, jc.ErrorIsNil)
421
err = bootstrapEnv(c, env)
422
c.Assert(err, jc.ErrorIsNil)
423
_, hc := testing.AssertStartInstanceWithConstraints(c, env, s.ControllerUUID, "100", constraints.MustParse("mem=1024"))
424
c.Check(*hc.Arch, gc.Equals, "amd64")
425
c.Check(*hc.Mem, gc.Equals, uint64(2048))
426
c.Check(*hc.CpuCores, gc.Equals, uint64(1))
427
c.Assert(hc.CpuPower, gc.IsNil)
430
func (s *localServerSuite) TestStartInstanceNetwork(c *gc.C) {
431
cfg, err := s.env.Config().Apply(coretesting.Attrs{
432
// A label that corresponds to a nova test service network
435
c.Assert(err, jc.ErrorIsNil)
436
err = s.env.SetConfig(cfg)
437
c.Assert(err, jc.ErrorIsNil)
439
inst, _ := testing.AssertStartInstance(c, s.env, s.ControllerUUID, "100")
440
err = s.env.StopInstances(inst.Id())
441
c.Assert(err, jc.ErrorIsNil)
444
func (s *localServerSuite) TestStartInstanceNetworkUnknownLabel(c *gc.C) {
445
cfg, err := s.env.Config().Apply(coretesting.Attrs{
446
// A label that has no related network in the nova test service
447
"network": "no-network-with-this-label",
449
c.Assert(err, jc.ErrorIsNil)
450
err = s.env.SetConfig(cfg)
451
c.Assert(err, jc.ErrorIsNil)
453
inst, _, _, err := testing.StartInstance(s.env, s.ControllerUUID, "100")
454
c.Check(inst, gc.IsNil)
455
c.Assert(err, gc.ErrorMatches, "No networks exist with label .*")
458
func (s *localServerSuite) TestStartInstanceNetworkUnknownId(c *gc.C) {
459
cfg, err := s.env.Config().Apply(coretesting.Attrs{
460
// A valid UUID but no related network in the nova test service
461
"network": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
463
c.Assert(err, jc.ErrorIsNil)
464
err = s.env.SetConfig(cfg)
465
c.Assert(err, jc.ErrorIsNil)
467
inst, _, _, err := testing.StartInstance(s.env, s.ControllerUUID, "100")
468
c.Check(inst, gc.IsNil)
469
c.Assert(err, gc.ErrorMatches, "cannot run instance: (\\n|.)*"+
471
"request \\(.*/servers\\) returned unexpected status: "+
472
"404; error info: .*itemNotFound.*")
475
func assertSecurityGroups(c *gc.C, env environs.Environ, expected []string) {
476
novaClient := openstack.GetNovaClient(env)
477
groups, err := novaClient.ListSecurityGroups()
478
c.Assert(err, jc.ErrorIsNil)
479
for _, name := range expected {
481
for _, group := range groups {
482
if group.Name == name {
488
c.Errorf("expected security group %q not found", name)
491
for _, group := range groups {
493
for _, name := range expected {
494
if group.Name == name {
500
c.Errorf("existing security group %q is not expected", group.Name)
505
func assertInstanceIds(c *gc.C, env environs.Environ, expected ...instance.Id) {
506
insts, err := env.AllInstances()
507
c.Assert(err, jc.ErrorIsNil)
508
instIds := make([]instance.Id, len(insts))
509
for i, inst := range insts {
510
instIds[i] = inst.Id()
512
c.Assert(instIds, jc.SameContents, expected)
515
func (s *localServerSuite) TestStopInstance(c *gc.C) {
516
env := s.openEnviron(c, coretesting.Attrs{"firewall-mode": config.FwInstance})
517
instanceName := "100"
518
inst, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, instanceName)
519
// Openstack now has three security groups for the server, the default
520
// group, one group for the entire environment, and another for the
522
modelUUID := env.Config().UUID()
523
allSecurityGroups := []string{
524
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
525
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, modelUUID, instanceName),
527
assertSecurityGroups(c, env, allSecurityGroups)
528
err := env.StopInstances(inst.Id())
529
c.Assert(err, jc.ErrorIsNil)
530
// The security group for this instance is now removed.
531
assertSecurityGroups(c, env, []string{
532
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
536
// Due to bug #1300755 it can happen that the security group intended for
537
// an instance is also used as the common security group of another
538
// environment. If this is the case, the attempt to delete the instance's
539
// security group fails but StopInstance succeeds.
540
func (s *localServerSuite) TestStopInstanceSecurityGroupNotDeleted(c *gc.C) {
541
coretesting.SkipIfPPC64EL(c, "lp:1425242")
543
// Force an error when a security group is deleted.
544
cleanup := s.srv.Nova.RegisterControlPoint(
545
"removeSecurityGroup",
546
func(sc hook.ServiceControl, args ...interface{}) error {
547
return fmt.Errorf("failed on purpose")
551
env := s.openEnviron(c, coretesting.Attrs{"firewall-mode": config.FwInstance})
552
instanceName := "100"
553
inst, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, instanceName)
554
modelUUID := env.Config().UUID()
555
allSecurityGroups := []string{
556
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
557
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, modelUUID, instanceName),
559
assertSecurityGroups(c, env, allSecurityGroups)
560
err := env.StopInstances(inst.Id())
561
c.Assert(err, jc.ErrorIsNil)
562
assertSecurityGroups(c, env, allSecurityGroups)
565
func (s *localServerSuite) TestDestroyEnvironmentDeletesSecurityGroupsFWModeInstance(c *gc.C) {
566
env := s.openEnviron(c, coretesting.Attrs{"firewall-mode": config.FwInstance})
567
instanceName := "100"
568
testing.AssertStartInstance(c, env, s.ControllerUUID, instanceName)
569
modelUUID := env.Config().UUID()
570
allSecurityGroups := []string{
571
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
572
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, modelUUID, instanceName),
574
assertSecurityGroups(c, env, allSecurityGroups)
576
c.Check(err, jc.ErrorIsNil)
577
assertSecurityGroups(c, env, []string{"default"})
580
func (s *localServerSuite) TestDestroyEnvironmentDeletesSecurityGroupsFWModeGlobal(c *gc.C) {
581
env := s.openEnviron(c, coretesting.Attrs{"firewall-mode": config.FwGlobal})
582
instanceName := "100"
583
testing.AssertStartInstance(c, env, s.ControllerUUID, instanceName)
584
modelUUID := env.Config().UUID()
585
allSecurityGroups := []string{
586
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
587
fmt.Sprintf("juju-%v-%v-global", s.ControllerUUID, modelUUID),
589
assertSecurityGroups(c, env, allSecurityGroups)
591
c.Check(err, jc.ErrorIsNil)
592
assertSecurityGroups(c, env, []string{"default"})
595
func (s *localServerSuite) TestDestroyController(c *gc.C) {
596
env := s.openEnviron(c, coretesting.Attrs{"uuid": utils.MustNewUUID().String()})
597
controllerEnv := s.env
599
controllerInstanceName := "100"
600
testing.AssertStartInstance(c, controllerEnv, s.ControllerUUID, controllerInstanceName)
601
hostedModelInstanceName := "200"
602
testing.AssertStartInstance(c, env, s.ControllerUUID, hostedModelInstanceName)
603
modelUUID := env.Config().UUID()
604
allControllerSecurityGroups := []string{
605
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, s.ControllerUUID),
606
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, s.ControllerUUID, controllerInstanceName),
608
allHostedModelSecurityGroups := []string{
609
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
610
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, modelUUID, hostedModelInstanceName),
612
assertSecurityGroups(c, controllerEnv, append(
613
allControllerSecurityGroups, allHostedModelSecurityGroups...,
616
err := controllerEnv.DestroyController(s.ControllerUUID)
617
c.Check(err, jc.ErrorIsNil)
618
assertSecurityGroups(c, controllerEnv, []string{"default"})
619
assertInstanceIds(c, env)
620
assertInstanceIds(c, controllerEnv)
623
func (s *localServerSuite) TestDestroyHostedModel(c *gc.C) {
624
env := s.openEnviron(c, coretesting.Attrs{"uuid": utils.MustNewUUID().String()})
625
controllerEnv := s.env
627
controllerInstanceName := "100"
628
controllerInstance, _ := testing.AssertStartInstance(c, controllerEnv, s.ControllerUUID, controllerInstanceName)
629
hostedModelInstanceName := "200"
630
testing.AssertStartInstance(c, env, s.ControllerUUID, hostedModelInstanceName)
631
modelUUID := env.Config().UUID()
632
allControllerSecurityGroups := []string{
633
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, s.ControllerUUID),
634
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, s.ControllerUUID, controllerInstanceName),
636
allHostedModelSecurityGroups := []string{
637
"default", fmt.Sprintf("juju-%v-%v", s.ControllerUUID, modelUUID),
638
fmt.Sprintf("juju-%v-%v-%v", s.ControllerUUID, modelUUID, hostedModelInstanceName),
640
assertSecurityGroups(c, controllerEnv, append(
641
allControllerSecurityGroups, allHostedModelSecurityGroups...,
645
c.Check(err, jc.ErrorIsNil)
646
assertSecurityGroups(c, controllerEnv, allControllerSecurityGroups)
647
assertInstanceIds(c, env)
648
assertInstanceIds(c, controllerEnv, controllerInstance.Id())
651
var instanceGathering = []struct {
655
{ids: []instance.Id{"id0"}},
656
{ids: []instance.Id{"id0", "id0"}},
657
{ids: []instance.Id{"id0", "id1"}},
658
{ids: []instance.Id{"id1", "id0"}},
659
{ids: []instance.Id{"id1", "id0", "id1"}},
661
ids: []instance.Id{""},
662
err: environs.ErrNoInstances,
665
ids: []instance.Id{"", ""},
666
err: environs.ErrNoInstances,
669
ids: []instance.Id{"", "", ""},
670
err: environs.ErrNoInstances,
673
ids: []instance.Id{"id0", ""},
674
err: environs.ErrPartialInstances,
677
ids: []instance.Id{"", "id1"},
678
err: environs.ErrPartialInstances,
681
ids: []instance.Id{"id0", "id1", ""},
682
err: environs.ErrPartialInstances,
685
ids: []instance.Id{"id0", "", "id0"},
686
err: environs.ErrPartialInstances,
689
ids: []instance.Id{"id0", "id0", ""},
690
err: environs.ErrPartialInstances,
693
ids: []instance.Id{"", "id0", "id1"},
694
err: environs.ErrPartialInstances,
698
func (s *localServerSuite) TestInstanceStatus(c *gc.C) {
699
// goose's test service always returns ACTIVE state.
700
inst, _ := testing.AssertStartInstance(c, s.env, s.ControllerUUID, "100")
701
c.Assert(inst.Status().Status, gc.Equals, status.StatusRunning)
702
err := s.env.StopInstances(inst.Id())
703
c.Assert(err, jc.ErrorIsNil)
706
func (s *localServerSuite) TestAllInstancesFloatingIP(c *gc.C) {
707
env := s.openEnviron(c, coretesting.Attrs{"use-floating-ip": true})
709
inst0, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, "100")
710
inst1, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, "101")
712
err := env.StopInstances(inst0.Id(), inst1.Id())
713
c.Assert(err, jc.ErrorIsNil)
716
insts, err := env.AllInstances()
717
c.Assert(err, jc.ErrorIsNil)
718
for _, inst := range insts {
719
c.Assert(openstack.InstanceFloatingIP(inst).IP, gc.Equals, fmt.Sprintf("10.0.0.%v", inst.Id()))
723
func (s *localServerSuite) assertInstancesGathering(c *gc.C, withFloatingIP bool) {
724
env := s.openEnviron(c, coretesting.Attrs{"use-floating-ip": withFloatingIP})
726
inst0, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, "100")
728
inst1, _ := testing.AssertStartInstance(c, env, s.ControllerUUID, "101")
731
err := env.StopInstances(inst0.Id(), inst1.Id())
732
c.Assert(err, jc.ErrorIsNil)
735
for i, test := range instanceGathering {
736
c.Logf("test %d: find %v -> expect len %d, err: %v", i, test.ids, len(test.ids), test.err)
737
ids := make([]instance.Id, len(test.ids))
738
for j, id := range test.ids {
746
insts, err := env.Instances(ids)
747
c.Assert(err, gc.Equals, test.err)
748
if err == environs.ErrNoInstances {
749
c.Assert(insts, gc.HasLen, 0)
751
c.Assert(insts, gc.HasLen, len(test.ids))
753
for j, inst := range insts {
755
c.Assert(inst.Id(), gc.Equals, ids[j])
757
c.Assert(openstack.InstanceFloatingIP(inst).IP, gc.Equals, fmt.Sprintf("10.0.0.%v", inst.Id()))
759
c.Assert(openstack.InstanceFloatingIP(inst), gc.IsNil)
762
c.Assert(inst, gc.IsNil)
768
func (s *localServerSuite) TestInstancesGathering(c *gc.C) {
769
s.assertInstancesGathering(c, false)
772
func (s *localServerSuite) TestInstancesGatheringWithFloatingIP(c *gc.C) {
773
s.assertInstancesGathering(c, true)
776
func (s *localServerSuite) TestInstancesBuildSpawning(c *gc.C) {
777
coretesting.SkipIfPPC64EL(c, "lp:1425242")
779
// HP servers are available once they are BUILD(spawning).
780
cleanup := s.srv.Nova.RegisterControlPoint(
782
func(sc hook.ServiceControl, args ...interface{}) error {
783
details := args[0].(*nova.ServerDetail)
784
details.Status = nova.StatusBuildSpawning
789
stateInst, _ := testing.AssertStartInstance(c, s.env, s.ControllerUUID, "100")
791
err := s.env.StopInstances(stateInst.Id())
792
c.Assert(err, jc.ErrorIsNil)
795
instances, err := s.env.Instances([]instance.Id{stateInst.Id()})
797
c.Assert(err, jc.ErrorIsNil)
798
c.Assert(instances, gc.HasLen, 1)
799
c.Assert(instances[0].Status().Message, gc.Equals, nova.StatusBuildSpawning)
802
func (s *localServerSuite) TestInstancesShutoffSuspended(c *gc.C) {
803
coretesting.SkipIfPPC64EL(c, "lp:1425242")
805
cleanup := s.srv.Nova.RegisterControlPoint(
807
func(sc hook.ServiceControl, args ...interface{}) error {
808
details := args[0].(*nova.ServerDetail)
810
case strings.HasSuffix(details.Name, "-100"):
811
details.Status = nova.StatusShutoff
812
case strings.HasSuffix(details.Name, "-101"):
813
details.Status = nova.StatusSuspended
815
c.Fatalf("unexpected instance details: %#v", details)
821
stateInst1, _ := testing.AssertStartInstance(c, s.env, s.ControllerUUID, "100")
822
stateInst2, _ := testing.AssertStartInstance(c, s.env, s.ControllerUUID, "101")
824
err := s.env.StopInstances(stateInst1.Id(), stateInst2.Id())
825
c.Assert(err, jc.ErrorIsNil)
828
instances, err := s.env.Instances([]instance.Id{stateInst1.Id(), stateInst2.Id()})
830
c.Assert(err, jc.ErrorIsNil)
831
c.Assert(instances, gc.HasLen, 2)
832
c.Assert(instances[0].Status().Message, gc.Equals, nova.StatusShutoff)
833
c.Assert(instances[1].Status().Message, gc.Equals, nova.StatusSuspended)
836
func (s *localServerSuite) TestInstancesErrorResponse(c *gc.C) {
837
coretesting.SkipIfPPC64EL(c, "lp:1425242")
839
cleanup := s.srv.Nova.RegisterControlPoint(
841
func(sc hook.ServiceControl, args ...interface{}) error {
842
return fmt.Errorf("strange error not instance")
847
instances, err := s.env.Instances([]instance.Id{"1"})
848
c.Check(instances, gc.IsNil)
849
c.Assert(err, gc.ErrorMatches, "(?s).*strange error not instance.*")
852
func (s *localServerSuite) TestInstancesMultiErrorResponse(c *gc.C) {
853
coretesting.SkipIfPPC64EL(c, "lp:1425242")
855
cleanup := s.srv.Nova.RegisterControlPoint(
857
func(sc hook.ServiceControl, args ...interface{}) error {
858
return fmt.Errorf("strange error no instances")
863
instances, err := s.env.Instances([]instance.Id{"1", "2"})
864
c.Check(instances, gc.IsNil)
865
c.Assert(err, gc.ErrorMatches, "(?s).*strange error no instances.*")
868
// TODO (wallyworld) - this test was copied from the ec2 provider.
869
// It should be moved to environs.jujutests.Tests.
870
func (s *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) {
871
err := bootstrapEnv(c, s.env)
872
c.Assert(err, jc.ErrorIsNil)
874
// Check that ControllerInstances returns the ID of the bootstrap machine.
875
ids, err := s.env.ControllerInstances(s.ControllerUUID)
876
c.Assert(err, jc.ErrorIsNil)
877
c.Assert(ids, gc.HasLen, 1)
879
insts, err := s.env.AllInstances()
880
c.Assert(err, jc.ErrorIsNil)
881
c.Assert(insts, gc.HasLen, 1)
882
c.Check(insts[0].Id(), gc.Equals, ids[0])
884
addresses, err := insts[0].Addresses()
885
c.Assert(err, jc.ErrorIsNil)
886
c.Assert(addresses, gc.Not(gc.HasLen), 0)
888
// TODO(wallyworld) - 2013-03-01 bug=1137005
889
// The nova test double needs to be updated to support retrieving instance userData.
890
// Until then, we can't check the cloud init script was generated correctly.
891
// When we can, we should also check cloudinit for a non-manager node (as in the
895
func (s *localServerSuite) assertGetImageMetadataSources(c *gc.C, stream, officialSourcePath string) {
896
// Create a config that matches s.TestConfig but with the specified stream.
897
attrs := coretesting.Attrs{}
899
attrs = coretesting.Attrs{"image-stream": stream}
901
env := s.openEnviron(c, attrs)
903
sources, err := environs.ImageMetadataSources(env)
904
c.Assert(err, jc.ErrorIsNil)
905
c.Assert(sources, gc.HasLen, 4)
906
var urls = make([]string, len(sources))
907
for i, source := range sources {
908
url, err := source.URL("")
909
c.Assert(err, jc.ErrorIsNil)
912
// The image-metadata-url ends with "/juju-dist-test/".
913
c.Check(strings.HasSuffix(urls[0], "/juju-dist-test/"), jc.IsTrue)
914
// The product-streams URL ends with "/imagemetadata".
915
c.Check(strings.HasSuffix(urls[1], "/imagemetadata/"), jc.IsTrue)
916
c.Assert(urls[2], gc.Equals, fmt.Sprintf("https://streams.canonical.com/juju/images/%s/", officialSourcePath))
917
c.Assert(urls[3], gc.Equals, fmt.Sprintf("http://cloud-images.ubuntu.com/%s/", officialSourcePath))
920
func (s *localServerSuite) TestGetImageMetadataSources(c *gc.C) {
921
s.assertGetImageMetadataSources(c, "", "releases")
922
s.assertGetImageMetadataSources(c, "released", "releases")
923
s.assertGetImageMetadataSources(c, "daily", "daily")
926
func (s *localServerSuite) TestGetImageMetadataSourcesNoProductStreams(c *gc.C) {
927
s.PatchValue(openstack.MakeServiceURL, func(client.AuthenticatingClient, string, []string) (string, error) {
928
return "", errors.New("cannae do it captain")
930
env := s.Open(c, s.env.Config())
931
sources, err := environs.ImageMetadataSources(env)
932
c.Assert(err, jc.ErrorIsNil)
933
c.Assert(sources, gc.HasLen, 3)
935
// Check that data sources are in the right order
936
c.Check(sources[0].Description(), gc.Equals, "image-metadata-url")
937
c.Check(sources[1].Description(), gc.Equals, "default cloud images")
938
c.Check(sources[2].Description(), gc.Equals, "default ubuntu cloud images")
941
func (s *localServerSuite) TestGetToolsMetadataSources(c *gc.C) {
942
s.PatchValue(&tools.DefaultBaseURL, "")
944
env := s.Open(c, s.env.Config())
945
sources, err := tools.GetMetadataSources(env)
946
c.Assert(err, jc.ErrorIsNil)
947
c.Assert(sources, gc.HasLen, 2)
948
var urls = make([]string, len(sources))
949
for i, source := range sources {
950
url, err := source.URL("")
951
c.Assert(err, jc.ErrorIsNil)
954
// The agent-metadata-url ends with "/juju-dist-test/tools/".
955
c.Check(strings.HasSuffix(urls[0], "/juju-dist-test/tools/"), jc.IsTrue)
956
// Check that the URL from keystone parses.
957
_, err = url.Parse(urls[1])
958
c.Assert(err, jc.ErrorIsNil)
961
func (s *localServerSuite) TestSupportsNetworking(c *gc.C) {
962
env := s.Open(c, s.env.Config())
963
_, ok := environs.SupportsNetworking(env)
964
c.Assert(ok, jc.IsFalse)
967
func (s *localServerSuite) TestFindImageBadDefaultImage(c *gc.C) {
968
imagetesting.PatchOfficialDataSources(&s.CleanupSuite, "")
969
env := s.Open(c, s.env.Config())
971
// An error occurs if no suitable image is found.
972
_, err := openstack.FindInstanceSpec(env, "saucy", "amd64", "mem=1G", nil)
973
c.Assert(err, gc.ErrorMatches, `no "saucy" images in some-region with arches \[amd64\]`)
976
func (s *localServerSuite) TestConstraintsValidator(c *gc.C) {
977
env := s.Open(c, s.env.Config())
978
validator, err := env.ConstraintsValidator()
979
c.Assert(err, jc.ErrorIsNil)
980
cons := constraints.MustParse("arch=amd64 cpu-power=10 virt-type=lxd")
981
unsupported, err := validator.Validate(cons)
982
c.Assert(err, jc.ErrorIsNil)
983
c.Assert(unsupported, jc.SameContents, []string{"cpu-power"})
986
func (s *localServerSuite) TestConstraintsValidatorVocab(c *gc.C) {
987
env := s.Open(c, s.env.Config())
988
validator, err := env.ConstraintsValidator()
989
c.Assert(err, jc.ErrorIsNil)
991
// i386 is a valid arch, but is no longer supported. No image
992
// data was created for it for the test.
993
cons := constraints.MustParse("arch=i386")
994
_, err = validator.Validate(cons)
995
c.Assert(err, gc.ErrorMatches, "invalid constraint value: arch=i386\nvalid values are: \\[amd64 arm64 ppc64el s390x\\]")
996
cons = constraints.MustParse("instance-type=foo")
997
_, err = validator.Validate(cons)
998
c.Assert(err, gc.ErrorMatches, "invalid constraint value: instance-type=foo\nvalid values are:.*")
1000
cons = constraints.MustParse("virt-type=foo")
1001
_, err = validator.Validate(cons)
1002
c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta("invalid constraint value: virt-type=foo\nvalid values are: [kvm lxd]"))
1005
func (s *localServerSuite) TestConstraintsMerge(c *gc.C) {
1006
env := s.Open(c, s.env.Config())
1007
validator, err := env.ConstraintsValidator()
1008
c.Assert(err, jc.ErrorIsNil)
1009
consA := constraints.MustParse("arch=amd64 mem=1G root-disk=10G")
1010
consB := constraints.MustParse("instance-type=m1.small")
1011
cons, err := validator.Merge(consA, consB)
1012
c.Assert(err, jc.ErrorIsNil)
1013
c.Assert(cons, gc.DeepEquals, constraints.MustParse("instance-type=m1.small"))
1016
func (s *localServerSuite) TestFindImageInstanceConstraint(c *gc.C) {
1017
env := s.Open(c, s.env.Config())
1018
imageMetadata := []*imagemetadata.ImageMetadata{{
1023
spec, err := openstack.FindInstanceSpec(
1024
env, series.LatestLts(), "amd64", "instance-type=m1.tiny",
1027
c.Assert(err, jc.ErrorIsNil)
1028
c.Assert(spec.InstanceType.Name, gc.Equals, "m1.tiny")
1031
func (s *localServerSuite) TestFindInstanceImageConstraintHypervisor(c *gc.C) {
1032
testVirtType := "qemu"
1033
env := s.Open(c, s.env.Config())
1034
imageMetadata := []*imagemetadata.ImageMetadata{{
1037
VirtType: testVirtType,
1040
spec, err := openstack.FindInstanceSpec(
1041
env, series.LatestLts(), "amd64", "virt-type="+testVirtType,
1044
c.Assert(err, jc.ErrorIsNil)
1045
c.Assert(spec.InstanceType.VirtType, gc.NotNil)
1046
c.Assert(*spec.InstanceType.VirtType, gc.Equals, testVirtType)
1047
c.Assert(spec.InstanceType.Name, gc.Equals, "m1.small")
1050
func (s *localServerSuite) TestFindInstanceImageWithHypervisorNoConstraint(c *gc.C) {
1051
testVirtType := "qemu"
1052
env := s.Open(c, s.env.Config())
1053
imageMetadata := []*imagemetadata.ImageMetadata{{
1056
VirtType: testVirtType,
1059
spec, err := openstack.FindInstanceSpec(
1060
env, series.LatestLts(), "amd64", "",
1063
c.Assert(err, jc.ErrorIsNil)
1064
c.Assert(spec.InstanceType.VirtType, gc.NotNil)
1065
c.Assert(*spec.InstanceType.VirtType, gc.Equals, testVirtType)
1066
c.Assert(spec.InstanceType.Name, gc.Equals, "m1.small")
1069
func (s *localServerSuite) TestFindInstanceNoConstraint(c *gc.C) {
1070
env := s.Open(c, s.env.Config())
1071
imageMetadata := []*imagemetadata.ImageMetadata{{
1076
spec, err := openstack.FindInstanceSpec(
1077
env, series.LatestLts(), "amd64", "",
1080
c.Assert(err, jc.ErrorIsNil)
1081
c.Assert(spec.InstanceType.VirtType, gc.IsNil)
1082
c.Assert(spec.InstanceType.Name, gc.Equals, "m1.small")
1085
func (s *localServerSuite) TestFindImageInvalidInstanceConstraint(c *gc.C) {
1086
env := s.Open(c, s.env.Config())
1087
imageMetadata := []*imagemetadata.ImageMetadata{{
1091
_, err := openstack.FindInstanceSpec(
1092
env, series.LatestLts(), "amd64", "instance-type=m1.large",
1095
c.Assert(err, gc.ErrorMatches, `no instance types in some-region matching constraints "instance-type=m1.large"`)
1098
func (s *localServerSuite) TestPrecheckInstanceValidInstanceType(c *gc.C) {
1099
env := s.Open(c, s.env.Config())
1100
cons := constraints.MustParse("instance-type=m1.small")
1102
err := env.PrecheckInstance(series.LatestLts(), cons, placement)
1103
c.Assert(err, jc.ErrorIsNil)
1106
func (s *localServerSuite) TestPrecheckInstanceInvalidInstanceType(c *gc.C) {
1107
env := s.Open(c, s.env.Config())
1108
cons := constraints.MustParse("instance-type=m1.large")
1110
err := env.PrecheckInstance(series.LatestLts(), cons, placement)
1111
c.Assert(err, gc.ErrorMatches, `invalid Openstack flavour "m1.large" specified`)
1114
func (t *localServerSuite) TestPrecheckInstanceAvailZone(c *gc.C) {
1115
placement := "zone=test-available"
1116
err := t.env.PrecheckInstance(series.LatestLts(), constraints.Value{}, placement)
1117
c.Assert(err, jc.ErrorIsNil)
1120
func (t *localServerSuite) TestPrecheckInstanceAvailZoneUnavailable(c *gc.C) {
1121
placement := "zone=test-unavailable"
1122
err := t.env.PrecheckInstance(series.LatestLts(), constraints.Value{}, placement)
1123
c.Assert(err, jc.ErrorIsNil)
1126
func (t *localServerSuite) TestPrecheckInstanceAvailZoneUnknown(c *gc.C) {
1127
placement := "zone=test-unknown"
1128
err := t.env.PrecheckInstance(series.LatestLts(), constraints.Value{}, placement)
1129
c.Assert(err, gc.ErrorMatches, `invalid availability zone "test-unknown"`)
1132
func (t *localServerSuite) TestPrecheckInstanceAvailZonesUnsupported(c *gc.C) {
1133
t.srv.Nova.SetAvailabilityZones() // no availability zone support
1134
placement := "zone=test-unknown"
1135
err := t.env.PrecheckInstance(series.LatestLts(), constraints.Value{}, placement)
1136
c.Assert(err, jc.Satisfies, jujuerrors.IsNotImplemented)
1139
func (s *localServerSuite) TestValidateImageMetadata(c *gc.C) {
1140
env := s.Open(c, s.env.Config())
1141
params, err := env.(simplestreams.MetadataValidator).MetadataLookupParams("some-region")
1142
c.Assert(err, jc.ErrorIsNil)
1143
params.Sources, err = environs.ImageMetadataSources(env)
1144
c.Assert(err, jc.ErrorIsNil)
1145
params.Series = "raring"
1146
image_ids, _, err := imagemetadata.ValidateImageMetadata(params)
1147
c.Assert(err, jc.ErrorIsNil)
1148
c.Assert(image_ids, jc.SameContents, []string{"id-y"})
1151
func (s *localServerSuite) TestImageMetadataSourceOrder(c *gc.C) {
1152
src := func(env environs.Environ) (simplestreams.DataSource, error) {
1153
return simplestreams.NewURLDataSource("my datasource", "bar", false, simplestreams.CUSTOM_CLOUD_DATA, false), nil
1155
environs.RegisterUserImageDataSourceFunc("my func", src)
1156
env := s.Open(c, s.env.Config())
1157
sources, err := environs.ImageMetadataSources(env)
1158
c.Assert(err, jc.ErrorIsNil)
1159
var sourceIds []string
1160
for _, s := range sources {
1161
sourceIds = append(sourceIds, s.Description())
1163
c.Assert(sourceIds, jc.DeepEquals, []string{
1164
"image-metadata-url", "my datasource", "keystone catalog", "default cloud images", "default ubuntu cloud images"})
1167
// TestEnsureGroup checks that when creating a duplicate security group, the existing group is
1168
// returned and the existing rules have been left as is.
1169
func (s *localServerSuite) TestEnsureGroup(c *gc.C) {
1170
rule := []nova.RuleInfo{
1178
assertRule := func(group nova.SecurityGroup) {
1179
c.Check(len(group.Rules), gc.Equals, 1)
1180
c.Check(*group.Rules[0].IPProtocol, gc.Equals, "tcp")
1181
c.Check(*group.Rules[0].FromPort, gc.Equals, 22)
1182
c.Check(*group.Rules[0].ToPort, gc.Equals, 22)
1185
group, err := openstack.EnsureGroup(s.env, "test group", rule)
1186
c.Assert(err, jc.ErrorIsNil)
1187
c.Assert(group.Name, gc.Equals, "test group")
1190
// Do it again and check that the existing group is returned.
1191
anotherRule := []nova.RuleInfo{
1198
group, err = openstack.EnsureGroup(s.env, "test group", anotherRule)
1199
c.Assert(err, jc.ErrorIsNil)
1200
c.Check(group.Id, gc.Equals, id)
1201
c.Assert(group.Name, gc.Equals, "test group")
1205
// localHTTPSServerSuite contains tests that run against an Openstack service
1206
// double connected on an HTTPS port with a self-signed certificate. This
1207
// service is set up and torn down for every test. This should only test
1208
// things that depend on the HTTPS connection, all other functional tests on a
1209
// local connection should be in localServerSuite
1210
type localHTTPSServerSuite struct {
1211
coretesting.BaseSuite
1212
attrs map[string]interface{}
1213
cred *identity.Credentials
1215
env environs.Environ
1218
func (s *localHTTPSServerSuite) SetUpSuite(c *gc.C) {
1219
s.BaseSuite.SetUpSuite(c)
1220
overrideCinderProvider(c, &s.CleanupSuite)
1223
func (s *localHTTPSServerSuite) createConfigAttrs(c *gc.C) map[string]interface{} {
1224
attrs := makeTestConfig(s.cred)
1225
attrs["agent-version"] = coretesting.FakeVersionNumber.String()
1226
attrs["authorized-keys"] = "fakekey"
1227
// In order to set up and tear down the environment properly, we must
1228
// disable hostname verification
1229
attrs["ssl-hostname-verification"] = false
1230
attrs["auth-url"] = s.cred.URL
1231
// Now connect and set up test-local tools and image-metadata URLs
1232
cl := client.NewNonValidatingClient(s.cred, identity.AuthUserPass, nil)
1233
err := cl.Authenticate()
1234
c.Assert(err, jc.ErrorIsNil)
1235
containerURL, err := cl.MakeServiceURL("object-store", nil)
1236
c.Assert(err, jc.ErrorIsNil)
1237
c.Check(containerURL[:8], gc.Equals, "https://")
1238
attrs["agent-metadata-url"] = containerURL + "/juju-dist-test/tools"
1239
c.Logf("Set agent-metadata-url=%q", attrs["agent-metadata-url"])
1240
attrs["image-metadata-url"] = containerURL + "/juju-dist-test"
1241
c.Logf("Set image-metadata-url=%q", attrs["image-metadata-url"])
1245
func (s *localHTTPSServerSuite) SetUpTest(c *gc.C) {
1246
s.BaseSuite.SetUpTest(c)
1247
s.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber)
1249
cred := &identity.Credentials{
1252
Region: "some-region",
1253
TenantName: "some tenant",
1255
// Note: start() will change cred.URL to point to s.srv.Server.URL
1256
s.srv.start(c, cred, newFullOpenstackService)
1258
attrs := s.createConfigAttrs(c)
1259
c.Assert(attrs["auth-url"].(string)[:8], gc.Equals, "https://")
1261
s.env, err = bootstrap.Prepare(
1262
envtesting.BootstrapContext(c),
1263
jujuclienttesting.NewMemStore(),
1264
prepareParams(attrs, s.cred),
1266
c.Assert(err, jc.ErrorIsNil)
1267
s.attrs = s.env.Config().AllAttrs()
1270
func (s *localHTTPSServerSuite) TearDownTest(c *gc.C) {
1272
err := s.env.Destroy()
1273
c.Check(err, jc.ErrorIsNil)
1277
s.BaseSuite.TearDownTest(c)
1280
func (s *localHTTPSServerSuite) TestMustDisableSSLVerify(c *gc.C) {
1281
coretesting.SkipIfPPC64EL(c, "lp:1425242")
1283
// If you don't have ssl-hostname-verification set to false, then we
1284
// fail to connect to the environment. Copy the attrs used by SetUp and
1285
// force hostname verification.
1286
newattrs := make(map[string]interface{}, len(s.attrs))
1287
for k, v := range s.attrs {
1290
newattrs["ssl-hostname-verification"] = true
1291
cfg, err := config.New(config.NoDefaults, newattrs)
1292
c.Assert(err, jc.ErrorIsNil)
1293
env, err := environs.New(environs.OpenParams{
1294
Cloud: makeCloudSpec(s.cred),
1297
c.Assert(err, jc.ErrorIsNil)
1298
_, err = env.AllInstances()
1299
c.Assert(err, gc.ErrorMatches, "(.|\n)*x509: certificate signed by unknown authority")
1302
func (s *localHTTPSServerSuite) TestCanBootstrap(c *gc.C) {
1303
restoreFinishBootstrap := envtesting.DisableFinishBootstrap()
1304
defer restoreFinishBootstrap()
1306
// For testing, we create a storage instance to which is uploaded tools and image metadata.
1307
metadataStorage := openstack.MetadataStorage(s.env)
1308
url, err := metadataStorage.URL("")
1309
c.Assert(err, jc.ErrorIsNil)
1310
c.Logf("Generating fake tools for: %v", url)
1311
envtesting.UploadFakeTools(c, metadataStorage, s.env.Config().AgentStream(), s.env.Config().AgentStream())
1312
defer envtesting.RemoveFakeTools(c, metadataStorage, s.env.Config().AgentStream())
1313
openstack.UseTestImageData(metadataStorage, s.cred)
1314
defer openstack.RemoveTestImageData(metadataStorage)
1316
err = bootstrapEnv(c, s.env)
1317
c.Assert(err, jc.ErrorIsNil)
1320
func (s *localHTTPSServerSuite) TestFetchFromImageMetadataSources(c *gc.C) {
1321
// Setup a custom URL for image metadata
1322
customStorage := openstack.CreateCustomStorage(s.env, "custom-metadata")
1323
customURL, err := customStorage.URL("")
1324
c.Assert(err, jc.ErrorIsNil)
1325
c.Check(customURL[:8], gc.Equals, "https://")
1327
config, err := s.env.Config().Apply(
1328
map[string]interface{}{"image-metadata-url": customURL},
1330
c.Assert(err, jc.ErrorIsNil)
1331
err = s.env.SetConfig(config)
1332
c.Assert(err, jc.ErrorIsNil)
1333
sources, err := environs.ImageMetadataSources(s.env)
1334
c.Assert(err, jc.ErrorIsNil)
1335
c.Assert(sources, gc.HasLen, 4)
1337
// Make sure there is something to download from each location
1338
metadata := "metadata-content"
1339
metadataStorage := openstack.ImageMetadataStorage(s.env)
1340
err = metadataStorage.Put(metadata, bytes.NewBufferString(metadata), int64(len(metadata)))
1341
c.Assert(err, jc.ErrorIsNil)
1343
custom := "custom-content"
1344
err = customStorage.Put(custom, bytes.NewBufferString(custom), int64(len(custom)))
1345
c.Assert(err, jc.ErrorIsNil)
1347
// Produce map of data sources keyed on description
1348
mappedSources := make(map[string]simplestreams.DataSource, len(sources))
1349
for i, s := range sources {
1350
c.Logf("datasource %d: %+v", i, s)
1351
mappedSources[s.Description()] = s
1354
// Read from the Config entry's image-metadata-url
1355
contentReader, url, err := mappedSources["image-metadata-url"].Fetch(custom)
1356
c.Assert(err, jc.ErrorIsNil)
1357
defer contentReader.Close()
1358
content, err := ioutil.ReadAll(contentReader)
1359
c.Assert(err, jc.ErrorIsNil)
1360
c.Assert(string(content), gc.Equals, custom)
1361
c.Check(url[:8], gc.Equals, "https://")
1363
// Check the entry we got from keystone
1364
contentReader, url, err = mappedSources["keystone catalog"].Fetch(metadata)
1365
c.Assert(err, jc.ErrorIsNil)
1366
defer contentReader.Close()
1367
content, err = ioutil.ReadAll(contentReader)
1368
c.Assert(err, jc.ErrorIsNil)
1369
c.Assert(string(content), gc.Equals, metadata)
1370
c.Check(url[:8], gc.Equals, "https://")
1371
// Verify that we are pointing at exactly where metadataStorage thinks we are
1372
metaURL, err := metadataStorage.URL(metadata)
1373
c.Assert(err, jc.ErrorIsNil)
1374
c.Check(url, gc.Equals, metaURL)
1378
func (s *localHTTPSServerSuite) TestFetchFromToolsMetadataSources(c *gc.C) {
1379
// Setup a custom URL for image metadata
1380
customStorage := openstack.CreateCustomStorage(s.env, "custom-tools-metadata")
1381
customURL, err := customStorage.URL("")
1382
c.Assert(err, jc.ErrorIsNil)
1383
c.Check(customURL[:8], gc.Equals, "https://")
1385
config, err := s.env.Config().Apply(
1386
map[string]interface{}{"agent-metadata-url": customURL},
1388
c.Assert(err, jc.ErrorIsNil)
1389
err = s.env.SetConfig(config)
1390
c.Assert(err, jc.ErrorIsNil)
1391
sources, err := tools.GetMetadataSources(s.env)
1392
c.Assert(err, jc.ErrorIsNil)
1393
c.Assert(sources, gc.HasLen, 3)
1395
// Make sure there is something to download from each location
1397
keystone := "keystone-tools-content"
1398
// The keystone entry just points at the root of the Swift storage, and
1399
// we have to create a container to upload any data. So we just point
1400
// into a subdirectory for the data we are downloading
1401
keystoneContainer := "tools-test"
1402
keystoneStorage := openstack.CreateCustomStorage(s.env, "tools-test")
1403
err = keystoneStorage.Put(keystone, bytes.NewBufferString(keystone), int64(len(keystone)))
1404
c.Assert(err, jc.ErrorIsNil)
1406
custom := "custom-tools-content"
1407
err = customStorage.Put(custom, bytes.NewBufferString(custom), int64(len(custom)))
1408
c.Assert(err, jc.ErrorIsNil)
1410
// Read from the Config entry's agent-metadata-url
1411
contentReader, url, err := sources[0].Fetch(custom)
1412
c.Assert(err, jc.ErrorIsNil)
1413
defer contentReader.Close()
1414
content, err := ioutil.ReadAll(contentReader)
1415
c.Assert(err, jc.ErrorIsNil)
1416
c.Assert(string(content), gc.Equals, custom)
1417
c.Check(url[:8], gc.Equals, "https://")
1419
// Check the entry we got from keystone
1420
// Now fetch the data, and verify the contents.
1421
contentReader, url, err = sources[1].Fetch(keystoneContainer + "/" + keystone)
1422
c.Assert(err, jc.ErrorIsNil)
1423
defer contentReader.Close()
1424
content, err = ioutil.ReadAll(contentReader)
1425
c.Assert(err, jc.ErrorIsNil)
1426
c.Assert(string(content), gc.Equals, keystone)
1427
c.Check(url[:8], gc.Equals, "https://")
1428
keystoneURL, err := keystoneStorage.URL(keystone)
1429
c.Assert(err, jc.ErrorIsNil)
1430
c.Check(url, gc.Equals, keystoneURL)
1432
// We *don't* test Fetch for sources[3] because it points to
1433
// streams.canonical.com
1436
func (s *localServerSuite) TestRemoveBlankContainer(c *gc.C) {
1437
storage := openstack.BlankContainerStorage()
1438
err := storage.Remove("some-file")
1439
c.Assert(err, gc.ErrorMatches, `cannot remove "some-file": swift container name is empty`)
1442
func (s *localServerSuite) TestAllInstancesIgnoresOtherMachines(c *gc.C) {
1443
err := bootstrapEnv(c, s.env)
1444
c.Assert(err, jc.ErrorIsNil)
1446
// Check that we see 1 instance in the environment
1447
insts, err := s.env.AllInstances()
1448
c.Assert(err, jc.ErrorIsNil)
1449
c.Check(insts, gc.HasLen, 1)
1451
// Now start a machine 'manually' in the same account, with a similar
1452
// but not matching name, and ensure it isn't seen by AllInstances
1453
// See bug #1257481, for how similar names were causing them to get
1454
// listed (and thus destroyed) at the wrong time
1455
existingModelName := s.TestConfig["name"]
1456
newMachineName := fmt.Sprintf("juju-%s-2-machine-0", existingModelName)
1458
// We grab the Nova client directly from the env, just to save time
1459
// looking all the stuff up
1460
novaClient := openstack.GetNovaClient(s.env)
1461
entity, err := novaClient.RunServer(nova.RunServerOpts{
1462
Name: newMachineName,
1463
FlavorId: "1", // test service has 1,2,3 for flavor ids
1464
ImageId: "1", // UseTestImageData sets up images 1 and 2
1466
c.Assert(err, jc.ErrorIsNil)
1467
c.Assert(entity, gc.NotNil)
1469
// List all servers with no filter, we should see both instances
1470
servers, err := novaClient.ListServersDetail(nova.NewFilter())
1471
c.Assert(err, jc.ErrorIsNil)
1472
c.Assert(servers, gc.HasLen, 2)
1474
insts, err = s.env.AllInstances()
1475
c.Assert(err, jc.ErrorIsNil)
1476
c.Check(insts, gc.HasLen, 1)
1479
func (s *localServerSuite) TestResolveNetworkUUID(c *gc.C) {
1480
var sampleUUID = "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
1481
networkId, err := openstack.ResolveNetwork(s.env, sampleUUID)
1482
c.Assert(err, jc.ErrorIsNil)
1483
c.Assert(networkId, gc.Equals, sampleUUID)
1486
func (s *localServerSuite) TestResolveNetworkLabel(c *gc.C) {
1487
// For now this test has to cheat and use knowledge of goose internals
1488
var networkLabel = "net"
1489
var expectNetworkId = "1"
1490
networkId, err := openstack.ResolveNetwork(s.env, networkLabel)
1491
c.Assert(err, jc.ErrorIsNil)
1492
c.Assert(networkId, gc.Equals, expectNetworkId)
1495
func (s *localServerSuite) TestResolveNetworkNotPresent(c *gc.C) {
1496
var notPresentNetwork = "no-network-with-this-label"
1497
networkId, err := openstack.ResolveNetwork(s.env, notPresentNetwork)
1498
c.Check(networkId, gc.Equals, "")
1499
c.Assert(err, gc.ErrorMatches, `No networks exist with label "no-network-with-this-label"`)
1502
// TODO(gz): TestResolveNetworkMultipleMatching when can inject new networks
1504
func (t *localServerSuite) TestStartInstanceAvailZone(c *gc.C) {
1505
inst, err := t.testStartInstanceAvailZone(c, "test-available")
1506
c.Assert(err, jc.ErrorIsNil)
1507
c.Assert(openstack.InstanceServerDetail(inst).AvailabilityZone, gc.Equals, "test-available")
1510
func (t *localServerSuite) TestStartInstanceAvailZoneUnavailable(c *gc.C) {
1511
_, err := t.testStartInstanceAvailZone(c, "test-unavailable")
1512
c.Assert(err, gc.ErrorMatches, `availability zone "test-unavailable" is unavailable`)
1515
func (t *localServerSuite) TestStartInstanceAvailZoneUnknown(c *gc.C) {
1516
_, err := t.testStartInstanceAvailZone(c, "test-unknown")
1517
c.Assert(err, gc.ErrorMatches, `invalid availability zone "test-unknown"`)
1520
func (t *localServerSuite) testStartInstanceAvailZone(c *gc.C, zone string) (instance.Instance, error) {
1521
err := bootstrapEnv(c, t.env)
1522
c.Assert(err, jc.ErrorIsNil)
1524
params := environs.StartInstanceParams{
1525
ControllerUUID: t.ControllerUUID,
1526
Placement: "zone=" + zone,
1528
result, err := testing.StartInstanceWithParams(t.env, "1", params)
1532
return result.Instance, nil
1535
func (t *localServerSuite) TestGetAvailabilityZones(c *gc.C) {
1536
var resultZones []nova.AvailabilityZone
1538
t.PatchValue(openstack.NovaListAvailabilityZones, func(c *nova.Client) ([]nova.AvailabilityZone, error) {
1539
return append([]nova.AvailabilityZone{}, resultZones...), resultErr
1541
env := t.env.(common.ZonedEnviron)
1543
resultErr = fmt.Errorf("failed to get availability zones")
1544
zones, err := env.AvailabilityZones()
1545
c.Assert(err, gc.Equals, resultErr)
1546
c.Assert(zones, gc.IsNil)
1549
resultZones = make([]nova.AvailabilityZone, 1)
1550
resultZones[0].Name = "whatever"
1551
zones, err = env.AvailabilityZones()
1552
c.Assert(err, jc.ErrorIsNil)
1553
c.Assert(zones, gc.HasLen, 1)
1554
c.Assert(zones[0].Name(), gc.Equals, "whatever")
1556
// A successful result is cached, currently for the lifetime
1557
// of the Environ. This will change if/when we have long-lived
1558
// Environs to cut down repeated IaaS requests.
1559
resultErr = fmt.Errorf("failed to get availability zones")
1560
resultZones[0].Name = "andever"
1561
zones, err = env.AvailabilityZones()
1562
c.Assert(err, jc.ErrorIsNil)
1563
c.Assert(zones, gc.HasLen, 1)
1564
c.Assert(zones[0].Name(), gc.Equals, "whatever")
1567
func (t *localServerSuite) TestGetAvailabilityZonesCommon(c *gc.C) {
1568
var resultZones []nova.AvailabilityZone
1569
t.PatchValue(openstack.NovaListAvailabilityZones, func(c *nova.Client) ([]nova.AvailabilityZone, error) {
1570
return append([]nova.AvailabilityZone{}, resultZones...), nil
1572
env := t.env.(common.ZonedEnviron)
1573
resultZones = make([]nova.AvailabilityZone, 2)
1574
resultZones[0].Name = "az1"
1575
resultZones[1].Name = "az2"
1576
resultZones[0].State.Available = true
1577
resultZones[1].State.Available = false
1578
zones, err := env.AvailabilityZones()
1579
c.Assert(err, jc.ErrorIsNil)
1580
c.Assert(zones, gc.HasLen, 2)
1581
c.Assert(zones[0].Name(), gc.Equals, resultZones[0].Name)
1582
c.Assert(zones[1].Name(), gc.Equals, resultZones[1].Name)
1583
c.Assert(zones[0].Available(), jc.IsTrue)
1584
c.Assert(zones[1].Available(), jc.IsFalse)
1587
type mockAvailabilityZoneAllocations struct {
1588
group []instance.Id // input param
1589
result []common.AvailabilityZoneInstances
1593
func (t *mockAvailabilityZoneAllocations) AvailabilityZoneAllocations(
1594
e common.ZonedEnviron, group []instance.Id,
1595
) ([]common.AvailabilityZoneInstances, error) {
1597
return t.result, t.err
1600
func (t *localServerSuite) TestStartInstanceDistributionParams(c *gc.C) {
1601
err := bootstrapEnv(c, t.env)
1602
c.Assert(err, jc.ErrorIsNil)
1604
var mock mockAvailabilityZoneAllocations
1605
t.PatchValue(openstack.AvailabilityZoneAllocations, mock.AvailabilityZoneAllocations)
1607
// no distribution group specified
1608
testing.AssertStartInstance(c, t.env, t.ControllerUUID, "1")
1609
c.Assert(mock.group, gc.HasLen, 0)
1611
// distribution group specified: ensure it's passed through to AvailabilityZone.
1612
expectedInstances := []instance.Id{"i-0", "i-1"}
1613
params := environs.StartInstanceParams{
1614
ControllerUUID: t.ControllerUUID,
1615
DistributionGroup: func() ([]instance.Id, error) {
1616
return expectedInstances, nil
1619
_, err = testing.StartInstanceWithParams(t.env, "1", params)
1620
c.Assert(err, jc.ErrorIsNil)
1621
c.Assert(mock.group, gc.DeepEquals, expectedInstances)
1624
func (t *localServerSuite) TestStartInstanceDistributionErrors(c *gc.C) {
1625
err := bootstrapEnv(c, t.env)
1626
c.Assert(err, jc.ErrorIsNil)
1628
mock := mockAvailabilityZoneAllocations{
1629
err: fmt.Errorf("AvailabilityZoneAllocations failed"),
1631
t.PatchValue(openstack.AvailabilityZoneAllocations, mock.AvailabilityZoneAllocations)
1632
_, _, _, err = testing.StartInstance(t.env, t.ControllerUUID, "1")
1633
c.Assert(jujuerrors.Cause(err), gc.Equals, mock.err)
1636
dgErr := fmt.Errorf("DistributionGroup failed")
1637
params := environs.StartInstanceParams{
1638
ControllerUUID: t.ControllerUUID,
1639
DistributionGroup: func() ([]instance.Id, error) {
1643
_, err = testing.StartInstanceWithParams(t.env, "1", params)
1644
c.Assert(jujuerrors.Cause(err), gc.Equals, dgErr)
1647
func (t *localServerSuite) TestStartInstanceDistribution(c *gc.C) {
1648
err := bootstrapEnv(c, t.env)
1649
c.Assert(err, jc.ErrorIsNil)
1651
// test-available is the only available AZ, so AvailabilityZoneAllocations
1652
// is guaranteed to return that.
1653
inst, _ := testing.AssertStartInstance(c, t.env, t.ControllerUUID, "1")
1654
c.Assert(openstack.InstanceServerDetail(inst).AvailabilityZone, gc.Equals, "test-available")
1657
func (t *localServerSuite) TestStartInstancePicksValidZoneForHost(c *gc.C) {
1658
coretesting.SkipIfPPC64EL(c, "lp:1425242")
1660
t.srv.Nova.SetAvailabilityZones(
1661
// bootstrap node will be on az1.
1662
nova.AvailabilityZone{
1664
State: nova.AvailabilityZoneState{
1668
// az2 will be made to return an error.
1669
nova.AvailabilityZone{
1671
State: nova.AvailabilityZoneState{
1675
// az3 will be valid to host an instance.
1676
nova.AvailabilityZone{
1678
State: nova.AvailabilityZoneState{
1684
err := bootstrapEnv(c, t.env)
1685
c.Assert(err, jc.ErrorIsNil)
1687
cleanup := t.srv.Nova.RegisterControlPoint(
1689
func(sc hook.ServiceControl, args ...interface{}) error {
1690
serverDetail := args[0].(*nova.ServerDetail)
1691
if serverDetail.AvailabilityZone == "az2" {
1692
return fmt.Errorf("No valid host was found")
1698
inst, _ := testing.AssertStartInstance(c, t.env, t.ControllerUUID, "1")
1699
c.Assert(openstack.InstanceServerDetail(inst).AvailabilityZone, gc.Equals, "az3")
1702
func (t *localServerSuite) TestStartInstanceWithUnknownAZError(c *gc.C) {
1703
coretesting.SkipIfPPC64EL(c, "lp:1425242")
1705
t.srv.Nova.SetAvailabilityZones(
1706
// bootstrap node will be on az1.
1707
nova.AvailabilityZone{
1709
State: nova.AvailabilityZoneState{
1713
// az2 will be made to return an unknown error.
1714
nova.AvailabilityZone{
1716
State: nova.AvailabilityZoneState{
1722
err := bootstrapEnv(c, t.env)
1723
c.Assert(err, jc.ErrorIsNil)
1725
cleanup := t.srv.Nova.RegisterControlPoint(
1727
func(sc hook.ServiceControl, args ...interface{}) error {
1728
serverDetail := args[0].(*nova.ServerDetail)
1729
if serverDetail.AvailabilityZone == "az2" {
1730
return fmt.Errorf("Some unknown error")
1736
_, _, _, err = testing.StartInstance(t.env, t.ControllerUUID, "1")
1737
c.Assert(err, gc.ErrorMatches, "(?s).*Some unknown error.*")
1740
func (t *localServerSuite) TestStartInstanceDistributionAZNotImplemented(c *gc.C) {
1741
err := bootstrapEnv(c, t.env)
1742
c.Assert(err, jc.ErrorIsNil)
1744
mock := mockAvailabilityZoneAllocations{
1745
err: jujuerrors.NotImplementedf("availability zones"),
1747
t.PatchValue(openstack.AvailabilityZoneAllocations, mock.AvailabilityZoneAllocations)
1749
// Instance will be created without an availability zone specified.
1750
inst, _ := testing.AssertStartInstance(c, t.env, t.ControllerUUID, "1")
1751
c.Assert(openstack.InstanceServerDetail(inst).AvailabilityZone, gc.Equals, "")
1754
func (t *localServerSuite) TestInstanceTags(c *gc.C) {
1755
err := bootstrapEnv(c, t.env)
1756
c.Assert(err, jc.ErrorIsNil)
1758
instances, err := t.env.AllInstances()
1759
c.Assert(err, jc.ErrorIsNil)
1760
c.Assert(instances, gc.HasLen, 1)
1763
openstack.InstanceServerDetail(instances[0]).Metadata,
1766
"juju-model-uuid": coretesting.ModelTag.Id(),
1767
"juju-controller-uuid": coretesting.ModelTag.Id(),
1768
"juju-is-controller": "true",
1773
func (t *localServerSuite) TestTagInstance(c *gc.C) {
1774
err := bootstrapEnv(c, t.env)
1775
c.Assert(err, jc.ErrorIsNil)
1777
assertMetadata := func(extraKey, extraValue string) {
1779
instances, err := t.env.AllInstances()
1780
c.Assert(err, jc.ErrorIsNil)
1781
c.Assert(instances, gc.HasLen, 1)
1783
openstack.InstanceServerDetail(instances[0]).Metadata,
1786
"juju-model-uuid": coretesting.ModelTag.Id(),
1787
"juju-controller-uuid": coretesting.ModelTag.Id(),
1788
"juju-is-controller": "true",
1789
extraKey: extraValue,
1794
instances, err := t.env.AllInstances()
1795
c.Assert(err, jc.ErrorIsNil)
1796
c.Assert(instances, gc.HasLen, 1)
1798
extraKey := "extra-k"
1799
extraValue := "extra-v"
1800
err = t.env.(environs.InstanceTagger).TagInstance(
1801
instances[0].Id(), map[string]string{extraKey: extraValue},
1803
c.Assert(err, jc.ErrorIsNil)
1804
assertMetadata(extraKey, extraValue)
1806
// Ensure that a second call updates existing tags.
1807
extraValue = "extra-v2"
1808
err = t.env.(environs.InstanceTagger).TagInstance(
1809
instances[0].Id(), map[string]string{extraKey: extraValue},
1811
c.Assert(err, jc.ErrorIsNil)
1812
assertMetadata(extraKey, extraValue)
1815
func prepareParams(attrs map[string]interface{}, cred *identity.Credentials) bootstrap.PrepareParams {
1816
return bootstrap.PrepareParams{
1817
ControllerConfig: coretesting.FakeControllerConfig(),
1819
ControllerName: attrs["name"].(string),
1820
Cloud: makeCloudSpec(cred),
1821
AdminSecret: testing.AdminSecret,
1825
func makeCloudSpec(cred *identity.Credentials) environs.CloudSpec {
1826
credential := makeCredential(cred)
1827
return environs.CloudSpec{
1831
Region: cred.Region,
1832
Credential: &credential,
1836
func makeCredential(cred *identity.Credentials) cloud.Credential {
1837
return cloud.NewCredential(
1838
cloud.UserPassAuthType,
1840
"username": cred.User,
1841
"password": cred.Secrets,
1842
"tenant-name": cred.TenantName,
1847
// noSwiftSuite contains tests that run against an OpenStack service double
1848
// that lacks Swift.
1849
type noSwiftSuite struct {
1850
coretesting.BaseSuite
1851
cred *identity.Credentials
1853
env environs.Environ
1856
func (s *noSwiftSuite) SetUpSuite(c *gc.C) {
1857
s.BaseSuite.SetUpSuite(c)
1858
restoreFinishBootstrap := envtesting.DisableFinishBootstrap()
1859
s.AddCleanup(func(*gc.C) { restoreFinishBootstrap() })
1861
s.PatchValue(&imagemetadata.SimplestreamsImagesPublicKey, sstesting.SignedMetadataPublicKey)
1862
s.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey)
1865
func (s *noSwiftSuite) SetUpTest(c *gc.C) {
1866
s.BaseSuite.SetUpTest(c)
1867
s.cred = &identity.Credentials{
1870
Region: "some-region",
1871
TenantName: "some tenant",
1873
s.srv.start(c, s.cred, newNovaOnlyOpenstackService)
1875
attrs := coretesting.FakeConfig().Merge(coretesting.Attrs{
1876
"name": "sample-no-swift",
1877
"type": "openstack",
1878
"auth-mode": "userpass",
1879
"agent-version": coretesting.FakeVersionNumber.String(),
1880
"authorized-keys": "fakekey",
1882
s.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber)
1883
// Serve fake tools and image metadata using "filestorage",
1884
// rather than Swift as the rest of the tests do.
1885
storageDir := c.MkDir()
1886
imagesDir := filepath.Join(storageDir, "images")
1887
toolsDir := filepath.Join(storageDir, "tools")
1888
for _, dir := range []string{imagesDir, toolsDir} {
1889
err := os.MkdirAll(dir, 0755)
1890
c.Assert(err, jc.ErrorIsNil)
1892
toolsStorage, err := filestorage.NewFileStorageWriter(storageDir)
1893
c.Assert(err, jc.ErrorIsNil)
1894
envtesting.UploadFakeTools(c, toolsStorage, "released", "released")
1895
s.PatchValue(&tools.DefaultBaseURL, storageDir)
1896
imageStorage, err := filestorage.NewFileStorageWriter(imagesDir)
1897
openstack.UseTestImageData(imageStorage, s.cred)
1898
imagetesting.PatchOfficialDataSources(&s.CleanupSuite, storageDir)
1900
env, err := bootstrap.Prepare(
1901
envtesting.BootstrapContext(c),
1902
jujuclienttesting.NewMemStore(),
1903
prepareParams(attrs, s.cred),
1905
c.Assert(err, jc.ErrorIsNil)
1909
func (s *noSwiftSuite) TearDownTest(c *gc.C) {
1911
s.BaseSuite.TearDownTest(c)
1914
func (s *noSwiftSuite) TestBootstrap(c *gc.C) {
1915
err := bootstrap.Bootstrap(envtesting.BootstrapContext(c), s.env, bootstrap.BootstrapParams{
1916
ControllerConfig: coretesting.FakeControllerConfig(),
1917
AdminSecret: testing.AdminSecret,
1918
CAPrivateKey: coretesting.CAKey,
1920
c.Assert(err, jc.ErrorIsNil)
1923
func newFullOpenstackService(mux *http.ServeMux, cred *identity.Credentials, auth identity.AuthMode) *novaservice.Nova {
1924
service := openstackservice.New(cred, auth)
1925
service.SetupHTTP(mux)
1929
func newNovaOnlyOpenstackService(mux *http.ServeMux, cred *identity.Credentials, auth identity.AuthMode) *novaservice.Nova {
1930
var identityService, fallbackService identityservice.IdentityService
1931
if auth == identity.AuthKeyPair {
1932
identityService = identityservice.NewKeyPair()
1934
identityService = identityservice.NewUserPass()
1935
fallbackService = identityservice.NewV3UserPass()
1937
userInfo := identityService.AddUser(cred.User, cred.Secrets, cred.TenantName)
1938
if cred.TenantName == "" {
1939
panic("Openstack service double requires a tenant to be specified.")
1941
novaService := novaservice.New(cred.URL, "v2", userInfo.TenantId, cred.Region, identityService, fallbackService)
1942
identityService.SetupHTTP(mux)
1943
novaService.SetupHTTP(mux)
1947
func bootstrapEnv(c *gc.C, env environs.Environ) error {
1948
return bootstrap.Bootstrap(envtesting.BootstrapContext(c), env, bootstrap.BootstrapParams{
1949
ControllerConfig: coretesting.FakeControllerConfig(),
1950
AdminSecret: testing.AdminSecret,
1951
CAPrivateKey: coretesting.CAKey,