Convert Autoscaling resources to new Schema format
blueprint property-schema-conversion Change-Id: I3caadb7f47816a642bbd0841cc2ba4b2fb33b403
This commit is contained in:
parent
582cf8f047
commit
496264eba2
@ -25,6 +25,7 @@ from heat.common import timeutils as iso8601utils
|
|||||||
from heat.openstack.common import log as logging
|
from heat.openstack.common import log as logging
|
||||||
from heat.openstack.common import timeutils
|
from heat.openstack.common import timeutils
|
||||||
from heat.engine.properties import Properties
|
from heat.engine.properties import Properties
|
||||||
|
from heat.engine import constraints
|
||||||
from heat.engine import properties
|
from heat.engine import properties
|
||||||
from heat.engine import scheduler
|
from heat.engine import scheduler
|
||||||
from heat.engine import stack_resource
|
from heat.engine import stack_resource
|
||||||
@ -63,34 +64,64 @@ class CooldownMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class InstanceGroup(stack_resource.StackResource):
|
class InstanceGroup(stack_resource.StackResource):
|
||||||
tags_schema = {'Key': {'Type': 'String',
|
|
||||||
'Required': True},
|
PROPERTIES = (
|
||||||
'Value': {'Type': 'String',
|
AVAILABILITY_ZONES, LAUNCH_CONFIGURATION_NAME, SIZE,
|
||||||
'Required': True}}
|
LOAD_BALANCER_NAMES, TAGS,
|
||||||
|
) = (
|
||||||
|
'AvailabilityZones', 'LaunchConfigurationName', 'Size',
|
||||||
|
'LoadBalancerNames', 'Tags',
|
||||||
|
)
|
||||||
|
|
||||||
|
_TAG_KEYS = (
|
||||||
|
TAG_KEY, TAG_VALUE,
|
||||||
|
) = (
|
||||||
|
'Key', 'Value',
|
||||||
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
'AvailabilityZones': {
|
AVAILABILITY_ZONES: properties.Schema(
|
||||||
'Required': True,
|
properties.Schema.LIST,
|
||||||
'Type': 'List',
|
_('Not Implemented.'),
|
||||||
'Description': _('Not Implemented.')},
|
required=True
|
||||||
'LaunchConfigurationName': {
|
),
|
||||||
'Required': True,
|
LAUNCH_CONFIGURATION_NAME: properties.Schema(
|
||||||
'Type': 'String',
|
properties.Schema.STRING,
|
||||||
'UpdateAllowed': True,
|
_('Name of LaunchConfiguration resource.'),
|
||||||
'Description': _('Name of LaunchConfiguration resource.')},
|
required=True,
|
||||||
'Size': {
|
update_allowed=True
|
||||||
'Required': True,
|
),
|
||||||
'Type': 'Number',
|
SIZE: properties.Schema(
|
||||||
'UpdateAllowed': True,
|
properties.Schema.NUMBER,
|
||||||
'Description': _('Desired number of instances.')},
|
_('Desired number of instances.'),
|
||||||
'LoadBalancerNames': {
|
required=True,
|
||||||
'Type': 'List',
|
update_allowed=True
|
||||||
'Description': _('List of LoadBalancer resources.')},
|
),
|
||||||
'Tags': {
|
LOAD_BALANCER_NAMES: properties.Schema(
|
||||||
'Type': 'List',
|
properties.Schema.LIST,
|
||||||
'Schema': {'Type': 'Map', 'Schema': tags_schema},
|
_('List of LoadBalancer resources.')
|
||||||
'Description': _('Tags to attach to this group.')}
|
),
|
||||||
|
TAGS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('Tags to attach to this group.'),
|
||||||
|
schema=properties.Schema(
|
||||||
|
properties.Schema.MAP,
|
||||||
|
schema={
|
||||||
|
TAG_KEY: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
TAG_VALUE: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
update_allowed_keys = ('Properties', 'UpdatePolicy',)
|
update_allowed_keys = ('Properties', 'UpdatePolicy',)
|
||||||
|
|
||||||
attributes_schema = {
|
attributes_schema = {
|
||||||
"InstanceList": _("A comma-delimited list of server ip addresses. "
|
"InstanceList": _("A comma-delimited list of server ip addresses. "
|
||||||
"(Heat extension).")
|
"(Heat extension).")
|
||||||
@ -152,7 +183,7 @@ class InstanceGroup(stack_resource.StackResource):
|
|||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
"""Create a nested stack and add the initial resources to it."""
|
"""Create a nested stack and add the initial resources to it."""
|
||||||
num_instances = int(self.properties['Size'])
|
num_instances = int(self.properties[self.SIZE])
|
||||||
initial_template = self._create_template(num_instances)
|
initial_template = self._create_template(num_instances)
|
||||||
return self.create_with_template(initial_template, {})
|
return self.create_with_template(initial_template, {})
|
||||||
|
|
||||||
@ -188,7 +219,7 @@ class InstanceGroup(stack_resource.StackResource):
|
|||||||
|
|
||||||
# Replace instances first if launch configuration has changed
|
# Replace instances first if launch configuration has changed
|
||||||
if (self.update_policy['RollingUpdate'] and
|
if (self.update_policy['RollingUpdate'] and
|
||||||
'LaunchConfigurationName' in prop_diff):
|
self.LAUNCH_CONFIGURATION_NAME in prop_diff):
|
||||||
policy = self.update_policy['RollingUpdate']
|
policy = self.update_policy['RollingUpdate']
|
||||||
self._replace(int(policy['MinInstancesInService']),
|
self._replace(int(policy['MinInstancesInService']),
|
||||||
int(policy['MaxBatchSize']),
|
int(policy['MaxBatchSize']),
|
||||||
@ -196,29 +227,29 @@ class InstanceGroup(stack_resource.StackResource):
|
|||||||
|
|
||||||
# Get the current capacity, we may need to adjust if
|
# Get the current capacity, we may need to adjust if
|
||||||
# Size has changed
|
# Size has changed
|
||||||
if 'Size' in prop_diff:
|
if self.SIZE in prop_diff:
|
||||||
inst_list = self.get_instances()
|
inst_list = self.get_instances()
|
||||||
if len(inst_list) != int(self.properties['Size']):
|
if len(inst_list) != int(self.properties[self.SIZE]):
|
||||||
self.resize(int(self.properties['Size']))
|
self.resize(int(self.properties[self.SIZE]))
|
||||||
|
|
||||||
def _tags(self):
|
def _tags(self):
|
||||||
"""
|
"""
|
||||||
Make sure that we add a tag that Ceilometer can pick up.
|
Make sure that we add a tag that Ceilometer can pick up.
|
||||||
These need to be prepended with 'metering.'.
|
These need to be prepended with 'metering.'.
|
||||||
"""
|
"""
|
||||||
tags = self.properties.get('Tags') or []
|
tags = self.properties.get(self.TAGS) or []
|
||||||
for t in tags:
|
for t in tags:
|
||||||
if t['Key'].startswith('metering.'):
|
if t[self.TAG_KEY].startswith('metering.'):
|
||||||
# the user has added one, don't add another.
|
# the user has added one, don't add another.
|
||||||
return tags
|
return tags
|
||||||
return tags + [{'Key': 'metering.groupname',
|
return tags + [{self.TAG_KEY: 'metering.groupname',
|
||||||
'Value': self.FnGetRefId()}]
|
self.TAG_VALUE: self.FnGetRefId()}]
|
||||||
|
|
||||||
def handle_delete(self):
|
def handle_delete(self):
|
||||||
return self.delete_nested()
|
return self.delete_nested()
|
||||||
|
|
||||||
def _get_instance_definition(self):
|
def _get_instance_definition(self):
|
||||||
conf_name = self.properties['LaunchConfigurationName']
|
conf_name = self.properties[self.LAUNCH_CONFIGURATION_NAME]
|
||||||
conf = self.stack.resource_by_refid(conf_name)
|
conf = self.stack.resource_by_refid(conf_name)
|
||||||
instance_definition = copy.deepcopy(conf.t)
|
instance_definition = copy.deepcopy(conf.t)
|
||||||
instance_definition['Type'] = 'AWS::EC2::Instance'
|
instance_definition['Type'] = 'AWS::EC2::Instance'
|
||||||
@ -331,10 +362,10 @@ class InstanceGroup(stack_resource.StackResource):
|
|||||||
This must be done after activation (instance in ACTIVE state),
|
This must be done after activation (instance in ACTIVE state),
|
||||||
otherwise the instances' IP addresses may not be available.
|
otherwise the instances' IP addresses may not be available.
|
||||||
'''
|
'''
|
||||||
if self.properties['LoadBalancerNames']:
|
if self.properties[self.LOAD_BALANCER_NAMES]:
|
||||||
id_list = [inst.FnGetRefId() for inst in self.get_instances()
|
id_list = [inst.FnGetRefId() for inst in self.get_instances()
|
||||||
if inst.FnGetRefId() not in exclude]
|
if inst.FnGetRefId() not in exclude]
|
||||||
for lb in self.properties['LoadBalancerNames']:
|
for lb in self.properties[self.LOAD_BALANCER_NAMES]:
|
||||||
lb_resource = self.stack[lb]
|
lb_resource = self.stack[lb]
|
||||||
if 'Instances' in lb_resource.properties_schema:
|
if 'Instances' in lb_resource.properties_schema:
|
||||||
lb_resource.json_snippet['Properties']['Instances'] = (
|
lb_resource.json_snippet['Properties']['Instances'] = (
|
||||||
@ -364,58 +395,97 @@ class InstanceGroup(stack_resource.StackResource):
|
|||||||
|
|
||||||
|
|
||||||
class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
||||||
tags_schema = {'Key': {'Type': 'String',
|
|
||||||
'Required': True},
|
PROPERTIES = (
|
||||||
'Value': {'Type': 'String',
|
AVAILABILITY_ZONES, LAUNCH_CONFIGURATION_NAME, MAX_SIZE, MIN_SIZE,
|
||||||
'Required': True}}
|
COOLDOWN, DESIRED_CAPACITY, HEALTH_CHECK_GRACE_PERIOD,
|
||||||
|
HEALTH_CHECK_TYPE, LOAD_BALANCER_NAMES, VPCZONE_IDENTIFIER, TAGS,
|
||||||
|
) = (
|
||||||
|
'AvailabilityZones', 'LaunchConfigurationName', 'MaxSize', 'MinSize',
|
||||||
|
'Cooldown', 'DesiredCapacity', 'HealthCheckGracePeriod',
|
||||||
|
'HealthCheckType', 'LoadBalancerNames', 'VPCZoneIdentifier', 'Tags',
|
||||||
|
)
|
||||||
|
|
||||||
|
_TAG_KEYS = (
|
||||||
|
TAG_KEY, TAG_VALUE,
|
||||||
|
) = (
|
||||||
|
'Key', 'Value',
|
||||||
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
'AvailabilityZones': {
|
AVAILABILITY_ZONES: properties.Schema(
|
||||||
'Required': True,
|
properties.Schema.LIST,
|
||||||
'Type': 'List',
|
_('Not Implemented.'),
|
||||||
'Description': _('Not Implemented.')},
|
required=True
|
||||||
'LaunchConfigurationName': {
|
),
|
||||||
'Required': True,
|
LAUNCH_CONFIGURATION_NAME: properties.Schema(
|
||||||
'Type': 'String',
|
properties.Schema.STRING,
|
||||||
'UpdateAllowed': True,
|
_('Name of LaunchConfiguration resource.'),
|
||||||
'Description': _('Name of LaunchConfiguration resource.')},
|
required=True,
|
||||||
'MaxSize': {
|
update_allowed=True
|
||||||
'Required': True,
|
),
|
||||||
'Type': 'String',
|
MAX_SIZE: properties.Schema(
|
||||||
'UpdateAllowed': True,
|
properties.Schema.STRING,
|
||||||
'Description': _('Maximum number of instances in the group.')},
|
_('Maximum number of instances in the group.'),
|
||||||
'MinSize': {
|
required=True,
|
||||||
'Required': True,
|
update_allowed=True
|
||||||
'UpdateAllowed': True,
|
),
|
||||||
'Type': 'String',
|
MIN_SIZE: properties.Schema(
|
||||||
'Description': _('Minimum number of instances in the group.')},
|
properties.Schema.STRING,
|
||||||
'Cooldown': {
|
_('Minimum number of instances in the group.'),
|
||||||
'Type': 'String',
|
required=True,
|
||||||
'UpdateAllowed': True,
|
update_allowed=True
|
||||||
'Description': _('Cooldown period, in seconds.')},
|
),
|
||||||
'DesiredCapacity': {
|
COOLDOWN: properties.Schema(
|
||||||
'Type': 'Number',
|
properties.Schema.STRING,
|
||||||
'UpdateAllowed': True,
|
_('Cooldown period, in seconds.'),
|
||||||
'Description': _('Desired initial number of instances.')},
|
update_allowed=True
|
||||||
'HealthCheckGracePeriod': {
|
),
|
||||||
'Type': 'Integer',
|
DESIRED_CAPACITY: properties.Schema(
|
||||||
'Implemented': False,
|
properties.Schema.NUMBER,
|
||||||
'Description': _('Not Implemented.')},
|
_('Desired initial number of instances.'),
|
||||||
'HealthCheckType': {
|
update_allowed=True
|
||||||
'Type': 'String',
|
),
|
||||||
'AllowedValues': ['EC2', 'ELB'],
|
HEALTH_CHECK_GRACE_PERIOD: properties.Schema(
|
||||||
'Implemented': False,
|
properties.Schema.INTEGER,
|
||||||
'Description': _('Not Implemented.')},
|
_('Not Implemented.'),
|
||||||
'LoadBalancerNames': {
|
implemented=False
|
||||||
'Type': 'List',
|
),
|
||||||
'Description': _('List of LoadBalancer resources.')},
|
HEALTH_CHECK_TYPE: properties.Schema(
|
||||||
'VPCZoneIdentifier': {
|
properties.Schema.STRING,
|
||||||
'Type': 'List',
|
_('Not Implemented.'),
|
||||||
'Description': _('List of VPC subnet identifiers.')},
|
constraints=[
|
||||||
'Tags': {
|
constraints.AllowedValues(['EC2', 'ELB']),
|
||||||
'Type': 'List',
|
],
|
||||||
'Schema': {'Type': 'Map', 'Schema': tags_schema},
|
implemented=False
|
||||||
'Description': _('Tags to attach to this group.')}
|
),
|
||||||
|
LOAD_BALANCER_NAMES: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('List of LoadBalancer resources.')
|
||||||
|
),
|
||||||
|
VPCZONE_IDENTIFIER: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('List of VPC subnet identifiers.')
|
||||||
|
),
|
||||||
|
TAGS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('Tags to attach to this group.'),
|
||||||
|
schema=properties.Schema(
|
||||||
|
properties.Schema.MAP,
|
||||||
|
schema={
|
||||||
|
TAG_KEY: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
TAG_VALUE: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
rolling_update_schema = {
|
rolling_update_schema = {
|
||||||
'MinInstancesInService': properties.Schema(properties.Schema.NUMBER,
|
'MinInstancesInService': properties.Schema(properties.Schema.NUMBER,
|
||||||
default=0),
|
default=0),
|
||||||
@ -428,13 +498,14 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
schema=
|
schema=
|
||||||
rolling_update_schema)
|
rolling_update_schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
update_allowed_keys = ('Properties', 'UpdatePolicy')
|
update_allowed_keys = ('Properties', 'UpdatePolicy')
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
if self.properties['DesiredCapacity']:
|
if self.properties[self.DESIRED_CAPACITY]:
|
||||||
num_to_create = int(self.properties['DesiredCapacity'])
|
num_to_create = int(self.properties[self.DESIRED_CAPACITY])
|
||||||
else:
|
else:
|
||||||
num_to_create = int(self.properties['MinSize'])
|
num_to_create = int(self.properties[self.MIN_SIZE])
|
||||||
initial_template = self._create_template(num_to_create)
|
initial_template = self._create_template(num_to_create)
|
||||||
return self.create_with_template(initial_template, {})
|
return self.create_with_template(initial_template, {})
|
||||||
|
|
||||||
@ -479,15 +550,15 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
|
|
||||||
# Figure out if an adjustment is required
|
# Figure out if an adjustment is required
|
||||||
new_capacity = None
|
new_capacity = None
|
||||||
if 'MinSize' in prop_diff:
|
if self.MIN_SIZE in prop_diff:
|
||||||
if capacity < int(self.properties['MinSize']):
|
if capacity < int(self.properties[self.MIN_SIZE]):
|
||||||
new_capacity = int(self.properties['MinSize'])
|
new_capacity = int(self.properties[self.MIN_SIZE])
|
||||||
if 'MaxSize' in prop_diff:
|
if self.MAX_SIZE in prop_diff:
|
||||||
if capacity > int(self.properties['MaxSize']):
|
if capacity > int(self.properties[self.MAX_SIZE]):
|
||||||
new_capacity = int(self.properties['MaxSize'])
|
new_capacity = int(self.properties[self.MAX_SIZE])
|
||||||
if 'DesiredCapacity' in prop_diff:
|
if self.DESIRED_CAPACITY in prop_diff:
|
||||||
if self.properties['DesiredCapacity']:
|
if self.properties[self.DESIRED_CAPACITY]:
|
||||||
new_capacity = int(self.properties['DesiredCapacity'])
|
new_capacity = int(self.properties[self.DESIRED_CAPACITY])
|
||||||
|
|
||||||
if new_capacity is not None:
|
if new_capacity is not None:
|
||||||
self.adjust(new_capacity, adjustment_type='ExactCapacity')
|
self.adjust(new_capacity, adjustment_type='ExactCapacity')
|
||||||
@ -500,7 +571,7 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
logger.info(_("%(name)s NOT performing scaling adjustment, "
|
logger.info(_("%(name)s NOT performing scaling adjustment, "
|
||||||
"cooldown %(cooldown)s") % {
|
"cooldown %(cooldown)s") % {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'cooldown': self.properties['Cooldown']})
|
'cooldown': self.properties[self.COOLDOWN]})
|
||||||
return
|
return
|
||||||
|
|
||||||
capacity = len(self.get_instances())
|
capacity = len(self.get_instances())
|
||||||
@ -519,8 +590,8 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
else math.ceil(delta))
|
else math.ceil(delta))
|
||||||
new_capacity = capacity + rounded
|
new_capacity = capacity + rounded
|
||||||
|
|
||||||
upper = int(self.properties['MaxSize'])
|
upper = int(self.properties[self.MAX_SIZE])
|
||||||
lower = int(self.properties['MinSize'])
|
lower = int(self.properties[self.MIN_SIZE])
|
||||||
|
|
||||||
if new_capacity > upper:
|
if new_capacity > upper:
|
||||||
if upper > capacity:
|
if upper > capacity:
|
||||||
@ -554,8 +625,8 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
the groupname and stack id.
|
the groupname and stack id.
|
||||||
Note: the group name must match what is returned from FnGetRefId
|
Note: the group name must match what is returned from FnGetRefId
|
||||||
"""
|
"""
|
||||||
autoscaling_tag = [{'Key': 'AutoScalingGroupName',
|
autoscaling_tag = [{self.TAG_KEY: 'AutoScalingGroupName',
|
||||||
'Value': self.FnGetRefId()}]
|
self.TAG_VALUE: self.FnGetRefId()}]
|
||||||
return super(AutoScalingGroup, self)._tags() + autoscaling_tag
|
return super(AutoScalingGroup, self)._tags() + autoscaling_tag
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -567,52 +638,83 @@ class AutoScalingGroup(InstanceGroup, CooldownMixin):
|
|||||||
# availability zones, it will be possible to specify multiple subnets.
|
# availability zones, it will be possible to specify multiple subnets.
|
||||||
# For now, only one subnet can be specified. The bug #1096017 tracks
|
# For now, only one subnet can be specified. The bug #1096017 tracks
|
||||||
# this issue.
|
# this issue.
|
||||||
if self.properties.get('VPCZoneIdentifier') and \
|
if self.properties.get(self.VPCZONE_IDENTIFIER) and \
|
||||||
len(self.properties['VPCZoneIdentifier']) != 1:
|
len(self.properties[self.VPCZONE_IDENTIFIER]) != 1:
|
||||||
raise exception.NotSupported(feature=_("Anything other than one "
|
raise exception.NotSupported(feature=_("Anything other than one "
|
||||||
"VPCZoneIdentifier"))
|
"VPCZoneIdentifier"))
|
||||||
|
|
||||||
|
|
||||||
class LaunchConfiguration(resource.Resource):
|
class LaunchConfiguration(resource.Resource):
|
||||||
tags_schema = {'Key': {'Type': 'String',
|
|
||||||
'Required': True},
|
PROPERTIES = (
|
||||||
'Value': {'Type': 'String',
|
IMAGE_ID, INSTANCE_TYPE, KEY_NAME, USER_DATA, SECURITY_GROUPS,
|
||||||
'Required': True}}
|
KERNEL_ID, RAM_DISK_ID, BLOCK_DEVICE_MAPPINGS, NOVA_SCHEDULER_HINTS,
|
||||||
|
) = (
|
||||||
|
'ImageId', 'InstanceType', 'KeyName', 'UserData', 'SecurityGroups',
|
||||||
|
'KernelId', 'RamDiskId', 'BlockDeviceMappings', 'NovaSchedulerHints',
|
||||||
|
)
|
||||||
|
|
||||||
|
_NOVA_SCHEDULER_HINT_KEYS = (
|
||||||
|
NOVA_SCHEDULER_HINT_KEY, NOVA_SCHEDULER_HINT_VALUE,
|
||||||
|
) = (
|
||||||
|
'Key', 'Value',
|
||||||
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
'ImageId': {
|
IMAGE_ID: properties.Schema(
|
||||||
'Type': 'String',
|
properties.Schema.STRING,
|
||||||
'Required': True,
|
_('Glance image ID or name.'),
|
||||||
'Description': _('Glance image ID or name.')},
|
required=True
|
||||||
'InstanceType': {
|
),
|
||||||
'Type': 'String',
|
INSTANCE_TYPE: properties.Schema(
|
||||||
'Required': True,
|
properties.Schema.STRING,
|
||||||
'Description': _('Nova instance type (flavor).')},
|
_('Nova instance type (flavor).'),
|
||||||
'KeyName': {
|
required=True
|
||||||
'Type': 'String',
|
),
|
||||||
'Description': _('Optional Nova keypair name.')},
|
KEY_NAME: properties.Schema(
|
||||||
'UserData': {
|
properties.Schema.STRING,
|
||||||
'Type': 'String',
|
_('Optional Nova keypair name.')
|
||||||
'Description': _('User data to pass to instance.')},
|
),
|
||||||
'SecurityGroups': {
|
USER_DATA: properties.Schema(
|
||||||
'Type': 'List',
|
properties.Schema.STRING,
|
||||||
'Description': _('Security group names to assign.')},
|
_('User data to pass to instance.')
|
||||||
'KernelId': {
|
),
|
||||||
'Type': 'String',
|
SECURITY_GROUPS: properties.Schema(
|
||||||
'Implemented': False,
|
properties.Schema.LIST,
|
||||||
'Description': _('Not Implemented.')},
|
_('Security group names to assign.')
|
||||||
'RamDiskId': {
|
),
|
||||||
'Type': 'String',
|
KERNEL_ID: properties.Schema(
|
||||||
'Implemented': False,
|
properties.Schema.STRING,
|
||||||
'Description': _('Not Implemented.')},
|
_('Not Implemented.'),
|
||||||
'BlockDeviceMappings': {
|
implemented=False
|
||||||
'Type': 'String',
|
),
|
||||||
'Implemented': False,
|
RAM_DISK_ID: properties.Schema(
|
||||||
'Description': _('Not Implemented.')},
|
properties.Schema.STRING,
|
||||||
'NovaSchedulerHints': {
|
_('Not Implemented.'),
|
||||||
'Type': 'List',
|
implemented=False
|
||||||
'Schema': {'Type': 'Map', 'Schema': tags_schema},
|
),
|
||||||
'Description': _('Scheduler hints to pass '
|
BLOCK_DEVICE_MAPPINGS: properties.Schema(
|
||||||
'to Nova (Heat extension).')},
|
properties.Schema.STRING,
|
||||||
|
_('Not Implemented.'),
|
||||||
|
implemented=False
|
||||||
|
),
|
||||||
|
NOVA_SCHEDULER_HINTS: properties.Schema(
|
||||||
|
properties.Schema.LIST,
|
||||||
|
_('Scheduler hints to pass to Nova (Heat extension).'),
|
||||||
|
schema=properties.Schema(
|
||||||
|
properties.Schema.MAP,
|
||||||
|
schema={
|
||||||
|
NOVA_SCHEDULER_HINT_KEY: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
NOVA_SCHEDULER_HINT_VALUE: properties.Schema(
|
||||||
|
properties.Schema.STRING,
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def FnGetRefId(self):
|
def FnGetRefId(self):
|
||||||
@ -620,31 +722,46 @@ class LaunchConfiguration(resource.Resource):
|
|||||||
|
|
||||||
|
|
||||||
class ScalingPolicy(signal_responder.SignalResponder, CooldownMixin):
|
class ScalingPolicy(signal_responder.SignalResponder, CooldownMixin):
|
||||||
|
PROPERTIES = (
|
||||||
|
AUTO_SCALING_GROUP_NAME, SCALING_ADJUSTMENT, ADJUSTMENT_TYPE,
|
||||||
|
COOLDOWN,
|
||||||
|
) = (
|
||||||
|
'AutoScalingGroupName', 'ScalingAdjustment', 'AdjustmentType',
|
||||||
|
'Cooldown',
|
||||||
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
'AutoScalingGroupName': {
|
AUTO_SCALING_GROUP_NAME: properties.Schema(
|
||||||
'Type': 'String',
|
properties.Schema.STRING,
|
||||||
'Required': True,
|
_('AutoScaling group name to apply policy to.'),
|
||||||
'Description': _('AutoScaling group name to apply policy to.')},
|
required=True
|
||||||
'ScalingAdjustment': {
|
),
|
||||||
'Type': 'Number',
|
SCALING_ADJUSTMENT: properties.Schema(
|
||||||
'Required': True,
|
properties.Schema.NUMBER,
|
||||||
'UpdateAllowed': True,
|
_('Size of adjustment.'),
|
||||||
'Description': _('Size of adjustment.')},
|
required=True,
|
||||||
'AdjustmentType': {
|
update_allowed=True
|
||||||
'Type': 'String',
|
),
|
||||||
'AllowedValues': ['ChangeInCapacity',
|
ADJUSTMENT_TYPE: properties.Schema(
|
||||||
'ExactCapacity',
|
properties.Schema.STRING,
|
||||||
'PercentChangeInCapacity'],
|
_('Type of adjustment (absolute or percentage).'),
|
||||||
'Required': True,
|
required=True,
|
||||||
'UpdateAllowed': True,
|
constraints=[
|
||||||
'Description': _('Type of adjustment (absolute or percentage).')},
|
constraints.AllowedValues(['ChangeInCapacity',
|
||||||
'Cooldown': {
|
'ExactCapacity',
|
||||||
'Type': 'Number',
|
'PercentChangeInCapacity']),
|
||||||
'UpdateAllowed': True,
|
],
|
||||||
'Description': _('Cooldown period, in seconds.')},
|
update_allowed=True
|
||||||
|
),
|
||||||
|
COOLDOWN: properties.Schema(
|
||||||
|
properties.Schema.NUMBER,
|
||||||
|
_('Cooldown period, in seconds.'),
|
||||||
|
update_allowed=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
update_allowed_keys = ('Properties',)
|
update_allowed_keys = ('Properties',)
|
||||||
|
|
||||||
attributes_schema = {
|
attributes_schema = {
|
||||||
"AlarmUrl": _("A signed url to handle the alarm. "
|
"AlarmUrl": _("A signed url to handle the alarm. "
|
||||||
"(Heat extension).")
|
"(Heat extension).")
|
||||||
@ -685,22 +802,22 @@ class ScalingPolicy(signal_responder.SignalResponder, CooldownMixin):
|
|||||||
logger.info(_("%(name)s NOT performing scaling action, "
|
logger.info(_("%(name)s NOT performing scaling action, "
|
||||||
"cooldown %(cooldown)s") % {
|
"cooldown %(cooldown)s") % {
|
||||||
'name': self.name,
|
'name': self.name,
|
||||||
'cooldown': self.properties['Cooldown']})
|
'cooldown': self.properties[self.COOLDOWN]})
|
||||||
return
|
return
|
||||||
|
|
||||||
asgn_id = self.properties['AutoScalingGroupName']
|
asgn_id = self.properties[self.AUTO_SCALING_GROUP_NAME]
|
||||||
group = self.stack.resource_by_refid(asgn_id)
|
group = self.stack.resource_by_refid(asgn_id)
|
||||||
|
|
||||||
logger.info(_('%(name)s Alarm, adjusting Group %(group)s '
|
logger.info(_('%(name)s Alarm, adjusting Group %(group)s '
|
||||||
'by %(filter)s') % {
|
'by %(filter)s') % {
|
||||||
'name': self.name, 'group': group.name,
|
'name': self.name, 'group': group.name,
|
||||||
'filter': self.properties['ScalingAdjustment']})
|
'filter': self.properties[self.SCALING_ADJUSTMENT]})
|
||||||
group.adjust(int(self.properties['ScalingAdjustment']),
|
group.adjust(int(self.properties[self.SCALING_ADJUSTMENT]),
|
||||||
self.properties['AdjustmentType'])
|
self.properties[self.ADJUSTMENT_TYPE])
|
||||||
|
|
||||||
self._cooldown_timestamp("%s : %s" %
|
self._cooldown_timestamp("%s : %s" %
|
||||||
(self.properties['AdjustmentType'],
|
(self.properties[self.ADJUSTMENT_TYPE],
|
||||||
self.properties['ScalingAdjustment']))
|
self.properties[self.SCALING_ADJUSTMENT]))
|
||||||
|
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
'''
|
'''
|
||||||
|
@ -42,40 +42,51 @@ class ResourceGroup(stack_resource.StackResource):
|
|||||||
"resource.[index].[attribute name]"
|
"resource.[index].[attribute name]"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
min_resource_schema = {
|
PROPERTIES = (
|
||||||
"type": properties.Schema(
|
COUNT, RESOURCE_DEF,
|
||||||
properties.Schema.STRING,
|
) = (
|
||||||
_("The type of the resources in the group"),
|
'count', 'resource_def',
|
||||||
required=True
|
)
|
||||||
),
|
|
||||||
"properties": properties.Schema(
|
_RESOURCE_DEF_KEYS = (
|
||||||
properties.Schema.MAP,
|
RESOURCE_DEF_TYPE, RESOURCE_DEF_PROPERTIES,
|
||||||
_("Property values for the resources in the group")
|
) = (
|
||||||
)
|
'type', 'properties',
|
||||||
}
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
"count": properties.Schema(
|
COUNT: properties.Schema(
|
||||||
properties.Schema.INTEGER,
|
properties.Schema.INTEGER,
|
||||||
_("The number of instances to create."),
|
_('The number of instances to create.'),
|
||||||
default=1,
|
default=1,
|
||||||
required=True,
|
required=True,
|
||||||
update_allowed=True,
|
|
||||||
constraints=[
|
constraints=[
|
||||||
constraints.Range(1)
|
constraints.Range(min=1),
|
||||||
]
|
],
|
||||||
|
update_allowed=True
|
||||||
),
|
),
|
||||||
"resource_def": properties.Schema(
|
RESOURCE_DEF: properties.Schema(
|
||||||
properties.Schema.MAP,
|
properties.Schema.MAP,
|
||||||
_("Resource definition for the resources in the group. The value "
|
_('Resource definition for the resources in the group. The value '
|
||||||
"of this property is the definition of a resource just as if it"
|
'of this property is the definition of a resource just as if '
|
||||||
" had been declared in the template itself."),
|
'it had been declared in the template itself.'),
|
||||||
required=True,
|
schema={
|
||||||
schema=min_resource_schema
|
RESOURCE_DEF_TYPE: properties.Schema(
|
||||||
)
|
properties.Schema.STRING,
|
||||||
|
_('The type of the resources in the group'),
|
||||||
|
required=True
|
||||||
|
),
|
||||||
|
RESOURCE_DEF_PROPERTIES: properties.Schema(
|
||||||
|
properties.Schema.MAP,
|
||||||
|
_('Property values for the resources in the group')
|
||||||
|
),
|
||||||
|
},
|
||||||
|
required=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes_schema = {}
|
attributes_schema = {}
|
||||||
|
|
||||||
update_allowed_keys = ("Properties",)
|
update_allowed_keys = ("Properties",)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -91,7 +102,7 @@ class ResourceGroup(stack_resource.StackResource):
|
|||||||
res_inst.validate()
|
res_inst.validate()
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
count = self.properties['count']
|
count = self.properties[self.COUNT]
|
||||||
return self.create_with_template(self._assemble_nested(count),
|
return self.create_with_template(self._assemble_nested(count),
|
||||||
{},
|
{},
|
||||||
self.stack.timeout_mins)
|
self.stack.timeout_mins)
|
||||||
@ -119,15 +130,15 @@ class ResourceGroup(stack_resource.StackResource):
|
|||||||
return res.FnGetAtt(attr_name)
|
return res.FnGetAtt(attr_name)
|
||||||
else:
|
else:
|
||||||
return [self.nested()[str(v)].FnGetAtt(key) for v
|
return [self.nested()[str(v)].FnGetAtt(key) for v
|
||||||
in range(self.properties['count'])]
|
in range(self.properties[self.COUNT])]
|
||||||
|
|
||||||
def _assemble_nested(self, count, include_all=False):
|
def _assemble_nested(self, count, include_all=False):
|
||||||
child_template = copy.deepcopy(template_template)
|
child_template = copy.deepcopy(template_template)
|
||||||
resource_def = self.properties['resource_def']
|
resource_def = self.properties[self.RESOURCE_DEF]
|
||||||
if not include_all:
|
if not include_all:
|
||||||
clean = dict((k, v) for k, v
|
resource_def_props = resource_def[self.RESOURCE_DEF_PROPERTIES]
|
||||||
in resource_def['properties'].items() if v)
|
clean = dict((k, v) for k, v in resource_def_props.items() if v)
|
||||||
resource_def['properties'] = clean
|
resource_def[self.RESOURCE_DEF_PROPERTIES] = clean
|
||||||
resources = dict((str(k), resource_def)
|
resources = dict((str(k), resource_def)
|
||||||
for k in range(count))
|
for k in range(count))
|
||||||
child_template['resources'] = resources
|
child_template['resources'] = resources
|
||||||
|
Loading…
Reference in New Issue
Block a user