~ubuntu-branches/ubuntu/wily/heat/wily-proposed

« back to all changes in this revision

Viewing changes to heat/engine/resources/aws/autoscaling/launch_config.py

  • Committer: Package Import Robot
  • Author(s): James Page, Corey Bryant, James Page
  • Date: 2015-03-30 11:11:18 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20150330111118-2qpycylx6swu4yhj
Tags: 2015.1~b3-0ubuntu1
[ Corey Bryant ]
* New upstream milestone release for OpenStack kilo:
  - d/control: Align with upstream dependencies.
  - d/p/sudoers_patch.patch: Rebased.
  - d/p/fix-requirements.patch: Rebased.

[ James Page ]
* d/p/fixup-assert-regex.patch: Tweak test to use assertRegexpMatches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
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
 
5
#
 
6
#         http://www.apache.org/licenses/LICENSE-2.0
 
7
#
 
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
 
12
#    under the License.
 
13
 
 
14
 
 
15
import six
 
16
 
 
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
 
23
 
 
24
 
 
25
class LaunchConfiguration(resource.Resource):
 
26
 
 
27
    PROPERTIES = (
 
28
        IMAGE_ID, INSTANCE_TYPE, KEY_NAME, USER_DATA, SECURITY_GROUPS,
 
29
        KERNEL_ID, RAM_DISK_ID, BLOCK_DEVICE_MAPPINGS, NOVA_SCHEDULER_HINTS,
 
30
        INSTANCE_ID,
 
31
    ) = (
 
32
        'ImageId', 'InstanceType', 'KeyName', 'UserData', 'SecurityGroups',
 
33
        'KernelId', 'RamDiskId', 'BlockDeviceMappings', 'NovaSchedulerHints',
 
34
        'InstanceId',
 
35
    )
 
36
 
 
37
    _NOVA_SCHEDULER_HINT_KEYS = (
 
38
        NOVA_SCHEDULER_HINT_KEY, NOVA_SCHEDULER_HINT_VALUE,
 
39
    ) = (
 
40
        'Key', 'Value',
 
41
    )
 
42
 
 
43
    _BLOCK_DEVICE_MAPPING_KEYS = (
 
44
        DEVICE_NAME, EBS, NO_DEVICE, VIRTUAL_NAME,
 
45
    ) = (
 
46
        'DeviceName', 'Ebs', 'NoDevice', 'VirtualName',
 
47
    )
 
48
 
 
49
    _EBS_KEYS = (
 
50
        DELETE_ON_TERMINATION, IOPS, SNAPSHOT_ID, VOLUME_SIZE,
 
51
        VOLUME_TYPE,
 
52
    ) = (
 
53
        'DeleteOnTermination', 'Iops', 'SnapshotId', 'VolumeSize',
 
54
        'VolumeType'
 
55
    )
 
56
 
 
57
    properties_schema = {
 
58
        IMAGE_ID: properties.Schema(
 
59
            properties.Schema.STRING,
 
60
            _('Glance image ID or name.'),
 
61
            constraints=[
 
62
                constraints.CustomConstraint('glance.image')
 
63
            ]
 
64
        ),
 
65
        INSTANCE_TYPE: properties.Schema(
 
66
            properties.Schema.STRING,
 
67
            _('Nova instance type (flavor).'),
 
68
            constraints=[
 
69
                constraints.CustomConstraint('nova.flavor')
 
70
            ]
 
71
        ),
 
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.'),
 
77
            constraints=[
 
78
                constraints.CustomConstraint("nova.server")
 
79
            ]
 
80
        ),
 
81
        KEY_NAME: properties.Schema(
 
82
            properties.Schema.STRING,
 
83
            _('Optional Nova keypair name.'),
 
84
            constraints=[
 
85
                constraints.CustomConstraint("nova.keypair")
 
86
            ]
 
87
        ),
 
88
        USER_DATA: properties.Schema(
 
89
            properties.Schema.STRING,
 
90
            _('User data to pass to instance.')
 
91
        ),
 
92
        SECURITY_GROUPS: properties.Schema(
 
93
            properties.Schema.LIST,
 
94
            _('Security group names to assign.')
 
95
        ),
 
96
        KERNEL_ID: properties.Schema(
 
97
            properties.Schema.STRING,
 
98
            _('Not Implemented.'),
 
99
            implemented=False
 
100
        ),
 
101
        RAM_DISK_ID: properties.Schema(
 
102
            properties.Schema.STRING,
 
103
            _('Not Implemented.'),
 
104
            implemented=False
 
105
        ),
 
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,
 
111
                schema={
 
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.'
 
116
                          'e.g. vdb'),
 
117
                        required=True,
 
118
                    ),
 
119
                    EBS: properties.Schema(
 
120
                        properties.Schema.MAP,
 
121
                        _('The ebs volume to attach to the instance.'),
 
122
                        schema={
 
123
                            DELETE_ON_TERMINATION: properties.Schema(
 
124
                                properties.Schema.BOOLEAN,
 
125
                                _('Indicate whether the volume should be '
 
126
                                  'deleted when the instance is terminated.'),
 
127
                                default=True
 
128
                            ),
 
129
                            IOPS: properties.Schema(
 
130
                                properties.Schema.NUMBER,
 
131
                                _('The number of I/O operations per second '
 
132
                                  'that the volume supports.'),
 
133
                                implemented=False
 
134
                            ),
 
135
                            SNAPSHOT_ID: properties.Schema(
 
136
                                properties.Schema.STRING,
 
137
                                _('The ID of the snapshot to create '
 
138
                                  'a volume from.'),
 
139
                                constraints=[
 
140
                                    constraints.CustomConstraint(
 
141
                                        'cinder.snapshot')
 
142
                                ]
 
143
                            ),
 
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 '
 
150
                                  'the size.'),
 
151
                            ),
 
152
                            VOLUME_TYPE: properties.Schema(
 
153
                                properties.Schema.STRING,
 
154
                                _('The volume type.'),
 
155
                                implemented=False
 
156
                            ),
 
157
                        },
 
158
                    ),
 
159
                    NO_DEVICE: properties.Schema(
 
160
                        properties.Schema.MAP,
 
161
                        _('The can be used to unmap a defined device.'),
 
162
                        implemented=False
 
163
                    ),
 
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.'),
 
169
                        implemented=False
 
170
                    ),
 
171
                },
 
172
            ),
 
173
        ),
 
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,
 
179
                schema={
 
180
                    NOVA_SCHEDULER_HINT_KEY: properties.Schema(
 
181
                        properties.Schema.STRING,
 
182
                        required=True
 
183
                    ),
 
184
                    NOVA_SCHEDULER_HINT_VALUE: properties.Schema(
 
185
                        properties.Schema.STRING,
 
186
                        required=True
 
187
                    ),
 
188
                },
 
189
            )
 
190
        ),
 
191
    }
 
192
 
 
193
    def rebuild_lc_properties(self, instance_id):
 
194
        server = self.client_plugin('nova').get_server(instance_id)
 
195
        instance_props = {
 
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]
 
201
        }
 
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)
 
207
 
 
208
        return lc_props
 
209
 
 
210
    def handle_create(self):
 
211
        instance_id = self.properties.get(self.INSTANCE_ID)
 
212
        if 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()
 
218
 
 
219
    def handle_update(self, json_snippet, tmpl_diff, prop_diff):
 
220
        if 'Metadata' in tmpl_diff:
 
221
            raise resource.UpdateReplace(self.name)
 
222
 
 
223
    def FnGetRefId(self):
 
224
        return self.physical_resource_name_or_FnGetRefId()
 
225
 
 
226
    def validate(self):
 
227
        '''
 
228
        Validate any of the provided params
 
229
        '''
 
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)
 
233
        if bdm:
 
234
            for mapping in bdm:
 
235
                ebs = mapping.get(self.EBS)
 
236
                if ebs:
 
237
                    snapshot_id = ebs.get(self.SNAPSHOT_ID)
 
238
                    if not snapshot_id:
 
239
                        msg = _("SnapshotId is missing, this is required "
 
240
                                "when specifying BlockDeviceMappings.")
 
241
                        raise exception.StackValidationFailed(message=msg)
 
242
                else:
 
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)
 
249
        if not 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)
 
256
 
 
257
 
 
258
def resource_mapping():
 
259
    return {
 
260
        'AWS::AutoScaling::LaunchConfiguration': LaunchConfiguration,
 
261
    }