Add crud operation of volume API v3
Currently the volume API v2 only supports query volumes and it's necessary for openstack-goclient to provide CRUD operation of volume for some projects. Change-Id: Ie4a0e9f70d6fbe748ebdab1aa0a651c0d59ef244
This commit is contained in:
parent
34a783684a
commit
82c7e3bc0f
284
volume/v3/volume.go
Normal file
284
volume/v3/volume.go
Normal file
@ -0,0 +1,284 @@
|
||||
// Copyright (c) 2016 Huawei Technologies Co., Ltd. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
/*
|
||||
Package volume implements a client library for accessing OpenStack Volume service
|
||||
|
||||
The CRUD operation of volumes can be retrieved using the api. Right now only
|
||||
|
||||
Show and List methods can work.
|
||||
|
||||
*/
|
||||
|
||||
package v3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"git.openstack.org/openstack/golang-client.git/openstack"
|
||||
"git.openstack.org/openstack/golang-client.git/util"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
Session openstack.Session
|
||||
Client http.Client
|
||||
URL string
|
||||
}
|
||||
|
||||
type RequestBody struct {
|
||||
// The volume name [OPTIONAL]
|
||||
Name string `json:"name"`
|
||||
// The size of the volume, in gibibytes (GiB) [REQUIRED]
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
type Body struct {
|
||||
VolumeBody RequestBody `json:"volume"`
|
||||
}
|
||||
|
||||
// Response is a structure for all properties of
|
||||
// an volume for a non detailed query
|
||||
type Response struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Consistencygroup_id string `json:"consistencygroup_id"`
|
||||
}
|
||||
|
||||
// DetailResponse is a structure for all properties of
|
||||
// an volume for a detailed query
|
||||
type DetailResponse struct {
|
||||
ID string `json:"id"`
|
||||
Attachments []map[string]string `json:"attachments"`
|
||||
Links []map[string]string `json:"links"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Protected bool `json:"protected"`
|
||||
Status string `json:"status"`
|
||||
MigrationStatus string `json:"migration_status"`
|
||||
UserID string `json:"user_id"`
|
||||
Encrypted bool `json:"encrypted"`
|
||||
Multiattach bool `json:"multiattach"`
|
||||
CreatedAt util.RFC8601DateTime `json:"created_at"`
|
||||
Description string `json:"description"`
|
||||
Volume_type string `json:"volume_type"`
|
||||
Name string `json:"name"`
|
||||
Source_volid string `json:"source_volid"`
|
||||
Snapshot_id string `json:"snapshot_id"`
|
||||
Size int64 `json:"size"`
|
||||
|
||||
Aavailability_zone string `json:"availability_zone"`
|
||||
Rreplication_status string `json:"replication_status"`
|
||||
Consistencygroup_id string `json:"consistencygroup_id"`
|
||||
}
|
||||
|
||||
type VolumeResponse struct {
|
||||
Volume Response `json:"volume"`
|
||||
}
|
||||
|
||||
type VolumesResponse struct {
|
||||
Volumes []Response `json:"volumes"`
|
||||
}
|
||||
|
||||
type DetailVolumeResponse struct {
|
||||
DetailVolume DetailResponse `json:"volume"`
|
||||
}
|
||||
|
||||
type DetailVolumesResponse struct {
|
||||
DetailVolumes []DetailResponse `json:"volumes"`
|
||||
}
|
||||
|
||||
func (volumeService Service) Create(reqBody *Body) (Response, error) {
|
||||
return volumeService.createVolume(reqBody)
|
||||
}
|
||||
|
||||
func (volumeService Service) createVolume(reqBody *Body) (Response, error) {
|
||||
nullResponse := Response{}
|
||||
|
||||
reqURL, err := url.Parse(volumeService.URL)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
urlPostFix := "/volumes"
|
||||
reqURL.Path += urlPostFix
|
||||
|
||||
var headers http.Header = http.Header{}
|
||||
headers.Set("Content-Type", "application/json")
|
||||
body, _ := json.Marshal(reqBody)
|
||||
resp, err := volumeService.Session.Post(reqURL.String(), nil, &headers, &body)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
err = util.CheckHTTPResponseStatusCode(resp)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nullResponse, errors.New("aaa")
|
||||
}
|
||||
|
||||
volumeResponse := new(VolumeResponse)
|
||||
if err = json.Unmarshal(rbody, volumeResponse); err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
return volumeResponse.Volume, nil
|
||||
}
|
||||
|
||||
func (volumeService Service) Show(id string) (Response, error) {
|
||||
return volumeService.getVolume(id)
|
||||
}
|
||||
|
||||
func (volumeService Service) getVolume(id string) (Response, error) {
|
||||
nullResponse := Response{}
|
||||
|
||||
reqURL, err := url.Parse(volumeService.URL)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
urlPostFix := "/volumes" + "/" + id
|
||||
reqURL.Path += urlPostFix
|
||||
|
||||
var headers http.Header = http.Header{}
|
||||
headers.Set("Content-Type", "application/json")
|
||||
resp, err := volumeService.Session.Get(reqURL.String(), nil, &headers)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
err = util.CheckHTTPResponseStatusCode(resp)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nullResponse, errors.New("aaa")
|
||||
}
|
||||
|
||||
volumeResponse := new(VolumeResponse)
|
||||
if err = json.Unmarshal(rbody, volumeResponse); err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
return volumeResponse.Volume, nil
|
||||
}
|
||||
|
||||
func (volumeService Service) List() ([]Response, error) {
|
||||
return volumeService.getAllVolumes()
|
||||
}
|
||||
|
||||
func (volumeService Service) getAllVolumes() ([]Response, error) {
|
||||
nullResponses := make([]Response, 0)
|
||||
|
||||
reqURL, err := url.Parse(volumeService.URL)
|
||||
if err != nil {
|
||||
return nullResponses, err
|
||||
}
|
||||
urlPostFix := "/volumes"
|
||||
reqURL.Path += urlPostFix
|
||||
|
||||
var headers http.Header = http.Header{}
|
||||
headers.Set("Content-Type", "application/json")
|
||||
resp, err := volumeService.Session.Get(reqURL.String(), nil, &headers)
|
||||
if err != nil {
|
||||
return nullResponses, err
|
||||
}
|
||||
|
||||
err = util.CheckHTTPResponseStatusCode(resp)
|
||||
if err != nil {
|
||||
return nullResponses, err
|
||||
}
|
||||
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nullResponses, errors.New("aaa")
|
||||
}
|
||||
|
||||
volumesResponse := new(VolumesResponse)
|
||||
if err = json.Unmarshal(rbody, volumesResponse); err != nil {
|
||||
return nullResponses, err
|
||||
}
|
||||
return volumesResponse.Volumes, nil
|
||||
}
|
||||
|
||||
func (volumeService Service) Update(id string, reqBody *Body) (Response, error) {
|
||||
return volumeService.updateVolume(id, reqBody)
|
||||
}
|
||||
|
||||
func (volumeService Service) updateVolume(id string, reqBody *Body) (Response, error) {
|
||||
nullResponse := Response{}
|
||||
|
||||
reqURL, err := url.Parse(volumeService.URL)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
urlPostFix := "/volumes" + "/" + id
|
||||
reqURL.Path += urlPostFix
|
||||
|
||||
var headers http.Header = http.Header{}
|
||||
headers.Set("Content-Type", "application/json")
|
||||
body, _ := json.Marshal(reqBody)
|
||||
resp, err := volumeService.Session.Put(reqURL.String(), nil, &headers, &body)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
err = util.CheckHTTPResponseStatusCode(resp)
|
||||
if err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
|
||||
rbody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nullResponse, errors.New("aaa")
|
||||
}
|
||||
|
||||
volumeResponse := new(VolumeResponse)
|
||||
if err = json.Unmarshal(rbody, volumeResponse); err != nil {
|
||||
return nullResponse, err
|
||||
}
|
||||
return volumeResponse.Volume, nil
|
||||
}
|
||||
|
||||
func (volumeService Service) Delete(id string) error {
|
||||
return volumeService.deleteVolume(id)
|
||||
}
|
||||
|
||||
func (volumeService Service) deleteVolume(id string) error {
|
||||
reqURL, err := url.Parse(volumeService.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
urlPostFix := "/volumes" + "/" + id
|
||||
reqURL.Path += urlPostFix
|
||||
|
||||
var headers http.Header = http.Header{}
|
||||
headers.Set("Content-Type", "application/json")
|
||||
resp, err := volumeService.Session.Delete(reqURL.String(), nil, &headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.CheckHTTPResponseStatusCode(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
204
volume/v3/volume_test.go
Normal file
204
volume/v3/volume_test.go
Normal file
@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2016 Huawei Technologies Co., Ltd. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
/*
|
||||
Package volume implements a client library for accessing OpenStack Volume service
|
||||
|
||||
The CRUD operation of volumes can be retrieved using the api.
|
||||
|
||||
*/
|
||||
|
||||
package v3_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.openstack.org/openstack/golang-client.git/openstack"
|
||||
"git.openstack.org/openstack/golang-client.git/testUtil"
|
||||
"git.openstack.org/openstack/golang-client.git/volume/v3"
|
||||
)
|
||||
|
||||
var tokn = "ae5aebe5-6a5d-4a40-840a-9736a067aff4"
|
||||
|
||||
/*
|
||||
func TestCreateVolume(t *testing.T) {
|
||||
anon := func(volumeService *v3.Service) {
|
||||
requestBody := v3.RequestBody{100, "myvol1"}
|
||||
volume, err := volumeService.Create(&requestBody)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expectedVolume := v3.Response{
|
||||
Name: "myvol1",
|
||||
ID: "f5fc9874-fc89-4814-a358-23ba83a6115f",
|
||||
Links: []map[string]string{{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "bookmark"}}}
|
||||
testUtil.Equals(t, expectedVolume, volume)
|
||||
}
|
||||
|
||||
//testCreateVolumeServiceAction(t, "volumes", sampleVolumesData, anon)
|
||||
}
|
||||
*/
|
||||
|
||||
func TestGetVolume(t *testing.T) {
|
||||
anon := func(volumeService *v3.Service) {
|
||||
volID := "f5fc9874-fc89-4814-a358-23ba83a6115f"
|
||||
volume, err := volumeService.Show(volID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expectedVolume := v3.Response{
|
||||
Name: "myvol1",
|
||||
ID: "f5fc9874-fc89-4814-a358-23ba83a6115f",
|
||||
Links: []map[string]string{{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "bookmark"}}}
|
||||
testUtil.Equals(t, expectedVolume, volume)
|
||||
}
|
||||
|
||||
testGetVolumeServiceAction(t, "f5fc9874-fc89-4814-a358-23ba83a6115f", sampleVolumeData, anon)
|
||||
}
|
||||
|
||||
func testGetVolumeServiceAction(t *testing.T, uriEndsWith string, testData string, volumeServiceAction func(*v3.Service)) {
|
||||
anon := func(req *http.Request) {
|
||||
reqURL := req.URL.String()
|
||||
if !strings.HasSuffix(reqURL, uriEndsWith) {
|
||||
t.Error(errors.New("Incorrect url created, expected:" + uriEndsWith + " at the end, actual url:" + reqURL))
|
||||
}
|
||||
}
|
||||
apiServer := testUtil.CreateGetJSONTestRequestServer(t, tokn, testData, anon)
|
||||
defer apiServer.Close()
|
||||
|
||||
auth := openstack.AuthToken{
|
||||
Access: openstack.AccessType{
|
||||
Token: openstack.Token{
|
||||
ID: tokn,
|
||||
},
|
||||
},
|
||||
}
|
||||
sess, _ := openstack.NewSession(http.DefaultClient, auth, nil)
|
||||
volumeService := v3.Service{
|
||||
Session: *sess,
|
||||
URL: apiServer.URL,
|
||||
}
|
||||
volumeServiceAction(&volumeService)
|
||||
}
|
||||
|
||||
func TestGetAllVolumes(t *testing.T) {
|
||||
anon := func(volumeService *v3.Service) {
|
||||
volumes, err := volumeService.List()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
expectedVolume := v3.Response{
|
||||
Name: "myvol1",
|
||||
ID: "f5fc9874-fc89-4814-a358-23ba83a6115f",
|
||||
Links: []map[string]string{{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "bookmark"}}}
|
||||
testUtil.Equals(t, expectedVolume, volumes[0])
|
||||
}
|
||||
|
||||
testGetAllVolumesServiceAction(t, "volumes", sampleVolumesData, anon)
|
||||
}
|
||||
|
||||
func testGetAllVolumesServiceAction(t *testing.T, uriEndsWith string, testData string, volumeServiceAction func(*v3.Service)) {
|
||||
anon := func(req *http.Request) {
|
||||
reqURL := req.URL.String()
|
||||
if !strings.HasSuffix(reqURL, uriEndsWith) {
|
||||
t.Error(errors.New("Incorrect url created, expected:" + uriEndsWith + " at the end, actual url:" + reqURL))
|
||||
}
|
||||
}
|
||||
apiServer := testUtil.CreateGetJSONTestRequestServer(t, tokn, testData, anon)
|
||||
defer apiServer.Close()
|
||||
|
||||
auth := openstack.AuthToken{
|
||||
Access: openstack.AccessType{
|
||||
Token: openstack.Token{
|
||||
ID: tokn,
|
||||
},
|
||||
},
|
||||
}
|
||||
sess, _ := openstack.NewSession(http.DefaultClient, auth, nil)
|
||||
volumeService := v3.Service{
|
||||
Session: *sess,
|
||||
URL: apiServer.URL,
|
||||
}
|
||||
volumeServiceAction(&volumeService)
|
||||
}
|
||||
|
||||
/*
|
||||
func TestDeleteVolume(t *testing.T) {
|
||||
anon := func(volumeService *v3.Service) {
|
||||
volID := "f5fc9874-fc89-4814-a358-23ba83a6115f"
|
||||
_, err := volumeService.Delete(volID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
volume, err := volumeService.Show(volID)
|
||||
|
||||
expectedVolume := v3.Response{}
|
||||
testUtil.Equals(t, expectedVolume, volume)
|
||||
}
|
||||
|
||||
testDeleteVolumeServiceAction(t, "f5fc9874-fc89-4814-a358-23ba83a6115f", anon)
|
||||
}
|
||||
|
||||
func testDeleteVolumeServiceAction(t *testing.T, uriEndsWith string, volumeServiceAction func(*v3.Service)) {
|
||||
apiServer := testUtil.CreateDeleteTestRequestServer(t, tokn, uriEndsWith)
|
||||
defer apiServer.Close()
|
||||
|
||||
auth := openstack.AuthToken{
|
||||
Access: openstack.AccessType{
|
||||
Token: openstack.Token{
|
||||
ID: tokn,
|
||||
},
|
||||
},
|
||||
}
|
||||
sess, _ := openstack.NewSession(http.DefaultClient, auth, nil)
|
||||
volumeService := v3.Service{
|
||||
Session: *sess,
|
||||
URL: apiServer.URL,
|
||||
}
|
||||
volumeServiceAction(&volumeService)
|
||||
}
|
||||
*/
|
||||
|
||||
var sampleVolumeData = `{
|
||||
"name":"myvol1",
|
||||
"id":"f5fc9874-fc89-4814-a358-23ba83a6115f",
|
||||
"links":[{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "bookmark"}]
|
||||
}`
|
||||
|
||||
var sampleVolumesData = `{
|
||||
"volumes":[
|
||||
{
|
||||
"name":"myvol1",
|
||||
"id":"f5fc9874-fc89-4814-a358-23ba83a6115f",
|
||||
"links":[{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/f5fc9874-fc89-4814-a358-23ba83a6115f", "rel": "bookmark"}]
|
||||
},
|
||||
{
|
||||
"name":"myvol2",
|
||||
"id":"60055a0a-2451-4d78-af9c-f2302150602f",
|
||||
"links":[{"href": "http://172.16.197.131:8776/v2/1d8837c5fcef4892951397df97661f97/volumes/60055a0a-2451-4d78-af9c-f2302150602f", "rel": "self"},
|
||||
{"href": "http://172.16.197.131:8776/1d8837c5fcef4892951397df97661f97/volumes/60055a0a-2451-4d78-af9c-f2302150602f", "rel": "bookmark"}]
|
||||
}
|
||||
]
|
||||
}`
|
Loading…
x
Reference in New Issue
Block a user