blob: 4c60936ac7045918aa3a1cbf0fe2743034bc1098 [file] [log] [blame]
feiskyda546142015-09-17 12:28:23 +08001package volumes
2
3import (
4 "fmt"
5
6 "github.com/rackspace/gophercloud"
7 "github.com/rackspace/gophercloud/pagination"
8)
9
10// CreateOptsBuilder allows extensions to add additional parameters to the
11// Create request.
12type CreateOptsBuilder interface {
13 ToVolumeCreateMap() (map[string]interface{}, error)
14}
15
16// CreateOpts contains options for creating a Volume. This object is passed to
17// the volumes.Create function. For more information about these parameters,
18// see the Volume object.
19type CreateOpts struct {
feiskycf0c7fe2015-11-05 22:06:17 +080020 // The availability zone [OPTIONAL]
21 AvailabilityZone string
22 // ConsistencyGroupID is the ID of a consistency group [OPTINAL]
23 ConsistencyGroupID string
24 // The volume description [OPTIONAL]
feiskyda546142015-09-17 12:28:23 +080025 Description string
feiskycf0c7fe2015-11-05 22:06:17 +080026 // One or more metadata key and value pairs to associate with the volume [OPTIONAL]
feiskyda546142015-09-17 12:28:23 +080027 Metadata map[string]string
feiskycf0c7fe2015-11-05 22:06:17 +080028 // The volume name [OPTIONAL]
feiskyda546142015-09-17 12:28:23 +080029 Name string
feiskycf0c7fe2015-11-05 22:06:17 +080030 // The size of the volume, in gibibytes (GiB) [REQUIRED]
feiskyda546142015-09-17 12:28:23 +080031 Size int
feiskycf0c7fe2015-11-05 22:06:17 +080032 // the ID of the existing volume snapshot [OPTIONAL]
33 SnapshotID string
34 // SourceReplica is a UUID of an existing volume to replicate with [OPTIONAL]
35 SourceReplica string
36 // the ID of the existing volume [OPTIONAL]
37 SourceVolID string
38 // The ID of the image from which you want to create the volume.
39 // Required to create a bootable volume.
40 ImageID string
41 // The associated volume type [OPTIONAL]
feiskyda546142015-09-17 12:28:23 +080042 VolumeType string
43}
44
45// ToVolumeCreateMap assembles a request body based on the contents of a
46// CreateOpts.
47func (opts CreateOpts) ToVolumeCreateMap() (map[string]interface{}, error) {
48 v := make(map[string]interface{})
49
50 if opts.Size == 0 {
51 return nil, fmt.Errorf("Required CreateOpts field 'Size' not set.")
52 }
53 v["size"] = opts.Size
54
feiskycf0c7fe2015-11-05 22:06:17 +080055 if opts.AvailabilityZone != "" {
56 v["availability_zone"] = opts.AvailabilityZone
57 }
58 if opts.ConsistencyGroupID != "" {
59 v["consistencygroup_id"] = opts.ConsistencyGroupID
feiskyda546142015-09-17 12:28:23 +080060 }
61 if opts.Description != "" {
feiskycf0c7fe2015-11-05 22:06:17 +080062 v["description"] = opts.Description
feiskyda546142015-09-17 12:28:23 +080063 }
64 if opts.ImageID != "" {
65 v["imageRef"] = opts.ImageID
66 }
67 if opts.Metadata != nil {
68 v["metadata"] = opts.Metadata
69 }
70 if opts.Name != "" {
feiskycf0c7fe2015-11-05 22:06:17 +080071 v["name"] = opts.Name
72 }
73 if opts.SourceReplica != "" {
74 v["source_replica"] = opts.SourceReplica
feiskyda546142015-09-17 12:28:23 +080075 }
76 if opts.SourceVolID != "" {
77 v["source_volid"] = opts.SourceVolID
78 }
79 if opts.SnapshotID != "" {
80 v["snapshot_id"] = opts.SnapshotID
81 }
82 if opts.VolumeType != "" {
83 v["volume_type"] = opts.VolumeType
84 }
85
86 return map[string]interface{}{"volume": v}, nil
87}
88
89// Create will create a new Volume based on the values in CreateOpts. To extract
90// the Volume object from the response, call the Extract method on the
91// CreateResult.
92func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
93 var res CreateResult
94
95 reqBody, err := opts.ToVolumeCreateMap()
96 if err != nil {
97 res.Err = err
98 return res
99 }
100
101 _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
feiskycf0c7fe2015-11-05 22:06:17 +0800102 OkCodes: []int{202},
feiskyda546142015-09-17 12:28:23 +0800103 })
104 return res
105}
106
107// Delete will delete the existing Volume with the provided ID.
108func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
109 var res DeleteResult
110 _, res.Err = client.Delete(deleteURL(client, id), nil)
111 return res
112}
113
114// Get retrieves the Volume with the provided ID. To extract the Volume object
115// from the response, call the Extract method on the GetResult.
116func Get(client *gophercloud.ServiceClient, id string) GetResult {
117 var res GetResult
118 _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
119 return res
120}
121
122// ListOptsBuilder allows extensions to add additional parameters to the List
123// request.
124type ListOptsBuilder interface {
125 ToVolumeListQuery() (string, error)
126}
127
128// ListOpts holds options for listing Volumes. It is passed to the volumes.List
129// function.
130type ListOpts struct {
131 // admin-only option. Set it to true to see all tenant volumes.
132 AllTenants bool `q:"all_tenants"`
133 // List only volumes that contain Metadata.
134 Metadata map[string]string `q:"metadata"`
135 // List only volumes that have Name as the display name.
136 Name string `q:"name"`
137 // List only volumes that have a status of Status.
138 Status string `q:"status"`
139}
140
141// ToVolumeListQuery formats a ListOpts into a query string.
142func (opts ListOpts) ToVolumeListQuery() (string, error) {
143 q, err := gophercloud.BuildQueryString(opts)
144 if err != nil {
145 return "", err
146 }
147 return q.String(), nil
148}
149
150// List returns Volumes optionally limited by the conditions provided in ListOpts.
151func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
152 url := listURL(client)
153 if opts != nil {
154 query, err := opts.ToVolumeListQuery()
155 if err != nil {
156 return pagination.Pager{Err: err}
157 }
158 url += query
159 }
160 createPage := func(r pagination.PageResult) pagination.Page {
161 return ListResult{pagination.SinglePageBase(r)}
162 }
163
164 return pagination.NewPager(client, url, createPage)
165}
166
167// UpdateOptsBuilder allows extensions to add additional parameters to the
168// Update request.
169type UpdateOptsBuilder interface {
170 ToVolumeUpdateMap() (map[string]interface{}, error)
171}
172
173// UpdateOpts contain options for updating an existing Volume. This object is passed
174// to the volumes.Update function. For more information about the parameters, see
175// the Volume object.
176type UpdateOpts struct {
177 // OPTIONAL
178 Name string
179 // OPTIONAL
180 Description string
181 // OPTIONAL
182 Metadata map[string]string
183}
184
185// ToVolumeUpdateMap assembles a request body based on the contents of an
186// UpdateOpts.
187func (opts UpdateOpts) ToVolumeUpdateMap() (map[string]interface{}, error) {
188 v := make(map[string]interface{})
189
190 if opts.Description != "" {
feiskycf0c7fe2015-11-05 22:06:17 +0800191 v["description"] = opts.Description
feiskyda546142015-09-17 12:28:23 +0800192 }
193 if opts.Metadata != nil {
194 v["metadata"] = opts.Metadata
195 }
196 if opts.Name != "" {
feiskycf0c7fe2015-11-05 22:06:17 +0800197 v["name"] = opts.Name
feiskyda546142015-09-17 12:28:23 +0800198 }
199
200 return map[string]interface{}{"volume": v}, nil
201}
202
203// Update will update the Volume with provided information. To extract the updated
204// Volume from the response, call the Extract method on the UpdateResult.
205func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
206 var res UpdateResult
207
208 reqBody, err := opts.ToVolumeUpdateMap()
209 if err != nil {
210 res.Err = err
211 return res
212 }
213
214 _, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
215 OkCodes: []int{200},
216 })
217 return res
218}
219
220// IDFromName is a convienience function that returns a server's ID given its name.
221func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
222 volumeCount := 0
223 volumeID := ""
224 if name == "" {
225 return "", fmt.Errorf("A volume name must be provided.")
226 }
227 pager := List(client, nil)
228 pager.EachPage(func(page pagination.Page) (bool, error) {
229 volumeList, err := ExtractVolumes(page)
230 if err != nil {
231 return false, err
232 }
233
234 for _, s := range volumeList {
235 if s.Name == name {
236 volumeCount++
237 volumeID = s.ID
238 }
239 }
240 return true, nil
241 })
242
243 switch volumeCount {
244 case 0:
245 return "", fmt.Errorf("Unable to find volume: %s", name)
246 case 1:
247 return volumeID, nil
248 default:
249 return "", fmt.Errorf("Found %d volumes matching %s", volumeCount, name)
250 }
251}