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

Commit b8b50b9

Browse files
authored
Merge pull request #565 from sameo/master
[rfr] Add OpenStack Image Service v2 (Glance) support
2 parents 985a863 + d71ec9c commit b8b50b9

22 files changed

+2590
-32
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Here be acceptance tests for the image service API.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// +build acceptance imageservice
2+
3+
package v2
4+
5+
import (
6+
"bytes"
7+
"os"
8+
"testing"
9+
10+
"github.com/rackspace/gophercloud"
11+
"github.com/rackspace/gophercloud/acceptance/tools"
12+
"github.com/rackspace/gophercloud/openstack"
13+
"github.com/rackspace/gophercloud/openstack/imageservice/v2/images"
14+
th "github.com/rackspace/gophercloud/testhelper"
15+
)
16+
17+
func newClient(t *testing.T) *gophercloud.ServiceClient {
18+
19+
authURL := os.Getenv("OS_AUTH_URL")
20+
username := os.Getenv("OS_USERNAME")
21+
password := os.Getenv("OS_PASSWORD")
22+
tenantName := os.Getenv("OS_TENANT_NAME")
23+
tenantID := os.Getenv("OS_TENANT_ID")
24+
domainName := os.Getenv("OS_DOMAIN_NAME")
25+
regionName := os.Getenv("OS_REGION_NAME")
26+
27+
t.Logf("Credentials used: OS_AUTH_URL='%s' OS_USERNAME='%s' OS_PASSWORD='*****' OS_TENANT_NAME='%s' OS_TENANT_NAME='%s' OS_REGION_NAME='%s' OS_TENANT_ID='%s' \n",
28+
authURL, username, tenantName, domainName, regionName, tenantID)
29+
30+
client, err := openstack.NewClient(authURL)
31+
th.AssertNoErr(t, err)
32+
33+
ao := gophercloud.AuthOptions{
34+
Username: username,
35+
Password: password,
36+
TenantName: tenantName,
37+
TenantID: tenantID,
38+
DomainName: domainName,
39+
}
40+
41+
err = openstack.AuthenticateV3(client, ao)
42+
th.AssertNoErr(t, err)
43+
t.Logf("Token is %v", client.TokenID)
44+
45+
c, err := openstack.NewImageServiceV2(client, gophercloud.EndpointOpts{
46+
Region: regionName,
47+
})
48+
th.AssertNoErr(t, err)
49+
return c
50+
}
51+
52+
func createTestImage(t *testing.T, client *gophercloud.ServiceClient) images.Image {
53+
//creating image
54+
imageName := tools.RandomString("ACCPT", 16)
55+
containerFormat := "ami"
56+
createResult := images.Create(client, images.CreateOpts{Name: imageName,
57+
ContainerFormat: containerFormat,
58+
DiskFormat: containerFormat})
59+
th.AssertNoErr(t, createResult.Err)
60+
image, err := createResult.Extract()
61+
th.AssertNoErr(t, err)
62+
t.Logf("Image %v", image)
63+
64+
//checking status
65+
image, err = images.Get(client, image.ID).Extract()
66+
th.AssertNoErr(t, err)
67+
th.AssertEquals(t, image.Status, images.ImageStatusQueued)
68+
69+
//uploading image data
70+
data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
71+
uploadResult := images.Upload(client, image.ID, bytes.NewReader(data))
72+
th.AssertNoErr(t, uploadResult.Err)
73+
74+
//checking status
75+
image, err = images.Get(client, image.ID).Extract()
76+
th.AssertNoErr(t, err)
77+
th.AssertEquals(t, image.Status, images.ImageStatusActive)
78+
th.AssertEquals(t, image.SizeBytes, 9)
79+
return *image
80+
}
81+
82+
func deleteImage(t *testing.T, client *gophercloud.ServiceClient, image images.Image) {
83+
//deteting image
84+
deleteResult := images.Delete(client, image.ID)
85+
th.AssertNoErr(t, deleteResult.Err)
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// +build acceptance imageservice
2+
3+
package v2
4+
5+
import (
6+
"bytes"
7+
"io/ioutil"
8+
"testing"
9+
10+
"github.com/rackspace/gophercloud/acceptance/tools"
11+
"github.com/rackspace/gophercloud/openstack/imageservice/v2/images"
12+
"github.com/rackspace/gophercloud/pagination"
13+
th "github.com/rackspace/gophercloud/testhelper"
14+
)
15+
16+
func TestListImages(t *testing.T) {
17+
client := newClient(t)
18+
19+
t.Logf("Id\tName\tOwner\tChecksum\tSizeBytes")
20+
21+
pager := images.List(client, nil)
22+
count, pages := 0, 0
23+
pager.EachPage(func(page pagination.Page) (bool, error) {
24+
pages++
25+
t.Logf("---")
26+
27+
images, err := images.ExtractImages(page)
28+
if err != nil {
29+
return false, err
30+
}
31+
32+
for _, i := range images {
33+
t.Logf("%s\t%s\t%s\t%s\t%v\t\n", i.ID, i.Name, i.Owner, i.Checksum, i.SizeBytes)
34+
count++
35+
}
36+
37+
return true, nil
38+
})
39+
40+
t.Logf("--------\n%d images listed on %d pages.\n", count, pages)
41+
}
42+
43+
func TestListImagesFilter(t *testing.T) {
44+
client := newClient(t)
45+
t.Logf("Id\tName\tOwner\tChecksum\tSizeBytes")
46+
47+
pager := images.List(client, images.ListOpts{Limit: 1})
48+
count, pages := 0, 0
49+
pager.EachPage(func(page pagination.Page) (bool, error) {
50+
pages++
51+
t.Logf("---")
52+
53+
images, err := images.ExtractImages(page)
54+
if err != nil {
55+
return false, err
56+
}
57+
58+
for _, i := range images {
59+
t.Logf("%s\t%s\t%s\t%s\t%v\t\n", i.ID, i.Name, i.Owner, i.Checksum, i.SizeBytes)
60+
count++
61+
}
62+
63+
return true, nil
64+
})
65+
66+
t.Logf("--------\n%d images listed on %d pages.\n", count, pages)
67+
68+
}
69+
70+
func TestCreateDeleteImage(t *testing.T) {
71+
client := newClient(t)
72+
imageName := tools.RandomString("ACCPT", 16)
73+
containerFormat := "ami"
74+
createResult := images.Create(client, images.CreateOpts{Name: &imageName,
75+
ContainerFormat: &containerFormat,
76+
DiskFormat: &containerFormat})
77+
78+
th.AssertNoErr(t, createResult.Err)
79+
image, err := createResult.Extract()
80+
th.AssertNoErr(t, err)
81+
82+
t.Logf("Image %v", image)
83+
84+
image, err = images.Get(client, image.ID).Extract()
85+
th.AssertNoErr(t, err)
86+
87+
th.AssertEquals(t, image.Status, images.ImageStatusQueued)
88+
89+
deleteResult := images.Delete(client, image.ID)
90+
th.AssertNoErr(t, deleteResult.Err)
91+
}
92+
93+
func TestUploadDownloadImage(t *testing.T) {
94+
client := newClient(t)
95+
96+
//creating image
97+
imageName := tools.RandomString("ACCPT", 16)
98+
containerFormat := "ami"
99+
createResult := images.Create(client, images.CreateOpts{Name: &imageName,
100+
ContainerFormat: &containerFormat,
101+
DiskFormat: &containerFormat})
102+
th.AssertNoErr(t, createResult.Err)
103+
image, err := createResult.Extract()
104+
th.AssertNoErr(t, err)
105+
t.Logf("Image %v", image)
106+
107+
//checking status
108+
image, err = images.Get(client, image.ID).Extract()
109+
th.AssertNoErr(t, err)
110+
th.AssertEquals(t, image.Status, images.ImageStatusQueued)
111+
112+
//uploading image data
113+
data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
114+
putImageResult := images.PutImageData(client, image.ID, bytes.NewReader(data))
115+
th.AssertNoErr(t, putImageResult.Err)
116+
117+
//checking status
118+
image, err = images.Get(client, image.ID).Extract()
119+
th.AssertNoErr(t, err)
120+
th.AssertEquals(t, image.Status, images.ImageStatusActive)
121+
th.AssertEquals(t, *image.SizeBytes, 9)
122+
123+
//downloading image data
124+
reader, err := images.GetImageData(client, image.ID).Extract()
125+
th.AssertNoErr(t, err)
126+
receivedData, err := ioutil.ReadAll(reader)
127+
t.Logf("Received data %v", receivedData)
128+
th.AssertNoErr(t, err)
129+
th.AssertByteArrayEquals(t, data, receivedData)
130+
131+
//deteting image
132+
deleteResult := images.Delete(client, image.ID)
133+
th.AssertNoErr(t, deleteResult.Err)
134+
135+
}
136+
137+
func TestUpdateImage(t *testing.T) {
138+
client := newClient(t)
139+
140+
//creating image
141+
image := createTestImage(t, client)
142+
143+
t.Logf("Image tags %v", image.Tags)
144+
145+
tags := []string{"acceptance-testing"}
146+
updatedImage, err := images.Update(client, image.ID, images.UpdateOpts{
147+
images.ReplaceImageTags{
148+
NewTags: tags}}).Extract()
149+
th.AssertNoErr(t, err)
150+
t.Logf("Received tags '%v'", tags)
151+
th.AssertDeepEquals(t, updatedImage.Tags, tags)
152+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// +build acceptance imageservice
2+
3+
package v2
4+
5+
import (
6+
"os"
7+
"testing"
8+
9+
members "github.com/rackspace/gophercloud/openstack/imageservice/v2/members"
10+
th "github.com/rackspace/gophercloud/testhelper"
11+
)
12+
13+
func TestImageMemberCreateListDelete(t *testing.T) {
14+
client := newClient(t)
15+
16+
//creating image
17+
image := createTestImage(t, client)
18+
defer deleteImage(t, client, image)
19+
20+
//creating member
21+
member, err := members.Create(client, image.ID, "tenant").Extract()
22+
th.AssertNoErr(t, err)
23+
th.AssertNotNil(t, member)
24+
25+
t.Logf("Member has been created for image %s", image.ID)
26+
27+
//listing member
28+
var mems *[]members.ImageMember
29+
mems, err = members.List(client, image.ID).Extract()
30+
th.AssertNoErr(t, err)
31+
th.AssertNotNil(t, mems)
32+
th.AssertEquals(t, 1, len(*mems))
33+
34+
t.Logf("Members after adding one %v", mems)
35+
36+
//checking just created member
37+
m := (*mems)[0]
38+
th.AssertEquals(t, "pending", m.Status)
39+
th.AssertEquals(t, "tenant", m.MemberID)
40+
41+
//deleting member
42+
deleteResult := members.Delete(client, image.ID, "tenant")
43+
th.AssertNoErr(t, deleteResult.Err)
44+
45+
//listing member
46+
mems, err = members.List(client, image.ID).Extract()
47+
th.AssertNoErr(t, err)
48+
th.AssertNotNil(t, mems)
49+
th.AssertEquals(t, 0, len(*mems))
50+
51+
t.Logf("Members after deleting one %v", mems)
52+
}
53+
54+
func TestImageMemberDetailsAndUpdate(t *testing.T) {
55+
// getting current tenant id
56+
memberTenantID := os.Getenv("OS_TENANT_ID")
57+
if memberTenantID == "" {
58+
t.Fatalf("Please define OS_TENANT_ID for image member updating test was '%s'", memberTenantID)
59+
}
60+
61+
client := newClient(t)
62+
63+
//creating image
64+
image := createTestImage(t, client)
65+
defer deleteImage(t, client, image)
66+
67+
//creating member
68+
member, err := members.Create(client, image.ID, memberTenantID).Extract()
69+
th.AssertNoErr(t, err)
70+
th.AssertNotNil(t, member)
71+
72+
//checking image member details
73+
member, err = members.Get(client, image.ID, memberTenantID).Extract()
74+
th.AssertNoErr(t, err)
75+
th.AssertNotNil(t, member)
76+
77+
th.AssertEquals(t, memberTenantID, member.MemberID)
78+
th.AssertEquals(t, "pending", member.Status)
79+
80+
t.Logf("Updating image's %s member status for tenant %s to 'accepted' ", image.ID, memberTenantID)
81+
82+
//updating image
83+
member, err = members.Update(client, image.ID, memberTenantID, "accepted").Extract()
84+
th.AssertNoErr(t, err)
85+
th.AssertNotNil(t, member)
86+
th.AssertEquals(t, "accepted", member.Status)
87+
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package v2

acceptance/openstack/orchestration/v1/buildinfo_test.go

-20
This file was deleted.

openstack/client.go

+12
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,15 @@ func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*
344344
}
345345
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
346346
}
347+
348+
// NewImageServiceV2 creates a ServiceClient that may be used to access the v2 image service.
349+
func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
350+
eo.ApplyDefaults("image")
351+
url, err := client.EndpointLocator(eo)
352+
if err != nil {
353+
return nil, err
354+
}
355+
return &gophercloud.ServiceClient{ProviderClient: client,
356+
Endpoint: url,
357+
ResourceBase: url + "v2/"}, nil
358+
}

openstack/imageservice/v2/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This provides a Go API which wraps any service implementing the [OpenStack Image Service API, version 2](http://developer.openstack.org/api-ref-image-v2.html).

0 commit comments

Comments
 (0)