blob: 5bfa75fc1d20f6b03d4137a3012e7ffc6397d715 [file] [log] [blame]
Zhi Kun Liu4be2f602014-02-08 11:52:05 +08001# Copyright 2012 OpenStack Foundation
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
16import json
17import time
18import urllib
19
Yuiko Takada4d41c2f2014-03-07 11:58:31 +000020from tempest.common import rest_client
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080021from tempest import config
22from tempest import exceptions
23
24CONF = config.CONF
25
26
Yuiko Takada4d41c2f2014-03-07 11:58:31 +000027class VolumesV2ClientJSON(rest_client.RestClient):
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080028 """
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +080029 Client class to send CRUD Volume V2 API requests to a Cinder endpoint
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080030 """
31
32 def __init__(self, auth_provider):
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +080033 super(VolumesV2ClientJSON, self).__init__(auth_provider)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080034
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +080035 self.api_version = "v2"
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080036 self.service = CONF.volume.catalog_type
37 self.build_interval = CONF.volume.build_interval
38 self.build_timeout = CONF.volume.build_timeout
39
40 def get_attachment_from_volume(self, volume):
41 """Return the element 'attachment' from input volumes."""
42 return volume['attachments'][0]
43
44 def list_volumes(self, params=None):
45 """List all the volumes created."""
46 url = 'volumes'
47 if params:
48 url += '?%s' % urllib.urlencode(params)
49
50 resp, body = self.get(url)
51 body = json.loads(body)
52 return resp, body['volumes']
53
54 def list_volumes_with_detail(self, params=None):
55 """List the details of all volumes."""
56 url = 'volumes/detail'
57 if params:
58 url += '?%s' % urllib.urlencode(params)
59
60 resp, body = self.get(url)
61 body = json.loads(body)
62 return resp, body['volumes']
63
64 def get_volume(self, volume_id):
65 """Returns the details of a single volume."""
66 url = "volumes/%s" % str(volume_id)
67 resp, body = self.get(url)
68 body = json.loads(body)
69 return resp, body['volume']
70
71 def create_volume(self, size, **kwargs):
72 """
73 Creates a new Volume.
74 size(Required): Size of volume in GB.
75 Following optional keyword arguments are accepted:
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +080076 name: Optional Volume Name.
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080077 metadata: A dictionary of values to be used as metadata.
78 volume_type: Optional Name of volume_type for the volume
79 snapshot_id: When specified the volume is created from this snapshot
80 imageRef: When specified the volume is created from this image
81 """
82 post_body = {'size': size}
83 post_body.update(kwargs)
84 post_body = json.dumps({'volume': post_body})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020085 resp, body = self.post('volumes', post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080086 body = json.loads(body)
87 return resp, body['volume']
88
89 def update_volume(self, volume_id, **kwargs):
90 """Updates the Specified Volume."""
91 put_body = json.dumps({'volume': kwargs})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +020092 resp, body = self.put('volumes/%s' % volume_id, put_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +080093 body = json.loads(body)
94 return resp, body['volume']
95
96 def delete_volume(self, volume_id):
97 """Deletes the Specified Volume."""
98 return self.delete("volumes/%s" % str(volume_id))
99
100 def upload_volume(self, volume_id, image_name, disk_format):
101 """Uploads a volume in Glance."""
102 post_body = {
103 'image_name': image_name,
104 'disk_format': disk_format
105 }
106 post_body = json.dumps({'os-volume_upload_image': post_body})
107 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200108 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800109 body = json.loads(body)
110 return resp, body['os-volume_upload_image']
111
112 def attach_volume(self, volume_id, instance_uuid, mountpoint):
113 """Attaches a volume to a given instance on a given mountpoint."""
114 post_body = {
115 'instance_uuid': instance_uuid,
116 'mountpoint': mountpoint,
117 }
118 post_body = json.dumps({'os-attach': post_body})
119 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200120 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800121 return resp, body
122
123 def detach_volume(self, volume_id):
124 """Detaches a volume from an instance."""
125 post_body = {}
126 post_body = json.dumps({'os-detach': post_body})
127 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200128 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800129 return resp, body
130
131 def reserve_volume(self, volume_id):
132 """Reserves a volume."""
133 post_body = {}
134 post_body = json.dumps({'os-reserve': post_body})
135 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200136 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800137 return resp, body
138
139 def unreserve_volume(self, volume_id):
140 """Restore a reserved volume ."""
141 post_body = {}
142 post_body = json.dumps({'os-unreserve': post_body})
143 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200144 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800145 return resp, body
146
147 def wait_for_volume_status(self, volume_id, status):
148 """Waits for a Volume to reach a given status."""
149 resp, body = self.get_volume(volume_id)
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +0800150 volume_name = body['name']
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800151 volume_status = body['status']
152 start = int(time.time())
153
154 while volume_status != status:
155 time.sleep(self.build_interval)
156 resp, body = self.get_volume(volume_id)
157 volume_status = body['status']
158 if volume_status == 'error':
159 raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
160
161 if int(time.time()) - start >= self.build_timeout:
162 message = ('Volume %s failed to reach %s status within '
163 'the required time (%s s).' %
164 (volume_name, status, self.build_timeout))
165 raise exceptions.TimeoutException(message)
166
167 def is_resource_deleted(self, id):
168 try:
169 self.get_volume(id)
170 except exceptions.NotFound:
171 return True
172 return False
173
174 def extend_volume(self, volume_id, extend_size):
175 """Extend a volume."""
176 post_body = {
177 'new_size': extend_size
178 }
179 post_body = json.dumps({'os-extend': post_body})
180 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200181 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800182 return resp, body
183
184 def reset_volume_status(self, volume_id, status):
185 """Reset the Specified Volume's Status."""
186 post_body = json.dumps({'os-reset_status': {"status": status}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200187 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800188 return resp, body
189
190 def volume_begin_detaching(self, volume_id):
191 """Volume Begin Detaching."""
192 post_body = json.dumps({'os-begin_detaching': {}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200193 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800194 return resp, body
195
196 def volume_roll_detaching(self, volume_id):
197 """Volume Roll Detaching."""
198 post_body = json.dumps({'os-roll_detaching': {}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200199 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800200 return resp, body
201
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +0800202 def create_volume_transfer(self, vol_id, name=None):
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800203 """Create a volume transfer."""
204 post_body = {
205 'volume_id': vol_id
206 }
Zhi Kun Liu8cc3c842014-01-07 10:44:34 +0800207 if name:
208 post_body['name'] = name
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800209 post_body = json.dumps({'transfer': post_body})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200210 resp, body = self.post('os-volume-transfer', post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800211 body = json.loads(body)
212 return resp, body['transfer']
213
214 def get_volume_transfer(self, transfer_id):
215 """Returns the details of a volume transfer."""
216 url = "os-volume-transfer/%s" % str(transfer_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200217 resp, body = self.get(url)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800218 body = json.loads(body)
219 return resp, body['transfer']
220
221 def list_volume_transfers(self, params=None):
222 """List all the volume transfers created."""
223 url = 'os-volume-transfer'
224 if params:
225 url += '?%s' % urllib.urlencode(params)
226 resp, body = self.get(url)
227 body = json.loads(body)
228 return resp, body['transfers']
229
230 def delete_volume_transfer(self, transfer_id):
231 """Delete a volume transfer."""
232 return self.delete("os-volume-transfer/%s" % str(transfer_id))
233
234 def accept_volume_transfer(self, transfer_id, transfer_auth_key):
235 """Accept a volume transfer."""
236 post_body = {
237 'auth_key': transfer_auth_key,
238 }
239 url = 'os-volume-transfer/%s/accept' % transfer_id
240 post_body = json.dumps({'accept': post_body})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200241 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800242 body = json.loads(body)
243 return resp, body['transfer']
244
245 def update_volume_readonly(self, volume_id, readonly):
246 """Update the Specified Volume readonly."""
247 post_body = {
248 'readonly': readonly
249 }
250 post_body = json.dumps({'os-update_readonly_flag': post_body})
251 url = 'volumes/%s/action' % (volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200252 resp, body = self.post(url, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800253 return resp, body
254
255 def force_delete_volume(self, volume_id):
256 """Force Delete Volume."""
257 post_body = json.dumps({'os-force_delete': {}})
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200258 resp, body = self.post('volumes/%s/action' % volume_id, post_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800259 return resp, body
260
261 def create_volume_metadata(self, volume_id, metadata):
262 """Create metadata for the volume."""
263 put_body = json.dumps({'metadata': metadata})
264 url = "volumes/%s/metadata" % str(volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200265 resp, body = self.post(url, put_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800266 body = json.loads(body)
267 return resp, body['metadata']
268
269 def get_volume_metadata(self, volume_id):
270 """Get metadata of the volume."""
271 url = "volumes/%s/metadata" % str(volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200272 resp, body = self.get(url)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800273 body = json.loads(body)
274 return resp, body['metadata']
275
276 def update_volume_metadata(self, volume_id, metadata):
277 """Update metadata for the volume."""
278 put_body = json.dumps({'metadata': metadata})
279 url = "volumes/%s/metadata" % str(volume_id)
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200280 resp, body = self.put(url, put_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800281 body = json.loads(body)
282 return resp, body['metadata']
283
284 def update_volume_metadata_item(self, volume_id, id, meta_item):
285 """Update metadata item for the volume."""
286 put_body = json.dumps({'meta': meta_item})
287 url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200288 resp, body = self.put(url, put_body)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800289 body = json.loads(body)
290 return resp, body['meta']
291
292 def delete_volume_metadata_item(self, volume_id, id):
293 """Delete metadata item for the volume."""
294 url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
Valeriy Ponomaryov88686d82014-02-16 12:24:51 +0200295 resp, body = self.delete(url)
Zhi Kun Liu4be2f602014-02-08 11:52:05 +0800296 return resp, body