1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from cinderclient.client import Client
18 from cinderclient.exceptions import NotFound
20 from snaps.domain.volume import (
21 QoSSpec, VolumeType, VolumeTypeEncryption, Volume)
22 from snaps.openstack.utils import keystone_utils
24 __author__ = 'spisarski'
26 logger = logging.getLogger('cinder_utils')
32 Utilities for basic neutron API calls
36 def cinder_client(os_creds):
38 Creates and returns a cinder client object
39 :return: the cinder client
41 return Client(version=os_creds.volume_api_version,
42 session=keystone_utils.keystone_session(os_creds),
43 region_name=os_creds.region_name)
46 def get_volume(cinder, volume_name=None, volume_settings=None):
48 Returns an OpenStack volume object for a given name
49 :param cinder: the Cinder client
50 :param volume_name: the volume name to lookup
51 :param volume_settings: the volume settings used for lookups
52 :return: the volume object or None
55 volume_name = volume_settings.name
57 volumes = cinder.volumes.list()
58 for volume in volumes:
59 if volume.name == volume_name:
61 name=volume.name, volume_id=volume.id,
62 description=volume.description, size=volume.size,
63 vol_type=volume.volume_type,
64 availability_zone=volume.availability_zone,
65 multi_attach=volume.multiattach,
66 attachments=volume.attachments)
69 def __get_os_volume_by_id(cinder, volume_id):
71 Returns an OpenStack volume object for a given name
72 :param cinder: the Cinder client
73 :param volume_id: the volume ID to lookup
74 :return: the SNAPS-OO Domain Volume object or None
76 return cinder.volumes.get(volume_id)
79 def get_volume_by_id(cinder, volume_id):
81 Returns an OpenStack volume object for a given name
82 :param cinder: the Cinder client
83 :param volume_id: the volume ID to lookup
84 :return: the SNAPS-OO Domain Volume object or None
86 volume = __get_os_volume_by_id(cinder, volume_id)
88 name=volume.name, volume_id=volume.id, description=volume.description,
89 size=volume.size, vol_type=volume.volume_type,
90 availability_zone=volume.availability_zone,
91 multi_attach=volume.multiattach, attachments=volume.attachments)
94 def get_volume_status(cinder, volume):
96 Returns a new OpenStack Volume object for a given OpenStack volume object
97 :param cinder: the Cinder client
98 :param volume: the domain Volume object
99 :return: the OpenStack Volume object
101 os_volume = cinder.volumes.get(volume.id)
102 return os_volume.status
105 def create_volume(cinder, volume_settings):
107 Creates and returns OpenStack volume object with an external URL
108 :param cinder: the cinder client
109 :param volume_settings: the volume settings object
110 :return: the OpenStack volume object
111 :raise Exception if using a file and it cannot be found
113 volume = cinder.volumes.create(
114 name=volume_settings.name, description=volume_settings.description,
115 size=volume_settings.size, imageRef=volume_settings.image_name,
116 volume_type=volume_settings.type_name,
117 availability_zone=volume_settings.availability_zone,
118 multiattach=volume_settings.multi_attach)
121 name=volume.name, volume_id=volume.id,
122 description=volume.description,
123 size=volume.size, vol_type=volume.volume_type,
124 availability_zone=volume.availability_zone,
125 multi_attach=volume.multiattach, attachments=volume.attachments)
128 def delete_volume(cinder, volume):
130 Deletes an volume from OpenStack
131 :param cinder: the cinder client
132 :param volume: the volume to delete
134 logger.info('Deleting volume named - %s', volume.name)
135 return cinder.volumes.delete(volume.id)
138 def get_volume_type(cinder, volume_type_name=None, volume_type_settings=None):
140 Returns an OpenStack volume type object for a given name
141 :param cinder: the Cinder client
142 :param volume_type_name: the volume type name to lookup
143 :param volume_type_settings: the volume type settings used for lookups
144 :return: the volume type object or None
146 if not volume_type_name and not volume_type_settings:
149 if volume_type_settings:
150 volume_type_name = volume_type_settings.name
152 volume_types = cinder.volume_types.list()
153 for vol_type in volume_types:
154 if vol_type.name == volume_type_name:
155 encryption = get_volume_encryption_by_type(cinder, vol_type)
156 return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
160 def __get_os_volume_type_by_id(cinder, volume_type_id):
162 Returns an OpenStack volume type object for a given name
163 :param cinder: the Cinder client
164 :param volume_type_id: the volume_type ID to lookup
165 :return: the SNAPS-OO Domain Volume object or None
168 return cinder.volume_types.get(volume_type_id)
170 logger.info('Volume with ID [%s] does not exist',
174 def get_volume_type_by_id(cinder, volume_type_id):
176 Returns an OpenStack volume type object for a given name
177 :param cinder: the Cinder client
178 :param volume_type_id: the volume_type ID to lookup
179 :return: the SNAPS-OO Domain Volume object or None
181 os_vol_type = __get_os_volume_type_by_id(cinder, volume_type_id)
183 temp_vol_type = VolumeType(os_vol_type.name, os_vol_type.id,
184 os_vol_type.is_public, None, None)
185 encryption = get_volume_encryption_by_type(cinder, temp_vol_type)
188 if os_vol_type.qos_specs_id:
189 qos_spec = get_qos_by_id(cinder, os_vol_type.qos_specs_id)
191 return VolumeType(os_vol_type.name, os_vol_type.id,
192 os_vol_type.is_public, encryption, qos_spec)
195 def create_volume_type(cinder, type_settings):
197 Creates and returns OpenStack volume type object with an external URL
198 :param cinder: the cinder client
199 :param type_settings: the volume type settings object
200 :return: the volume type domain object
201 :raise Exception if using a file and it cannot be found
203 vol_type = cinder.volume_types.create(
204 type_settings.name, type_settings.description,
205 type_settings.public)
207 vol_encryption = None
208 if type_settings.encryption:
210 vol_encryption = create_volume_encryption(
211 cinder, vol_type, type_settings.encryption)
212 except Exception as e:
213 logger.warn('Error creating volume encryption - %s', e)
216 if type_settings.qos_spec_name:
218 qos_spec = get_qos(cinder, qos_name=type_settings.qos_spec_name)
219 cinder.qos_specs.associate(qos_spec, vol_type.id)
220 except NotFound as e:
221 logger.warn('Unable to locate qos_spec named %s - %s',
222 type_settings.qos_spec_name, e)
224 return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
225 vol_encryption, qos_spec)
228 def delete_volume_type(cinder, vol_type):
230 Deletes an volume from OpenStack
231 :param cinder: the cinder client
232 :param vol_type: the VolumeType domain object
234 logger.info('Deleting volume named - %s', vol_type.name)
235 cinder.volume_types.delete(vol_type.id)
238 def get_volume_encryption_by_type(cinder, volume_type):
240 Returns an OpenStack volume type object for a given name
241 :param cinder: the Cinder client
242 :param volume_type: the VolumeType domain object
243 :return: the VolumeEncryption domain object or None
245 os_vol_type = __get_os_volume_type_by_id(cinder, volume_type.id)
246 encryption = cinder.volume_encryption_types.get(os_vol_type)
247 if hasattr(encryption, 'encryption_id'):
249 if hasattr(encryption, 'cipher'):
250 cipher = encryption.cipher
252 if hasattr(encryption, 'key_size'):
253 key_size = encryption.key_size
254 return VolumeTypeEncryption(
255 encryption.encryption_id, encryption.volume_type_id,
256 encryption.control_location, encryption.provider, cipher, key_size)
259 def create_volume_encryption(cinder, volume_type, encryption_settings):
261 Creates and returns OpenStack volume type object with an external URL
262 :param cinder: the cinder client
263 :param volume_type: the VolumeType object to associate the encryption
264 :param encryption_settings: the volume type encryption settings object
265 :return: the VolumeTypeEncryption domain object
267 specs = {'name': encryption_settings.name,
268 'provider': encryption_settings.provider_class}
269 if encryption_settings.key_size:
270 specs['key_size'] = encryption_settings.key_size
271 if encryption_settings.provider_class:
272 specs['provider_class'] = encryption_settings.provider_class
273 if encryption_settings.control_location:
274 specs['control_location'] = encryption_settings.control_location.value
275 if encryption_settings.cipher:
276 specs['cipher'] = encryption_settings.cipher
278 encryption = cinder.volume_encryption_types.create(volume_type.id, specs)
281 if hasattr(encryption, 'cipher'):
282 cipher = encryption.cipher
284 if hasattr(encryption, 'key_size'):
285 key_size = encryption.key_size
286 return VolumeTypeEncryption(
287 encryption.encryption_id, encryption.volume_type_id,
288 encryption.control_location, encryption.provider, cipher, key_size)
291 def delete_volume_type_encryption(cinder, vol_type):
293 Deletes an volume from OpenStack
294 :param cinder: the cinder client
295 :param vol_type: the associated VolumeType domain object
297 logger.info('Deleting volume encryption for volume type - %s',
299 os_vol_type = __get_os_volume_type_by_id(cinder, vol_type.id)
300 cinder.volume_encryption_types.delete(os_vol_type)
303 def __get_os_qos(cinder, qos_name=None, qos_settings=None):
305 Returns an OpenStack QoS object for a given name
306 :param cinder: the Cinder client
307 :param qos_name: the qos name to lookup
308 :param qos_settings: the qos settings used for lookups
309 :return: the qos object or None
311 if not qos_name and not qos_settings:
315 qos_name = qos_settings.name
317 qoss = cinder.qos_specs.list()
319 if qos.name == qos_name:
323 def get_qos(cinder, qos_name=None, qos_settings=None):
325 Returns an OpenStack QoS object for a given name
326 :param cinder: the Cinder client
327 :param qos_name: the qos name to lookup
328 :param qos_settings: the qos settings used for lookups
329 :return: the qos object or None
331 os_qos = __get_os_qos(cinder, qos_name, qos_settings)
333 return QoSSpec(name=os_qos.name, spec_id=os_qos.id,
334 consumer=os_qos.consumer)
337 def get_qos_by_id(cinder, qos_id):
339 Returns an OpenStack qos object for a given name
340 :param cinder: the Cinder client
341 :param qos_id: the qos ID to lookup
342 :return: the SNAPS-OO Domain Volume object or None
344 qos = cinder.qos_specs.get(qos_id)
345 return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
348 def create_qos(cinder, qos_settings):
350 Creates and returns OpenStack qos object with an external URL
351 :param cinder: the cinder client
352 :param qos_settings: the qos settings object
353 :return: the qos domain object
354 :raise Exception if using a file and it cannot be found
356 specs = qos_settings.specs
357 specs['consumer'] = qos_settings.consumer.value
358 qos = cinder.qos_specs.create(qos_settings.name, qos_settings.specs)
359 return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
362 def delete_qos(cinder, qos):
364 Deletes an QoS from OpenStack
365 :param cinder: the cinder client
366 :param qos: the qos domain object to delete
368 logger.info('Deleting QoS named - %s', qos.name)
369 cinder.qos_specs.delete(qos.id)