Skip to content

Commit 7ec75f3

Browse files
author
Mohammad Fatemipour
committed
Implementing re-image volumeaction
1 parent a75271e commit 7ec75f3

6 files changed

Lines changed: 122 additions & 0 deletions

File tree

acceptance/openstack/blockstorage/extensions/extensions.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,38 @@ func ChangeVolumeType(t *testing.T, client *gophercloud.ServiceClient, volume *v
313313

314314
return nil
315315
}
316+
317+
// ReImage will re-image a volume
318+
func ReImage(t *testing.T, client *gophercloud.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+
}

acceptance/openstack/blockstorage/extensions/volumeactions_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,26 @@ func TestVolumeActionsChangeType(t *testing.T) {
145145
tools.PrintResource(t, newVolume)
146146
}
147147

148+
func TestVolumeActionsReImage(t *testing.T) {
149+
clients.SkipReleasesBelow(t, "stable/yoga")
150+
151+
choices, err := clients.AcceptanceTestChoicesFromEnv()
152+
if err != nil {
153+
t.Fatal(err)
154+
}
155+
156+
blockClient, err := clients.NewBlockStorageV3Client()
157+
th.AssertNoErr(t, err)
158+
blockClient.Microversion = "3.68"
159+
160+
volume, err := blockstorage.CreateVolume(t, blockClient)
161+
th.AssertNoErr(t, err)
162+
defer blockstorage.DeleteVolume(t, blockClient, volume)
163+
164+
err = ReImage(t, blockClient, volume, choices.ImageID)
165+
th.AssertNoErr(t, err)
166+
}
167+
148168
// Note(jtopjian): I plan to work on this at some point, but it requires
149169
// setting up a server with iscsi utils.
150170
/*

openstack/blockstorage/extensions/volumeactions/requests.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,30 @@ func ChangeType(client *gophercloud.ServiceClient, id string, opts ChangeTypeOpt
391391
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
392392
return
393393
}
394+
395+
// ReImageOpts contains options for Re-image a volume.
396+
type ReImageOpts struct {
397+
// New image id
398+
ImageID string `json:"image_id"`
399+
// set true to re-image volumes in reserved state
400+
ReImageReserved bool `json:"reimage_reserved"`
401+
}
402+
403+
// ToReImageMap assembles a request body based on the contents of a ReImageOpts.
404+
func (opts ReImageOpts) ToReImageMap() (map[string]interface{}, error) {
405+
return gophercloud.BuildRequestBody(opts, "os-reimage")
406+
}
407+
408+
// ReImage will re-image a volume based on the values in ReImageOpts
409+
func ReImage(client *gophercloud.ServiceClient, id string, opts ReImageOpts) (r ReImageResult) {
410+
b, err := opts.ToReImageMap()
411+
if err != nil {
412+
r.Err = err
413+
return
414+
}
415+
resp, err := client.Post(actionURL(client, id), b, nil, &gophercloud.RequestOpts{
416+
OkCodes: []int{202},
417+
})
418+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
419+
return
420+
}

openstack/blockstorage/extensions/volumeactions/results.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,8 @@ type ForceDeleteResult struct {
214214
type ChangeTypeResult struct {
215215
gophercloud.ErrResult
216216
}
217+
218+
// ReImageResult contains the response body and error from a ReImage request.
219+
type ReImageResult struct {
220+
gophercloud.ErrResult
221+
}

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,26 @@ func MockSetBootableResponse(t *testing.T) {
327327
})
328328
}
329329

330+
func MockReImageResponse(t *testing.T) {
331+
th.Mux.HandleFunc("/volumes/cd281d77-8217-4830-be95-9528227c105c/action", func(w http.ResponseWriter, r *http.Request) {
332+
th.TestMethod(t, r, "POST")
333+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
334+
th.TestHeader(t, r, "Content-Type", "application/json")
335+
th.TestHeader(t, r, "Accept", "application/json")
336+
th.TestJSONRequest(t, r, `
337+
{
338+
"os-reimage": {
339+
"image_id": "71543ced-a8af-45b6-a5c4-a46282108a90",
340+
"reimage_reserved": false
341+
}
342+
}
343+
`)
344+
w.Header().Add("Content-Type", "application/json")
345+
w.Header().Add("Content-Length", "0")
346+
w.WriteHeader(http.StatusAccepted)
347+
})
348+
}
349+
330350
func MockChangeTypeResponse(t *testing.T) {
331351
th.Mux.HandleFunc("/volumes/cd281d77-8217-4830-be95-9528227c105c/action",
332352
func(w http.ResponseWriter, r *http.Request) {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ func TestSetBootable(t *testing.T) {
195195
th.AssertNoErr(t, err)
196196
}
197197

198+
func TestReImage(t *testing.T) {
199+
th.SetupHTTP()
200+
defer th.TeardownHTTP()
201+
202+
MockReImageResponse(t)
203+
204+
options := volumeactions.ReImageOpts{
205+
ImageID: "71543ced-a8af-45b6-a5c4-a46282108a90",
206+
ReImageReserved: false,
207+
}
208+
209+
err := volumeactions.ReImage(client.ServiceClient(), "cd281d77-8217-4830-be95-9528227c105c", options).ExtractErr()
210+
th.AssertNoErr(t, err)
211+
}
212+
198213
func TestChangeType(t *testing.T) {
199214
th.SetupHTTP()
200215
defer th.TeardownHTTP()

0 commit comments

Comments
 (0)