Skip to content

Commit 2804b72

Browse files
vitkhabjtopjian
authored andcommitted
Added method to get info from Volume actions volume_upload_image method response (#417)
* Added response body to volumeactions.UploadImageResults * Added Extract method to UploadImageResult object * Fixed format * Fix coverage * Added structure VolumeImage * Added example response to MockUploadImageResponse * Little fix for volume id in tests * Added VolumeImageVolumeType sruct * Added time parsing to VolumeImage and VolumeImageVolumeType results * Renamed VolumeImageVolumeType to ImageVolumeType. Changed Id in names to ID. * Detailed TestUploadImage * Changed gophercloud.ErrResult to gophercloud.Result in UploadImageResult struct * Fixed typo * BlockStorage v2: Updating volume upload acceptance test
1 parent 4af874e commit 2804b72

6 files changed

Lines changed: 169 additions & 12 deletions

File tree

‎acceptance/openstack/blockstorage/extensions/extensions.go‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
// CreateUploadImage will upload volume it as volume-baked image. An name of new image or err will be
1818
// returned
19-
func CreateUploadImage(t *testing.T, client *gophercloud.ServiceClient, volume *volumes.Volume) (string, error) {
19+
func CreateUploadImage(t *testing.T, client *gophercloud.ServiceClient, volume *volumes.Volume) (volumeactions.VolumeImage, error) {
2020
if testing.Short() {
2121
t.Skip("Skipping test that requires volume-backed image uploading in short mode.")
2222
}
@@ -27,19 +27,20 @@ func CreateUploadImage(t *testing.T, client *gophercloud.ServiceClient, volume *
2727
Force: true,
2828
}
2929

30-
if err := volumeactions.UploadImage(client, volume.ID, uploadImageOpts).ExtractErr(); err != nil {
31-
return "", err
30+
volumeImage, err := volumeactions.UploadImage(client, volume.ID, uploadImageOpts).Extract()
31+
if err != nil {
32+
return volumeImage, err
3233
}
3334

3435
t.Logf("Uploading volume %s as volume-backed image %s", volume.ID, imageName)
3536

3637
if err := volumes.WaitForStatus(client, volume.ID, "available", 60); err != nil {
37-
return "", err
38+
return volumeImage, err
3839
}
3940

4041
t.Logf("Uploaded volume %s as volume-backed image %s", volume.ID, imageName)
4142

42-
return imageName, nil
43+
return volumeImage, nil
4344

4445
}
4546

‎acceptance/openstack/blockstorage/extensions/volumeactions_test.go‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77

88
"github.com/gophercloud/gophercloud/acceptance/clients"
9+
"github.com/gophercloud/gophercloud/acceptance/tools"
910
"github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes"
1011

1112
blockstorage "github.com/gophercloud/gophercloud/acceptance/openstack/blockstorage/v2"
@@ -28,12 +29,14 @@ func TestVolumeActionsUploadImageDestroy(t *testing.T) {
2829
}
2930
defer blockstorage.DeleteVolume(t, blockClient, volume)
3031

31-
imageName, err := CreateUploadImage(t, blockClient, volume)
32+
volumeImage, err := CreateUploadImage(t, blockClient, volume)
3233
if err != nil {
3334
t.Fatalf("Unable to upload volume-backed image: %v", err)
3435
}
3536

36-
err = DeleteUploadedImage(t, computeClient, imageName)
37+
tools.PrintResource(t, volumeImage)
38+
39+
err = DeleteUploadedImage(t, computeClient, volumeImage.ImageName)
3740
if err != nil {
3841
t.Fatalf("Unable to delete volume-backed image: %v", err)
3942
}

‎openstack/blockstorage/extensions/volumeactions/requests.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func UploadImage(client *gophercloud.ServiceClient, id string, opts UploadImageO
246246
r.Err = err
247247
return
248248
}
249-
_, r.Err = client.Post(uploadURL(client, id), b, nil, &gophercloud.RequestOpts{
249+
_, r.Err = client.Post(uploadURL(client, id), b, &r.Body, &gophercloud.RequestOpts{
250250
OkCodes: []int{202},
251251
})
252252
return

‎openstack/blockstorage/extensions/volumeactions/results.go‎

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package volumeactions
22

3-
import "github.com/gophercloud/gophercloud"
3+
import (
4+
"encoding/json"
5+
"time"
6+
7+
"github.com/gophercloud/gophercloud"
8+
)
49

510
// AttachResult contains the response body and error from a Get request.
611
type AttachResult struct {
@@ -19,7 +24,7 @@ type DetachResult struct {
1924

2025
// UploadImageResult contains the response body and error from a UploadImage request.
2126
type UploadImageResult struct {
22-
gophercloud.ErrResult
27+
gophercloud.Result
2328
}
2429

2530
// ReserveResult contains the response body and error from a Get request.
@@ -50,6 +55,101 @@ func (r commonResult) Extract() (map[string]interface{}, error) {
5055
return s.ConnectionInfo, err
5156
}
5257

58+
// ImageVolumeType contains volume type object obtained from UploadImage action.
59+
type ImageVolumeType struct {
60+
// The ID of a volume type.
61+
ID string `json:"id"`
62+
// Human-readable display name for the volume type.
63+
Name string `json:"name"`
64+
// Human-readable description for the volume type.
65+
Description string `json:"display_description"`
66+
// Flag for public access.
67+
IsPublic bool `json:"is_public"`
68+
// Extra specifications for volume type.
69+
ExtraSpecs map[string]interface{} `json:"extra_specs"`
70+
// ID of quality of service specs.
71+
QosSpecsID string `json:"qos_specs_id"`
72+
// Flag for deletion status of volume type.
73+
Deleted bool `json:"deleted"`
74+
// The date when volume type was deleted.
75+
DeletedAt time.Time `json:"-"`
76+
// The date when volume type was created.
77+
CreatedAt time.Time `json:"-"`
78+
// The date when this volume was last updated.
79+
UpdatedAt time.Time `json:"-"`
80+
}
81+
82+
func (r *ImageVolumeType) UnmarshalJSON(b []byte) error {
83+
type tmp ImageVolumeType
84+
var s struct {
85+
tmp
86+
CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"`
87+
UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"`
88+
DeletedAt gophercloud.JSONRFC3339MilliNoZ `json:"deleted_at"`
89+
}
90+
err := json.Unmarshal(b, &s)
91+
if err != nil {
92+
return err
93+
}
94+
*r = ImageVolumeType(s.tmp)
95+
96+
r.CreatedAt = time.Time(s.CreatedAt)
97+
r.UpdatedAt = time.Time(s.UpdatedAt)
98+
r.DeletedAt = time.Time(s.DeletedAt)
99+
100+
return err
101+
}
102+
103+
// VolumeImage contains information about volume upload to an image service.
104+
type VolumeImage struct {
105+
// The ID of a volume an image is created from.
106+
VolumeID string `json:"id"`
107+
// Container format, may be bare, ofv, ova, etc.
108+
ContainerFormat string `json:"container_format"`
109+
// Disk format, may be raw, qcow2, vhd, vdi, vmdk, etc.
110+
DiskFormat string `json:"disk_format"`
111+
// Human-readable description for the volume.
112+
Description string `json:"display_description"`
113+
// The ID of an image being created.
114+
ImageID string `json:"image_id"`
115+
// Human-readable display name for the image.
116+
ImageName string `json:"image_name"`
117+
// Size of the volume in GB.
118+
Size int `json:"size"`
119+
// Current status of the volume.
120+
Status string `json:"status"`
121+
// The date when this volume was last updated.
122+
UpdatedAt time.Time `json:"-"`
123+
// Volume type object of used volume.
124+
VolumeType ImageVolumeType `json:"volume_type"`
125+
}
126+
127+
func (r *VolumeImage) UnmarshalJSON(b []byte) error {
128+
type tmp VolumeImage
129+
var s struct {
130+
tmp
131+
UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"`
132+
}
133+
err := json.Unmarshal(b, &s)
134+
if err != nil {
135+
return err
136+
}
137+
*r = VolumeImage(s.tmp)
138+
139+
r.UpdatedAt = time.Time(s.UpdatedAt)
140+
141+
return err
142+
}
143+
144+
// Extract will get an object with info about image being uploaded out of the UploadImageResult object.
145+
func (r UploadImageResult) Extract() (VolumeImage, error) {
146+
var s struct {
147+
VolumeImage VolumeImage `json:"os-volume_upload_image"`
148+
}
149+
err := r.ExtractInto(&s)
150+
return s.VolumeImage, err
151+
}
152+
53153
// InitializeConnectionResult contains the response body and error from a Get request.
54154
type InitializeConnectionResult struct {
55155
commonResult

‎openstack/blockstorage/extensions/volumeactions/testing/fixtures.go‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,34 @@ func MockUploadImageResponse(t *testing.T) {
9595
w.Header().Add("Content-Type", "application/json")
9696
w.WriteHeader(http.StatusAccepted)
9797

98-
fmt.Fprintf(w, `{}`)
98+
fmt.Fprintf(w, `
99+
{
100+
"os-volume_upload_image": {
101+
"container_format": "bare",
102+
"display_description": null,
103+
"id": "cd281d77-8217-4830-be95-9528227c105c",
104+
"image_id": "ecb92d98-de08-45db-8235-bbafe317269c",
105+
"image_name": "test",
106+
"disk_format": "raw",
107+
"size": 5,
108+
"status": "uploading",
109+
"updated_at": "2017-07-17T09:29:22.000000",
110+
"volume_type": {
111+
"created_at": "2016-05-04T08:54:14.000000",
112+
"deleted": false,
113+
"deleted_at": null,
114+
"description": null,
115+
"extra_specs": {
116+
"volume_backend_name": "basic.ru-2a"
117+
},
118+
"id": "b7133444-62f6-4433-8da3-70ac332229b7",
119+
"is_public": true,
120+
"name": "basic.ru-2a",
121+
"updated_at": "2016-05-04T09:15:33.000000"
122+
}
123+
}
124+
}
125+
`)
99126
})
100127
}
101128

‎openstack/blockstorage/extensions/volumeactions/testing/requests_test.go‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package testing
22

33
import (
44
"testing"
5+
"time"
56

67
"github.com/gophercloud/gophercloud"
78
"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"
@@ -55,8 +56,33 @@ func TestUploadImage(t *testing.T) {
5556
Force: true,
5657
}
5758

58-
err := volumeactions.UploadImage(client.ServiceClient(), "cd281d77-8217-4830-be95-9528227c105c", options).ExtractErr()
59+
actual, err := volumeactions.UploadImage(client.ServiceClient(), "cd281d77-8217-4830-be95-9528227c105c", options).Extract()
5960
th.AssertNoErr(t, err)
61+
62+
expected := volumeactions.VolumeImage{
63+
VolumeID: "cd281d77-8217-4830-be95-9528227c105c",
64+
ContainerFormat: "bare",
65+
DiskFormat: "raw",
66+
Description: "",
67+
ImageID: "ecb92d98-de08-45db-8235-bbafe317269c",
68+
ImageName: "test",
69+
Size: 5,
70+
Status: "uploading",
71+
UpdatedAt: time.Date(2017, 7, 17, 9, 29, 22, 0, time.UTC),
72+
VolumeType: volumeactions.ImageVolumeType{
73+
ID: "b7133444-62f6-4433-8da3-70ac332229b7",
74+
Name: "basic.ru-2a",
75+
Description: "",
76+
IsPublic: true,
77+
ExtraSpecs: map[string]interface{}{"volume_backend_name": "basic.ru-2a"},
78+
QosSpecsID: "",
79+
Deleted: false,
80+
DeletedAt: time.Time{},
81+
CreatedAt: time.Date(2016, 5, 4, 8, 54, 14, 0, time.UTC),
82+
UpdatedAt: time.Date(2016, 5, 4, 9, 15, 33, 0, time.UTC),
83+
},
84+
}
85+
th.AssertDeepEquals(t, expected, actual)
6086
}
6187

6288
func TestReserve(t *testing.T) {

0 commit comments

Comments
 (0)