4 # Copyright 2017 RIFT.IO Inc
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
19 from glanceclient
import client
as glclient
20 import glanceclient
.exc
as GlanceException
25 class GlanceAPIVersionException(Exception):
26 def __init__(self
, errors
):
28 super(GlanceAPIVersionException
, self
).__init
__("Multiple Exception Received")
31 return self
.__repr
__()
34 msg
= "{} : Following Exception(s) have occured during Neutron API discovery".format(self
.__class
__)
35 for n
,e
in enumerate(self
.errors
):
37 msg
+= " {}: {}".format(n
, str(e
))
40 class GlanceDriver(object):
42 GlanceDriver Class for image management
44 ### List of supported API versions in prioritized order
45 supported_versions
= ["2"]
49 region_name
= 'RegionOne',
50 service_type
= 'image',
53 Constructor for GlanceDriver class
55 sess_handle (instance of class SessionDriver)
56 region_name (string ): Region name
57 service_type(string) : Service type name
58 logger (instance of logging.Logger)
60 self
._sess
_handle
= sess_handle
63 self
.log
= logging
.getLogger('rwcal.openstack.glance')
64 self
.log
.setLevel(logging
.DEBUG
)
69 #### Attempt to use API versions in prioritized order defined in
70 #### GlanceDriver.supported_versions
71 def select_version(version
):
73 self
.log
.info("Attempting to use Glance v%s APIs", version
)
74 gldrv
= glclient
.Client(version
= version
,
75 region_name
= region_name
,
76 service_type
= service_type
,
77 session
=self
._sess
_handle
.session
)
78 except Exception as e
:
82 self
.log
.info("Glance API v%s selected", version
)
83 return (version
, gldrv
)
86 for v
in GlanceDriver
.supported_versions
:
88 (self
._version
, self
._gl
_drv
) = select_version(v
)
89 except Exception as e
:
94 raise GlanceAPIVersionException(errors
)
97 def glance_endpoint(self
):
98 return self
._gl
_drv
.http_client
.get_endpoint()
101 def project_id(self
):
102 return self
._sess
_handle
.project_id
104 def _get_glance_connection(self
):
106 Returns instance of object glanceclient.client.Client
111 def image_list(self
):
113 Returns list of dictionaries. Each dictionary contains attributes associated with
118 Returns: List of dictionaries.
122 image_info
= self
._gl
_drv
.images
.list()
123 except Exception as e
:
124 self
.log
.exception("List Image operation failed. Exception: %s", str(e
))
126 images
= [ img
for img
in image_info
]
129 def image_create(self
, **kwargs
):
133 A dictionary of kwargs with following keys
135 'name'(string) : Name of the image
136 'location'(string) : URL (http://....) where image is located
137 'disk_format'(string) : Disk format
138 Possible values are 'ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso'
139 'container_format'(string): Container format
140 Possible values are 'ami', 'ari', 'aki', 'bare', 'ovf'
141 'tags' : A list of user tags
142 'checksum' : The image md5 checksum
145 image_id (string) : UUID of the image
149 image
= self
._gl
_drv
.images
.create(**kwargs
)
150 except Exception as e
:
151 self
.log
.exception("Create Image operation failed. Exception: %s", str(e
))
156 def image_upload(self
, image_id
, fd
):
161 image_id: UUID of the image
162 fd : File descriptor for the image file
166 self
._gl
_drv
.images
.upload(image_id
, fd
)
167 except Exception as e
:
168 self
.log
.exception("Image upload operation failed. Exception: %s",str(e
))
171 def image_add_location(self
, image_id
, location
, metadata
):
173 Add image URL location
176 image_id : UUID of the image
177 location : http URL for the image
182 self
._gl
_drv
.images
.add_location(image_id
, location
, metadata
)
183 except Exception as e
:
184 self
.log
.exception("Image location add operation failed. Exception: %s",str(e
))
187 def image_update(self
, image_id
, remove_props
= None, **kwargs
):
192 image_id: UUID of the image
193 remove_props: list of property names to remove
195 'my_custom_property1',
196 'my_custom_property2'
198 kwargs: A dctionary of kwargs with the image attributes and their new values
200 'my_custom_property'(name of property) : Value of the custom property
203 If remove_props is not None, it is assumed that the function is called to
204 remove the specified property from the image, and kwargs is None.
205 Otherwise, the image properties are updated with kwargs. Its either-or.
207 assert image_id
== self
._image
_get
(image_id
)['id']
209 if remove_props
is not None:
210 self
._gl
_drv
.images
.update(image_id
, remove_props
=remove_props
)
212 self
._gl
_drv
.images
.update(image_id
, **kwargs
)
213 except Exception as e
:
214 self
.log
.exception("Update Image operation failed for image_id : %s. Exception: %s",image_id
, str(e
))
217 def image_delete(self
, image_id
):
222 image_id: UUID of the image
227 assert image_id
== self
._image
_get
(image_id
)['id']
229 self
._gl
_drv
.images
.delete(image_id
)
230 except Exception as e
:
231 self
.log
.exception("Delete Image operation failed for image_id : %s. Exception: %s",image_id
, str(e
))
235 def _image_get(self
, image_id
):
237 Returns a dictionary object of VM image attributes
240 image_id (string): UUID of the image
243 A dictionary of the image attributes
247 image
= self
._gl
_drv
.images
.get(image_id
)
248 except GlanceException
.HTTPBadRequest
as e
:
249 # RIFT-14241: The get image request occasionally returns the below message. Retry in case of bad request exception.
250 # Error code 400.: Message: Bad request syntax ('0').: Error code explanation: 400 = Bad request syntax or unsupported method. (HTTP 400)
251 self
.log
.warning("Got bad request response during get_image request. Retrying.")
255 image
= self
._gl
_drv
.images
.get(image_id
)
257 self
.log
.exception("Get Image operation failed for image_id : %s. Exception: %s", image_id
, str(e
))
259 except Exception as e
:
260 self
.log
.exception("Get Image operation failed for image_id : %s. Exception: %s", image_id
, str(e
))
265 def image_get(self
, image_id
):
267 Returns a dictionary object of VM image attributes
270 image_id (string): UUID of the image
273 A dictionary of the image attributes
275 return self
._image
_get
(image_id
)
277 def image_verify(self
, image_id
):
279 Verifies if image with image-id exists and is in active state
282 image_id(string): UUID of the image
286 Raises except if image not found or not in active state
288 img
= self
.image_get(image_id
)
289 if img
['status'] != 'active':
290 raise GlanceException
.NotFound("Image with image_id: %s not found in active state. Current State: %s"
291 %(img
['id'], img
['status']))