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.
19 from snaps import file_utils
20 from glanceclient.client import Client
22 from snaps.domain.image import Image
23 from snaps.openstack.utils import keystone_utils
25 __author__ = 'spisarski'
27 logger = logging.getLogger('glance_utils')
33 Utilities for basic neutron API calls
37 def glance_client(os_creds):
39 Creates and returns a glance client object
40 :return: the glance client
42 return Client(version=os_creds.image_api_version,
43 session=keystone_utils.keystone_session(os_creds),
44 region_name=os_creds.region_name)
47 def get_image(glance, image_name=None, image_settings=None):
49 Returns an OpenStack image object for a given name
50 :param glance: the Glance client
51 :param image_name: the image name to lookup
52 :param image_settings: the image settings used for lookups
53 :return: the image object or None
57 if image_settings.exists:
58 img_filter = {'name': image_settings.name}
60 img_filter = {'name': image_settings.name,
61 'disk_format': image_settings.format}
63 img_filter = {'name': image_name}
65 images = glance.images.list(**{'filters': img_filter})
67 if glance.version == VERSION_1:
68 image = glance.images.get(image.id)
69 return Image(name=image.name, image_id=image.id,
70 size=image.size, properties=image.properties)
71 elif glance.version == VERSION_2:
73 name=image['name'], image_id=image['id'],
74 size=image['size'], properties=image.get('properties'))
77 def get_image_by_id(glance, image_id):
79 Returns an OpenStack image object for a given name
80 :param glance: the Glance client
81 :param image_id: the image ID to lookup
82 :return: the SNAPS-OO Domain Image object or None
84 image = glance.images.get(image_id)
86 name=image['name'], image_id=image['id'],
87 size=image['size'], properties=image.get('properties'))
90 def get_image_status(glance, image):
92 Returns a new OpenStack Image object for a given OpenStack image object
93 :param glance: the Glance client
94 :param image: the domain Image object
95 :return: the OpenStack Image object
97 if glance.version == VERSION_1:
98 os_image = glance.images.get(image.id)
99 return os_image.status
100 elif glance.version == VERSION_2:
101 os_image = glance.images.get(image.id)
102 return os_image['status']
104 raise GlanceException('Unsupported glance client version')
107 def create_image(glance, image_settings):
109 Creates and returns OpenStack image object with an external URL
110 :param glance: the glance client
111 :param image_settings: the image settings object
112 :return: the OpenStack image object
113 :raise Exception if using a file and it cannot be found
115 if glance.version == VERSION_1:
116 return __create_image_v1(glance, image_settings)
117 elif glance.version == VERSION_2:
118 return __create_image_v2(glance, image_settings)
120 raise GlanceException('Unsupported glance client version')
123 def __create_image_v1(glance, image_settings):
125 Creates and returns OpenStack image object with an external URL
126 :param glance: the glance client
127 :param image_settings: the image settings object
128 :return: the OpenStack image object
129 :raise exceptions from the Glance client or IOError when opening a file
132 'name': image_settings.name, 'disk_format': image_settings.format,
133 'container_format': 'bare', 'is_public': image_settings.public}
138 if image_settings.extra_properties:
139 kwargs['properties'] = image_settings.extra_properties
141 if image_settings.url:
142 kwargs['location'] = image_settings.url
143 elif image_settings.image_file:
144 image_file = open(image_settings.image_file, 'rb')
145 kwargs['data'] = image_file
148 'Unable to create image with name - %s. No file or URL',
152 created_image = glance.images.create(**kwargs)
153 return Image(name=image_settings.name, image_id=created_image.id,
154 size=created_image.size,
155 properties=created_image.properties)
161 def __create_image_v2(glance, image_settings):
163 Creates and returns OpenStack image object with an external URL
164 :param glance: the glance client v2
165 :param image_settings: the image settings object
166 :return: the OpenStack image object
167 :raise GlanceException or IOException or URLError
169 cleanup_temp_file = False
171 if image_settings.image_file:
172 image_filename = image_settings.image_file
173 elif image_settings.url:
174 file_name = str(uuid.uuid4())
176 image_file = file_utils.download(
177 image_settings.url, './tmp', file_name)
178 image_filename = image_file.name
181 os.remove(image_file.name)
184 cleanup_temp_file = True
186 raise GlanceException('Filename or URL of image not configured')
191 kwargs['name'] = image_settings.name
192 kwargs['disk_format'] = image_settings.format
193 kwargs['container_format'] = 'bare'
195 if image_settings.public:
196 kwargs['visibility'] = 'public'
198 if image_settings.extra_properties:
199 kwargs.update(image_settings.extra_properties)
201 os_image = glance.images.create(**kwargs)
202 image_file = open(image_filename, 'rb')
203 glance.images.upload(os_image['id'], image_file)
205 logger.error('Unexpected exception creating image. Rolling back')
207 delete_image(glance, Image(
208 name=os_image['name'], image_id=os_image['id'],
209 size=os_image['size'], properties=os_image.get('properties')))
213 logger.debug('Closing file %s', image_file.name)
215 if cleanup_temp_file:
216 logger.info('Removing file %s', image_file.name)
217 os.remove(image_filename)
219 return get_image_by_id(glance, os_image['id'])
222 def delete_image(glance, image):
224 Deletes an image from OpenStack
225 :param glance: the glance client
226 :param image: the image to delete
228 logger.info('Deleting image named - %s', image.name)
229 glance.images.delete(image.id)
232 class GlanceException(Exception):
234 Exception when calls to the Glance client cannot be served properly