1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Resource class and its manager for volumes on Block Storage V2 API
18 """
19
20 from yakumo import base
21 from yakumo.constant import UNDEF
22 from yakumo import mapper
23 from yakumo import utils
24
25 from yakumo.cinder.v2.snapshot import Resource as Snapshot
26 from yakumo.cinder.v2.volume_type import Resource as VolumeType
27 from yakumo.nova.v2.image import Resource as NovaV2Image
28 from yakumo.glance.v1.image import Resource as GlanceV1Image
29 from yakumo.glance.v2.image import Resource as GlanceV2Image
30
31
32 ATTRIBUTE_MAPPING = [
33 ('name', 'name', mapper.Noop),
34 ('description', 'description', mapper.Noop),
35 ('volume_type', 'volume_type', mapper.Noop),
36 ('size', 'size', mapper.Noop),
37 ('availability_zone', 'availability_zone',
38 mapper.Resource('availability_zone')),
39 ('source_image', 'imageRef', mapper.Resource('image')),
40 ('source_volume', 'source_volid', mapper.Resource('cinder.volume')),
41 ('source_snapshot', 'snapshot_id',
42 mapper.Resource('cinder.volume_snapshot')),
43 ('source_replica', 'source_replica', mapper.Noop),
44 ('consistencygroup', 'consistencygroup_id',
45 mapper.Resource('cinder.consistency_group')),
46 ('scheduler_hints', 'scheduler_hints', mapper.Noop),
47 ('metadata', 'metadata', mapper.Noop),
48 ('project', 'tenant_id', mapper.Resource('project')),
49 ('project', 'os-vol-tenant-attr:tenant_id', mapper.Resource('project')),
50 ('is_multiattach', 'multiattach', mapper.Noop),
51 ('id', 'id', mapper.Noop),
52 ('attachments', 'attachments', mapper.Noop),
53 ('attachment', 'attachment', mapper.Resource('volume_attachment')),
54 ('host', 'host', mapper.Noop),
55 ('host', 'os-vol-host-attr:host', mapper.Noop),
56 ('volume_replication_driver', 'os-volume-replication:driver_data',
57 mapper.DateTime),
58 ('replication_status', 'replication_status', mapper.Noop),
59 ('extended_replication_status', 'os-volume-replication:extended_status',
60 mapper.Noop),
61 ('migration_status', 'migration_status', mapper.Noop),
62 ('backend_volume_id', 'os-vol-mig-status-attr:name_id', mapper.Noop),
63 ('user', 'user_id', mapper.Resource('user')),
64 ('status', 'status', mapper.Noop),
65 ('is_bootable', 'bootable', mapper.BoolStr),
66 ('is_encrypted', 'encrypted', mapper.Noop),
67 ('created_at', 'created_at', mapper.DateTime),
68 ('updated_at', 'updated_at', mapper.DateTime),
69 ]
70
71
73 """resource class for volumes on Block Storage V2 API"""
74
75 _stable_state = ['available', 'in-use', 'error', 'error_deleting']
76
78 """
79 Update properties of a volume
80
81 @keyword name: Volume name
82 @type name: str
83 @keyword description: Description
84 @type description: str
85 @keyword metadata: Metadata (key=value)
86 @type metadata: dict
87 @rtype: None
88 """
89 super(Resource, self).update(
90 name=name,
91 description=description,
92 metadata=metadata)
93
103
115
128
130 """
131 Extend a volume
132
133 @keyword size: new size; should be larger than the current size
134 @type size: int
135 @rtype: None
136 """
137 self._http.post(self._url_resource_path, self._id, 'action',
138 data=utils.get_json_body("os-extend", new_size=size))
139
140 - def reset_status(self, status=None, attach_status=None,
141 migration_status=None):
142 """
143 Reset status of a volume
144
145 @keyword status: new status
146 @type status: str
147 @keyword attach_status: new attach status
148 @type status: str
149 @keyword migration_status: new migration status
150 @type migration_status: str
151 @rtype: None
152 """
153 self._http.post(self._url_resource_path, self._id, 'action',
154 data=utils.get_json_body(
155 "os-reset_status",
156 status=status,
157 attach_status=attach_status,
158 migration_status=migration_status))
159
171
183
192
194 """
195 Force detach a volume
196
197 @keyword attachment: Volume attachment
198 @type attachment: yakumo.server.volume_attachment.Resource
199 @keyword connector: Connector information
200 @type connector: dict
201 @rtype: None
202 """
203 self._http.post(self._url_resource_path, self._id, 'action',
204 data=utils.get_json_body(
205 "os-force_detach",
206 attachment=attachment,
207 connector=connector))
208
209 - def upload(self, name=None, disk_format='raw', force=False):
210 """
211 Upload volume image to Glance
212
213 @keyword name: Image name
214 @type name: str
215 @keyword disk_format: Disk format (default: 'raw')
216 @type disk_format: str
217 @keyword force: Force creation
218 @type force: bool
219 """
220 ret = self._http.post(self._url_resource_path, self._id, 'action',
221 data=utils.get_json_body(
222 "os-volume_upload_image",
223 image_name=name,
224 disk_format=disk_format,
225 force=force))
226 image_id = ret.get('os-volume_upload_image', {}).get('image_id')
227 return self._client.image.get_empty(image_id)
228
229
231 """manager class for volumes on Block Storage V2 API"""
232
233 resource_class = Resource
234 service_type = 'volume'
235 _attr_mapping = ATTRIBUTE_MAPPING
236 _json_resource_key = 'volume'
237 _json_resources_key = 'volumes'
238 _url_resource_list_path = '/volumes/detail'
239 _url_resource_path = '/volumes'
240
246
257
258 - def create(self, name=UNDEF, description=UNDEF, volume_type=UNDEF,
259 size=UNDEF, availability_zone=UNDEF, source=UNDEF,
260 is_replication=UNDEF, consistency_group=UNDEF,
261 scheduler_hints=UNDEF, metadata=UNDEF,
262 project=UNDEF, is_multiattach=UNDEF):
263 """
264 Create a volume
265
266 @keyword name: Volume name
267 @type name: str
268 @keyword description: Description
269 @type description: str
270 @keyword volume_type: Volume type
271 @type volume_type: yakumo.cinder.v2.volume_type.Resource
272 @keyword size: Size in GB
273 @type size: int
274 @keyword availability_zone: Availability zone
275 @type availability_zone: yakumo.availability_zone.Resource
276 @keyword source: Source image/snapshot/volume (optional)
277 @type source: one of yakumo.image.Resource,
278 yakumo.volume_snapshot.Resource and yakumo.volume.Resource
279 @keyword is_replication: Whether the volume is a replica of another
280 volume
281 @type source: bool
282 @keyword consistency_group: Consistency group (optional)
283 @type consistency_group: yakumo.cinder.v2.consistency_group.Resource
284 @keyword scheduler_hints: Scheduler hints (optional)
285 @type scheduler_hints: dict
286 @keyword metadata: Metadata (key=value)
287 @type metadata: dict
288 @keyword is_multiattach: Whether multiattach is allowed
289 @type is_multiattach: bool
290 @return: Created volume
291 @rtype: yakumo.cinder.v2.volume.Resource
292 """
293 source_image = UNDEF
294 source_volume = UNDEF
295 source_snapshot = UNDEF
296 source_replica = UNDEF
297 if isinstance(source, Resource):
298 if is_replication is not UNDEF:
299 source_replica = source
300 else:
301 source_volume = source
302 elif isinstance(source, Snapshot):
303 source_snapshot = source
304 elif isinstance(source, (GlanceV1Image, GlanceV2Image, NovaV2Image)):
305 source_image = source
306 return super(Manager, self).create(
307 name=name,
308 description=description,
309 volume_type=volume_type,
310 size=size,
311 availability_zone=availability_zone,
312 source_image=source_image,
313 source_volume=source_volume,
314 source_snapshot=source_snapshot,
315 source_replica=source_replica,
316 consistency_group=consistency_group,
317 scheduler_hints=scheduler_hints,
318 metadata=metadata,
319 is_multiattach=is_multiattach)
320
324 """
325 Manage a volume
326
327 @keyword name: Volume name
328 @type name: str
329 @keyword description: Description
330 @type description: str
331 @keyword volume_type: Volume type
332 @type volume_type: yakumo.cinder.v2.volume_type.Resource
333 @keyword size: Size in GB
334 @type size: int
335 @keyword availability_zone: Availability zone
336 @type availability_zone: yakumo.availability_zone.Resource
337 @keyword metadata: Metadata (key=value)
338 @type metadata: dict
339 @keyword host: Reference for volume host
340 @type host: str
341 @keyword ref: Reference for existing volume (key=value)
342 @type ref: dict
343 @keyword is_bootable: Whether volume is bootable
344 @type is_bootable: bool
345 @return: Created volume
346 @rtype: yakumo.cinder.v2.volume.Resource
347 """
348 json_attr = self._attr2json(dict(
349 name=name,
350 description=description,
351 volume_type=volume_type,
352 size=size,
353 availability_zone=availability_zone,
354 metadata=metadata,
355 host=host,
356 ref=ref,
357 is_bootable=is_bootable))
358 ret = self._http.post(self._url_resource_path, 'os-volume-manage',
359 data=utils.get_json_body("volume", **json_attr))
360 attrs = self._json2attr(ret)
361 return self.get_empty(attrs[self._id_attr])
362