Second patch for volume support.
[snaps.git] / snaps / openstack / utils / cinder_utils.py
1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
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:
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,
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.
15 import logging
16
17 from cinderclient.client import Client
18 from cinderclient.exceptions import NotFound
19
20 from snaps.domain.volume import QoSSpec, VolumeType, VolumeTypeEncryption
21 from snaps.openstack.utils import keystone_utils
22
23 __author__ = 'spisarski'
24
25 logger = logging.getLogger('cinder_utils')
26
27 VERSION_2 = 2
28 VERSION_3 = 3
29
30 """
31 Utilities for basic neutron API calls
32 """
33
34
35 def cinder_client(os_creds):
36     """
37     Creates and returns a cinder client object
38     :return: the cinder client
39     """
40     return Client(version=os_creds.volume_api_version,
41                   session=keystone_utils.keystone_session(os_creds),
42                   region_name=os_creds.region_name)
43
44
45 def get_volume_type(cinder, volume_type_name=None, volume_type_settings=None):
46     """
47     Returns an OpenStack volume type object for a given name
48     :param cinder: the Cinder client
49     :param volume_type_name: the volume type name to lookup
50     :param volume_type_settings: the volume type settings used for lookups
51     :return: the volume type object or None
52     """
53     if not volume_type_name and not volume_type_settings:
54         return None
55
56     if volume_type_settings:
57         volume_type_name = volume_type_settings.name
58
59     volume_types = cinder.volume_types.list()
60     for vol_type in volume_types:
61         if vol_type.name == volume_type_name:
62             encryption = get_volume_encryption_by_type(cinder, vol_type)
63             return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
64                               encryption, None)
65
66
67 def __get_os_volume_type_by_id(cinder, volume_type_id):
68     """
69     Returns an OpenStack volume type object for a given name
70     :param cinder: the Cinder client
71     :param volume_type_id: the volume_type ID to lookup
72     :return: the SNAPS-OO Domain Volume object or None
73     """
74     try:
75         return cinder.volume_types.get(volume_type_id)
76     except NotFound:
77         logger.info('Volume with ID [%s] does not exist',
78                     volume_type_id)
79
80
81 def get_volume_type_by_id(cinder, volume_type_id):
82     """
83     Returns an OpenStack volume type object for a given name
84     :param cinder: the Cinder client
85     :param volume_type_id: the volume_type ID to lookup
86     :return: the SNAPS-OO Domain Volume object or None
87     """
88     os_vol_type = __get_os_volume_type_by_id(cinder, volume_type_id)
89     if os_vol_type:
90         temp_vol_type = VolumeType(os_vol_type.name, os_vol_type.id,
91                                    os_vol_type.is_public, None, None)
92         encryption = get_volume_encryption_by_type(cinder, temp_vol_type)
93
94         qos_spec = None
95         if os_vol_type.qos_specs_id:
96             qos_spec = get_qos_by_id(cinder, os_vol_type.qos_specs_id)
97
98         return VolumeType(os_vol_type.name, os_vol_type.id,
99                           os_vol_type.is_public, encryption, qos_spec)
100
101
102 def create_volume_type(cinder, type_settings):
103     """
104     Creates and returns OpenStack volume type object with an external URL
105     :param cinder: the cinder client
106     :param type_settings: the volume type settings object
107     :return: the volume type domain object
108     :raise Exception if using a file and it cannot be found
109     """
110     vol_type = cinder.volume_types.create(
111         type_settings.name, type_settings.description,
112         type_settings.public)
113
114     vol_encryption = None
115     if type_settings.encryption:
116         try:
117             vol_encryption = create_volume_encryption(
118                 cinder, vol_type, type_settings.encryption)
119         except Exception as e:
120             logger.warn('Error creating volume encryption - %s', e)
121
122     qos_spec = None
123     if type_settings.qos_spec_name:
124         try:
125             qos_spec = get_qos(cinder, qos_name=type_settings.qos_spec_name)
126             cinder.qos_specs.associate(qos_spec, vol_type.id)
127         except NotFound as e:
128             logger.warn('Unable to locate qos_spec named %s - %s',
129                         type_settings.qos_spec_name, e)
130
131     return VolumeType(vol_type.name, vol_type.id, vol_type.is_public,
132                       vol_encryption, qos_spec)
133
134
135 def delete_volume_type(cinder, vol_type):
136     """
137     Deletes an volume from OpenStack
138     :param cinder: the cinder client
139     :param vol_type: the VolumeType domain object
140     """
141     logger.info('Deleting volume named - %s', vol_type.name)
142     cinder.volume_types.delete(vol_type.id)
143
144
145 def get_volume_encryption_by_type(cinder, volume_type):
146     """
147     Returns an OpenStack volume type object for a given name
148     :param cinder: the Cinder client
149     :param volume_type: the VolumeType domain object
150     :return: the VolumeEncryption domain object or None
151     """
152     os_vol_type = __get_os_volume_type_by_id(cinder, volume_type.id)
153     encryption = cinder.volume_encryption_types.get(os_vol_type)
154     if hasattr(encryption, 'encryption_id'):
155         cipher = None
156         if hasattr(encryption, 'cipher'):
157             cipher = encryption.cipher
158         key_size = None
159         if hasattr(encryption, 'key_size'):
160             key_size = encryption.key_size
161         return VolumeTypeEncryption(
162             encryption.encryption_id, encryption.volume_type_id,
163             encryption.control_location, encryption.provider, cipher, key_size)
164
165
166 def create_volume_encryption(cinder, volume_type, encryption_settings):
167     """
168     Creates and returns OpenStack volume type object with an external URL
169     :param cinder: the cinder client
170     :param volume_type: the VolumeType object to associate the encryption
171     :param encryption_settings: the volume type encryption settings object
172     :return: the VolumeTypeEncryption domain object
173     """
174     specs = {'name': encryption_settings.name,
175              'provider': encryption_settings.provider_class}
176     if encryption_settings.key_size:
177         specs['key_size'] = encryption_settings.key_size
178     if encryption_settings.provider_class:
179         specs['provider_class'] = encryption_settings.provider_class
180     if encryption_settings.control_location:
181         specs['control_location'] = encryption_settings.control_location.value
182     if encryption_settings.cipher:
183         specs['cipher'] = encryption_settings.cipher
184
185     encryption = cinder.volume_encryption_types.create(volume_type.id, specs)
186
187     cipher = None
188     if hasattr(encryption, 'cipher'):
189         cipher = encryption.cipher
190     key_size = None
191     if hasattr(encryption, 'key_size'):
192         key_size = encryption.key_size
193     return VolumeTypeEncryption(
194         encryption.encryption_id, encryption.volume_type_id,
195         encryption.control_location, encryption.provider, cipher, key_size)
196
197
198 def delete_volume_type_encryption(cinder, vol_type):
199     """
200     Deletes an volume from OpenStack
201     :param cinder: the cinder client
202     :param vol_type: the associated VolumeType domain object
203     """
204     logger.info('Deleting volume encryption for volume type - %s',
205                 vol_type.name)
206     os_vol_type = __get_os_volume_type_by_id(cinder, vol_type.id)
207     cinder.volume_encryption_types.delete(os_vol_type)
208
209
210 def __get_os_qos(cinder, qos_name=None, qos_settings=None):
211     """
212     Returns an OpenStack QoS object for a given name
213     :param cinder: the Cinder client
214     :param qos_name: the qos name to lookup
215     :param qos_settings: the qos settings used for lookups
216     :return: the qos object or None
217     """
218     if not qos_name and not qos_settings:
219         return None
220
221     if qos_settings:
222         qos_name = qos_settings.name
223
224     qoss = cinder.qos_specs.list()
225     for qos in qoss:
226         if qos.name == qos_name:
227             return qos
228
229
230 def get_qos(cinder, qos_name=None, qos_settings=None):
231     """
232     Returns an OpenStack QoS object for a given name
233     :param cinder: the Cinder client
234     :param qos_name: the qos name to lookup
235     :param qos_settings: the qos settings used for lookups
236     :return: the qos object or None
237     """
238     os_qos = __get_os_qos(cinder, qos_name, qos_settings)
239     if os_qos:
240         return QoSSpec(name=os_qos.name, spec_id=os_qos.id,
241                        consumer=os_qos.consumer)
242
243
244 def get_qos_by_id(cinder, qos_id):
245     """
246     Returns an OpenStack qos object for a given name
247     :param cinder: the Cinder client
248     :param qos_id: the qos ID to lookup
249     :return: the SNAPS-OO Domain Volume object or None
250     """
251     qos = cinder.qos_specs.get(qos_id)
252     return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
253
254
255 def create_qos(cinder, qos_settings):
256     """
257     Creates and returns OpenStack qos object with an external URL
258     :param cinder: the cinder client
259     :param qos_settings: the qos settings object
260     :return: the qos domain object
261     :raise Exception if using a file and it cannot be found
262     """
263     specs = qos_settings.specs
264     specs['consumer'] = qos_settings.consumer.value
265     qos = cinder.qos_specs.create(qos_settings.name, qos_settings.specs)
266     return QoSSpec(name=qos.name, spec_id=qos.id, consumer=qos.consumer)
267
268
269 def delete_qos(cinder, qos):
270     """
271     Deletes an QoS from OpenStack
272     :param cinder: the cinder client
273     :param qos: the qos domain object to delete
274     """
275     logger.info('Deleting QoS named - %s', qos.name)
276     cinder.qos_specs.delete(qos.id)