2
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3
# not use this file except in compliance with the License. You may obtain
4
# a copy of the License at
6
# http://www.apache.org/licenses/LICENSE-2.0
8
# Unless required by applicable law or agreed to in writing, software
9
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
# License for the specific language governing permissions and limitations
17
from heat.common import exception
18
from heat.common.i18n import _
19
from heat.engine import constraints
20
from heat.engine import function
21
from heat.engine import properties
22
from heat.engine import resource
25
class LaunchConfiguration(resource.Resource):
28
IMAGE_ID, INSTANCE_TYPE, KEY_NAME, USER_DATA, SECURITY_GROUPS,
29
KERNEL_ID, RAM_DISK_ID, BLOCK_DEVICE_MAPPINGS, NOVA_SCHEDULER_HINTS,
32
'ImageId', 'InstanceType', 'KeyName', 'UserData', 'SecurityGroups',
33
'KernelId', 'RamDiskId', 'BlockDeviceMappings', 'NovaSchedulerHints',
37
_NOVA_SCHEDULER_HINT_KEYS = (
38
NOVA_SCHEDULER_HINT_KEY, NOVA_SCHEDULER_HINT_VALUE,
43
_BLOCK_DEVICE_MAPPING_KEYS = (
44
DEVICE_NAME, EBS, NO_DEVICE, VIRTUAL_NAME,
46
'DeviceName', 'Ebs', 'NoDevice', 'VirtualName',
50
DELETE_ON_TERMINATION, IOPS, SNAPSHOT_ID, VOLUME_SIZE,
53
'DeleteOnTermination', 'Iops', 'SnapshotId', 'VolumeSize',
58
IMAGE_ID: properties.Schema(
59
properties.Schema.STRING,
60
_('Glance image ID or name.'),
62
constraints.CustomConstraint('glance.image')
65
INSTANCE_TYPE: properties.Schema(
66
properties.Schema.STRING,
67
_('Nova instance type (flavor).'),
69
constraints.CustomConstraint('nova.flavor')
72
INSTANCE_ID: properties.Schema(
73
properties.Schema.STRING,
74
_('The ID of an existing instance you want to use to create '
75
'the launch configuration. All properties are derived from '
76
'the instance with the exception of BlockDeviceMapping.'),
78
constraints.CustomConstraint("nova.server")
81
KEY_NAME: properties.Schema(
82
properties.Schema.STRING,
83
_('Optional Nova keypair name.'),
85
constraints.CustomConstraint("nova.keypair")
88
USER_DATA: properties.Schema(
89
properties.Schema.STRING,
90
_('User data to pass to instance.')
92
SECURITY_GROUPS: properties.Schema(
93
properties.Schema.LIST,
94
_('Security group names to assign.')
96
KERNEL_ID: properties.Schema(
97
properties.Schema.STRING,
98
_('Not Implemented.'),
101
RAM_DISK_ID: properties.Schema(
102
properties.Schema.STRING,
103
_('Not Implemented.'),
106
BLOCK_DEVICE_MAPPINGS: properties.Schema(
107
properties.Schema.LIST,
108
_('Block device mappings to attach to instance.'),
109
schema=properties.Schema(
110
properties.Schema.MAP,
112
DEVICE_NAME: properties.Schema(
113
properties.Schema.STRING,
114
_('A device name where the volume will be '
115
'attached in the system at /dev/device_name.'
119
EBS: properties.Schema(
120
properties.Schema.MAP,
121
_('The ebs volume to attach to the instance.'),
123
DELETE_ON_TERMINATION: properties.Schema(
124
properties.Schema.BOOLEAN,
125
_('Indicate whether the volume should be '
126
'deleted when the instance is terminated.'),
129
IOPS: properties.Schema(
130
properties.Schema.NUMBER,
131
_('The number of I/O operations per second '
132
'that the volume supports.'),
135
SNAPSHOT_ID: properties.Schema(
136
properties.Schema.STRING,
137
_('The ID of the snapshot to create '
140
constraints.CustomConstraint(
144
VOLUME_SIZE: properties.Schema(
145
properties.Schema.STRING,
146
_('The size of the volume, in GB. Must be '
147
'equal or greater than the size of the '
148
'snapshot. It is safe to leave this blank '
149
'and have the Compute service infer '
152
VOLUME_TYPE: properties.Schema(
153
properties.Schema.STRING,
154
_('The volume type.'),
159
NO_DEVICE: properties.Schema(
160
properties.Schema.MAP,
161
_('The can be used to unmap a defined device.'),
164
VIRTUAL_NAME: properties.Schema(
165
properties.Schema.STRING,
166
_('The name of the virtual device. The name must be '
167
'in the form ephemeralX where X is a number '
168
'starting from zero (0); for example, ephemeral0.'),
174
NOVA_SCHEDULER_HINTS: properties.Schema(
175
properties.Schema.LIST,
176
_('Scheduler hints to pass to Nova (Heat extension).'),
177
schema=properties.Schema(
178
properties.Schema.MAP,
180
NOVA_SCHEDULER_HINT_KEY: properties.Schema(
181
properties.Schema.STRING,
184
NOVA_SCHEDULER_HINT_VALUE: properties.Schema(
185
properties.Schema.STRING,
193
def rebuild_lc_properties(self, instance_id):
194
server = self.client_plugin('nova').get_server(instance_id)
196
self.IMAGE_ID: server.image['id'],
197
self.INSTANCE_TYPE: server.flavor['id'],
198
self.KEY_NAME: server.key_name,
199
self.SECURITY_GROUPS: [sg['name']
200
for sg in server.security_groups]
202
lc_props = function.resolve(self.properties.data)
203
for key, value in six.iteritems(instance_props):
204
# the properties which are specified in launch configuration,
205
# will override the attributes from the instance
206
lc_props.setdefault(key, value)
210
def handle_create(self):
211
instance_id = self.properties.get(self.INSTANCE_ID)
213
lc_props = self.rebuild_lc_properties(instance_id)
214
defn = self.t.freeze(properties=lc_props)
215
self.properties = defn.properties(
216
self.properties_schema, self.context)
217
self._update_stored_properties()
219
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
220
if 'Metadata' in tmpl_diff:
221
raise resource.UpdateReplace(self.name)
223
def FnGetRefId(self):
224
return self.physical_resource_name_or_FnGetRefId()
228
Validate any of the provided params
230
super(LaunchConfiguration, self).validate()
231
# now we don't support without snapshot_id in bdm
232
bdm = self.properties.get(self.BLOCK_DEVICE_MAPPINGS)
235
ebs = mapping.get(self.EBS)
237
snapshot_id = ebs.get(self.SNAPSHOT_ID)
239
msg = _("SnapshotId is missing, this is required "
240
"when specifying BlockDeviceMappings.")
241
raise exception.StackValidationFailed(message=msg)
243
msg = _("Ebs is missing, this is required "
244
"when specifying BlockDeviceMappings.")
245
raise exception.StackValidationFailed(message=msg)
246
# validate the 'InstanceId', 'ImageId' and 'InstanceType',
247
# if without 'InstanceId', 'ImageId' and 'InstanceType' are required
248
instance_id = self.properties.get(self.INSTANCE_ID)
250
image_id = self.properties.get(self.IMAGE_ID)
251
instance_type = self.properties.get(self.INSTANCE_TYPE)
252
if not image_id or not instance_type:
253
msg = _('If without InstanceId, '
254
'ImageId and InstanceType are required.')
255
raise exception.StackValidationFailed(message=msg)
258
def resource_mapping():
260
'AWS::AutoScaling::LaunchConfiguration': LaunchConfiguration,