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))
46 def get_image(glance, image_name=None):
48 Returns an OpenStack image object for a given name
49 :param glance: the Glance client
50 :param image_name: the image name to lookup
51 :return: the image object or None
53 images = glance.images.list()
55 if glance.version == VERSION_1:
56 if image.name == image_name:
57 image = glance.images.get(image.id)
58 return Image(name=image.name, image_id=image.id,
59 size=image.size, properties=image.properties)
60 elif glance.version == VERSION_2:
61 if image['name'] == image_name:
63 name=image['name'], image_id=image['id'],
64 size=image['size'], properties=image.get('properties'))
68 def get_image_status(glance, image):
70 Returns a new OpenStack Image object for a given OpenStack image object
71 :param glance: the Glance client
72 :param image: the domain Image object
73 :return: the OpenStack Image object
75 if glance.version == VERSION_1:
76 os_image = glance.images.get(image.id)
77 return os_image.status
78 elif glance.version == VERSION_2:
79 os_image = glance.images.get(image.id)
80 return os_image['status']
82 raise GlanceException('Unsupported glance client version')
85 def create_image(glance, image_settings):
87 Creates and returns OpenStack image object with an external URL
88 :param glance: the glance client
89 :param image_settings: the image settings object
90 :return: the OpenStack image object
91 :raise Exception if using a file and it cannot be found
93 if glance.version == VERSION_1:
94 return __create_image_v1(glance, image_settings)
95 elif glance.version == VERSION_2:
96 return __create_image_v2(glance, image_settings)
98 raise GlanceException('Unsupported glance client version')
101 def __create_image_v1(glance, image_settings):
103 Creates and returns OpenStack image object with an external URL
104 :param glance: the glance client
105 :param image_settings: the image settings object
106 :return: the OpenStack image object
107 :raise exceptions from the Glance client or IOError when opening a file
111 # TODO/REFACTOR - replace each call with one including kwargs
112 if image_settings.url:
113 if image_settings.extra_properties:
114 created_image = glance.images.create(
115 name=image_settings.name, disk_format=image_settings.format,
116 container_format="bare", location=image_settings.url,
117 properties=image_settings.extra_properties,
118 is_public=image_settings.public)
120 created_image = glance.images.create(
121 name=image_settings.name, disk_format=image_settings.format,
122 container_format="bare", location=image_settings.url,
123 is_public=image_settings.public)
124 elif image_settings.image_file:
125 image_file = open(image_settings.image_file, 'rb')
126 if image_settings.extra_properties:
127 created_image = glance.images.create(
128 name=image_settings.name, disk_format=image_settings.format,
129 container_format="bare", data=image_file,
130 properties=image_settings.extra_properties,
131 is_public=image_settings.public)
133 created_image = glance.images.create(
134 name=image_settings.name, disk_format=image_settings.format,
135 container_format="bare", data=image_file,
136 is_public=image_settings.public)
138 return Image(name=image_settings.name, image_id=created_image.id,
139 size=created_image.size, properties=created_image.properties)
142 def __create_image_v2(glance, image_settings):
144 Creates and returns OpenStack image object with an external URL
145 :param glance: the glance client v2
146 :param image_settings: the image settings object
147 :return: the OpenStack image object
148 :raise GlanceException or IOException or URLError
150 cleanup_temp_file = False
152 if image_settings.image_file:
153 image_filename = image_settings.image_file
154 elif image_settings.url:
155 file_name = str(uuid.uuid4())
157 image_file = file_utils.download(
158 image_settings.url, './tmp', file_name)
159 image_filename = image_file.name
161 os.remove('./tmp/' + file_name)
164 cleanup_temp_file = True
166 raise GlanceException('Filename or URL of image not configured')
171 kwargs['name'] = image_settings.name
172 kwargs['disk_format'] = image_settings.format
173 kwargs['container_format'] = 'bare'
175 if image_settings.public:
176 kwargs['visibility'] = 'public'
178 if image_settings.extra_properties:
179 kwargs.update(image_settings.extra_properties)
181 created_image = glance.images.create(**kwargs)
182 image_file = open(image_filename, 'rb')
183 glance.images.upload(created_image['id'], image_file)
185 logger.error('Unexpected exception creating image. Rolling back')
187 delete_image(glance, created_image)
192 if cleanup_temp_file:
193 os.remove(image_filename)
195 updated_image = glance.images.get(created_image['id'])
197 name=updated_image['name'], image_id=updated_image['id'],
198 size=updated_image['size'], properties=updated_image.get('properties'))
201 def delete_image(glance, image):
203 Deletes an image from OpenStack
204 :param glance: the glance client
205 :param image: the image to delete
207 if glance.version == VERSION_1:
208 glance.images.delete(image)
209 elif glance.version == VERSION_2:
210 glance.images.delete(image.id)
212 raise GlanceException('Unsupported glance client version')
215 class GlanceException(Exception):
217 Exception when calls to the Glance client cannot be served properly