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)
68 def get_volume_by_id(cinder, volume_id):
70 Returns an OpenStack volume object for a given name
71 :param cinder: the Cinder client
72 :param volume_id: the volume ID to lookup
73 :return: the SNAPS-OO Domain Volume object or None
75 volume = cinder.volumes.get(volume_id)
77 name=volume.name, volume_id=volume.id, description=volume.description,
78 size=volume.size, vol_type=volume.volume_type,
79 availability_zone=volume.availability_zone,
80 multi_attach=volume.multiattach)
83 def get_volume_status(cinder, volume):
85 Returns a new OpenStack Volume object for a given OpenStack volume object
86 :param cinder: the Cinder client
87 :param volume: the domain Volume object
88 :return: the OpenStack Volume object
90 os_volume = cinder.volumes.get(volume.id)
91 return os_volume.status
94 def create_volume(cinder, volume_settings):
96 Creates and returns OpenStack volume object with an external URL
97 :param cinder: the cinder client
98 :param volume_settings: the volume settings object
99 :return: the OpenStack volume object
100 :raise Exception if using a file and it cannot be found
102 created_volume = cinder.volumes.create(
103 name=volume_settings.name, description=volume_settings.description,
104 size=volume_settings.size, imageRef=volume_settings.image_name,
105 volume_type=volume_settings.type_name,
106 availability_zone=volume_settings.availability_zone,
107 multiattach=volume_settings.multi_attach)
110 name=created_volume.name, volume_id=created_volume.id,
111 description=created_volume.description,
112 size=created_volume.size, vol_type=created_volume.volume_type,
113 availability_zone=created_volume.availability_zone,
114 multi_attach=created_volume.multiattach)
117 def delete_volume(cinder, volume):
119 Deletes an volume from OpenStack
120 :param cinder: the cinder client
121 :param volume: the volume to delete
123 logger.info('Deleting volume named - %s', volume.name)
124 cinder.volumes.delete(volume.id)
127 def get_volume_type(cinder, volume_type_name=None, volume_type_settings=None):
129 Returns an OpenStack volume type object for a given name
130 :param cinder: the Cinder client
131 :param volume_type_name: the volume type name to lookup
132 :param volume_type_settings: the volume type settings used for lookups
133 :return: the volume type object or None
135 if not volume_type_name and not volume_type_settings:
138 if volume_type_settings:
139 volume_type_name = volume_type_settings.name
141 volume_types = cinder.volume_types.list()
142 for vol_type in volume_types:
143 if vol_type.name == volume_type_name:
144 encryption = get_volume_encryption_by_type(cinder, vol_type)
145 return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
149 def __get_os_volume_type_by_id(cinder, volume_type_id):
151 Returns an OpenStack volume type object for a given name
152 :param cinder: the Cinder client
153 :param volume_type_id: the volume_type ID to lookup
154 :return: the SNAPS-OO Domain Volume object or None
157 return cinder.volume_types.get(volume_type_id)
159 logger.info('Volume with ID [%s] does not exist',
163 def get_volume_type_by_id(cinder, volume_type_id):
165 Returns an OpenStack volume type object for a given name
166 :param cinder: the Cinder client
167 :param volume_type_id: the volume_type ID to lookup
168 :return: the SNAPS-OO Domain Volume object or None
170 os_vol_type = __get_os_volume_type_by_id(cinder, volume_type_id)
172 temp_vol_type = VolumeType(os_vol_type.name, os_vol_type.id,
173 os_vol_type.is_public, None, None)
174 encryption = get_volume_encryption_by_type(cinder, temp_vol_type)
177 if os_vol_type.qos_specs_id:
178 qos_spec = get_qos_by_id(cinder, os_vol_type.qos_specs_id)
180 return VolumeType(os_vol_type.name, os_vol_type.id,
181 os_vol_type.is_public, encryption, qos_spec)
184 def create_volume_type(cinder, type_settings):
186 Creates and returns OpenStack volume type object with an external URL
187 :param cinder: the cinder client
188 :param type_settings: the volume type settings object
189 :return: the volume type domain object
190 :raise Exception if using a file and it cannot be found
192 vol_type = cinder.volume_types.create(
193 type_settings.name, type_settings.description,
194 type_settings.public)
196 vol_encryption = None
197 if type_settings.encryption:
199 vol_encryption = create_volume_encryption(
200 cinder, vol_type, type_settings.encryption)
201 except Exception as e:
202 logger.warn('Error creating volume encryption - %s', e)
205 if type_settings.qos_spec_name:
207 qos_spec = get_qos(cinder, qos_name=type_settings.qos_spec_name)
208 cinder.qos_specs.associate(qos_spec, vol_type.id)
209 except NotFound as e:
210 logger.warn('Unable to locate qos_spec named %s - %s',
211 type_settings.qos_spec_name, e)
213 return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
214 vol_encryption, qos_spec)
217 def delete_volume_type(cinder, vol_type):
219 Deletes an volume from OpenStack
220 :param cinder: the cinder client
221 :param vol_type: the VolumeType domain object
223 logger.info('Deleting volume named - %s', vol_type.name)
224 cinder.volume_types.delete(vol_type.id)
227 def get_volume_encryption_by_type(cinder, volume_type):
229 Returns an OpenStack volume type object for a given name
230 :param cinder: the Cinder client
231 :param volume_type: the VolumeType domain object
232 :return: the VolumeEncryption domain object or None
234 os_vol_type = __get_os_volume_type_by_id(cinder, volume_type.id)
235 encryption = cinder.volume_encryption_types.get(os_vol_type)
236 if hasattr(encryption, 'encryption_id'):
238 if hasattr(encryption, 'cipher'):
239 cipher = encryption.cipher
241 if hasattr(encryption, 'key_size'):
242 key_size = encryption.key_size
243 return VolumeTypeEncryption(
244 encryption.encryption_id, encryption.volume_type_id,
245 encryption.control_location, encryption.provider, cipher, key_size)
248 def create_volume_encryption(cinder, volume_type, encryption_settings):
250 Creates and returns OpenStack volume type object with an external URL
251 :param cinder: the cinder client
252 :param volume_type: the VolumeType object to associate the encryption
253 :param encryption_settings: the volume type encryption settings object
254 :return: the VolumeTypeEncryption domain object
256 specs = {'name': encryption_settings.name,
257 'provider': encryption_settings.provider_class}
258 if encryption_settings.key_size:
259 specs['key_size'] = encryption_settings.key_size
260 if encryption_settings.provider_class:
261 specs['provider_class'] = encryption_settings.provider_class
262 if encryption_settings.control_location:
263 specs['control_location'] = encryption_settings.control_location.value
264 if encryption_settings.cipher:
265 specs['cipher'] = encryption_settings.cipher
267 encryption = cinder.volume_encryption_types.create(volume_type.id, specs)
270 if hasattr(encryption, 'cipher'):
271 cipher = encryption.cipher
273 if hasattr(encryption, 'key_size'):
274 key_size = encryption.key_size
275 return VolumeTypeEncryption(
276 encryption.encryption_id, encryption.volume_type_id,
277 encryption.control_location, encryption.provider, cipher, key_size)
280 def delete_volume_type_encryption(cinder, vol_type):
282 Deletes an volume from OpenStack
283 :param cinder: the cinder client
284 :param vol_type: the associated VolumeType domain object
286 logger.info('Deleting volume encryption for volume type - %s',
288 os_vol_type = __get_os_volume_type_by_id(cinder, vol_type.id)
289 cinder.volume_encryption_types.delete(os_vol_type)
292 def __get_os_qos(cinder, qos_name=None, qos_settings=None):
294 Returns an OpenStack QoS object for a given name
295 :param cinder: the Cinder client
296 :param qos_name: the qos name to lookup
297 :param qos_settings: the qos settings used for lookups
298 :return: the qos object or None
300 if not qos_name and not qos_settings:
304 qos_name = qos_settings.name
306 qoss = cinder.qos_specs.list()
308 if qos.name == qos_name:
312 def get_qos(cinder, qos_name=None, qos_settings=None):
314 Returns an OpenStack QoS object for a given name
315 :param cinder: the Cinder client
316 :param qos_name: the qos name to lookup
317 :param qos_settings: the qos settings used for lookups
318 :return: the qos object or None
320 os_qos = __get_os_qos(cinder, qos_name, qos_settings)
322 return QoSSpec(name=os_qos.name, spec_id=os_qos.id,
323 consumer=os_qos.consumer)
326 def get_qos_by_id(cinder, qos_id):
328 Returns an OpenStack qos object for a given name
329 :param cinder: the Cinder client
330 :param qos_id: the qos ID to lookup
331 :return: the SNAPS-OO Domain Volume object or None
333 qos = cinder.qos_specs.get(qos_id)
334 return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
337 def create_qos(cinder, qos_settings):
339 Creates and returns OpenStack qos object with an external URL
340 :param cinder: the cinder client
341 :param qos_settings: the qos settings object
342 :return: the qos domain object
343 :raise Exception if using a file and it cannot be found
345 specs = qos_settings.specs
346 specs['consumer'] = qos_settings.consumer.value
347 qos = cinder.qos_specs.create(qos_settings.name, qos_settings.specs)
348 return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
351 def delete_qos(cinder, qos):
353 Deletes an QoS from OpenStack
354 :param cinder: the cinder client
355 :param qos: the qos domain object to delete
357 logger.info('Deleting QoS named - %s', qos.name)
358 cinder.qos_specs.delete(qos.id)