Improvements - Autoscaling (#4985)

This commit is contained in:
Bert Blommers 2022-03-29 21:46:06 +00:00 committed by GitHub
parent c134afaf60
commit cf2690ca1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 568 additions and 156 deletions

View File

@ -338,7 +338,7 @@
## autoscaling ## autoscaling
<details> <details>
<summary>47% implemented</summary> <summary>49% implemented</summary>
- [X] attach_instances - [X] attach_instances
- [X] attach_load_balancer_target_groups - [X] attach_load_balancer_target_groups
@ -389,7 +389,7 @@
- [ ] get_predictive_scaling_forecast - [ ] get_predictive_scaling_forecast
- [ ] put_lifecycle_hook - [ ] put_lifecycle_hook
- [ ] put_notification_configuration - [ ] put_notification_configuration
- [ ] put_scaling_policy - [X] put_scaling_policy
- [ ] put_scheduled_update_group_action - [ ] put_scheduled_update_group_action
- [ ] put_warm_pool - [ ] put_warm_pool
- [ ] record_lifecycle_action_heartbeat - [ ] record_lifecycle_action_heartbeat
@ -1547,7 +1547,7 @@
- [ ] delete_ipam_pool - [ ] delete_ipam_pool
- [ ] delete_ipam_scope - [ ] delete_ipam_scope
- [X] delete_key_pair - [X] delete_key_pair
- [ ] delete_launch_template - [X] delete_launch_template
- [ ] delete_launch_template_versions - [ ] delete_launch_template_versions
- [ ] delete_local_gateway_route - [ ] delete_local_gateway_route
- [ ] delete_local_gateway_route_table_vpc_association - [ ] delete_local_gateway_route_table_vpc_association

View File

@ -79,7 +79,7 @@ autoscaling
- [ ] get_predictive_scaling_forecast - [ ] get_predictive_scaling_forecast
- [ ] put_lifecycle_hook - [ ] put_lifecycle_hook
- [ ] put_notification_configuration - [ ] put_notification_configuration
- [ ] put_scaling_policy - [X] put_scaling_policy
- [ ] put_scheduled_update_group_action - [ ] put_scheduled_update_group_action
- [ ] put_warm_pool - [ ] put_warm_pool
- [ ] record_lifecycle_action_heartbeat - [ ] record_lifecycle_action_heartbeat

View File

@ -163,7 +163,7 @@ ec2
- [ ] delete_ipam_pool - [ ] delete_ipam_pool
- [ ] delete_ipam_scope - [ ] delete_ipam_scope
- [X] delete_key_pair - [X] delete_key_pair
- [ ] delete_launch_template - [X] delete_launch_template
- [ ] delete_launch_template_versions - [ ] delete_launch_template_versions
- [ ] delete_local_gateway_route - [ ] delete_local_gateway_route
- [ ] delete_local_gateway_route_table_vpc_association - [ ] delete_local_gateway_route_table_vpc_association

View File

@ -66,18 +66,24 @@ class FakeScalingPolicy(BaseModel):
self, self,
name, name,
policy_type, policy_type,
metric_aggregation_type,
adjustment_type, adjustment_type,
as_name, as_name,
min_adjustment_magnitude,
scaling_adjustment, scaling_adjustment,
cooldown, cooldown,
target_tracking_config, target_tracking_config,
step_adjustments, step_adjustments,
estimated_instance_warmup,
predictive_scaling_configuration,
autoscaling_backend, autoscaling_backend,
): ):
self.name = name self.name = name
self.policy_type = policy_type self.policy_type = policy_type
self.metric_aggregation_type = metric_aggregation_type
self.adjustment_type = adjustment_type self.adjustment_type = adjustment_type
self.as_name = as_name self.as_name = as_name
self.min_adjustment_magnitude = min_adjustment_magnitude
self.scaling_adjustment = scaling_adjustment self.scaling_adjustment = scaling_adjustment
if cooldown is not None: if cooldown is not None:
self.cooldown = cooldown self.cooldown = cooldown
@ -85,6 +91,8 @@ class FakeScalingPolicy(BaseModel):
self.cooldown = DEFAULT_COOLDOWN self.cooldown = DEFAULT_COOLDOWN
self.target_tracking_config = target_tracking_config self.target_tracking_config = target_tracking_config
self.step_adjustments = step_adjustments self.step_adjustments = step_adjustments
self.estimated_instance_warmup = estimated_instance_warmup
self.predictive_scaling_configuration = predictive_scaling_configuration
self.autoscaling_backend = autoscaling_backend self.autoscaling_backend = autoscaling_backend
@property @property
@ -390,7 +398,7 @@ class FakeAutoScalingGroup(CloudFormationModel):
self.launch_template = self.ec2_backend.get_launch_template_by_name( self.launch_template = self.ec2_backend.get_launch_template_by_name(
launch_template_name launch_template_name
) )
self.launch_template_version = int(launch_template["version"]) self.launch_template_version = launch_template["version"]
@staticmethod @staticmethod
def __set_string_propagate_at_launch_booleans_on_tags(tags): def __set_string_propagate_at_launch_booleans_on_tags(tags):
@ -963,27 +971,35 @@ class AutoScalingBackend(BaseBackend):
def delete_lifecycle_hook(self, as_name, name): def delete_lifecycle_hook(self, as_name, name):
self.lifecycle_hooks.pop("%s_%s" % (as_name, name), None) self.lifecycle_hooks.pop("%s_%s" % (as_name, name), None)
def create_autoscaling_policy( def put_scaling_policy(
self, self,
name, name,
policy_type, policy_type,
metric_aggregation_type,
adjustment_type, adjustment_type,
as_name, as_name,
min_adjustment_magnitude,
scaling_adjustment, scaling_adjustment,
cooldown, cooldown,
target_tracking_config, target_tracking_config,
step_adjustments, step_adjustments,
estimated_instance_warmup,
predictive_scaling_configuration,
): ):
policy = FakeScalingPolicy( policy = FakeScalingPolicy(
name, name,
policy_type, policy_type,
adjustment_type, metric_aggregation_type,
as_name, adjustment_type=adjustment_type,
scaling_adjustment, as_name=as_name,
cooldown, min_adjustment_magnitude=min_adjustment_magnitude,
target_tracking_config, scaling_adjustment=scaling_adjustment,
step_adjustments, cooldown=cooldown,
self, target_tracking_config=target_tracking_config,
step_adjustments=step_adjustments,
estimated_instance_warmup=estimated_instance_warmup,
predictive_scaling_configuration=predictive_scaling_configuration,
autoscaling_backend=self,
) )
self.policies[name] = policy self.policies[name] = policy

View File

@ -268,15 +268,21 @@ class AutoScalingResponse(BaseResponse):
def put_scaling_policy(self): def put_scaling_policy(self):
params = self._get_params() params = self._get_params()
policy = self.autoscaling_backend.create_autoscaling_policy( policy = self.autoscaling_backend.put_scaling_policy(
name=params.get("PolicyName"), name=params.get("PolicyName"),
policy_type=params.get("PolicyType", "SimpleScaling"), policy_type=params.get("PolicyType", "SimpleScaling"),
metric_aggregation_type=params.get("MetricAggregationType"),
adjustment_type=params.get("AdjustmentType"), adjustment_type=params.get("AdjustmentType"),
as_name=params.get("AutoScalingGroupName"), as_name=params.get("AutoScalingGroupName"),
min_adjustment_magnitude=params.get("MinAdjustmentMagnitude"),
scaling_adjustment=self._get_int_param("ScalingAdjustment"), scaling_adjustment=self._get_int_param("ScalingAdjustment"),
cooldown=self._get_int_param("Cooldown"), cooldown=self._get_int_param("Cooldown"),
target_tracking_config=params.get("TargetTrackingConfiguration", {}), target_tracking_config=params.get("TargetTrackingConfiguration", {}),
step_adjustments=params.get("StepAdjustments", []), step_adjustments=params.get("StepAdjustments", []),
estimated_instance_warmup=params.get("EstimatedInstanceWarmup"),
predictive_scaling_configuration=params.get(
"PredictiveScalingConfiguration", {}
),
) )
template = self.response_template(CREATE_SCALING_POLICY_TEMPLATE) template = self.response_template(CREATE_SCALING_POLICY_TEMPLATE)
return template.render(policy=policy) return template.render(policy=policy)
@ -441,7 +447,7 @@ DESCRIBE_LAUNCH_CONFIGURATIONS_TEMPLATE = """<DescribeLaunchConfigurationsRespon
<LaunchConfigurations> <LaunchConfigurations>
{% for launch_configuration in launch_configurations %} {% for launch_configuration in launch_configurations %}
<member> <member>
<AssociatePublicIpAddress>{{ launch_configuration.associate_public_ip_address }}</AssociatePublicIpAddress> <AssociatePublicIpAddress>{{ 'true' if launch_configuration.associate_public_ip_address else 'false' }}</AssociatePublicIpAddress>
<SecurityGroups> <SecurityGroups>
{% for security_group in launch_configuration.security_groups %} {% for security_group in launch_configuration.security_groups %}
<member>{{ security_group }}</member> <member>{{ security_group }}</member>
@ -805,38 +811,198 @@ DESCRIBE_SCALING_POLICIES_TEMPLATE = """<DescribePoliciesResponse xmlns="http://
{% for policy in policies %} {% for policy in policies %}
<member> <member>
<PolicyARN>{{ policy.arn }}</PolicyARN> <PolicyARN>{{ policy.arn }}</PolicyARN>
{% if policy.adjustment_type %}
<AdjustmentType>{{ policy.adjustment_type }}</AdjustmentType> <AdjustmentType>{{ policy.adjustment_type }}</AdjustmentType>
{% endif %}
{% if policy.scaling_adjustment %} {% if policy.scaling_adjustment %}
<ScalingAdjustment>{{ policy.scaling_adjustment }}</ScalingAdjustment> <ScalingAdjustment>{{ policy.scaling_adjustment }}</ScalingAdjustment>
{% endif %} {% endif %}
{% if policy.min_adjustment_magnitude %}
<MinAdjustmentMagnitude>{{ policy.min_adjustment_magnitude }}</MinAdjustmentMagnitude>
{% endif %}
<PolicyName>{{ policy.name }}</PolicyName> <PolicyName>{{ policy.name }}</PolicyName>
<PolicyType>{{ policy.policy_type }}</PolicyType> <PolicyType>{{ policy.policy_type }}</PolicyType>
<MetricAggregationType>{{ policy.metric_aggregation_type }}</MetricAggregationType>
<AutoScalingGroupName>{{ policy.as_name }}</AutoScalingGroupName> <AutoScalingGroupName>{{ policy.as_name }}</AutoScalingGroupName>
{% if policy.policy_type == 'SimpleScaling' %} {% if policy.policy_type == 'SimpleScaling' %}
<Cooldown>{{ policy.cooldown }}</Cooldown> <Cooldown>{{ policy.cooldown }}</Cooldown>
{% endif %} {% endif %}
{% if policy.policy_type == 'TargetTrackingScaling' %} {% if policy.policy_type == 'TargetTrackingScaling' %}
<TargetTrackingConfiguration> <TargetTrackingConfiguration>
{% if policy.target_tracking_config.get("PredefinedMetricSpecification") %}
<PredefinedMetricSpecification> <PredefinedMetricSpecification>
<PredefinedMetricType>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("PredefinedMetricType", "") }}</PredefinedMetricType> <PredefinedMetricType>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("PredefinedMetricType", "") }}</PredefinedMetricType>
{% if policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") %} {% if policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") %}
<ResourceLabel>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") }}</ResourceLabel> <ResourceLabel>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") }}</ResourceLabel>
{% endif %} {% endif %}
</PredefinedMetricSpecification> </PredefinedMetricSpecification>
{% endif %}
{% if policy.target_tracking_config.get("CustomizedMetricSpecification") %}
<CustomizedMetricSpecification>
<MetricName>{{ policy.target_tracking_config["CustomizedMetricSpecification"].get("MetricName") }}</MetricName>
<Namespace>{{ policy.target_tracking_config["CustomizedMetricSpecification"].get("Namespace") }}</Namespace>
<Dimensions>
{% for dim in policy.target_tracking_config["CustomizedMetricSpecification"].get("Dimensions", []) %}
<member>
<Name>{{ dim.get("Name") }}</Name>
<Value>{{ dim.get("Value") }}</Value>
</member>
{% endfor %}
</Dimensions>
<Statistic>{{ policy.target_tracking_config["CustomizedMetricSpecification"].get("Statistic") }}</Statistic>
{% if policy.target_tracking_config["CustomizedMetricSpecification"].get("Unit") %}
<Unit>{{ policy.target_tracking_config["CustomizedMetricSpecification"].get("Unit") }}</Unit>
{% endif %}
</CustomizedMetricSpecification>
{% endif %}
<TargetValue>{{ policy.target_tracking_config.get("TargetValue") }}</TargetValue> <TargetValue>{{ policy.target_tracking_config.get("TargetValue") }}</TargetValue>
</TargetTrackingConfiguration> </TargetTrackingConfiguration>
{% endif %} {% endif %}
{% if policy.policy_type == 'StepScaling' %} {% if policy.policy_type == 'StepScaling' %}
<StepAdjustments> <StepAdjustments>
{% for step in policy.step_adjustments %} {% for step in policy.step_adjustments %}
<entry> <member>
{% if "MetricIntervalLowerBound" in step %}
<MetricIntervalLowerBound>{{ step.get("MetricIntervalLowerBound") }}</MetricIntervalLowerBound> <MetricIntervalLowerBound>{{ step.get("MetricIntervalLowerBound") }}</MetricIntervalLowerBound>
{% endif %}
{% if "MetricIntervalUpperBound" in step %}
<MetricIntervalUpperBound>{{ step.get("MetricIntervalUpperBound") }}</MetricIntervalUpperBound> <MetricIntervalUpperBound>{{ step.get("MetricIntervalUpperBound") }}</MetricIntervalUpperBound>
{% endif %}
{% if "ScalingAdjustment" in step %}
<ScalingAdjustment>{{ step.get("ScalingAdjustment") }}</ScalingAdjustment> <ScalingAdjustment>{{ step.get("ScalingAdjustment") }}</ScalingAdjustment>
</entry> {% endif %}
</member>
{% endfor %} {% endfor %}
</StepAdjustments> </StepAdjustments>
{% endif %} {% endif %}
{% if policy.estimated_instance_warmup %}
<EstimatedInstanceWarmup>{{ policy.estimated_instance_warmup }}</EstimatedInstanceWarmup>
{% endif %}
{% if policy.policy_type == 'PredictiveScaling' %}
<PredictiveScalingConfiguration>
<MetricSpecifications>
{% for config in policy.predictive_scaling_configuration.get("MetricSpecifications", []) %}
<member>
<TargetValue>{{ config.get("TargetValue") }}</TargetValue>
{% if config.get("PredefinedMetricPairSpecification", {}).get("PredefinedMetricType") %}
<PredefinedMetricPairSpecification>
<PredefinedMetricType>{{ config.get("PredefinedMetricPairSpecification", {}).get("PredefinedMetricType") }}</PredefinedMetricType>
<ResourceLabel>{{ config.get("PredefinedMetricPairSpecification", {}).get("ResourceLabel", "") }}</ResourceLabel>
</PredefinedMetricPairSpecification>
{% endif %}
{% if config.get("PredefinedScalingMetricSpecification", {}).get("PredefinedMetricType") %}
<PredefinedScalingMetricSpecification>
<PredefinedMetricType>{{ config.get("PredefinedScalingMetricSpecification", {}).get("PredefinedMetricType", "") }}</PredefinedMetricType>
<ResourceLabel>{{ config.get("PredefinedScalingMetricSpecification", {}).get("ResourceLabel", "") }}</ResourceLabel>
</PredefinedScalingMetricSpecification>
{% endif %}
{% if config.get("PredefinedLoadMetricSpecification", {}).get("PredefinedMetricType") %}
<PredefinedLoadMetricSpecification>
<PredefinedMetricType>{{ config.get("PredefinedLoadMetricSpecification", {}).get("PredefinedMetricType", "") }}</PredefinedMetricType>
<ResourceLabel>{{ config.get("PredefinedLoadMetricSpecification", {}).get("ResourceLabel", "") }}</ResourceLabel>
</PredefinedLoadMetricSpecification>
{% endif %}
{% if config.get("CustomizedScalingMetricSpecification", {}).get("MetricDataQueries") %}
<CustomizedScalingMetricSpecification>
<MetricDataQueries>
{% for query in config.get("CustomizedScalingMetricSpecification", {}).get("MetricDataQueries", []) %}
<member>
<Id>{{ query.get("Id") }}</Id>
<Expression>{{ query.get("Expression") }}</Expression>
<MetricStat>
<Metric>
<Namespace>{{ query.get("MetricStat", {}).get("Metric", {}).get("Namespace") }}</Namespace>
<MetricName>{{ query.get("MetricStat", {}).get("Metric", {}).get("MetricName") }}</MetricName>
<Dimensions>
{% for dim in query.get("MetricStat", {}).get("Metric", {}).get("Dimensions", []) %}
<Name>{{ dim.get("Name") }}</Name>
<Value>{{ dim.get("Value") }}</Value>
{% endfor %}
</Dimensions>
</Metric>
<Stat>{{ query.get("MetricStat", {}).get("Stat") }}</Stat>
<Unit>{{ query.get("MetricStat", {}).get("Unit") }}</Unit>
</MetricStat>
<Label>{{ query.get("Label") }}</Label>
<ReturnData>{{ 'true' if query.get("ReturnData") else 'false' }}</ReturnData>
</member>
{% endfor %}
</MetricDataQueries>
</CustomizedScalingMetricSpecification>
{% endif %}
{% if config.get("CustomizedLoadMetricSpecification", {}).get("MetricDataQueries") %}
<CustomizedLoadMetricSpecification>
<MetricDataQueries>
{% for query in config.get("CustomizedLoadMetricSpecification", {}).get("MetricDataQueries", []) %}
<member>
<Id>{{ query.get("Id") }}</Id>
<Expression>{{ query.get("Expression") }}</Expression>
<MetricStat>
<Metric>
<Namespace>{{ query.get("MetricStat", {}).get("Metric", {}).get("Namespace") }}</Namespace>
<MetricName>{{ query.get("MetricStat", {}).get("Metric", {}).get("MetricName") }}</MetricName>
<Dimensions>
{% for dim in query.get("MetricStat", {}).get("Metric", {}).get("Dimensions", []) %}
<Name>{{ dim.get("Name") }}</Name>
<Value>{{ dim.get("Value") }}</Value>
{% endfor %}
</Dimensions>
</Metric>
<Stat>{{ query.get("MetricStat", {}).get("Stat") }}</Stat>
<Unit>{{ query.get("MetricStat", {}).get("Unit") }}</Unit>
</MetricStat>
<Label>{{ query.get("Label") }}</Label>
<ReturnData>{{ 'true' if query.get("ReturnData") else 'false' }}</ReturnData>
</member>
{% endfor %}
</MetricDataQueries>
</CustomizedLoadMetricSpecification>
{% endif %}
{% if config.get("CustomizedCapacityMetricSpecification", {}).get("MetricDataQueries") %}
<CustomizedCapacityMetricSpecification>
<MetricDataQueries>
{% for query in config.get("CustomizedCapacityMetricSpecification", {}).get("MetricDataQueries", []) %}
<member>
<Id>{{ query.get("Id") }}</Id>
<Expression>{{ query.get("Expression") }}</Expression>
<MetricStat>
<Metric>
<Namespace>{{ query.get("MetricStat", {}).get("Metric", {}).get("Namespace") }}</Namespace>
<MetricName>{{ query.get("MetricStat", {}).get("Metric", {}).get("MetricName") }}</MetricName>
<Dimensions>
{% for dim in query.get("MetricStat", {}).get("Metric", {}).get("Dimensions", []) %}
<Name>{{ dim.get("Name") }}</Name>
<Value>{{ dim.get("Value") }}</Value>
{% endfor %}
</Dimensions>
</Metric>
<Stat>{{ query.get("MetricStat", {}).get("Stat") }}</Stat>
<Unit>{{ query.get("MetricStat", {}).get("Unit") }}</Unit>
</MetricStat>
<Label>{{ query.get("Label") }}</Label>
<ReturnData>{{ 'true' if query.get("ReturnData") else 'false' }}</ReturnData>
</member>
{% endfor %}
</MetricDataQueries>
</CustomizedCapacityMetricSpecification>
{% endif %}
</member>
{% endfor %}
</MetricSpecifications>
{% if "Mode" in policy.predictive_scaling_configuration %}
<Mode>{{ policy.predictive_scaling_configuration.get("Mode") }}</Mode>
{% endif %}
{% if "SchedulingBufferTime" in policy.predictive_scaling_configuration %}
<SchedulingBufferTime>{{ policy.predictive_scaling_configuration.get("SchedulingBufferTime") }}</SchedulingBufferTime>
{% endif %}
{% if "MaxCapacityBreachBehavior" in policy.predictive_scaling_configuration %}
<MaxCapacityBreachBehavior>{{ policy.predictive_scaling_configuration.get("MaxCapacityBreachBehavior") }}</MaxCapacityBreachBehavior>
{% endif %}
{% if "MaxCapacityBuffer" in policy.predictive_scaling_configuration %}
<MaxCapacityBuffer>{{ policy.predictive_scaling_configuration.get("MaxCapacityBuffer") }}</MaxCapacityBuffer>
{% endif %}
</PredictiveScalingConfiguration>
{% endif %}
<Alarms/> <Alarms/>
</member> </member>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,120 @@
from collections import OrderedDict
from .core import TaggedEC2Resource
from ..utils import generic_filter, random_launch_template_id, utc_date_and_time
from ..exceptions import InvalidLaunchTemplateNameError
class LaunchTemplateVersion(object):
def __init__(self, template, number, data, description):
self.template = template
self.number = number
self.data = data
self.description = description
self.create_time = utc_date_and_time()
@property
def image_id(self):
return self.data.get("ImageId", "")
@property
def instance_type(self):
return self.data.get("InstanceType", "")
@property
def security_groups(self):
return self.data.get("SecurityGroups", [])
@property
def user_data(self):
return self.data.get("UserData", "")
class LaunchTemplate(TaggedEC2Resource):
def __init__(self, backend, name, template_data, version_description):
self.ec2_backend = backend
self.name = name
self.id = random_launch_template_id()
self.create_time = utc_date_and_time()
self.versions = []
self.create_version(template_data, version_description)
self.default_version_number = 1
def create_version(self, data, description):
num = len(self.versions) + 1
version = LaunchTemplateVersion(self, num, data, description)
self.versions.append(version)
return version
def is_default(self, version):
return self.default_version == version.number
def get_version(self, num):
if str(num).lower() == "$latest":
return self.versions[-1]
if str(num).lower() == "$default":
return self.default_version()
return self.versions[int(num) - 1]
def default_version(self):
return self.versions[self.default_version_number - 1]
def latest_version(self):
return self.versions[-1]
@property
def latest_version_number(self):
return self.latest_version().number
def get_filter_value(self, filter_name):
if filter_name == "launch-template-name":
return self.name
else:
return super().get_filter_value(filter_name, "DescribeLaunchTemplates")
class LaunchTemplateBackend(object):
def __init__(self):
self.launch_template_name_to_ids = {}
self.launch_templates = OrderedDict()
self.launch_template_insert_order = []
super().__init__()
def create_launch_template(self, name, description, template_data):
if name in self.launch_template_name_to_ids:
raise InvalidLaunchTemplateNameError()
template = LaunchTemplate(self, name, template_data, description)
self.launch_templates[template.id] = template
self.launch_template_name_to_ids[template.name] = template.id
self.launch_template_insert_order.append(template.id)
return template
def get_launch_template(self, template_id):
return self.launch_templates[template_id]
def get_launch_template_by_name(self, name):
return self.get_launch_template(self.launch_template_name_to_ids[name])
def delete_launch_template(self, name, tid):
if name:
tid = self.launch_template_name_to_ids[name]
return self.launch_templates.pop(tid)
def describe_launch_templates(
self, template_names=None, template_ids=None, filters=None
):
if template_names and not template_ids:
template_ids = []
for name in template_names:
template_ids.append(self.launch_template_name_to_ids[name])
if template_ids:
templates = [
self.launch_templates[tid]
for tid in template_ids
if tid in self.launch_templates
]
else:
templates = list(self.launch_templates.values())
return generic_filter(filters, templates)

View File

@ -70,7 +70,6 @@ from .exceptions import (
InvalidDependantParameterError, InvalidDependantParameterError,
InvalidDependantParameterTypeError, InvalidDependantParameterTypeError,
InvalidFlowLogIdError, InvalidFlowLogIdError,
InvalidLaunchTemplateNameError,
InvalidNetworkAclIdError, InvalidNetworkAclIdError,
InvalidNetworkAttachmentIdError, InvalidNetworkAttachmentIdError,
InvalidNetworkInterfaceIdError, InvalidNetworkInterfaceIdError,
@ -122,6 +121,7 @@ from .exceptions import (
InvalidCarrierGatewayID, InvalidCarrierGatewayID,
) )
from ._models.core import TaggedEC2Resource from ._models.core import TaggedEC2Resource
from ._models.launch_templates import LaunchTemplateBackend
from ._models.vpc_service_configuration import VPCServiceConfigurationBackend from ._models.vpc_service_configuration import VPCServiceConfigurationBackend
from .utils import ( from .utils import (
EC2_RESOURCE_TO_PREFIX, EC2_RESOURCE_TO_PREFIX,
@ -142,7 +142,6 @@ from .utils import (
random_transit_gateway_attachment_id, random_transit_gateway_attachment_id,
random_transit_gateway_route_table_id, random_transit_gateway_route_table_id,
random_vpc_ep_id, random_vpc_ep_id,
random_launch_template_id,
random_nat_gateway_id, random_nat_gateway_id,
random_transit_gateway_id, random_transit_gateway_id,
random_key_pair, random_key_pair,
@ -189,6 +188,7 @@ from .utils import (
rsa_public_key_parse, rsa_public_key_parse,
rsa_public_key_fingerprint, rsa_public_key_fingerprint,
describe_tag_filter, describe_tag_filter,
utc_date_and_time,
) )
INSTANCE_TYPES = load_resource(__name__, "resources/instance_types.json") INSTANCE_TYPES = load_resource(__name__, "resources/instance_types.json")
@ -217,14 +217,6 @@ MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS = 1000
DEFAULT_VPC_ENDPOINT_SERVICES = [] DEFAULT_VPC_ENDPOINT_SERVICES = []
def utc_date_and_time():
x = datetime.utcnow()
# Better performing alternative to x.strftime("%Y-%m-%dT%H:%M:%S.000Z")
return "{}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.000Z".format(
x.year, x.month, x.day, x.hour, x.minute, x.second
)
def validate_resource_ids(resource_ids): def validate_resource_ids(resource_ids):
if not resource_ids: if not resource_ids:
raise MissingParameterError(parameter="resourceIdSet") raise MissingParameterError(parameter="resourceIdSet")
@ -8415,109 +8407,6 @@ class NatGatewayBackend(object):
return nat_gw return nat_gw
class LaunchTemplateVersion(object):
def __init__(self, template, number, data, description):
self.template = template
self.number = number
self.data = data
self.description = description
self.create_time = utc_date_and_time()
@property
def image_id(self):
return self.data.get("ImageId", "")
@property
def instance_type(self):
return self.data.get("InstanceType", "")
@property
def security_groups(self):
return self.data.get("SecurityGroups", [])
@property
def user_data(self):
return self.data.get("UserData", "")
class LaunchTemplate(TaggedEC2Resource):
def __init__(self, backend, name, template_data, version_description):
self.ec2_backend = backend
self.name = name
self.id = random_launch_template_id()
self.create_time = utc_date_and_time()
self.versions = []
self.create_version(template_data, version_description)
self.default_version_number = 1
def create_version(self, data, description):
num = len(self.versions) + 1
version = LaunchTemplateVersion(self, num, data, description)
self.versions.append(version)
return version
def is_default(self, version):
return self.default_version == version.number
def get_version(self, num):
return self.versions[num - 1]
def default_version(self):
return self.versions[self.default_version_number - 1]
def latest_version(self):
return self.versions[-1]
@property
def latest_version_number(self):
return self.latest_version().number
def get_filter_value(self, filter_name):
if filter_name == "launch-template-name":
return self.name
else:
return super().get_filter_value(filter_name, "DescribeLaunchTemplates")
class LaunchTemplateBackend(object):
def __init__(self):
self.launch_template_name_to_ids = {}
self.launch_templates = OrderedDict()
self.launch_template_insert_order = []
super().__init__()
def create_launch_template(self, name, description, template_data):
if name in self.launch_template_name_to_ids:
raise InvalidLaunchTemplateNameError()
template = LaunchTemplate(self, name, template_data, description)
self.launch_templates[template.id] = template
self.launch_template_name_to_ids[template.name] = template.id
self.launch_template_insert_order.append(template.id)
return template
def get_launch_template(self, template_id):
return self.launch_templates[template_id]
def get_launch_template_by_name(self, name):
return self.get_launch_template(self.launch_template_name_to_ids[name])
def describe_launch_templates(
self, template_names=None, template_ids=None, filters=None
):
if template_names and not template_ids:
template_ids = []
for name in template_names:
template_ids.append(self.launch_template_name_to_ids[name])
if template_ids:
templates = [self.launch_templates[tid] for tid in template_ids]
else:
templates = list(self.launch_templates.values())
return generic_filter(filters, templates)
class IamInstanceProfileAssociation(CloudFormationModel): class IamInstanceProfileAssociation(CloudFormationModel):
def __init__(self, ec2_backend, association_id, instance, iam_instance_profile): def __init__(self, ec2_backend, association_id, instance, iam_instance_profile):
self.ec2_backend = ec2_backend self.ec2_backend = ec2_backend

View File

@ -644,5 +644,22 @@
"name": "amzn-ami-minimal-hvm-2018.03.0.20181129-x86_64-ebs", "name": "amzn-ami-minimal-hvm-2018.03.0.20181129-x86_64-ebs",
"virtualization_type": "hvm", "virtualization_type": "hvm",
"hypervisor": "xen" "hypervisor": "xen"
},
{
"architecture": "x86_64",
"ami_id": "ami-04681a1dbd79675a5",
"image_location": "amazon/amzn2-ami-hvm-2.0.20180810-x86_64-gp2",
"image_type": "machine",
"public": true,
"owner_id": "137112412989",
"platform": "Linux/UNIX",
"state": "available",
"description": "Amazon Linux 2 AMI 2.0.20180810 x86_64 HVM gp2",
"hypervisor": "xen",
"name": "amzn2-ami-hvm-2.0.20180810-x86_64-gp2",
"root_device_name": "/dev/xvda",
"root_device_type": "ebs",
"sriov": "simple",
"virtualization_type": "hvm"
} }
] ]

View File

@ -175,8 +175,25 @@ class LaunchTemplates(EC2BaseResponse):
) )
return pretty_xml(tree) return pretty_xml(tree)
# def delete_launch_template(self): def delete_launch_template(self):
# pass name = self._get_param("LaunchTemplateName")
tid = self._get_param("LaunchTemplateId")
if self.is_not_dryrun("DeleteLaunchTemplate"):
template = self.ec2_backend.delete_launch_template(name, tid)
tree = xml_root("DeleteLaunchTemplatesResponse")
xml_serialize(
tree,
"launchTemplate",
{
"defaultVersionNumber": template.default_version_number,
"launchTemplateId": template.id,
"launchTemplateName": template.name,
},
)
return pretty_xml(tree)
# def delete_launch_template_versions(self): # def delete_launch_template_versions(self):
# pass # pass

View File

@ -5,6 +5,7 @@ import random
import re import re
import ipaddress import ipaddress
from datetime import datetime
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
@ -297,6 +298,14 @@ def create_dns_entries(service_name, vpc_endpoint_id):
return dns_entries return dns_entries
def utc_date_and_time():
x = datetime.utcnow()
# Better performing alternative to x.strftime("%Y-%m-%dT%H:%M:%S.000Z")
return "{}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}.000Z".format(
x.year, x.month, x.day, x.hour, x.minute, x.second
)
def split_route_id(route_id): def split_route_id(route_id):
values = route_id.split("~") values = route_id.split("~")
return values[0], values[1] return values[0], values[1]

View File

@ -10,6 +10,9 @@ TestAccAWSAPIGatewayV2RouteResponse
TestAccAWSAPIGatewayV2VpcLink TestAccAWSAPIGatewayV2VpcLink
TestAccAWSAppsyncApiKey TestAccAWSAppsyncApiKey
TestAccAWSAppsyncGraphqlApi TestAccAWSAppsyncGraphqlApi
TestAccAWSAutoscalingAttachment
TestAccAwsAutoScalingGroupDataSource
TestAccAWSAutoscalingPolicy
TestAccAWSAvailabilityZones TestAccAWSAvailabilityZones
TestAccAWSBatchJobDefinition TestAccAWSBatchJobDefinition
TestAccAWSBatchJobQueue TestAccAWSBatchJobQueue

View File

@ -13,7 +13,7 @@ from tests import EXAMPLE_AMI_ID
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
@mock_elb @mock_elb
def test_create_autoscaling_group_boto3_within_elb(): def test_create_autoscaling_group_within_elb():
mocked_networking = setup_networking() mocked_networking = setup_networking()
elb_client = boto3.client("elb", region_name="us-east-1") elb_client = boto3.client("elb", region_name="us-east-1")
elb_client.create_load_balancer( elb_client.create_load_balancer(
@ -115,7 +115,7 @@ def test_create_autoscaling_group_boto3_within_elb():
@mock_autoscaling @mock_autoscaling
def test_create_autoscaling_groups_defaults_boto3(): def test_create_autoscaling_groups_defaults():
"""Test with the minimum inputs and check that all of the proper defaults """Test with the minimum inputs and check that all of the proper defaults
are assigned for the other attributes""" are assigned for the other attributes"""
@ -223,7 +223,7 @@ def test_propogate_tags():
@mock_autoscaling @mock_autoscaling
def test_autoscaling_group_delete_boto3(): def test_autoscaling_group_delete():
mocked_networking = setup_networking() mocked_networking = setup_networking()
as_client = boto3.client("autoscaling", region_name="us-east-1") as_client = boto3.client("autoscaling", region_name="us-east-1")
as_client.create_launch_configuration( as_client.create_launch_configuration(
@ -430,7 +430,7 @@ def test_detach_load_balancer():
@mock_autoscaling @mock_autoscaling
def test_create_autoscaling_group_boto3(): def test_create_autoscaling_group():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
@ -566,6 +566,75 @@ def test_create_autoscaling_group_from_template():
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200) response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
@mock_ec2
@mock_autoscaling
def test_create_auto_scaling_from_template_version__latest():
ec2_client = boto3.client("ec2", region_name="us-west-1")
launch_template_name = "tester"
ec2_client.create_launch_template(
LaunchTemplateName=launch_template_name,
LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID, "InstanceType": "t2.medium"},
)
asg_client = boto3.client("autoscaling", region_name="us-west-1")
asg_client.create_auto_scaling_group(
AutoScalingGroupName="name",
DesiredCapacity=1,
MinSize=1,
MaxSize=1,
LaunchTemplate={
"LaunchTemplateName": launch_template_name,
"Version": "$Latest",
},
AvailabilityZones=["us-west-1a"],
)
response = asg_client.describe_auto_scaling_groups(AutoScalingGroupNames=["name"])[
"AutoScalingGroups"
][0]
response.should.have.key("LaunchTemplate")
response["LaunchTemplate"].should.have.key("LaunchTemplateName").equals(
launch_template_name
)
response["LaunchTemplate"].should.have.key("Version").equals("$Latest")
@mock_ec2
@mock_autoscaling
def test_create_auto_scaling_from_template_version__default():
ec2_client = boto3.client("ec2", region_name="us-west-1")
launch_template_name = "tester"
ec2_client.create_launch_template(
LaunchTemplateName=launch_template_name,
LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID, "InstanceType": "t2.medium"},
)
ec2_client.create_launch_template_version(
LaunchTemplateName=launch_template_name,
LaunchTemplateData={"ImageId": EXAMPLE_AMI_ID, "InstanceType": "t3.medium"},
VersionDescription="v2",
)
asg_client = boto3.client("autoscaling", region_name="us-west-1")
asg_client.create_auto_scaling_group(
AutoScalingGroupName="name",
DesiredCapacity=1,
MinSize=1,
MaxSize=1,
LaunchTemplate={
"LaunchTemplateName": launch_template_name,
"Version": "$Default",
},
AvailabilityZones=["us-west-1a"],
)
response = asg_client.describe_auto_scaling_groups(AutoScalingGroupNames=["name"])[
"AutoScalingGroups"
][0]
response.should.have.key("LaunchTemplate")
response["LaunchTemplate"].should.have.key("LaunchTemplateName").equals(
launch_template_name
)
response["LaunchTemplate"].should.have.key("Version").equals("$Default")
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
def test_create_autoscaling_group_no_template_ref(): def test_create_autoscaling_group_no_template_ref():
@ -629,7 +698,7 @@ def test_create_autoscaling_group_multiple_template_ref():
@mock_autoscaling @mock_autoscaling
def test_create_autoscaling_group_boto3_no_launch_configuration(): def test_create_autoscaling_group_no_launch_configuration():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
@ -651,7 +720,7 @@ def test_create_autoscaling_group_boto3_no_launch_configuration():
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
def test_create_autoscaling_group_boto3_multiple_launch_configurations(): def test_create_autoscaling_group_multiple_launch_configurations():
mocked_networking = setup_networking() mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1") ec2_client = boto3.client("ec2", region_name="us-east-1")
@ -689,7 +758,7 @@ def test_create_autoscaling_group_boto3_multiple_launch_configurations():
@mock_autoscaling @mock_autoscaling
def test_describe_autoscaling_groups_boto3_launch_config(): def test_describe_autoscaling_groups_launch_config():
mocked_networking = setup_networking(region_name="eu-north-1") mocked_networking = setup_networking(region_name="eu-north-1")
client = boto3.client("autoscaling", region_name="eu-north-1") client = boto3.client("autoscaling", region_name="eu-north-1")
client.create_launch_configuration( client.create_launch_configuration(
@ -729,7 +798,7 @@ def test_describe_autoscaling_groups_boto3_launch_config():
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
def test_describe_autoscaling_groups_boto3_launch_template(): def test_describe_autoscaling_groups_launch_template():
mocked_networking = setup_networking() mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1") ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template( template = ec2_client.create_launch_template(
@ -770,7 +839,7 @@ def test_describe_autoscaling_groups_boto3_launch_template():
@mock_autoscaling @mock_autoscaling
def test_describe_autoscaling_instances_boto3_launch_config(): def test_describe_autoscaling_instances_launch_config():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
@ -801,7 +870,7 @@ def test_describe_autoscaling_instances_boto3_launch_config():
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
def test_describe_autoscaling_instances_boto3_launch_template(): def test_describe_autoscaling_instances_launch_template():
mocked_networking = setup_networking() mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1") ec2_client = boto3.client("ec2", region_name="us-east-1")
template = ec2_client.create_launch_template( template = ec2_client.create_launch_template(
@ -871,7 +940,7 @@ def test_describe_autoscaling_instances_instanceid_filter():
@mock_autoscaling @mock_autoscaling
def test_update_autoscaling_group_boto3_launch_config(): def test_update_autoscaling_group_launch_config():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
@ -914,7 +983,7 @@ def test_update_autoscaling_group_boto3_launch_config():
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
def test_update_autoscaling_group_boto3_launch_template(): def test_update_autoscaling_group_launch_template():
mocked_networking = setup_networking() mocked_networking = setup_networking()
ec2_client = boto3.client("ec2", region_name="us-east-1") ec2_client = boto3.client("ec2", region_name="us-east-1")
ec2_client.create_launch_template( ec2_client.create_launch_template(
@ -1019,7 +1088,7 @@ def test_update_autoscaling_group_max_size_desired_capacity_change():
@mock_autoscaling @mock_autoscaling
def test_autoscaling_describe_policies_boto3(): def test_autoscaling_describe_policies():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration( _ = client.create_launch_configuration(
@ -1048,6 +1117,7 @@ def test_autoscaling_describe_policies_boto3():
AutoScalingGroupName="test_asg", AutoScalingGroupName="test_asg",
PolicyName="test_policy_down", PolicyName="test_policy_down",
PolicyType="SimpleScaling", PolicyType="SimpleScaling",
MetricAggregationType="Minimum",
AdjustmentType="PercentChangeInCapacity", AdjustmentType="PercentChangeInCapacity",
ScalingAdjustment=-10, ScalingAdjustment=-10,
Cooldown=60, Cooldown=60,
@ -1080,6 +1150,7 @@ def test_autoscaling_describe_policies_boto3():
response["ScalingPolicies"].should.have.length_of(1) response["ScalingPolicies"].should.have.length_of(1)
policy = response["ScalingPolicies"][0] policy = response["ScalingPolicies"][0]
policy["PolicyType"].should.equal("SimpleScaling") policy["PolicyType"].should.equal("SimpleScaling")
policy["MetricAggregationType"].should.equal("Minimum")
policy["AdjustmentType"].should.equal("PercentChangeInCapacity") policy["AdjustmentType"].should.equal("PercentChangeInCapacity")
policy["ScalingAdjustment"].should.equal(-10) policy["ScalingAdjustment"].should.equal(-10)
policy["Cooldown"].should.equal(60) policy["Cooldown"].should.equal(60)
@ -1275,6 +1346,44 @@ def test_create_autoscaling_policy_with_policytype__stepscaling():
policy.shouldnt.have.key("Cooldown") policy.shouldnt.have.key("Cooldown")
@mock_autoscaling
@mock_ec2
def test_create_autoscaling_policy_with_predictive_scaling_config():
mocked_networking = setup_networking(region_name="eu-west-1")
client = boto3.client("autoscaling", region_name="eu-west-1")
launch_config_name = "lg_name"
asg_name = "asg_test"
client.create_launch_configuration(
LaunchConfigurationName=launch_config_name,
ImageId=EXAMPLE_AMI_ID,
InstanceType="m1.small",
)
client.create_auto_scaling_group(
LaunchConfigurationName=launch_config_name,
AutoScalingGroupName=asg_name,
MinSize=1,
MaxSize=2,
VPCZoneIdentifier=mocked_networking["subnet1"],
)
client.put_scaling_policy(
AutoScalingGroupName=asg_name,
PolicyName=launch_config_name,
PolicyType="PredictiveScaling",
PredictiveScalingConfiguration={
"MetricSpecifications": [{"TargetValue": 5}],
"SchedulingBufferTime": 7,
},
)
resp = client.describe_policies(AutoScalingGroupName=asg_name)
policy = resp["ScalingPolicies"][0]
policy.should.have.key("PredictiveScalingConfiguration").equals(
{"MetricSpecifications": [{"TargetValue": 5.0}], "SchedulingBufferTime": 7}
)
@mock_elb @mock_elb
@mock_autoscaling @mock_autoscaling
@mock_ec2 @mock_ec2
@ -2343,7 +2452,7 @@ def test_set_instance_protection():
@mock_autoscaling @mock_autoscaling
def test_set_desired_capacity_up_boto3(): def test_set_desired_capacity_up():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration( _ = client.create_launch_configuration(
@ -2371,7 +2480,7 @@ def test_set_desired_capacity_up_boto3():
@mock_autoscaling @mock_autoscaling
def test_set_desired_capacity_down_boto3(): def test_set_desired_capacity_down():
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
_ = client.create_launch_configuration( _ = client.create_launch_configuration(
@ -2640,7 +2749,7 @@ def test_autoscaling_lifecyclehook():
@pytest.mark.parametrize("original,new", [(2, 1), (2, 3), (1, 5), (1, 1)]) @pytest.mark.parametrize("original,new", [(2, 1), (2, 3), (1, 5), (1, 1)])
@mock_autoscaling @mock_autoscaling
def test_set_desired_capacity_without_protection_boto3(original, new): def test_set_desired_capacity_without_protection(original, new):
mocked_networking = setup_networking() mocked_networking = setup_networking()
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(

View File

@ -11,7 +11,7 @@ from tests import EXAMPLE_AMI_ID
@mock_autoscaling @mock_autoscaling
def test_create_launch_configuration_boto3(): def test_create_launch_configuration():
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
LaunchConfigurationName="tester", LaunchConfigurationName="tester",
@ -46,7 +46,7 @@ def test_create_launch_configuration_boto3():
@mock_autoscaling @mock_autoscaling
def test_create_launch_configuration_with_block_device_mappings_boto3(): def test_create_launch_configuration_with_block_device_mappings():
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
LaunchConfigurationName="tester", LaunchConfigurationName="tester",
@ -136,7 +136,7 @@ def test_create_launch_configuration_additional_params_default_to_false():
@mock_autoscaling @mock_autoscaling
def test_create_launch_configuration_defaults_boto3(): def test_create_launch_configuration_defaults():
"""Test with the minimum inputs and check that all of the proper defaults """Test with the minimum inputs and check that all of the proper defaults
are assigned for the other attributes""" are assigned for the other attributes"""
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
@ -158,7 +158,7 @@ def test_create_launch_configuration_defaults_boto3():
@mock_autoscaling @mock_autoscaling
def test_launch_configuration_describe_filter_boto3(): def test_launch_configuration_describe_filter():
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
for name in ["tester", "tester2", "tester3"]: for name in ["tester", "tester2", "tester3"]:
client.create_launch_configuration( client.create_launch_configuration(
@ -200,7 +200,7 @@ def test_launch_configuration_describe_paginated():
@mock_autoscaling @mock_autoscaling
def test_launch_configuration_delete_boto3(): def test_launch_configuration_delete():
client = boto3.client("autoscaling", region_name="us-east-1") client = boto3.client("autoscaling", region_name="us-east-1")
client.create_launch_configuration( client.create_launch_configuration(
LaunchConfigurationName="tester", LaunchConfigurationName="tester",

View File

@ -410,6 +410,74 @@ def test_create_launch_template_with_tag_spec():
) )
@mock_ec2
def test_delete_launch_template__dryrun():
cli = boto3.client("ec2", region_name="us-east-1")
template_name = str(uuid4())
cli.create_launch_template(
LaunchTemplateName=template_name,
LaunchTemplateData={"ImageId": "ami-abc123"},
TagSpecifications=[
{"ResourceType": "instance", "Tags": [{"Key": "key", "Value": "value"}]}
],
)
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(1)
with pytest.raises(ClientError) as exc:
cli.delete_launch_template(DryRun=True, LaunchTemplateName=template_name)
err = exc.value.response["Error"]
err.should.have.key("Code").equals("DryRunOperation")
# Template still exists
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(1)
@mock_ec2
def test_delete_launch_template__by_name():
cli = boto3.client("ec2", region_name="us-east-1")
template_name = str(uuid4())
cli.create_launch_template(
LaunchTemplateName=template_name, LaunchTemplateData={"ImageId": "ami-abc123"}
)
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(1)
cli.delete_launch_template(LaunchTemplateName=template_name)
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(0)
@mock_ec2
def test_delete_launch_template__by_id():
cli = boto3.client("ec2", region_name="us-east-1")
template_name = str(uuid4())
template_id = cli.create_launch_template(
LaunchTemplateName=template_name, LaunchTemplateData={"ImageId": "ami-abc123"}
)["LaunchTemplate"]["LaunchTemplateId"]
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(1)
cli.delete_launch_template(LaunchTemplateId=template_id)
cli.describe_launch_templates(LaunchTemplateNames=[template_name])[
"LaunchTemplates"
].should.have.length_of(0)
def retrieve_all_templates(client, filters=[]): # pylint: disable=W0102 def retrieve_all_templates(client, filters=[]): # pylint: disable=W0102
resp = client.describe_launch_templates(Filters=filters) resp = client.describe_launch_templates(Filters=filters)
all_templates = resp["LaunchTemplates"] all_templates = resp["LaunchTemplates"]

View File

@ -204,7 +204,6 @@ def test_route_table_associations_boto3():
# Refresh # Refresh
r = client.describe_route_tables(RouteTableIds=[route_table.id])["RouteTables"][0] r = client.describe_route_tables(RouteTableIds=[route_table.id])["RouteTables"][0]
r["Associations"].should.have.length_of(1) r["Associations"].should.have.length_of(1)
print(r)
# Associate # Associate
association_id = client.associate_route_table( association_id = client.associate_route_table(
@ -915,7 +914,6 @@ def test_associate_route_table_by_subnet():
{"Name": "association.route-table-association-id", "Values": [assoc_id]} {"Name": "association.route-table-association-id", "Values": [assoc_id]}
] ]
)["RouteTables"] )["RouteTables"]
print(verify[0]["Associations"])
# First assocation is the main # First assocation is the main
verify[0]["Associations"][0].should.have.key("Main").equals(True) verify[0]["Associations"][0].should.have.key("Main").equals(True)