blob: 9c6fe6821829fad826ea7a9bfefca6e5e70a7034 [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
songwenping99d6e002021-01-05 03:07:46 +000016from urllib import parse as urllib
17
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080018from oslo_serialization import jsonutils as json
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080019
zhufl3cb47722018-11-09 14:31:49 +080020from tempest.lib.api_schema.response.volume import volumes as schema
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080021from tempest.lib.common import rest_client
ghanshyamde676ba2018-02-19 06:20:00 +000022from tempest.lib import exceptions as lib_exc
23from tempest.lib.services.volume import base_client
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080024
25
ghanshyamde676ba2018-02-19 06:20:00 +000026class VolumesClient(base_client.BaseClient):
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080027 """Client class to send CRUD Volume V3 API requests"""
jeremy.zhang79a1cbf2017-05-07 16:09:17 +080028
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 """
songwenpinga6ee2d12021-02-22 10:24:16 +080035 if isinstance(params, str):
ghanshyamde676ba2018-02-19 06:20:00 +000036 return params
37 return urllib.urlencode(params)
38
Lee Yarwoode5597402019-02-15 20:17:00 +000039 def list_hosts(self):
40 """Lists all hosts summary info that is not disabled.
41
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020042 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-all-hosts-for-a-project
Lee Yarwoode5597402019-02-15 20:17:00 +000043 """
44 resp, body = self.get('os-hosts')
45 body = json.loads(body)
46 self.expected_success(200, resp.status)
47 return rest_client.ResponseBody(resp, body)
48
ghanshyamde676ba2018-02-19 06:20:00 +000049 def list_volumes(self, detail=False, params=None):
50 """List all the volumes created.
51
52 Params can be a string (must be urlencoded) or a dictionary.
53 For a full list of available parameters, please refer to the official
54 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020055 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes-with-details
56 https://docs.openstack.org/api-ref/block-storage/v3/index.html#list-accessible-volumes
ghanshyamde676ba2018-02-19 06:20:00 +000057 """
58 url = 'volumes'
zhufl3cb47722018-11-09 14:31:49 +080059 list_schema = schema.list_volumes_no_detail
ghanshyamde676ba2018-02-19 06:20:00 +000060 if detail:
zhufl3cb47722018-11-09 14:31:49 +080061 list_schema = schema.list_volumes_with_detail
ghanshyamde676ba2018-02-19 06:20:00 +000062 url += '/detail'
63 if params:
64 url += '?%s' % self._prepare_params(params)
65
66 resp, body = self.get(url)
67 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +080068 self.validate_response(list_schema, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +000069 return rest_client.ResponseBody(resp, body)
70
Lee Yarwoode5597402019-02-15 20:17:00 +000071 def migrate_volume(self, volume_id, **kwargs):
72 """Migrate a volume to a new backend
73
74 For a full list of available parameters please refer to the offical
75 API reference:
76
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020077 https://docs.openstack.org/api-ref/block-storage/v3/index.html#migrate-a-volume
Lee Yarwoode5597402019-02-15 20:17:00 +000078 """
79 post_body = json.dumps({'os-migrate_volume': kwargs})
80 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
81 self.expected_success(202, resp.status)
82 return rest_client.ResponseBody(resp, body)
83
ghanshyamde676ba2018-02-19 06:20:00 +000084 def show_volume(self, volume_id):
85 """Returns the details of a single volume."""
86 url = "volumes/%s" % volume_id
87 resp, body = self.get(url)
88 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +080089 self.validate_response(schema.show_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +000090 return rest_client.ResponseBody(resp, body)
91
92 def create_volume(self, **kwargs):
93 """Creates a new Volume.
94
95 For a full list of available parameters, please refer to the official
96 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +020097 https://docs.openstack.org/api-ref/block-storage/v3/index.html#create-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +000098 """
99 post_body = json.dumps({'volume': kwargs})
100 resp, body = self.post('volumes', post_body)
101 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800102 self.validate_response(schema.create_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000103 return rest_client.ResponseBody(resp, body)
104
105 def update_volume(self, volume_id, **kwargs):
106 """Updates the Specified Volume.
107
108 For a full list of available parameters, please refer to the official
109 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200110 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000111 """
112 put_body = json.dumps({'volume': kwargs})
113 resp, body = self.put('volumes/%s' % volume_id, put_body)
114 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800115 self.validate_response(schema.update_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000116 return rest_client.ResponseBody(resp, body)
117
118 def delete_volume(self, volume_id, **params):
119 """Deletes the Specified Volume.
120
121 For a full list of available parameters, please refer to the official
122 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200123 https://docs.openstack.org/api-ref/block-storage/v3/index.html#delete-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000124 """
125 url = 'volumes/%s' % volume_id
126 if params:
127 url += '?%s' % urllib.urlencode(params)
128 resp, body = self.delete(url)
zhufl3cb47722018-11-09 14:31:49 +0800129 self.validate_response(schema.delete_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000130 return rest_client.ResponseBody(resp, body)
131
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800132 def show_volume_summary(self, **params):
133 """Get volumes summary.
134
135 For a full list of available parameters, please refer to the official
136 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200137 https://docs.openstack.org/api-ref/block-storage/v3/#get-volumes-summary
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800138 """
139 url = 'volumes/summary'
140 if params:
141 url += '?%s' % urllib.urlencode(params)
142 resp, body = self.get(url)
143 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800144 self.validate_response(schema.show_volume_summary, resp, body)
jeremy.zhang79a1cbf2017-05-07 16:09:17 +0800145 return rest_client.ResponseBody(resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000146
147 def upload_volume(self, volume_id, **kwargs):
zhuflaa605d52019-08-21 15:17:02 +0800148 """Uploads a volume in Glance.
149
150 For a full list of available parameters, please refer to the official
151 API reference:
152 https://docs.openstack.org/api-ref/block-storage/v3/index.html#upload-volume-to-image
153 """
ghanshyamde676ba2018-02-19 06:20:00 +0000154 post_body = json.dumps({'os-volume_upload_image': kwargs})
155 url = 'volumes/%s/action' % (volume_id)
156 resp, body = self.post(url, post_body)
157 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800158 # TODO(zhufl): This is under discussion, so will be merged
159 # in a seperate patch.
160 # https://bugs.launchpad.net/cinder/+bug/1880566
161 # self.validate_response(schema.upload_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000162 self.expected_success(202, resp.status)
163 return rest_client.ResponseBody(resp, body)
164
165 def attach_volume(self, volume_id, **kwargs):
166 """Attaches a volume to a given instance on a given mountpoint.
167
168 For a full list of available parameters, please refer to the official
169 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200170 https://docs.openstack.org/api-ref/block-storage/v3/index.html#attach-volume-to-a-server
ghanshyamde676ba2018-02-19 06:20:00 +0000171 """
172 post_body = json.dumps({'os-attach': kwargs})
173 url = 'volumes/%s/action' % (volume_id)
174 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800175 self.validate_response(schema.attach_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000176 return rest_client.ResponseBody(resp, body)
177
178 def set_bootable_volume(self, volume_id, **kwargs):
179 """Set a bootable flag for a volume - true or false.
180
181 For a full list of available parameters, please refer to the official
182 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200183 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-bootable-status
ghanshyamde676ba2018-02-19 06:20:00 +0000184 """
185 post_body = json.dumps({'os-set_bootable': kwargs})
186 url = 'volumes/%s/action' % (volume_id)
187 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800188 self.validate_response(schema.set_bootable_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000189 return rest_client.ResponseBody(resp, body)
190
191 def detach_volume(self, volume_id):
192 """Detaches a volume from an instance."""
193 post_body = json.dumps({'os-detach': {}})
194 url = 'volumes/%s/action' % (volume_id)
195 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800196 self.validate_response(schema.detach_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000197 return rest_client.ResponseBody(resp, body)
198
199 def reserve_volume(self, volume_id):
200 """Reserves a volume."""
201 post_body = json.dumps({'os-reserve': {}})
202 url = 'volumes/%s/action' % (volume_id)
203 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800204 self.validate_response(schema.reserve_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000205 return rest_client.ResponseBody(resp, body)
206
207 def unreserve_volume(self, volume_id):
208 """Restore a reserved volume ."""
209 post_body = json.dumps({'os-unreserve': {}})
210 url = 'volumes/%s/action' % (volume_id)
211 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800212 self.validate_response(schema.unreserve_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000213 return rest_client.ResponseBody(resp, body)
214
215 def is_resource_deleted(self, id):
216 """Check the specified resource is deleted or not.
217
218 :param id: A checked resource id
219 :raises lib_exc.DeleteErrorException: If the specified resource is on
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600220 the status the delete was failed.
ghanshyamde676ba2018-02-19 06:20:00 +0000221 """
222 try:
223 volume = self.show_volume(id)
224 except lib_exc.NotFound:
225 return True
226 if volume["volume"]["status"] == "error_deleting":
zhufl0ded98f2019-06-13 11:44:24 +0800227 raise lib_exc.DeleteErrorException(
228 "Volume %s failed to delete and is in error_deleting status" %
Martin Kopec14e2a4e2020-07-24 09:35:38 +0000229 volume['volume']['id'])
ghanshyamde676ba2018-02-19 06:20:00 +0000230 return False
231
232 @property
233 def resource_type(self):
234 """Returns the primary type of resource this client works with."""
235 return 'volume'
236
237 def extend_volume(self, volume_id, **kwargs):
238 """Extend a volume.
239
240 For a full list of available parameters, please refer to the official
241 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200242 https://docs.openstack.org/api-ref/block-storage/v3/index.html#extend-a-volume-size
ghanshyamde676ba2018-02-19 06:20:00 +0000243 """
244 post_body = json.dumps({'os-extend': kwargs})
245 url = 'volumes/%s/action' % (volume_id)
246 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800247 self.validate_response(schema.extend_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000248 return rest_client.ResponseBody(resp, body)
249
250 def reset_volume_status(self, volume_id, **kwargs):
251 """Reset the Specified Volume's Status.
252
253 For a full list of available parameters, please refer to the official
254 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200255 https://docs.openstack.org/api-ref/block-storage/v3/index.html#reset-a-volume-s-statuses
ghanshyamde676ba2018-02-19 06:20:00 +0000256 """
257 post_body = json.dumps({'os-reset_status': kwargs})
258 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800259 self.validate_response(schema.reset_volume_status, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000260 return rest_client.ResponseBody(resp, body)
261
262 def update_volume_readonly(self, volume_id, **kwargs):
zhuflaa605d52019-08-21 15:17:02 +0800263 """Update the Specified Volume readonly.
264
265 For a full list of available parameters, please refer to the official
266 API reference:
267 https://docs.openstack.org/api-ref/block-storage/v3/index.html#updates-volume-read-only-access-mode-flag
268 """
ghanshyamde676ba2018-02-19 06:20:00 +0000269 post_body = json.dumps({'os-update_readonly_flag': kwargs})
270 url = 'volumes/%s/action' % (volume_id)
271 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800272 self.validate_response(schema.update_volume_readonly, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000273 return rest_client.ResponseBody(resp, body)
274
275 def force_delete_volume(self, volume_id):
276 """Force Delete Volume."""
277 post_body = json.dumps({'os-force_delete': {}})
278 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800279 self.validate_response(schema.force_delete_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000280 return rest_client.ResponseBody(resp, body)
281
282 def create_volume_metadata(self, volume_id, metadata):
283 """Create metadata for the volume.
284
285 For a full list of available parameters, please refer to the official
286 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200287 https://docs.openstack.org/api-ref/block-storage/v3/index.html#create-metadata-for-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000288 """
289 put_body = json.dumps({'metadata': metadata})
290 url = "volumes/%s/metadata" % volume_id
291 resp, body = self.post(url, put_body)
292 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800293 self.validate_response(schema.create_volume_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000294 return rest_client.ResponseBody(resp, body)
295
296 def show_volume_metadata(self, volume_id):
297 """Get metadata of the volume."""
298 url = "volumes/%s/metadata" % volume_id
299 resp, body = self.get(url)
300 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800301 self.validate_response(schema.show_volume_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000302 return rest_client.ResponseBody(resp, body)
303
304 def update_volume_metadata(self, volume_id, metadata):
305 """Update metadata for the volume.
306
307 For a full list of available parameters, please refer to the official
308 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200309 https://docs.openstack.org/api-ref/block-storage/v3/index.html#update-a-volume-s-metadata
ghanshyamde676ba2018-02-19 06:20:00 +0000310 """
311 put_body = json.dumps({'metadata': metadata})
312 url = "volumes/%s/metadata" % volume_id
313 resp, body = self.put(url, put_body)
314 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800315 self.validate_response(schema.update_volume_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000316 return rest_client.ResponseBody(resp, body)
317
318 def show_volume_metadata_item(self, volume_id, id):
319 """Show metadata item for the volume."""
320 url = "volumes/%s/metadata/%s" % (volume_id, id)
321 resp, body = self.get(url)
322 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800323 self.validate_response(schema.show_volume_metadata_item, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000324 return rest_client.ResponseBody(resp, body)
325
326 def update_volume_metadata_item(self, volume_id, id, meta_item):
327 """Update metadata item for the volume."""
328 put_body = json.dumps({'meta': meta_item})
329 url = "volumes/%s/metadata/%s" % (volume_id, id)
330 resp, body = self.put(url, put_body)
331 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800332 self.validate_response(schema.update_volume_metadata_item, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000333 return rest_client.ResponseBody(resp, body)
334
335 def delete_volume_metadata_item(self, volume_id, id):
336 """Delete metadata item for the volume."""
337 url = "volumes/%s/metadata/%s" % (volume_id, id)
338 resp, body = self.delete(url)
zhufl3cb47722018-11-09 14:31:49 +0800339 self.validate_response(schema.delete_volume_metadata_item, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000340 return rest_client.ResponseBody(resp, body)
341
342 def retype_volume(self, volume_id, **kwargs):
343 """Updates volume with new volume type.
344
345 For a full list of available parameters, please refer to the official
346 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200347 https://docs.openstack.org/api-ref/block-storage/v3/index.html#retype-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000348 """
349 post_body = json.dumps({'os-retype': kwargs})
350 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800351 self.validate_response(schema.retype_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000352 return rest_client.ResponseBody(resp, body)
353
354 def force_detach_volume(self, volume_id, **kwargs):
355 """Force detach a volume.
356
357 For a full list of available parameters, please refer to the official
358 API reference:
zhufldf959302019-11-19 10:25:13 +0800359 https://docs.openstack.org/api-ref/block-storage/v3/index.html#force-detach-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000360 """
361 post_body = json.dumps({'os-force_detach': kwargs})
362 url = 'volumes/%s/action' % volume_id
363 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800364 self.validate_response(schema.force_detach_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000365 return rest_client.ResponseBody(resp, body)
366
367 def update_volume_image_metadata(self, volume_id, **kwargs):
368 """Update image metadata for the volume.
369
370 For a full list of available parameters, please refer to the official
371 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200372 https://docs.openstack.org/api-ref/block-storage/v3/index.html#set-image-metadata-for-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000373 """
374 post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
375 url = "volumes/%s/action" % (volume_id)
376 resp, body = self.post(url, post_body)
377 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800378 self.validate_response(schema.update_volume_image_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000379 return rest_client.ResponseBody(resp, body)
380
381 def delete_volume_image_metadata(self, volume_id, key_name):
382 """Delete image metadata item for the volume."""
383 post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
384 url = "volumes/%s/action" % (volume_id)
385 resp, body = self.post(url, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800386 self.validate_response(schema.delete_volume_image_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000387 return rest_client.ResponseBody(resp, body)
388
389 def show_volume_image_metadata(self, volume_id):
390 """Show image metadata for the volume."""
391 post_body = json.dumps({'os-show_image_metadata': {}})
392 url = "volumes/%s/action" % volume_id
393 resp, body = self.post(url, post_body)
394 body = json.loads(body)
zhufl3cb47722018-11-09 14:31:49 +0800395 self.validate_response(schema.show_volume_image_metadata, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000396 return rest_client.ResponseBody(resp, body)
397
398 def unmanage_volume(self, volume_id):
399 """Unmanage volume.
400
401 For a full list of available parameters, please refer to the official
402 API reference:
Andreas Jaegerbf30ae72019-07-22 19:22:57 +0200403 https://docs.openstack.org/api-ref/block-storage/v3/index.html#unmanage-a-volume
ghanshyamde676ba2018-02-19 06:20:00 +0000404 """
405 post_body = json.dumps({'os-unmanage': {}})
406 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
zhufl3cb47722018-11-09 14:31:49 +0800407 self.validate_response(schema.unmanage_volume, resp, body)
ghanshyamde676ba2018-02-19 06:20:00 +0000408 return rest_client.ResponseBody(resp, body)