blob: 9b284c30f1eb76a79c64a08f51139eff5263e209 [file] [log] [blame]
Joe Topjian1c15e3f2016-08-08 10:48:38 -06001// Package v2 contains common functions for creating compute-based resources
2// for use in acceptance tests. See the `*_test.go` files for example usages.
3package v2
4
5import (
6 "crypto/rand"
7 "crypto/rsa"
8 "fmt"
9 "testing"
10
11 "github.com/gophercloud/gophercloud"
12 "github.com/gophercloud/gophercloud/acceptance/clients"
13 "github.com/gophercloud/gophercloud/acceptance/tools"
14 "github.com/gophercloud/gophercloud/openstack/blockstorage/v1/volumes"
15 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
16 dsr "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/defsecrules"
17 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
18 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
19 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/networks"
20 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/quotasets"
21 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/schedulerhints"
22 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups"
23 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
24 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
25 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/volumeattach"
26 "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
27 "github.com/gophercloud/gophercloud/openstack/compute/v2/images"
28 "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
29
30 "golang.org/x/crypto/ssh"
31)
32
33// AssociateFloatingIP will associate a floating IP with an instance. An error
34// will be returned if the floating IP was unable to be associated.
35func AssociateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP, server *servers.Server) error {
36 associateOpts := floatingips.AssociateOpts{
37 FloatingIP: floatingIP.IP,
38 }
39
40 t.Logf("Attempting to associate floating IP %s to instance %s", floatingIP.IP, server.ID)
41 err := floatingips.AssociateInstance(client, server.ID, associateOpts).ExtractErr()
42 if err != nil {
43 return err
44 }
45
46 return nil
47}
48
49// AssociateFloatingIPWithFixedIP will associate a floating IP with an
50// instance's specific fixed IP. An error will be returend if the floating IP
51// was unable to be associated.
52func AssociateFloatingIPWithFixedIP(t *testing.T, client *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP, server *servers.Server, fixedIP string) error {
53 associateOpts := floatingips.AssociateOpts{
54 FloatingIP: floatingIP.IP,
55 FixedIP: fixedIP,
56 }
57
58 t.Logf("Attempting to associate floating IP %s to fixed IP %s on instance %s", floatingIP.IP, fixedIP, server.ID)
59 err := floatingips.AssociateInstance(client, server.ID, associateOpts).ExtractErr()
60 if err != nil {
61 return err
62 }
63
64 return nil
65}
66
67// CreateBootableVolumeServer works like CreateServer but is configured with
68// one or more block devices defined by passing in []bootfromvolume.BlockDevice.
69// An error will be returned if a server was unable to be created.
70func CreateBootableVolumeServer(t *testing.T, client *gophercloud.ServiceClient, blockDevices []bootfromvolume.BlockDevice, choices *clients.AcceptanceTestChoices) (*servers.Server, error) {
71 if testing.Short() {
72 t.Skip("Skipping test that requires server creation in short mode.")
73 }
74
75 var server *servers.Server
76
77 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
78 if err != nil {
79 return server, err
80 }
81
82 name := tools.RandomString("ACPTTEST", 16)
83 t.Logf("Attempting to create bootable volume server: %s", name)
84
85 serverCreateOpts := servers.CreateOpts{
86 Name: name,
87 FlavorRef: choices.FlavorID,
Joe Topjian1c15e3f2016-08-08 10:48:38 -060088 Networks: []servers.Network{
89 servers.Network{UUID: networkID},
90 },
91 }
92
93 server, err = bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
94 serverCreateOpts,
95 blockDevices,
96 }).Extract()
97
98 if err != nil {
99 return server, err
100 }
101
Joe Topjian50cdddf2016-09-16 10:56:09 -0600102 if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil {
103 return server, err
104 }
105
106 newServer, err := servers.Get(client, server.ID).Extract()
107
108 return newServer, nil
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600109}
110
111// CreateDefaultRule will create a default security group rule with a
112// random port range between 80 and 90. An error will be returned if
113// a default rule was unable to be created.
114func CreateDefaultRule(t *testing.T, client *gophercloud.ServiceClient) (dsr.DefaultRule, error) {
115 createOpts := dsr.CreateOpts{
116 FromPort: tools.RandomInt(80, 89),
117 ToPort: tools.RandomInt(90, 99),
118 IPProtocol: "TCP",
119 CIDR: "0.0.0.0/0",
120 }
121
122 defaultRule, err := dsr.Create(client, createOpts).Extract()
123 if err != nil {
124 return *defaultRule, err
125 }
126
127 t.Logf("Created default rule: %s", defaultRule.ID)
128
129 return *defaultRule, nil
130}
131
132// CreateFloatingIP will allocate a floating IP.
133// An error will be returend if one was unable to be allocated.
134func CreateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices) (*floatingips.FloatingIP, error) {
135 createOpts := floatingips.CreateOpts{
136 Pool: choices.FloatingIPPoolName,
137 }
138 floatingIP, err := floatingips.Create(client, createOpts).Extract()
139 if err != nil {
140 return floatingIP, err
141 }
142
143 t.Logf("Created floating IP: %s", floatingIP.ID)
144 return floatingIP, nil
145}
146
147func createKey() (string, error) {
148 privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
149 if err != nil {
150 return "", err
151 }
152
153 publicKey := privateKey.PublicKey
154 pub, err := ssh.NewPublicKey(&publicKey)
155 if err != nil {
156 return "", err
157 }
158
159 pubBytes := ssh.MarshalAuthorizedKey(pub)
160 pk := string(pubBytes)
161 return pk, nil
162}
163
164// CreateKeyPair will create a KeyPair with a random name. An error will occur
165// if the keypair failed to be created. An error will be returned if the
166// keypair was unable to be created.
167func CreateKeyPair(t *testing.T, client *gophercloud.ServiceClient) (*keypairs.KeyPair, error) {
168 keyPairName := tools.RandomString("keypair_", 5)
169
170 t.Logf("Attempting to create keypair: %s", keyPairName)
171 createOpts := keypairs.CreateOpts{
172 Name: keyPairName,
173 }
174 keyPair, err := keypairs.Create(client, createOpts).Extract()
175 if err != nil {
176 return keyPair, err
177 }
178
179 t.Logf("Created keypair: %s", keyPairName)
180 return keyPair, nil
181}
182
Joe Topjian50cdddf2016-09-16 10:56:09 -0600183// CreateMultiEphemeralServer works like CreateServer but is configured with
184// one or more block devices defined by passing in []bootfromvolume.BlockDevice.
185// These block devices act like block devices when booting from a volume but
186// are actually local ephemeral disks.
187// An error will be returned if a server was unable to be created.
188func CreateMultiEphemeralServer(t *testing.T, client *gophercloud.ServiceClient, blockDevices []bootfromvolume.BlockDevice, choices *clients.AcceptanceTestChoices) (*servers.Server, error) {
189 if testing.Short() {
190 t.Skip("Skipping test that requires server creation in short mode.")
191 }
192
193 var server *servers.Server
194
195 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
196 if err != nil {
197 return server, err
198 }
199
200 name := tools.RandomString("ACPTTEST", 16)
201 t.Logf("Attempting to create bootable volume server: %s", name)
202
203 serverCreateOpts := servers.CreateOpts{
204 Name: name,
205 FlavorRef: choices.FlavorID,
206 ImageRef: choices.ImageID,
207 Networks: []servers.Network{
208 servers.Network{UUID: networkID},
209 },
210 }
211
212 server, err = bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
213 serverCreateOpts,
214 blockDevices,
215 }).Extract()
216
217 if err != nil {
218 return server, err
219 }
220
221 if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil {
222 return server, err
223 }
224
225 newServer, err := servers.Get(client, server.ID).Extract()
226
227 return newServer, nil
228}
229
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600230// CreateSecurityGroup will create a security group with a random name.
231// An error will be returned if one was failed to be created.
232func CreateSecurityGroup(t *testing.T, client *gophercloud.ServiceClient) (secgroups.SecurityGroup, error) {
233 createOpts := secgroups.CreateOpts{
234 Name: tools.RandomString("secgroup_", 5),
235 Description: "something",
236 }
237
238 securityGroup, err := secgroups.Create(client, createOpts).Extract()
239 if err != nil {
240 return *securityGroup, err
241 }
242
243 t.Logf("Created security group: %s", securityGroup.ID)
244 return *securityGroup, nil
245}
246
247// CreateSecurityGroupRule will create a security group rule with a random name
248// and a random TCP port range between port 80 and 99. An error will be
249// returned if the rule failed to be created.
250func CreateSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, securityGroupID string) (secgroups.Rule, error) {
251 createOpts := secgroups.CreateRuleOpts{
252 ParentGroupID: securityGroupID,
253 FromPort: tools.RandomInt(80, 89),
254 ToPort: tools.RandomInt(90, 99),
255 IPProtocol: "TCP",
256 CIDR: "0.0.0.0/0",
257 }
258
259 rule, err := secgroups.CreateRule(client, createOpts).Extract()
260 if err != nil {
261 return *rule, err
262 }
263
264 t.Logf("Created security group rule: %s", rule.ID)
265 return *rule, nil
266}
267
268// CreateServer creates a basic instance with a randomly generated name.
269// The flavor of the instance will be the value of the OS_FLAVOR_ID environment variable.
270// The image will be the value of the OS_IMAGE_ID environment variable.
271// The instance will be launched on the network specified in OS_NETWORK_NAME.
272// An error will be returned if the instance was unable to be created.
273func CreateServer(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices) (*servers.Server, error) {
274 if testing.Short() {
275 t.Skip("Skipping test that requires server creation in short mode.")
276 }
277
278 var server *servers.Server
279
280 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
281 if err != nil {
282 return server, err
283 }
284
285 name := tools.RandomString("ACPTTEST", 16)
286 t.Logf("Attempting to create server: %s", name)
287
288 pwd := tools.MakeNewPassword("")
289
290 server, err = servers.Create(client, servers.CreateOpts{
291 Name: name,
292 FlavorRef: choices.FlavorID,
293 ImageRef: choices.ImageID,
294 AdminPass: pwd,
295 Networks: []servers.Network{
296 servers.Network{UUID: networkID},
297 },
Joe Topjianf464c962016-09-12 08:02:43 -0600298 Metadata: map[string]string{
299 "abc": "def",
300 },
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600301 Personality: servers.Personality{
302 &servers.File{
303 Path: "/etc/test",
304 Contents: []byte("hello world"),
305 },
306 },
307 }).Extract()
308 if err != nil {
309 return server, err
310 }
311
Joe Topjian50cdddf2016-09-16 10:56:09 -0600312 if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil {
313 return server, err
314 }
315
316 return server, nil
317}
318
319// CreateServerWithoutImageRef creates a basic instance with a randomly generated name.
320// The flavor of the instance will be the value of the OS_FLAVOR_ID environment variable.
321// The image is intentionally missing to trigger an error.
322// The instance will be launched on the network specified in OS_NETWORK_NAME.
323// An error will be returned if the instance was unable to be created.
324func CreateServerWithoutImageRef(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices) (*servers.Server, error) {
325 if testing.Short() {
326 t.Skip("Skipping test that requires server creation in short mode.")
327 }
328
329 var server *servers.Server
330
331 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
332 if err != nil {
333 return server, err
334 }
335
336 name := tools.RandomString("ACPTTEST", 16)
337 t.Logf("Attempting to create server: %s", name)
338
339 pwd := tools.MakeNewPassword("")
340
341 server, err = servers.Create(client, servers.CreateOpts{
342 Name: name,
343 FlavorRef: choices.FlavorID,
344 AdminPass: pwd,
345 Networks: []servers.Network{
346 servers.Network{UUID: networkID},
347 },
348 Personality: servers.Personality{
349 &servers.File{
350 Path: "/etc/test",
351 Contents: []byte("hello world"),
352 },
353 },
354 }).Extract()
355 if err != nil {
356 return server, err
357 }
358
359 if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil {
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600360 return server, err
361 }
362
363 return server, nil
364}
365
366// CreateServerGroup will create a server with a random name. An error will be
367// returned if the server group failed to be created.
368func CreateServerGroup(t *testing.T, client *gophercloud.ServiceClient, policy string) (*servergroups.ServerGroup, error) {
369 sg, err := servergroups.Create(client, &servergroups.CreateOpts{
370 Name: "test",
371 Policies: []string{policy},
372 }).Extract()
373
374 if err != nil {
375 return sg, err
376 }
377
378 return sg, nil
379}
380
381// CreateServerInServerGroup works like CreateServer but places the instance in
382// a specified Server Group.
383func CreateServerInServerGroup(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices, serverGroup *servergroups.ServerGroup) (*servers.Server, error) {
384 if testing.Short() {
385 t.Skip("Skipping test that requires server creation in short mode.")
386 }
387
388 var server *servers.Server
389
390 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
391 if err != nil {
392 return server, err
393 }
394
395 name := tools.RandomString("ACPTTEST", 16)
396 t.Logf("Attempting to create server: %s", name)
397
398 pwd := tools.MakeNewPassword("")
399
400 serverCreateOpts := servers.CreateOpts{
401 Name: name,
402 FlavorRef: choices.FlavorID,
403 ImageRef: choices.ImageID,
404 AdminPass: pwd,
405 Networks: []servers.Network{
406 servers.Network{UUID: networkID},
407 },
408 }
409
410 schedulerHintsOpts := schedulerhints.CreateOptsExt{
411 serverCreateOpts,
412 schedulerhints.SchedulerHints{
413 Group: serverGroup.ID,
414 },
415 }
416 server, err = servers.Create(client, schedulerHintsOpts).Extract()
417 if err != nil {
418 return server, err
419 }
420
421 return server, nil
422}
423
424// CreateServerWithPublicKey works the same as CreateServer, but additionally
425// configures the server with a specified Key Pair name.
426func CreateServerWithPublicKey(t *testing.T, client *gophercloud.ServiceClient, choices *clients.AcceptanceTestChoices, keyPairName string) (*servers.Server, error) {
427 if testing.Short() {
428 t.Skip("Skipping test that requires server creation in short mode.")
429 }
430
431 var server *servers.Server
432
433 networkID, err := GetNetworkIDFromTenantNetworks(t, client, choices.NetworkName)
434 if err != nil {
435 return server, err
436 }
437
438 name := tools.RandomString("ACPTTEST", 16)
439 t.Logf("Attempting to create server: %s", name)
440
441 serverCreateOpts := servers.CreateOpts{
442 Name: name,
443 FlavorRef: choices.FlavorID,
444 ImageRef: choices.ImageID,
445 Networks: []servers.Network{
446 servers.Network{UUID: networkID},
447 },
448 }
449
450 server, err = servers.Create(client, keypairs.CreateOptsExt{
451 serverCreateOpts,
452 keyPairName,
453 }).Extract()
454 if err != nil {
455 return server, err
456 }
457
Joe Topjian50cdddf2016-09-16 10:56:09 -0600458 if err := WaitForComputeStatus(client, server, "ACTIVE"); err != nil {
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600459 return server, err
460 }
461
462 return server, nil
463}
464
Gleb37b56e82016-09-06 19:07:58 +0300465// CreateVolumeAttachment will attach a volume to a server. An error will be
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600466// returned if the volume failed to attach.
467func CreateVolumeAttachment(t *testing.T, client *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, server *servers.Server, volume *volumes.Volume) (*volumeattach.VolumeAttachment, error) {
468 volumeAttachOptions := volumeattach.CreateOpts{
469 VolumeID: volume.ID,
470 }
471
472 t.Logf("Attempting to attach volume %s to server %s", volume.ID, server.ID)
473 volumeAttachment, err := volumeattach.Create(client, server.ID, volumeAttachOptions).Extract()
474 if err != nil {
475 return volumeAttachment, err
476 }
477
Joe Topjian50cdddf2016-09-16 10:56:09 -0600478 if err := volumes.WaitForStatus(blockClient, volume.ID, "in-use", 60); err != nil {
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600479 return volumeAttachment, err
480 }
481
482 return volumeAttachment, nil
483}
484
485// DeleteDefaultRule deletes a default security group rule.
486// A fatal error will occur if the rule failed to delete. This works best when
487// using it as a deferred function.
488func DeleteDefaultRule(t *testing.T, client *gophercloud.ServiceClient, defaultRule dsr.DefaultRule) {
489 err := dsr.Delete(client, defaultRule.ID).ExtractErr()
490 if err != nil {
491 t.Fatalf("Unable to delete default rule %s: %v", defaultRule.ID, err)
492 }
493
494 t.Logf("Deleted default rule: %s", defaultRule.ID)
495}
496
497// DeleteFloatingIP will de-allocate a floating IP. A fatal error will occur if
498// the floating IP failed to de-allocate. This works best when using it as a
499// deferred function.
500func DeleteFloatingIP(t *testing.T, client *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP) {
501 err := floatingips.Delete(client, floatingIP.ID).ExtractErr()
502 if err != nil {
503 t.Fatalf("Unable to delete floating IP %s: %v", floatingIP.ID, err)
504 }
505
506 t.Logf("Deleted floating IP: %s", floatingIP.ID)
507}
508
509// DeleteKeyPair will delete a specified keypair. A fatal error will occur if
510// the keypair failed to be deleted. This works best when used as a deferred
511// function.
512func DeleteKeyPair(t *testing.T, client *gophercloud.ServiceClient, keyPair *keypairs.KeyPair) {
513 err := keypairs.Delete(client, keyPair.Name).ExtractErr()
514 if err != nil {
515 t.Fatalf("Unable to delete keypair %s: %v", keyPair.Name, err)
516 }
517
518 t.Logf("Deleted keypair: %s", keyPair.Name)
519}
520
521// DeleteSecurityGroup will delete a security group. A fatal error will occur
522// if the group failed to be deleted. This works best as a deferred function.
523func DeleteSecurityGroup(t *testing.T, client *gophercloud.ServiceClient, securityGroup secgroups.SecurityGroup) {
524 err := secgroups.Delete(client, securityGroup.ID).ExtractErr()
525 if err != nil {
526 t.Fatalf("Unable to delete security group %s: %s", securityGroup.ID, err)
527 }
528
529 t.Logf("Deleted security group: %s", securityGroup.ID)
530}
531
532// DeleteSecurityGroupRule will delete a security group rule. A fatal error
533// will occur if the rule failed to be deleted. This works best when used
534// as a deferred function.
535func DeleteSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, rule secgroups.Rule) {
536 err := secgroups.DeleteRule(client, rule.ID).ExtractErr()
537 if err != nil {
538 t.Fatalf("Unable to delete rule: %v", err)
539 }
540
541 t.Logf("Deleted security group rule: %s", rule.ID)
542}
543
544// DeleteServer deletes an instance via its UUID.
545// A fatal error will occur if the instance failed to be destroyed. This works
546// best when using it as a deferred function.
547func DeleteServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server) {
548 err := servers.Delete(client, server.ID).ExtractErr()
549 if err != nil {
550 t.Fatalf("Unable to delete server %s: %s", server.ID, err)
551 }
552
553 t.Logf("Deleted server: %s", server.ID)
554}
555
556// DeleteServerGroup will delete a server group. A fatal error will occur if
557// the server group failed to be deleted. This works best when used as a
558// deferred function.
559func DeleteServerGroup(t *testing.T, client *gophercloud.ServiceClient, serverGroup *servergroups.ServerGroup) {
560 err := servergroups.Delete(client, serverGroup.ID).ExtractErr()
561 if err != nil {
562 t.Fatalf("Unable to delete server group %s: %v", serverGroup.ID, err)
563 }
564
565 t.Logf("Deleted server group %s", serverGroup.ID)
566}
567
568// DeleteVolumeAttachment will disconnect a volume from an instance. A fatal
569// error will occur if the volume failed to detach. This works best when used
Gleb37b56e82016-09-06 19:07:58 +0300570// as a deferred function.
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600571func DeleteVolumeAttachment(t *testing.T, client *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, server *servers.Server, volumeAttachment *volumeattach.VolumeAttachment) {
572
573 err := volumeattach.Delete(client, server.ID, volumeAttachment.VolumeID).ExtractErr()
574 if err != nil {
575 t.Fatalf("Unable to detach volume: %v", err)
576 }
577
Joe Topjian50cdddf2016-09-16 10:56:09 -0600578 if err := volumes.WaitForStatus(blockClient, volumeAttachment.ID, "available", 60); err != nil {
Joe Topjian1c15e3f2016-08-08 10:48:38 -0600579 t.Fatalf("Unable to wait for volume: %v", err)
580 }
581 t.Logf("Deleted volume: %s", volumeAttachment.VolumeID)
582}
583
584// DisassociateFloatingIP will disassociate a floating IP from an instance. A
585// fatal error will occur if the floating IP failed to disassociate. This works
586// best when using it as a deferred function.
587func DisassociateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP, server *servers.Server) {
588 disassociateOpts := floatingips.DisassociateOpts{
589 FloatingIP: floatingIP.IP,
590 }
591
592 err := floatingips.DisassociateInstance(client, server.ID, disassociateOpts).ExtractErr()
593 if err != nil {
594 t.Fatalf("Unable to disassociate floating IP %s from server %s: %v", floatingIP.IP, server.ID, err)
595 }
596
597 t.Logf("Disassociated floating IP %s from server %s", floatingIP.IP, server.ID)
598}
599
600// GetNetworkIDFromNetworks will return the network ID from a specified network
601// UUID using the os-networks API extension. An error will be returned if the
602// network could not be retrieved.
603func GetNetworkIDFromNetworks(t *testing.T, client *gophercloud.ServiceClient, networkName string) (string, error) {
604 allPages, err := networks.List(client).AllPages()
605 if err != nil {
606 t.Fatalf("Unable to list networks: %v", err)
607 }
608
609 networkList, err := networks.ExtractNetworks(allPages)
610 if err != nil {
611 t.Fatalf("Unable to list networks: %v", err)
612 }
613
614 networkID := ""
615 for _, network := range networkList {
616 t.Logf("Network: %v", network)
617 if network.Label == networkName {
618 networkID = network.ID
619 }
620 }
621
622 t.Logf("Found network ID for %s: %s", networkName, networkID)
623
624 return networkID, nil
625}
626
627// GetNetworkIDFromTenantNetworks will return the network UUID for a given
628// network name using the os-tenant-networks API extension. An error will be
629// returned if the network could not be retrieved.
630func GetNetworkIDFromTenantNetworks(t *testing.T, client *gophercloud.ServiceClient, networkName string) (string, error) {
631 allPages, err := tenantnetworks.List(client).AllPages()
632 if err != nil {
633 return "", err
634 }
635
636 allTenantNetworks, err := tenantnetworks.ExtractNetworks(allPages)
637 if err != nil {
638 return "", err
639 }
640
641 for _, network := range allTenantNetworks {
642 if network.Name == networkName {
643 return network.ID, nil
644 }
645 }
646
647 return "", fmt.Errorf("Failed to obtain network ID for network %s", networkName)
648}
649
650// ImportPublicKey will create a KeyPair with a random name and a specified
651// public key. An error will be returned if the keypair failed to be created.
652func ImportPublicKey(t *testing.T, client *gophercloud.ServiceClient, publicKey string) (*keypairs.KeyPair, error) {
653 keyPairName := tools.RandomString("keypair_", 5)
654
655 t.Logf("Attempting to create keypair: %s", keyPairName)
656 createOpts := keypairs.CreateOpts{
657 Name: keyPairName,
658 PublicKey: publicKey,
659 }
660 keyPair, err := keypairs.Create(client, createOpts).Extract()
661 if err != nil {
662 return keyPair, err
663 }
664
665 t.Logf("Created keypair: %s", keyPairName)
666 return keyPair, nil
667}
668
669// ResizeServer performs a resize action on an instance. An error will be
670// returned if the instance failed to resize.
671// The new flavor that the instance will be resized to is specified in OS_FLAVOR_ID_RESIZE.
672func ResizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *clients.AcceptanceTestChoices) error {
673 opts := &servers.ResizeOpts{
674 FlavorRef: choices.FlavorIDResize,
675 }
676 if res := servers.Resize(client, server.ID, opts); res.Err != nil {
677 return res.Err
678 }
679
680 if err := WaitForComputeStatus(client, server, "VERIFY_RESIZE"); err != nil {
681 return err
682 }
683
684 return nil
685}
686
687// WaitForComputeStatus will poll an instance's status until it either matches
688// the specified status or the status becomes ERROR.
689func WaitForComputeStatus(client *gophercloud.ServiceClient, server *servers.Server, status string) error {
690 return tools.WaitFor(func() (bool, error) {
691 latest, err := servers.Get(client, server.ID).Extract()
692 if err != nil {
693 return false, err
694 }
695
696 if latest.Status == status {
697 // Success!
698 return true, nil
699 }
700
701 if latest.Status == "ERROR" {
702 return false, fmt.Errorf("Instance in ERROR state")
703 }
704
705 return false, nil
706 })
707}
708
709// PrintServer will print an instance and all of its attributes.
710func PrintServer(t *testing.T, server *servers.Server) {
711 t.Logf("ID: %s", server.ID)
712 t.Logf("TenantID: %s", server.TenantID)
713 t.Logf("UserID: %s", server.UserID)
714 t.Logf("Name: %s", server.Name)
715 t.Logf("Updated: %s", server.Updated)
716 t.Logf("Created: %s", server.Created)
717 t.Logf("HostID: %s", server.HostID)
718 t.Logf("Status: %s", server.Status)
719 t.Logf("Progress: %d", server.Progress)
720 t.Logf("AccessIPv4: %s", server.AccessIPv4)
721 t.Logf("AccessIPv6: %s", server.AccessIPv6)
722 t.Logf("Image: %s", server.Image)
723 t.Logf("Flavor: %s", server.Flavor)
724 t.Logf("Addresses: %#v", server.Addresses)
725 t.Logf("Metadata: %#v", server.Metadata)
726 t.Logf("Links: %#v", server.Links)
727 t.Logf("KeyName: %s", server.KeyName)
728 t.Logf("AdminPass: %s", server.AdminPass)
729 t.Logf("SecurityGroups: %#v", server.SecurityGroups)
730}
731
732// PrintDefaultRule will print a default security group rule and all of its attributes.
733func PrintDefaultRule(t *testing.T, defaultRule *dsr.DefaultRule) {
734 t.Logf("\tID: %s", defaultRule.ID)
735 t.Logf("\tFrom Port: %d", defaultRule.FromPort)
736 t.Logf("\tTo Port: %d", defaultRule.ToPort)
737 t.Logf("\tIP Protocol: %s", defaultRule.IPProtocol)
738 t.Logf("\tIP Range: %s", defaultRule.IPRange.CIDR)
739 t.Logf("\tParent Group ID: %s", defaultRule.ParentGroupID)
740 t.Logf("\tGroup Tenant ID: %s", defaultRule.Group.TenantID)
741 t.Logf("\tGroup Name: %s", defaultRule.Group.Name)
742}
743
744// PrintFlavor will print a flavor and all of its attributes.
745func PrintFlavor(t *testing.T, flavor *flavors.Flavor) {
746 t.Logf("ID: %s", flavor.ID)
747 t.Logf("Name: %s", flavor.Name)
748 t.Logf("RAM: %d", flavor.RAM)
749 t.Logf("Disk: %d", flavor.Disk)
750 t.Logf("Swap: %d", flavor.Swap)
751 t.Logf("RxTxFactor: %f", flavor.RxTxFactor)
752}
753
754// PrintFloatingIP will print a floating IP and all of its attributes.
755func PrintFloatingIP(t *testing.T, floatingIP *floatingips.FloatingIP) {
756 t.Logf("ID: %s", floatingIP.ID)
757 t.Logf("Fixed IP: %s", floatingIP.FixedIP)
758 t.Logf("Instance ID: %s", floatingIP.InstanceID)
759 t.Logf("IP: %s", floatingIP.IP)
760 t.Logf("Pool: %s", floatingIP.Pool)
761}
762
763// PrintImage will print an image and all of its attributes.
764func PrintImage(t *testing.T, image images.Image) {
765 t.Logf("ID: %s", image.ID)
766 t.Logf("Name: %s", image.Name)
767 t.Logf("MinDisk: %d", image.MinDisk)
768 t.Logf("MinRAM: %d", image.MinRAM)
769 t.Logf("Status: %s", image.Status)
770 t.Logf("Progress: %d", image.Progress)
771 t.Logf("Metadata: %#v", image.Metadata)
772 t.Logf("Created: %s", image.Created)
773 t.Logf("Updated: %s", image.Updated)
774}
775
776// PrintKeyPair will print keypair and all of its attributes.
777func PrintKeyPair(t *testing.T, keypair *keypairs.KeyPair) {
778 t.Logf("Name: %s", keypair.Name)
779 t.Logf("Fingerprint: %s", keypair.Fingerprint)
780 t.Logf("Public Key: %s", keypair.PublicKey)
781 t.Logf("Private Key: %s", keypair.PrivateKey)
782 t.Logf("UserID: %s", keypair.UserID)
783}
784
785// PrintNetwork will print an os-networks based network and all of its attributes.
786func PrintNetwork(t *testing.T, network *networks.Network) {
787 t.Logf("Bridge: %s", network.Bridge)
788 t.Logf("BridgeInterface: %s", network.BridgeInterface)
789 t.Logf("Broadcast: %s", network.Broadcast)
790 t.Logf("CIDR: %s", network.CIDR)
791 t.Logf("CIDRv6: %s", network.CIDRv6)
792 t.Logf("CreatedAt: %v", network.CreatedAt)
793 t.Logf("Deleted: %t", network.Deleted)
794 t.Logf("DeletedAt: %v", network.DeletedAt)
795 t.Logf("DHCPStart: %s", network.DHCPStart)
796 t.Logf("DNS1: %s", network.DNS1)
797 t.Logf("DNS2: %s", network.DNS2)
798 t.Logf("Gateway: %s", network.Gateway)
799 t.Logf("Gatewayv6: %s", network.Gatewayv6)
800 t.Logf("Host: %s", network.Host)
801 t.Logf("ID: %s", network.ID)
802 t.Logf("Injected: %t", network.Injected)
803 t.Logf("Label: %s", network.Label)
804 t.Logf("MultiHost: %t", network.MultiHost)
805 t.Logf("Netmask: %s", network.Netmask)
806 t.Logf("Netmaskv6: %s", network.Netmaskv6)
807 t.Logf("Priority: %d", network.Priority)
808 t.Logf("ProjectID: %s", network.ProjectID)
809 t.Logf("RXTXBase: %d", network.RXTXBase)
810 t.Logf("UpdatedAt: %v", network.UpdatedAt)
811 t.Logf("VLAN: %d", network.VLAN)
812 t.Logf("VPNPrivateAddress: %s", network.VPNPrivateAddress)
813 t.Logf("VPNPublicAddress: %s", network.VPNPublicAddress)
814 t.Logf("VPNPublicPort: %d", network.VPNPublicPort)
815}
816
817// PrintQuotaSet will print a quota set and all of its attributes.
818func PrintQuotaSet(t *testing.T, quotaSet *quotasets.QuotaSet) {
819 t.Logf("instances: %d\n", quotaSet.Instances)
820 t.Logf("cores: %d\n", quotaSet.Cores)
821 t.Logf("ram: %d\n", quotaSet.Ram)
822 t.Logf("key_pairs: %d\n", quotaSet.KeyPairs)
823 t.Logf("metadata_items: %d\n", quotaSet.MetadataItems)
824 t.Logf("security_groups: %d\n", quotaSet.SecurityGroups)
825 t.Logf("security_group_rules: %d\n", quotaSet.SecurityGroupRules)
826 t.Logf("fixed_ips: %d\n", quotaSet.FixedIps)
827 t.Logf("floating_ips: %d\n", quotaSet.FloatingIps)
828 t.Logf("injected_file_content_bytes: %d\n", quotaSet.InjectedFileContentBytes)
829 t.Logf("injected_file_path_bytes: %d\n", quotaSet.InjectedFilePathBytes)
830 t.Logf("injected_files: %d\n", quotaSet.InjectedFiles)
831}
832
833// PrintSecurityGroup will print a security group and all of its attributes and rules.
834func PrintSecurityGroup(t *testing.T, securityGroup *secgroups.SecurityGroup) {
835 t.Logf("ID: %s", securityGroup.ID)
836 t.Logf("Name: %s", securityGroup.Name)
837 t.Logf("Description: %s", securityGroup.Description)
838 t.Logf("Tenant ID: %s", securityGroup.TenantID)
839 t.Logf("Rules:")
840
841 for _, rule := range securityGroup.Rules {
842 t.Logf("\tID: %s", rule.ID)
843 t.Logf("\tFrom Port: %d", rule.FromPort)
844 t.Logf("\tTo Port: %d", rule.ToPort)
845 t.Logf("\tIP Protocol: %s", rule.IPProtocol)
846 t.Logf("\tIP Range: %s", rule.IPRange.CIDR)
847 t.Logf("\tParent Group ID: %s", rule.ParentGroupID)
848 t.Logf("\tGroup Tenant ID: %s", rule.Group.TenantID)
849 t.Logf("\tGroup Name: %s", rule.Group.Name)
850 }
851}
852
853// PrintServerGroup will print a server group and all of its attributes.
854func PrintServerGroup(t *testing.T, serverGroup *servergroups.ServerGroup) {
855 t.Logf("ID: %s", serverGroup.ID)
856 t.Logf("Name: %s", serverGroup.Name)
857 t.Logf("Policies: %#v", serverGroup.Policies)
858 t.Logf("Members: %#v", serverGroup.Members)
859 t.Logf("Metadata: %#v", serverGroup.Metadata)
860}
861
862// PrintTenantNetwork will print an os-tenant-networks based network and all of its attributes.
863func PrintTenantNetwork(t *testing.T, network *tenantnetworks.Network) {
864 t.Logf("ID: %s", network.ID)
865 t.Logf("Name: %s", network.Name)
866 t.Logf("CIDR: %s", network.CIDR)
867}
868
869// PrintVolumeAttachment will print a volume attachment and all of its attributes.
870func PrintVolumeAttachment(t *testing.T, volumeAttachment *volumeattach.VolumeAttachment) {
871 t.Logf("ID: %s", volumeAttachment.ID)
872 t.Logf("Device: %s", volumeAttachment.Device)
873 t.Logf("VolumeID: %s", volumeAttachment.VolumeID)
874 t.Logf("ServerID: %s", volumeAttachment.ServerID)
875}