Skip to content

Commit c1e8296

Browse files
committed
Replace
1 parent 1f1b77b commit c1e8296

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+2443
-2934
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package extensions
2+
3+
import (
4+
"testing"
5+
6+
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
7+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/extensions/backups"
8+
9+
blockstorage "github.com/opentelekomcloud/gophertelekomcloud/acceptance/openstack/evs/v3"
10+
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
11+
)
12+
13+
func TestBackupsCRUD(t *testing.T) {
14+
blockClient, err := clients.NewBlockStorageV3Client()
15+
th.AssertNoErr(t, err)
16+
17+
volume, err := blockstorage.CreateVolume(t, blockClient)
18+
th.AssertNoErr(t, err)
19+
defer blockstorage.DeleteVolume(t, blockClient, volume)
20+
21+
backup, err := CreateBackup(t, blockClient, volume.ID)
22+
th.AssertNoErr(t, err)
23+
defer DeleteBackup(t, blockClient, backup.ID)
24+
25+
allPages, err := backups.List(blockClient, nil).AllPages()
26+
th.AssertNoErr(t, err)
27+
28+
allBackups, err := backups.ExtractBackups(allPages)
29+
th.AssertNoErr(t, err)
30+
31+
var found bool
32+
for _, v := range allBackups {
33+
if backup.Name == v.Name {
34+
found = true
35+
}
36+
}
37+
38+
th.AssertEquals(t, found, true)
39+
}
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
// Package extensions contains common functions for creating block storage
2+
// resources that are extensions of the block storage API. See the `*_test.go`
3+
// files for example usages.
4+
package extensions
5+
6+
import (
7+
"fmt"
8+
"strings"
9+
"testing"
10+
11+
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
12+
"github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools"
13+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/compute/v2/images"
14+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/compute/v2/servers"
15+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/extensions/backups"
16+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/extensions/volumeactions"
17+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/v2/volumes"
18+
v3 "github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/v3/volumes"
19+
"github.com/opentelekomcloud/gophertelekomcloud/openstack/evs/v3/volumetypes"
20+
th "github.com/opentelekomcloud/gophertelekomcloud/testhelper"
21+
)
22+
23+
// CreateUploadImage will upload volume it as volume-baked image. An name of new image or err will be
24+
// returned
25+
func CreateUploadImage(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) (volumeactions.VolumeImage, error) {
26+
if testing.Short() {
27+
t.Skip("Skipping test that requires volume-backed image uploading in short mode.")
28+
}
29+
30+
imageName := tools.RandomString("ACPTTEST", 16)
31+
uploadImageOpts := volumeactions.UploadImageOpts{
32+
ImageName: imageName,
33+
Force: true,
34+
}
35+
36+
volumeImage, err := volumeactions.UploadImage(client, volume.ID, uploadImageOpts).Extract()
37+
if err != nil {
38+
return volumeImage, err
39+
}
40+
41+
t.Logf("Uploading volume %s as volume-backed image %s", volume.ID, imageName)
42+
43+
if err := volumes.WaitForStatus(client, volume.ID, "available", 60); err != nil {
44+
return volumeImage, err
45+
}
46+
47+
t.Logf("Uploaded volume %s as volume-backed image %s", volume.ID, imageName)
48+
49+
return volumeImage, nil
50+
51+
}
52+
53+
// DeleteUploadedImage deletes uploaded image. An error will be returned
54+
// if the deletion request failed.
55+
func DeleteUploadedImage(t *testing.T, client *golangsdk.ServiceClient, imageID string) error {
56+
if testing.Short() {
57+
t.Skip("Skipping test that requires volume-backed image removing in short mode.")
58+
}
59+
60+
t.Logf("Removing image %s", imageID)
61+
62+
err := images.Delete(client, imageID).ExtractErr()
63+
if err != nil {
64+
return err
65+
}
66+
67+
return nil
68+
}
69+
70+
// CreateVolumeAttach will attach a volume to an instance. An error will be
71+
// returned if the attachment failed.
72+
func CreateVolumeAttach(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume, server *servers.Server) error {
73+
if testing.Short() {
74+
t.Skip("Skipping test that requires volume attachment in short mode.")
75+
}
76+
77+
attachOpts := volumeactions.AttachOpts{
78+
MountPoint: "/mnt",
79+
Mode: "rw",
80+
InstanceUUID: server.ID,
81+
}
82+
83+
t.Logf("Attempting to attach volume %s to server %s", volume.ID, server.ID)
84+
85+
if err := volumeactions.Attach(client, volume.ID, attachOpts).ExtractErr(); err != nil {
86+
return err
87+
}
88+
89+
if err := volumes.WaitForStatus(client, volume.ID, "in-use", 60); err != nil {
90+
return err
91+
}
92+
93+
t.Logf("Attached volume %s to server %s", volume.ID, server.ID)
94+
95+
return nil
96+
}
97+
98+
// CreateVolumeReserve creates a volume reservation. An error will be returned
99+
// if the reservation failed.
100+
func CreateVolumeReserve(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) error {
101+
if testing.Short() {
102+
t.Skip("Skipping test that requires volume reservation in short mode.")
103+
}
104+
105+
t.Logf("Attempting to reserve volume %s", volume.ID)
106+
107+
if err := volumeactions.Reserve(client, volume.ID).ExtractErr(); err != nil {
108+
return err
109+
}
110+
111+
t.Logf("Reserved volume %s", volume.ID)
112+
113+
return nil
114+
}
115+
116+
// DeleteVolumeAttach will detach a volume from an instance. A fatal error will
117+
// occur if the snapshot failed to be deleted. This works best when used as a
118+
// deferred function.
119+
func DeleteVolumeAttach(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) {
120+
t.Logf("Attepting to detach volume volume: %s", volume.ID)
121+
122+
detachOpts := volumeactions.DetachOpts{
123+
AttachmentID: volume.Attachments[0].AttachmentID,
124+
}
125+
126+
if err := volumeactions.Detach(client, volume.ID, detachOpts).ExtractErr(); err != nil {
127+
t.Fatalf("Unable to detach volume %s: %v", volume.ID, err)
128+
}
129+
130+
if err := volumes.WaitForStatus(client, volume.ID, "available", 60); err != nil {
131+
t.Fatalf("Volume %s failed to become unavailable in 60 seconds: %v", volume.ID, err)
132+
}
133+
134+
t.Logf("Detached volume: %s", volume.ID)
135+
}
136+
137+
// DeleteVolumeReserve deletes a volume reservation. A fatal error will occur
138+
// if the deletion request failed. This works best when used as a deferred
139+
// function.
140+
func DeleteVolumeReserve(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) {
141+
if testing.Short() {
142+
t.Skip("Skipping test that requires volume reservation in short mode.")
143+
}
144+
145+
t.Logf("Attempting to unreserve volume %s", volume.ID)
146+
147+
if err := volumeactions.Unreserve(client, volume.ID).ExtractErr(); err != nil {
148+
t.Fatalf("Unable to unreserve volume %s: %v", volume.ID, err)
149+
}
150+
151+
t.Logf("Unreserved volume %s", volume.ID)
152+
}
153+
154+
// ExtendVolumeSize will extend the size of a volume.
155+
func ExtendVolumeSize(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) error {
156+
t.Logf("Attempting to extend the size of volume %s", volume.ID)
157+
158+
extendOpts := volumeactions.ExtendSizeOpts{
159+
NewSize: 2,
160+
}
161+
162+
err := volumeactions.ExtendSize(client, volume.ID, extendOpts).ExtractErr()
163+
if err != nil {
164+
return err
165+
}
166+
167+
if err := volumes.WaitForStatus(client, volume.ID, "available", 60); err != nil {
168+
return err
169+
}
170+
171+
return nil
172+
}
173+
174+
// SetImageMetadata will apply the metadata to a volume.
175+
func SetImageMetadata(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) error {
176+
t.Logf("Attempting to apply image metadata to volume %s", volume.ID)
177+
178+
imageMetadataOpts := volumeactions.ImageMetadataOpts{
179+
Metadata: map[string]string{
180+
"image_name": "testimage",
181+
},
182+
}
183+
184+
err := volumeactions.SetImageMetadata(client, volume.ID, imageMetadataOpts).ExtractErr()
185+
if err != nil {
186+
return err
187+
}
188+
189+
return nil
190+
}
191+
192+
// CreateBackup will create a backup based on a volume. An error will be
193+
// will be returned if the backup could not be created.
194+
func CreateBackup(t *testing.T, client *golangsdk.ServiceClient, volumeID string) (*backups.Backup, error) {
195+
t.Logf("Attempting to create a backup of volume %s", volumeID)
196+
197+
backupName := tools.RandomString("ACPTTEST", 16)
198+
createOpts := backups.CreateOpts{
199+
VolumeID: volumeID,
200+
Name: backupName,
201+
}
202+
203+
backup, err := backups.Create(client, createOpts).Extract()
204+
if err != nil {
205+
return nil, err
206+
}
207+
208+
err = WaitForBackupStatus(client, backup.ID, "available")
209+
if err != nil {
210+
return nil, err
211+
}
212+
213+
backup, err = backups.Get(client, backup.ID).Extract()
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
t.Logf("Successfully created backup %s", backup.ID)
219+
tools.PrintResource(t, backup)
220+
221+
th.AssertEquals(t, backup.Name, backupName)
222+
223+
return backup, nil
224+
}
225+
226+
// DeleteBackup will delete a backup. A fatal error will occur if the backup
227+
// could not be deleted. This works best when used as a deferred function.
228+
func DeleteBackup(t *testing.T, client *golangsdk.ServiceClient, backupID string) {
229+
if err := backups.Delete(client, backupID).ExtractErr(); err != nil {
230+
t.Fatalf("Unable to delete backup %s: %s", backupID, err)
231+
}
232+
233+
t.Logf("Deleted backup %s", backupID)
234+
}
235+
236+
// WaitForBackupStatus will continually poll a backup, checking for a particular
237+
// status. It will do this for the amount of seconds defined.
238+
func WaitForBackupStatus(client *golangsdk.ServiceClient, id, status string) error {
239+
return tools.WaitFor(func() (bool, error) {
240+
current, err := backups.Get(client, id).Extract()
241+
if err != nil {
242+
return false, err
243+
}
244+
245+
if current.Status == status {
246+
return true, nil
247+
}
248+
249+
return false, nil
250+
})
251+
}
252+
253+
// SetBootable will set a bootable status to a volume.
254+
func SetBootable(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume) error {
255+
t.Logf("Attempting to apply bootable status to volume %s", volume.ID)
256+
257+
bootableOpts := volumeactions.BootableOpts{
258+
Bootable: true,
259+
}
260+
261+
err := volumeactions.SetBootable(client, volume.ID, bootableOpts).ExtractErr()
262+
if err != nil {
263+
return err
264+
}
265+
266+
vol, err := v3.Get(client, volume.ID).Extract()
267+
if err != nil {
268+
return err
269+
}
270+
271+
if strings.ToLower(vol.Bootable) != "true" {
272+
return fmt.Errorf("Volume bootable status is %q, expected 'true'", vol.Bootable)
273+
}
274+
275+
bootableOpts = volumeactions.BootableOpts{
276+
Bootable: false,
277+
}
278+
279+
err = volumeactions.SetBootable(client, volume.ID, bootableOpts).ExtractErr()
280+
if err != nil {
281+
return err
282+
}
283+
284+
vol, err = v3.Get(client, volume.ID).Extract()
285+
if err != nil {
286+
return err
287+
}
288+
289+
if strings.ToLower(vol.Bootable) == "true" {
290+
return fmt.Errorf("Volume bootable status is %q, expected 'false'", vol.Bootable)
291+
}
292+
293+
return nil
294+
}
295+
296+
// ChangeVolumeType will extend the size of a volume.
297+
func ChangeVolumeType(t *testing.T, client *golangsdk.ServiceClient, volume *v3.Volume, vt *volumetypes.VolumeType) error {
298+
t.Logf("Attempting to change the type of volume %s from %s to %s", volume.ID, volume.VolumeType, vt.Name)
299+
300+
changeOpts := volumeactions.ChangeTypeOpts{
301+
NewType: vt.Name,
302+
MigrationPolicy: volumeactions.MigrationPolicyOnDemand,
303+
}
304+
305+
err := volumeactions.ChangeType(client, volume.ID, changeOpts).ExtractErr()
306+
if err != nil {
307+
return err
308+
}
309+
310+
if err := volumes.WaitForStatus(client, volume.ID, "available", 60); err != nil {
311+
return err
312+
}
313+
314+
return nil
315+
}
316+
317+
// ReImage will re-image a volume
318+
func ReImage(t *testing.T, client *golangsdk.ServiceClient, volume *volumes.Volume, imageID string) error {
319+
t.Logf("Attempting to re-image volume %s", volume.ID)
320+
321+
reimageOpts := volumeactions.ReImageOpts{
322+
ImageID: imageID,
323+
ReImageReserved: false,
324+
}
325+
326+
err := volumeactions.ReImage(client, volume.ID, reimageOpts).ExtractErr()
327+
if err != nil {
328+
return err
329+
}
330+
331+
err = volumes.WaitForStatus(client, volume.ID, "available", 60)
332+
if err != nil {
333+
return err
334+
}
335+
336+
vol, err := v3.Get(client, volume.ID).Extract()
337+
if err != nil {
338+
return err
339+
}
340+
341+
if vol.VolumeImageMetadata == nil {
342+
return fmt.Errorf("volume does not have VolumeImageMetadata map")
343+
}
344+
345+
if strings.ToLower(vol.VolumeImageMetadata["image_id"]) != imageID {
346+
return fmt.Errorf("volume image id '%s', expected '%s'", vol.VolumeImageMetadata["image_id"], imageID)
347+
}
348+
349+
return nil
350+
}

0 commit comments

Comments
 (0)