blob: e60382a00aa84e2efe75ebaab368964863739df4 [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"""
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080027
ghanshyamde676ba2018-02-19 06:20:00 +000028 def _prepare_params(self, params):
29 """Prepares params for use in get or _ext_get methods.
30
31 If params is a string it will be left as it is, but if it's not it will
32 be urlencoded.
33 """
34 if isinstance(params, six.string_types):
35 return params
36 return urllib.urlencode(params)
37
Lee Yarwoode5597402019-02-15 20:17:00 +000038 def list_hosts(self):
39 """Lists all hosts summary info that is not disabled.
40
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020041 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-all-hosts-for-a-project
Lee Yarwoode5597402019-02-15 20:17:00 +000042 """
43 resp, body = self.get('os-hosts')
44 body = json.loads(body)
45 self.expected_success(200, resp.status)
46 return rest_client.ResponseBody(resp, body)
47
ghanshyamde676ba2018-02-19 06:20:00 +000048 def list_volumes(self, detail=False, params=None):
49 """List all the volumes created.
50
51 Params can be a string (must be urlencoded) or a dictionary.
52 For a full list of available parameters, please refer to the official
53 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020054 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes-with-details
55 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes
ghanshyamde676ba2018-02-19 06:20:00 +000056 """
57 url = 'volumes'
58 if detail:
59 url += '/detail'
60 if params:
61 url += '?%s' % self._prepare_params(params)
62
63 resp, body = self.get(url)
64 body = json.loads(body)
65 self.expected_success(200, resp.status)
66 return rest_client.ResponseBody(resp, body)
67
Lee Yarwoode5597402019-02-15 20:17:00 +000068 def migrate_volume(self, volume_id, **kwargs):
69 """Migrate a volume to a new backend
70
71 For a full list of available parameters please refer to the offical
72 API reference:
73
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020074 https://docs.openstack.org/api-ref/block-storage/v3/index.html#migrate-a-volume
Lee Yarwoode5597402019-02-15 20:17:00 +000075 """
76 post_body = json.dumps({'os-migrate_volume': kwargs})
77 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
78 self.expected_success(202, resp.status)
79 return rest_client.ResponseBody(resp, body)
80
ghanshyamde676ba2018-02-19 06:20:00 +000081 def show_volume(self, volume_id):
82 """Returns the details of a single volume."""
83 url = "volumes/%s" % volume_id
84 resp, body = self.get(url)
85 body = json.loads(body)
86 self.expected_success(200, resp.status)
87 return rest_client.ResponseBody(resp, body)
88
89 def create_volume(self, **kwargs):
90 """Creates a new Volume.
91
92 For a full list of available parameters, please refer to the official
93 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020094 https://docs.openstack.org/api-ref/block-storage/v3/index.html#create-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +000095 """
96 post_body = json.dumps({'volume': kwargs})
97 resp, body = self.post('volumes', post_body)
98 body = json.loads(body)
99 self.expected_success(202, resp.status)
100 return rest_client.ResponseBody(resp, body)
101
102 def update_volume(self, volume_id, **kwargs):
103 """Updates the Specified Volume.
104
105 For a full list of available parameters, please refer to the official
106 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200107 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000108 """
109 put_body = json.dumps({'volume': kwargs})
110 resp, body = self.put('volumes/%s' % volume_id, put_body)
111 body = json.loads(body)
112 self.expected_success(200, resp.status)
113 return rest_client.ResponseBody(resp, body)
114
115 def delete_volume(self, volume_id, **params):
116 """Deletes the Specified Volume.
117
118 For a full list of available parameters, please refer to the official
119 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200120 https://docs.openstack.org/api-ref/block-storage/v3/index.html#delete-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000121 """
122 url = 'volumes/%s' % volume_id
123 if params:
124 url += '?%s' % urllib.urlencode(params)
125 resp, body = self.delete(url)
126 self.expected_success(202, resp.status)
127 return rest_client.ResponseBody(resp, body)
128
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800129 def show_volume_summary(self, **params):
130 """Get volumes summary.
131
132 For a full list of available parameters, please refer to the official
133 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200134 https://docs.openstack.org/api-ref/block-storage/v3/#get-volumes-summary
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800135 """
136 url = 'volumes/summary'
137 if params:
138 url += '?%s' % urllib.urlencode(params)
139 resp, body = self.get(url)
140 body = json.loads(body)
141 self.expected_success(200, resp.status)
142 return rest_client.ResponseBody(resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000143
144 def upload_volume(self, volume_id, **kwargs):
145 """Uploads a volume in Glance."""
146 post_body = json.dumps({'os-volume_upload_image': kwargs})
147 url = 'volumes/%s/action' % (volume_id)
148 resp, body = self.post(url, post_body)
149 body = json.loads(body)
150 self.expected_success(202, resp.status)
151 return rest_client.ResponseBody(resp, body)
152
153 def attach_volume(self, volume_id, **kwargs):
154 """Attaches a volume to a given instance on a given mountpoint.
155
156 For a full list of available parameters, please refer to the official
157 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200158 https://docs.openstack.org/api-ref/block-storage/v3/index.html#attach-volume-to-a-server
ghanshyamde676ba2018-02-19 06:20:00 +0000159 """
160 post_body = json.dumps({'os-attach': kwargs})
161 url = 'volumes/%s/action' % (volume_id)
162 resp, body = self.post(url, post_body)
163 self.expected_success(202, resp.status)
164 return rest_client.ResponseBody(resp, body)
165
166 def set_bootable_volume(self, volume_id, **kwargs):
167 """Set a bootable flag for a volume - true or false.
168
169 For a full list of available parameters, please refer to the official
170 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200171 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-bootable-status
ghanshyamde676ba2018-02-19 06:20:00 +0000172 """
173 post_body = json.dumps({'os-set_bootable': kwargs})
174 url = 'volumes/%s/action' % (volume_id)
175 resp, body = self.post(url, post_body)
176 self.expected_success(200, resp.status)
177 return rest_client.ResponseBody(resp, body)
178
179 def detach_volume(self, volume_id):
180 """Detaches a volume from an instance."""
181 post_body = json.dumps({'os-detach': {}})
182 url = 'volumes/%s/action' % (volume_id)
183 resp, body = self.post(url, post_body)
184 self.expected_success(202, resp.status)
185 return rest_client.ResponseBody(resp, body)
186
187 def reserve_volume(self, volume_id):
188 """Reserves a volume."""
189 post_body = json.dumps({'os-reserve': {}})
190 url = 'volumes/%s/action' % (volume_id)
191 resp, body = self.post(url, post_body)
192 self.expected_success(202, resp.status)
193 return rest_client.ResponseBody(resp, body)
194
195 def unreserve_volume(self, volume_id):
196 """Restore a reserved volume ."""
197 post_body = json.dumps({'os-unreserve': {}})
198 url = 'volumes/%s/action' % (volume_id)
199 resp, body = self.post(url, post_body)
200 self.expected_success(202, resp.status)
201 return rest_client.ResponseBody(resp, body)
202
203 def is_resource_deleted(self, id):
204 """Check the specified resource is deleted or not.
205
206 :param id: A checked resource id
207 :raises lib_exc.DeleteErrorException: If the specified resource is on
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600208 the status the delete was failed.
ghanshyamde676ba2018-02-19 06:20:00 +0000209 """
210 try:
211 volume = self.show_volume(id)
212 except lib_exc.NotFound:
213 return True
214 if volume["volume"]["status"] == "error_deleting":
zhufl0ded98f2019-06-13 11:44:24 +0800215 raise lib_exc.DeleteErrorException(
216 "Volume %s failed to delete and is in error_deleting status" %
217 volume['id'])
ghanshyamde676ba2018-02-19 06:20:00 +0000218 return False
219
220 @property
221 def resource_type(self):
222 """Returns the primary type of resource this client works with."""
223 return 'volume'
224
225 def extend_volume(self, volume_id, **kwargs):
226 """Extend a volume.
227
228 For a full list of available parameters, please refer to the official
229 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200230 https://docs.openstack.org/api-ref/block-storage/v3/index.html#extend-a-volume-size
ghanshyamde676ba2018-02-19 06:20:00 +0000231 """
232 post_body = json.dumps({'os-extend': kwargs})
233 url = 'volumes/%s/action' % (volume_id)
234 resp, body = self.post(url, post_body)
235 self.expected_success(202, resp.status)
236 return rest_client.ResponseBody(resp, body)
237
238 def reset_volume_status(self, volume_id, **kwargs):
239 """Reset the Specified Volume's Status.
240
241 For a full list of available parameters, please refer to the official
242 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200243 https://docs.openstack.org/api-ref/block-storage/v3/index.html#reset-a-volume-s-statuses
ghanshyamde676ba2018-02-19 06:20:00 +0000244 """
245 post_body = json.dumps({'os-reset_status': kwargs})
246 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
247 self.expected_success(202, resp.status)
248 return rest_client.ResponseBody(resp, body)
249
250 def update_volume_readonly(self, volume_id, **kwargs):
251 """Update the Specified Volume readonly."""
252 post_body = json.dumps({'os-update_readonly_flag': kwargs})
253 url = 'volumes/%s/action' % (volume_id)
254 resp, body = self.post(url, post_body)
255 self.expected_success(202, resp.status)
256 return rest_client.ResponseBody(resp, body)
257
258 def force_delete_volume(self, volume_id):
259 """Force Delete Volume."""
260 post_body = json.dumps({'os-force_delete': {}})
261 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
262 self.expected_success(202, resp.status)
263 return rest_client.ResponseBody(resp, body)
264
265 def create_volume_metadata(self, volume_id, metadata):
266 """Create metadata for the volume.
267
268 For a full list of available parameters, please refer to the official
269 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200270 https://docs.openstack.org/api-ref/block-storage/v3/index.html#create-metadata-for-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000271 """
272 put_body = json.dumps({'metadata': metadata})
273 url = "volumes/%s/metadata" % volume_id
274 resp, body = self.post(url, put_body)
275 body = json.loads(body)
276 self.expected_success(200, resp.status)
277 return rest_client.ResponseBody(resp, body)
278
279 def show_volume_metadata(self, volume_id):
280 """Get metadata of the volume."""
281 url = "volumes/%s/metadata" % volume_id
282 resp, body = self.get(url)
283 body = json.loads(body)
284 self.expected_success(200, resp.status)
285 return rest_client.ResponseBody(resp, body)
286
287 def update_volume_metadata(self, volume_id, metadata):
288 """Update metadata for the volume.
289
290 For a full list of available parameters, please refer to the official
291 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200292 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-metadata
ghanshyamde676ba2018-02-19 06:20:00 +0000293 """
294 put_body = json.dumps({'metadata': metadata})
295 url = "volumes/%s/metadata" % volume_id
296 resp, body = self.put(url, put_body)
297 body = json.loads(body)
298 self.expected_success(200, resp.status)
299 return rest_client.ResponseBody(resp, body)
300
301 def show_volume_metadata_item(self, volume_id, id):
302 """Show metadata item for the volume."""
303 url = "volumes/%s/metadata/%s" % (volume_id, id)
304 resp, body = self.get(url)
305 body = json.loads(body)
306 self.expected_success(200, resp.status)
307 return rest_client.ResponseBody(resp, body)
308
309 def update_volume_metadata_item(self, volume_id, id, meta_item):
310 """Update metadata item for the volume."""
311 put_body = json.dumps({'meta': meta_item})
312 url = "volumes/%s/metadata/%s" % (volume_id, id)
313 resp, body = self.put(url, put_body)
314 body = json.loads(body)
315 self.expected_success(200, resp.status)
316 return rest_client.ResponseBody(resp, body)
317
318 def delete_volume_metadata_item(self, volume_id, id):
319 """Delete metadata item for the volume."""
320 url = "volumes/%s/metadata/%s" % (volume_id, id)
321 resp, body = self.delete(url)
322 self.expected_success(200, resp.status)
323 return rest_client.ResponseBody(resp, body)
324
325 def retype_volume(self, volume_id, **kwargs):
326 """Updates volume with new volume type.
327
328 For a full list of available parameters, please refer to the official
329 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200330 https://docs.openstack.org/api-ref/block-storage/v3/index.html#retype-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000331 """
332 post_body = json.dumps({'os-retype': kwargs})
333 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
334 self.expected_success(202, resp.status)
335 return rest_client.ResponseBody(resp, body)
336
337 def force_detach_volume(self, volume_id, **kwargs):
338 """Force detach a volume.
339
340 For a full list of available parameters, please refer to the official
341 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200342 https://docs.openstack.org/api-ref/block-storage/v3/index.html#force-delete-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000343 """
344 post_body = json.dumps({'os-force_detach': kwargs})
345 url = 'volumes/%s/action' % volume_id
346 resp, body = self.post(url, post_body)
347 self.expected_success(202, resp.status)
348 return rest_client.ResponseBody(resp, body)
349
350 def update_volume_image_metadata(self, volume_id, **kwargs):
351 """Update image metadata for the volume.
352
353 For a full list of available parameters, please refer to the official
354 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200355 https://docs.openstack.org/api-ref/block-storage/v3/index.html#set-image-metadata-for-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000356 """
357 post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
358 url = "volumes/%s/action" % (volume_id)
359 resp, body = self.post(url, post_body)
360 body = json.loads(body)
361 self.expected_success(200, resp.status)
362 return rest_client.ResponseBody(resp, body)
363
364 def delete_volume_image_metadata(self, volume_id, key_name):
365 """Delete image metadata item for the volume."""
366 post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
367 url = "volumes/%s/action" % (volume_id)
368 resp, body = self.post(url, post_body)
369 self.expected_success(200, resp.status)
370 return rest_client.ResponseBody(resp, body)
371
372 def show_volume_image_metadata(self, volume_id):
373 """Show image metadata for the volume."""
374 post_body = json.dumps({'os-show_image_metadata': {}})
375 url = "volumes/%s/action" % volume_id
376 resp, body = self.post(url, post_body)
377 body = json.loads(body)
378 self.expected_success(200, resp.status)
379 return rest_client.ResponseBody(resp, body)
380
381 def unmanage_volume(self, volume_id):
382 """Unmanage volume.
383
384 For a full list of available parameters, please refer to the official
385 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200386 https://docs.openstack.org/api-ref/block-storage/v3/index.html#unmanage-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000387 """
388 post_body = json.dumps({'os-unmanage': {}})
389 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
390 self.expected_success(202, resp.status)
391 return rest_client.ResponseBody(resp, body)