Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 8f70e47

Browse files
funrun11Samuel Ortiz
authored andcommitted
OpenStack Glance support
* added show image member details API support * added delete image member API support * added updated image member API support * added acceptense tests * bugfixes
1 parent 0fdf619 commit 8f70e47

File tree

6 files changed

+341
-15
lines changed

6 files changed

+341
-15
lines changed

acceptance/openstack/imageservice/v2/imageservice_test.go

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ package v2
55
import (
66
"bytes"
77
"io/ioutil"
8+
"os"
89
"testing"
910

11+
"github.com/rackspace/gophercloud"
1012
"github.com/rackspace/gophercloud/acceptance/tools"
1113
images "github.com/rackspace/gophercloud/openstack/imageservice/v2"
1214
"github.com/rackspace/gophercloud/pagination"
@@ -137,6 +139,96 @@ func TestUploadDownloadImage(t *testing.T) {
137139
func TestUpdateImage(t *testing.T) {
138140
client := newClient(t)
139141

142+
//creating image
143+
image := createTestImage(t, client)
144+
145+
t.Logf("Image tags %v", image.Tags)
146+
147+
tags := []string{"acceptance-testing"}
148+
updatedImage, err := images.Update(client, image.ID, images.UpdateOpts{
149+
images.ReplaceImageTags{
150+
NewTags: tags}}).Extract()
151+
th.AssertNoErr(t, err)
152+
t.Logf("Received tags '%v'", tags)
153+
th.AssertDeepEquals(t, updatedImage.Tags, tags)
154+
}
155+
156+
func TestImageMemberCreateListDelete(t *testing.T) {
157+
client := newClient(t)
158+
159+
//creating image
160+
image := createTestImage(t, client)
161+
defer deleteImage(t, client, image)
162+
163+
//creating member
164+
member, err := images.CreateMember(client, image.ID, "tenant").Extract()
165+
th.AssertNoErr(t, err)
166+
th.AssertNotNil(t, member)
167+
168+
//listing member
169+
var members *[]images.ImageMember
170+
members, err = images.ListMembers(client, image.ID).Extract()
171+
th.AssertNoErr(t, err)
172+
th.AssertNotNil(t, members)
173+
th.AssertEquals(t, 1, len(*members))
174+
175+
t.Logf("Members after adding one %v", members)
176+
177+
//checking just created member
178+
m := (*members)[0]
179+
th.AssertEquals(t, "pending", m.Status)
180+
th.AssertEquals(t, "tenant", m.MemberID)
181+
182+
//deleting member
183+
deleteResult := images.DeleteMember(client, image.ID, "tenant")
184+
th.AssertNoErr(t, deleteResult.Err)
185+
186+
//listing member
187+
members, err = images.ListMembers(client, image.ID).Extract()
188+
th.AssertNoErr(t, err)
189+
th.AssertNotNil(t, members)
190+
th.AssertEquals(t, 0, len(*members))
191+
192+
t.Logf("Members after deleting one %v", members)
193+
}
194+
195+
func TestImageMemberDetailsAndUpdate(t *testing.T) {
196+
// getting current tenant id
197+
memberTenantID := os.Getenv("OS_TENANT_ID")
198+
if memberTenantID == "" {
199+
t.Fatalf("Please define OS_TENANT_ID for image member updating test was '%s'", memberTenantID)
200+
}
201+
202+
client := newClient(t)
203+
204+
//creating image
205+
image := createTestImage(t, client)
206+
defer deleteImage(t, client, image)
207+
208+
//creating member
209+
member, err := images.CreateMember(client, image.ID, memberTenantID).Extract()
210+
th.AssertNoErr(t, err)
211+
th.AssertNotNil(t, member)
212+
213+
//checking image member details
214+
member, err = images.ShowMemberDetails(client, image.ID, memberTenantID).Extract()
215+
th.AssertNoErr(t, err)
216+
th.AssertNotNil(t, member)
217+
218+
th.AssertEquals(t, memberTenantID, member.MemberID)
219+
th.AssertEquals(t, "pending", member.Status)
220+
221+
t.Logf("Updating image's %s member status for tenant %s to 'accepted' ", image.ID, memberTenantID)
222+
223+
//updating image
224+
member, err = images.UpdateMember(client, image.ID, memberTenantID, "accepted").Extract()
225+
th.AssertNoErr(t, err)
226+
th.AssertNotNil(t, member)
227+
th.AssertEquals(t, "accepted", member.Status)
228+
229+
}
230+
231+
func createTestImage(t *testing.T, client *gophercloud.ServiceClient) images.Image {
140232
//creating image
141233
imageName := tools.RandomString("ACCPT", 16)
142234
containerFormat := "ami"
@@ -152,14 +244,11 @@ func TestUpdateImage(t *testing.T) {
152244
image, err = images.Get(client, image.ID).Extract()
153245
th.AssertNoErr(t, err)
154246
th.AssertEquals(t, image.Status, images.ImageStatusQueued)
247+
return *image
248+
}
155249

156-
t.Logf("Image tags %v", image.Tags)
157-
158-
tags := []string{"acceptance-testing"}
159-
updatedImage, err := images.Update(client, image.ID, images.UpdateOpts{
160-
images.ReplaceImageTags{
161-
NewTags: tags}}).Extract()
162-
th.AssertNoErr(t, err)
163-
t.Logf("Received tags '%v'", tags)
164-
th.AssertDeepEquals(t, updatedImage.Tags, tags)
250+
func deleteImage(t *testing.T, client *gophercloud.ServiceClient, image images.Image) {
251+
//deteting image
252+
deleteResult := images.Delete(client, image.ID)
253+
th.AssertNoErr(t, deleteResult.Err)
165254
}

openstack/imageservice/v2/fixtures.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,3 +447,79 @@ func HandleImageMemberEmptyList(t *testing.T) {
447447
}`)
448448
})
449449
}
450+
451+
// HandleImageMemberDetails setup
452+
func HandleImageMemberDetails(t *testing.T) {
453+
th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
454+
th.TestMethod(t, r, "GET")
455+
th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
456+
457+
w.WriteHeader(http.StatusOK)
458+
fmt.Fprintf(w, `{
459+
"status": "pending",
460+
"created_at": "2013-11-26T07:21:21Z",
461+
"updated_at": "2013-11-26T07:21:21Z",
462+
"image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
463+
"member_id": "8989447062e04a818baf9e073fd04fa7",
464+
"schema": "/v2/schemas/member"
465+
}`)
466+
})
467+
}
468+
469+
// HandleImageMemberDeleteSuccessfully setup
470+
func HandleImageMemberDeleteSuccessfully(t *testing.T) *CallsCounter {
471+
var counter CallsCounter
472+
th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
473+
counter.Counter = counter.Counter + 1
474+
475+
th.TestMethod(t, r, "DELETE")
476+
th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
477+
478+
w.WriteHeader(http.StatusNoContent)
479+
})
480+
return &counter
481+
}
482+
483+
// HandleImageMemberDeleteByNonOwner setup
484+
func HandleImageMemberDeleteByNonOwner(t *testing.T) *CallsCounter {
485+
var counter CallsCounter
486+
th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
487+
counter.Counter = counter.Counter + 1
488+
489+
th.TestMethod(t, r, "DELETE")
490+
th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
491+
492+
w.WriteHeader(http.StatusForbidden)
493+
})
494+
return &counter
495+
}
496+
497+
// HandleImageMemberUpdate setup
498+
func HandleImageMemberUpdate(t *testing.T) *CallsCounter {
499+
var counter CallsCounter
500+
th.Mux.HandleFunc("/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/members/8989447062e04a818baf9e073fd04fa7", func(w http.ResponseWriter, r *http.Request) {
501+
counter.Counter = counter.Counter + 1
502+
503+
th.TestMethod(t, r, "PUT")
504+
th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID)
505+
506+
th.TestJSONRequest(t, r, `{"status": "accepted"}`)
507+
508+
w.WriteHeader(http.StatusOK)
509+
510+
fmt.Fprintf(w, `{
511+
"status": "accepted",
512+
"created_at": "2013-11-26T07:21:21Z",
513+
"updated_at": "2013-11-26T07:21:21Z",
514+
"image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea",
515+
"member_id": "8989447062e04a818baf9e073fd04fa7",
516+
"schema": "/v2/schemas/member"
517+
}`)
518+
})
519+
return &counter
520+
}
521+
522+
// CallsCounter for checking if request handler was called at all
523+
type CallsCounter struct {
524+
Counter int
525+
}

openstack/imageservice/v2/requests.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ func CreateMember(client *gophercloud.ServiceClient, id string, member string) C
221221
}
222222

223223
// ListMembers returns list of members for specifed image id
224+
// More details: http://developer.openstack.org/api-ref-image-v2.html#listImageMembers-v2
224225
func ListMembers(client *gophercloud.ServiceClient, id string) ListMembersResult {
225226
var res ListMembersResult
226227
_, res.Err = client.Get(listMembersURL(client, id), &res.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
@@ -239,6 +240,47 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
239240
return res
240241
}
241242

243+
// ShowMemberDetails Shows image member details.
244+
// More details: http://developer.openstack.org/api-ref-image-v2.html#getImageMember-v2
245+
func ShowMemberDetails(client *gophercloud.ServiceClient, imageID string, memberID string) MemberDetailsResult {
246+
var res MemberDetailsResult
247+
_, res.Err = client.Get(imageMemberURL(client, imageID, memberID), &res.Body, &gophercloud.RequestOpts{OkCodes: []int{200}})
248+
return res
249+
}
250+
251+
// DeleteMember Deletes membership for given image.
252+
// Callee should be image owner
253+
// More details: http://developer.openstack.org/api-ref-image-v2.html#deleteImageMember-v2
254+
func DeleteMember(client *gophercloud.ServiceClient, imageID string, memberID string) MemberDeleteResult {
255+
var res MemberDeleteResult
256+
response, err := client.Delete(imageMemberURL(client, imageID, memberID), &gophercloud.RequestOpts{OkCodes: []int{204, 403}})
257+
258+
//some problems in http stack or lower
259+
if err != nil {
260+
res.Err = err
261+
return res
262+
}
263+
264+
// Callee is not owner of specified image
265+
if response.StatusCode == 403 {
266+
res.Err = fmt.Errorf("You must be the owner of the specified image. "+
267+
"(image '%s')", imageID)
268+
return res
269+
}
270+
return res
271+
}
272+
273+
// UpdateMember fuction updates member
274+
// More details: http://developer.openstack.org/api-ref-image-v2.html#updateImageMember-v2
275+
func UpdateMember(client *gophercloud.ServiceClient, imageID string, memberID string, status string) MemberUpdateResult {
276+
var res MemberUpdateResult
277+
body := map[string]interface{}{}
278+
body["status"] = status
279+
_, res.Err = client.Put(imageMemberURL(client, imageID, memberID), body, &res.Body,
280+
&gophercloud.RequestOpts{OkCodes: []int{200}})
281+
return res
282+
}
283+
242284
// UpdateOptsBuilder implemets UpdateOptsBuilder
243285
type UpdateOptsBuilder interface {
244286
// returns value implementing json.Marshaler which when marshaled matches the patch schema:
@@ -249,7 +291,7 @@ type UpdateOptsBuilder interface {
249291
// UpdateOpts implements UpdateOpts
250292
type UpdateOpts []Patch
251293

252-
// ToImageUpdateMap TODO
294+
// ToImageUpdateMap builder
253295
func (opts UpdateOpts) ToImageUpdateMap() []interface{} {
254296
m := make([]interface{}, len(opts))
255297
for i, patch := range opts {
@@ -265,12 +307,26 @@ type Patch interface {
265307
ToImagePatchMap() map[string]interface{}
266308
}
267309

310+
// UpdateVisibility updated visibility
311+
type UpdateVisibility struct {
312+
Visibility ImageVisibility
313+
}
314+
315+
// ToImagePatchMap builder
316+
func (u UpdateVisibility) ToImagePatchMap() map[string]interface{} {
317+
m := map[string]interface{}{}
318+
m["op"] = "relace"
319+
m["path"] = "/visibility"
320+
m["value"] = u.Visibility
321+
return m
322+
}
323+
268324
// ReplaceImageName implements Patch
269325
type ReplaceImageName struct {
270326
NewName string
271327
}
272328

273-
// ToImagePatchMap TODO
329+
// ToImagePatchMap builder
274330
func (r ReplaceImageName) ToImagePatchMap() map[string]interface{} {
275331
m := map[string]interface{}{}
276332
m["op"] = "replace"
@@ -284,7 +340,7 @@ type ReplaceImageTags struct {
284340
NewTags []string
285341
}
286342

287-
// ToImagePatchMap TODO
343+
// ToImagePatchMap builder
288344
func (r ReplaceImageTags) ToImagePatchMap() map[string]interface{} {
289345
m := map[string]interface{}{}
290346
m["op"] = "replace"

0 commit comments

Comments
 (0)