blob: a1185c41b40cdeed34c6b7cc7333493bb7e2dc55 [file] [log] [blame]
jeremy.zhang79a1cbf2017-05-07 16:09:17 +08001# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from oslo_serialization import jsonutils as json
ghanshyamde676ba2018-02-19 06:20:00 +000017import six
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080018from six.moves.urllib import parse as urllib
19
20from tempest.lib.common import rest_client
ghanshyamde676ba2018-02-19 06:20:00 +000021from tempest.lib import exceptions as lib_exc
22from tempest.lib.services.volume import base_client
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080023
24
ghanshyamde676ba2018-02-19 06:20:00 +000025class VolumesClient(base_client.BaseClient):
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080026 """Client class to send CRUD Volume V3 API requests"""
27 api_version = "v3"
28
ghanshyamde676ba2018-02-19 06:20:00 +000029 def _prepare_params(self, params):
30 """Prepares params for use in get or _ext_get methods.
31
32 If params is a string it will be left as it is, but if it's not it will
33 be urlencoded.
34 """
35 if isinstance(params, six.string_types):
36 return params
37 return urllib.urlencode(params)
38
39 def list_volumes(self, detail=False, params=None):
40 """List all the volumes created.
41
42 Params can be a string (must be urlencoded) or a dictionary.
43 For a full list of available parameters, please refer to the official
44 API reference:
45 https://developer.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes-with-details
46 https://developer.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes
47 """
48 url = 'volumes'
49 if detail:
50 url += '/detail'
51 if params:
52 url += '?%s' % self._prepare_params(params)
53
54 resp, body = self.get(url)
55 body = json.loads(body)
56 self.expected_success(200, resp.status)
57 return rest_client.ResponseBody(resp, body)
58
59 def show_volume(self, volume_id):
60 """Returns the details of a single volume."""
61 url = "volumes/%s" % volume_id
62 resp, body = self.get(url)
63 body = json.loads(body)
64 self.expected_success(200, resp.status)
65 return rest_client.ResponseBody(resp, body)
66
67 def create_volume(self, **kwargs):
68 """Creates a new Volume.
69
70 For a full list of available parameters, please refer to the official
71 API reference:
72 https://developer.openstack.org/api-ref/block-storage/v3/index.html#create-a-volume
73 """
74 post_body = json.dumps({'volume': kwargs})
75 resp, body = self.post('volumes', post_body)
76 body = json.loads(body)
77 self.expected_success(202, resp.status)
78 return rest_client.ResponseBody(resp, body)
79
80 def update_volume(self, volume_id, **kwargs):
81 """Updates the Specified Volume.
82
83 For a full list of available parameters, please refer to the official
84 API reference:
85 https://developer.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume
86 """
87 put_body = json.dumps({'volume': kwargs})
88 resp, body = self.put('volumes/%s' % volume_id, put_body)
89 body = json.loads(body)
90 self.expected_success(200, resp.status)
91 return rest_client.ResponseBody(resp, body)
92
93 def delete_volume(self, volume_id, **params):
94 """Deletes the Specified Volume.
95
96 For a full list of available parameters, please refer to the official
97 API reference:
98 https://developer.openstack.org/api-ref/block-storage/v3/index.html#delete-a-volume
99 """
100 url = 'volumes/%s' % volume_id
101 if params:
102 url += '?%s' % urllib.urlencode(params)
103 resp, body = self.delete(url)
104 self.expected_success(202, resp.status)
105 return rest_client.ResponseBody(resp, body)
106
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800107 def show_volume_summary(self, **params):
108 """Get volumes summary.
109
110 For a full list of available parameters, please refer to the official
111 API reference:
112 https://developer.openstack.org/api-ref/block-storage/v3/#get-volumes-summary
113 """
114 url = 'volumes/summary'
115 if params:
116 url += '?%s' % urllib.urlencode(params)
117 resp, body = self.get(url)
118 body = json.loads(body)
119 self.expected_success(200, resp.status)
120 return rest_client.ResponseBody(resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000121
122 def upload_volume(self, volume_id, **kwargs):
123 """Uploads a volume in Glance."""
124 post_body = json.dumps({'os-volume_upload_image': kwargs})
125 url = 'volumes/%s/action' % (volume_id)
126 resp, body = self.post(url, post_body)
127 body = json.loads(body)
128 self.expected_success(202, resp.status)
129 return rest_client.ResponseBody(resp, body)
130
131 def attach_volume(self, volume_id, **kwargs):
132 """Attaches a volume to a given instance on a given mountpoint.
133
134 For a full list of available parameters, please refer to the official
135 API reference:
136 https://developer.openstack.org/api-ref/block-storage/v3/index.html#attach-volume-to-a-server
137 """
138 post_body = json.dumps({'os-attach': kwargs})
139 url = 'volumes/%s/action' % (volume_id)
140 resp, body = self.post(url, post_body)
141 self.expected_success(202, resp.status)
142 return rest_client.ResponseBody(resp, body)
143
144 def set_bootable_volume(self, volume_id, **kwargs):
145 """Set a bootable flag for a volume - true or false.
146
147 For a full list of available parameters, please refer to the official
148 API reference:
149 https://developer.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-bootable-status
150 """
151 post_body = json.dumps({'os-set_bootable': kwargs})
152 url = 'volumes/%s/action' % (volume_id)
153 resp, body = self.post(url, post_body)
154 self.expected_success(200, resp.status)
155 return rest_client.ResponseBody(resp, body)
156
157 def detach_volume(self, volume_id):
158 """Detaches a volume from an instance."""
159 post_body = json.dumps({'os-detach': {}})
160 url = 'volumes/%s/action' % (volume_id)
161 resp, body = self.post(url, post_body)
162 self.expected_success(202, resp.status)
163 return rest_client.ResponseBody(resp, body)
164
165 def reserve_volume(self, volume_id):
166 """Reserves a volume."""
167 post_body = json.dumps({'os-reserve': {}})
168 url = 'volumes/%s/action' % (volume_id)
169 resp, body = self.post(url, post_body)
170 self.expected_success(202, resp.status)
171 return rest_client.ResponseBody(resp, body)
172
173 def unreserve_volume(self, volume_id):
174 """Restore a reserved volume ."""
175 post_body = json.dumps({'os-unreserve': {}})
176 url = 'volumes/%s/action' % (volume_id)
177 resp, body = self.post(url, post_body)
178 self.expected_success(202, resp.status)
179 return rest_client.ResponseBody(resp, body)
180
181 def is_resource_deleted(self, id):
182 """Check the specified resource is deleted or not.
183
184 :param id: A checked resource id
185 :raises lib_exc.DeleteErrorException: If the specified resource is on
186 the status the delete was failed.
187 """
188 try:
189 volume = self.show_volume(id)
190 except lib_exc.NotFound:
191 return True
192 if volume["volume"]["status"] == "error_deleting":
193 raise lib_exc.DeleteErrorException(resource_id=id)
194 return False
195
196 @property
197 def resource_type(self):
198 """Returns the primary type of resource this client works with."""
199 return 'volume'
200
201 def extend_volume(self, volume_id, **kwargs):
202 """Extend a volume.
203
204 For a full list of available parameters, please refer to the official
205 API reference:
206 https://developer.openstack.org/api-ref/block-storage/v3/index.html#extend-a-volume-size
207 """
208 post_body = json.dumps({'os-extend': kwargs})
209 url = 'volumes/%s/action' % (volume_id)
210 resp, body = self.post(url, post_body)
211 self.expected_success(202, resp.status)
212 return rest_client.ResponseBody(resp, body)
213
214 def reset_volume_status(self, volume_id, **kwargs):
215 """Reset the Specified Volume's Status.
216
217 For a full list of available parameters, please refer to the official
218 API reference:
219 https://developer.openstack.org/api-ref/block-storage/v3/index.html#reset-a-volume-s-statuses
220 """
221 post_body = json.dumps({'os-reset_status': kwargs})
222 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
223 self.expected_success(202, resp.status)
224 return rest_client.ResponseBody(resp, body)
225
226 def update_volume_readonly(self, volume_id, **kwargs):
227 """Update the Specified Volume readonly."""
228 post_body = json.dumps({'os-update_readonly_flag': kwargs})
229 url = 'volumes/%s/action' % (volume_id)
230 resp, body = self.post(url, post_body)
231 self.expected_success(202, resp.status)
232 return rest_client.ResponseBody(resp, body)
233
234 def force_delete_volume(self, volume_id):
235 """Force Delete Volume."""
236 post_body = json.dumps({'os-force_delete': {}})
237 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
238 self.expected_success(202, resp.status)
239 return rest_client.ResponseBody(resp, body)
240
241 def create_volume_metadata(self, volume_id, metadata):
242 """Create metadata for the volume.
243
244 For a full list of available parameters, please refer to the official
245 API reference:
246 https://developer.openstack.org/api-ref/block-storage/v3/index.html#create-metadata-for-volume
247 """
248 put_body = json.dumps({'metadata': metadata})
249 url = "volumes/%s/metadata" % volume_id
250 resp, body = self.post(url, put_body)
251 body = json.loads(body)
252 self.expected_success(200, resp.status)
253 return rest_client.ResponseBody(resp, body)
254
255 def show_volume_metadata(self, volume_id):
256 """Get metadata of the volume."""
257 url = "volumes/%s/metadata" % volume_id
258 resp, body = self.get(url)
259 body = json.loads(body)
260 self.expected_success(200, resp.status)
261 return rest_client.ResponseBody(resp, body)
262
263 def update_volume_metadata(self, volume_id, metadata):
264 """Update metadata for the volume.
265
266 For a full list of available parameters, please refer to the official
267 API reference:
268 https://developer.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-metadata
269 """
270 put_body = json.dumps({'metadata': metadata})
271 url = "volumes/%s/metadata" % volume_id
272 resp, body = self.put(url, put_body)
273 body = json.loads(body)
274 self.expected_success(200, resp.status)
275 return rest_client.ResponseBody(resp, body)
276
277 def show_volume_metadata_item(self, volume_id, id):
278 """Show metadata item for the volume."""
279 url = "volumes/%s/metadata/%s" % (volume_id, id)
280 resp, body = self.get(url)
281 body = json.loads(body)
282 self.expected_success(200, resp.status)
283 return rest_client.ResponseBody(resp, body)
284
285 def update_volume_metadata_item(self, volume_id, id, meta_item):
286 """Update metadata item for the volume."""
287 put_body = json.dumps({'meta': meta_item})
288 url = "volumes/%s/metadata/%s" % (volume_id, id)
289 resp, body = self.put(url, put_body)
290 body = json.loads(body)
291 self.expected_success(200, resp.status)
292 return rest_client.ResponseBody(resp, body)
293
294 def delete_volume_metadata_item(self, volume_id, id):
295 """Delete metadata item for the volume."""
296 url = "volumes/%s/metadata/%s" % (volume_id, id)
297 resp, body = self.delete(url)
298 self.expected_success(200, resp.status)
299 return rest_client.ResponseBody(resp, body)
300
301 def retype_volume(self, volume_id, **kwargs):
302 """Updates volume with new volume type.
303
304 For a full list of available parameters, please refer to the official
305 API reference:
306 https://developer.openstack.org/api-ref/block-storage/v3/index.html#retype-a-volume
307 """
308 post_body = json.dumps({'os-retype': kwargs})
309 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
310 self.expected_success(202, resp.status)
311 return rest_client.ResponseBody(resp, body)
312
313 def force_detach_volume(self, volume_id, **kwargs):
314 """Force detach a volume.
315
316 For a full list of available parameters, please refer to the official
317 API reference:
318 https://developer.openstack.org/api-ref/block-storage/v3/index.html#force-delete-a-volume
319 """
320 post_body = json.dumps({'os-force_detach': kwargs})
321 url = 'volumes/%s/action' % volume_id
322 resp, body = self.post(url, post_body)
323 self.expected_success(202, resp.status)
324 return rest_client.ResponseBody(resp, body)
325
326 def update_volume_image_metadata(self, volume_id, **kwargs):
327 """Update image metadata for the volume.
328
329 For a full list of available parameters, please refer to the official
330 API reference:
331 https://developer.openstack.org/api-ref/block-storage/v3/index.html#set-image-metadata-for-a-volume
332 """
333 post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
334 url = "volumes/%s/action" % (volume_id)
335 resp, body = self.post(url, post_body)
336 body = json.loads(body)
337 self.expected_success(200, resp.status)
338 return rest_client.ResponseBody(resp, body)
339
340 def delete_volume_image_metadata(self, volume_id, key_name):
341 """Delete image metadata item for the volume."""
342 post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
343 url = "volumes/%s/action" % (volume_id)
344 resp, body = self.post(url, post_body)
345 self.expected_success(200, resp.status)
346 return rest_client.ResponseBody(resp, body)
347
348 def show_volume_image_metadata(self, volume_id):
349 """Show image metadata for the volume."""
350 post_body = json.dumps({'os-show_image_metadata': {}})
351 url = "volumes/%s/action" % volume_id
352 resp, body = self.post(url, post_body)
353 body = json.loads(body)
354 self.expected_success(200, resp.status)
355 return rest_client.ResponseBody(resp, body)
356
357 def unmanage_volume(self, volume_id):
358 """Unmanage volume.
359
360 For a full list of available parameters, please refer to the official
361 API reference:
362 https://developer.openstack.org/api-ref/block-storage/v3/index.html#unmanage-a-volume
363 """
364 post_body = json.dumps({'os-unmanage': {}})
365 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
366 self.expected_success(202, resp.status)
367 return rest_client.ResponseBody(resp, body)