blob: a8d5b203f4e36c26c6a43a26c8b1ae9182a0a061 [file] [log] [blame]
dfilppi9981f552017-08-07 20:10:53 +00001#########
2# Copyright (c) 2015 GigaSpaces Technologies Ltd. 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.
15import httplib
16from urlparse import urlparse
17
18from cloudify import ctx
19from cloudify.decorators import operation
20from cloudify.exceptions import NonRecoverableError
21
22from openstack_plugin_common import (
23 with_glance_client,
24 get_resource_id,
25 use_external_resource,
26 get_openstack_ids_of_connected_nodes_by_openstack_type,
27 delete_resource_and_runtime_properties,
28 validate_resource,
29 COMMON_RUNTIME_PROPERTIES_KEYS,
30 OPENSTACK_ID_PROPERTY,
31 OPENSTACK_TYPE_PROPERTY,
32 OPENSTACK_NAME_PROPERTY)
33
34
35IMAGE_OPENSTACK_TYPE = 'image'
36IMAGE_STATUS_ACTIVE = 'active'
37
38RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS
39REQUIRED_PROPERTIES = ['container_format', 'disk_format']
40
41
42@operation
43@with_glance_client
44def create(glance_client, **kwargs):
45 if use_external_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE):
46 return
47
48 img_dict = {
49 'name': get_resource_id(ctx, IMAGE_OPENSTACK_TYPE)
50 }
51 _validate_image_dictionary()
52 img_properties = ctx.node.properties['image']
53 img_dict.update({key: value for key, value in img_properties.iteritems()
54 if key != 'data'})
55 img = glance_client.images.create(**img_dict)
56 img_path = img_properties.get('data', '')
57 img_url = ctx.node.properties.get('image_url')
58 try:
59 _validate_image()
60 if img_path:
61 with open(img_path, 'rb') as image_file:
62 glance_client.images.upload(
63 image_id=img.id,
64 image_data=image_file)
65 elif img_url:
66 img = glance_client.images.add_location(img.id, img_url, {})
67
68 except:
69 _remove_protected(glance_client)
70 glance_client.images.delete(image_id=img.id)
71 raise
72
73 ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = img.id
74 ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \
75 IMAGE_OPENSTACK_TYPE
76 ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = img.name
77
78
79def _get_image_by_ctx(glance_client, ctx):
80 return glance_client.images.get(
81 image_id=ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY])
82
83
84@operation
85@with_glance_client
86def start(glance_client, start_retry_interval, **kwargs):
87 img = _get_image_by_ctx(glance_client, ctx)
88 if img.status != IMAGE_STATUS_ACTIVE:
89 return ctx.operation.retry(
90 message='Waiting for image to get uploaded',
91 retry_after=start_retry_interval)
92
93
94@operation
95@with_glance_client
96def delete(glance_client, **kwargs):
97 _remove_protected(glance_client)
98 delete_resource_and_runtime_properties(ctx, glance_client,
99 RUNTIME_PROPERTIES_KEYS)
100
101
102@operation
103@with_glance_client
104def creation_validation(glance_client, **kwargs):
105 validate_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE)
106 _validate_image_dictionary()
107 _validate_image()
108
109
110def _validate_image_dictionary():
111 img = ctx.node.properties['image']
112 missing = ''
113 try:
114 for prop in REQUIRED_PROPERTIES:
115 if prop not in img:
116 missing += '{0} '.format(prop)
117 except TypeError:
118 missing = ' '.join(REQUIRED_PROPERTIES)
119 if missing:
120 raise NonRecoverableError('Required properties are missing: {'
121 '0}. Please update your image '
122 'dictionary.'.format(missing))
123
124
125def _validate_image():
126 img = ctx.node.properties['image']
127 img_path = img.get('data')
128 img_url = ctx.node.properties.get('image_url')
129 if not img_url and not img_path:
130 raise NonRecoverableError('Neither image url nor image path was '
131 'provided')
132 if img_url and img_path:
133 raise NonRecoverableError('Multiple image sources provided')
134 if img_url:
135 _check_url(img_url)
136 if img_path:
137 _check_path()
138
139
140def _check_url(url):
141 p = urlparse(url)
142 conn = httplib.HTTPConnection(p.netloc)
143 conn.request('HEAD', p.path)
144 resp = conn.getresponse()
145 if resp.status >= 400:
146 raise NonRecoverableError('Invalid image URL')
147
148
149def _check_path():
150 img = ctx.node.properties['image']
151 img_path = img.get('data')
152 try:
153 with open(img_path, 'rb'):
154 pass
155 except TypeError:
156 if not img.get('url'):
157 raise NonRecoverableError('No path or url provided')
158 except IOError:
159 raise NonRecoverableError(
160 'Unable to open image file with path: "{}"'.format(img_path))
161
162
163def _remove_protected(glance_client):
164 if use_external_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE):
165 return
166
167 is_protected = ctx.node.properties['image'].get('protected', False)
168 if is_protected:
169 img_id = ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY]
170 glance_client.images.update(img_id, protected=False)
171
172
173def handle_image_from_relationship(obj_dict, property_name_to_put, ctx):
174 images = get_openstack_ids_of_connected_nodes_by_openstack_type(
175 ctx, IMAGE_OPENSTACK_TYPE)
176 if images:
177 obj_dict.update({property_name_to_put: images[0]})