Autoscaling - add support for TargetTracking/StepAdjustments in scaling policy (#4449)
This commit is contained in:
parent
ecd8d2478f
commit
fff69b9faa
@ -7,7 +7,7 @@ from moto.packages.boto.ec2.blockdevicemapping import (
|
|||||||
from moto.ec2.exceptions import InvalidInstanceIdError
|
from moto.ec2.exceptions import InvalidInstanceIdError
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from moto.core import BaseBackend, BaseModel, CloudFormationModel
|
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel, CloudFormationModel
|
||||||
from moto.core.utils import camelcase_to_underscores
|
from moto.core.utils import camelcase_to_underscores
|
||||||
from moto.ec2 import ec2_backends
|
from moto.ec2 import ec2_backends
|
||||||
from moto.elb import elb_backends
|
from moto.elb import elb_backends
|
||||||
@ -70,6 +70,8 @@ class FakeScalingPolicy(BaseModel):
|
|||||||
as_name,
|
as_name,
|
||||||
scaling_adjustment,
|
scaling_adjustment,
|
||||||
cooldown,
|
cooldown,
|
||||||
|
target_tracking_config,
|
||||||
|
step_adjustments,
|
||||||
autoscaling_backend,
|
autoscaling_backend,
|
||||||
):
|
):
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -81,8 +83,14 @@ class FakeScalingPolicy(BaseModel):
|
|||||||
self.cooldown = cooldown
|
self.cooldown = cooldown
|
||||||
else:
|
else:
|
||||||
self.cooldown = DEFAULT_COOLDOWN
|
self.cooldown = DEFAULT_COOLDOWN
|
||||||
|
self.target_tracking_config = target_tracking_config
|
||||||
|
self.step_adjustments = step_adjustments
|
||||||
self.autoscaling_backend = autoscaling_backend
|
self.autoscaling_backend = autoscaling_backend
|
||||||
|
|
||||||
|
@property
|
||||||
|
def arn(self):
|
||||||
|
return f"arn:aws:autoscaling:{self.autoscaling_backend.region}:{ACCOUNT_ID}:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/{self.as_name}:policyName/{self.name}"
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
if self.adjustment_type == "ExactCapacity":
|
if self.adjustment_type == "ExactCapacity":
|
||||||
self.autoscaling_backend.set_desired_capacity(
|
self.autoscaling_backend.set_desired_capacity(
|
||||||
@ -612,6 +620,7 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
self.ec2_backend = ec2_backend
|
self.ec2_backend = ec2_backend
|
||||||
self.elb_backend = elb_backend
|
self.elb_backend = elb_backend
|
||||||
self.elbv2_backend = elbv2_backend
|
self.elbv2_backend = elbv2_backend
|
||||||
|
self.region = self.elbv2_backend.region_name
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
ec2_backend = self.ec2_backend
|
ec2_backend = self.ec2_backend
|
||||||
@ -943,7 +952,15 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
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 create_autoscaling_policy(
|
||||||
self, name, policy_type, adjustment_type, as_name, scaling_adjustment, cooldown
|
self,
|
||||||
|
name,
|
||||||
|
policy_type,
|
||||||
|
adjustment_type,
|
||||||
|
as_name,
|
||||||
|
scaling_adjustment,
|
||||||
|
cooldown,
|
||||||
|
target_tracking_config,
|
||||||
|
step_adjustments,
|
||||||
):
|
):
|
||||||
policy = FakeScalingPolicy(
|
policy = FakeScalingPolicy(
|
||||||
name,
|
name,
|
||||||
@ -952,6 +969,8 @@ class AutoScalingBackend(BaseBackend):
|
|||||||
as_name,
|
as_name,
|
||||||
scaling_adjustment,
|
scaling_adjustment,
|
||||||
cooldown,
|
cooldown,
|
||||||
|
target_tracking_config,
|
||||||
|
step_adjustments,
|
||||||
self,
|
self,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -273,13 +273,16 @@ class AutoScalingResponse(BaseResponse):
|
|||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
def put_scaling_policy(self):
|
def put_scaling_policy(self):
|
||||||
|
params = self._get_params()
|
||||||
policy = self.autoscaling_backend.create_autoscaling_policy(
|
policy = self.autoscaling_backend.create_autoscaling_policy(
|
||||||
name=self._get_param("PolicyName"),
|
name=params.get("PolicyName"),
|
||||||
policy_type=self._get_param("PolicyType"),
|
policy_type=params.get("PolicyType", "SimpleScaling"),
|
||||||
adjustment_type=self._get_param("AdjustmentType"),
|
adjustment_type=params.get("AdjustmentType"),
|
||||||
as_name=self._get_param("AutoScalingGroupName"),
|
as_name=params.get("AutoScalingGroupName"),
|
||||||
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", {}),
|
||||||
|
step_adjustments=params.get("StepAdjustments", []),
|
||||||
)
|
)
|
||||||
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)
|
||||||
@ -801,14 +804,39 @@ DESCRIBE_SCALING_POLICIES_TEMPLATE = """<DescribePoliciesResponse xmlns="http://
|
|||||||
<ScalingPolicies>
|
<ScalingPolicies>
|
||||||
{% for policy in policies %}
|
{% for policy in policies %}
|
||||||
<member>
|
<member>
|
||||||
<PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c322
|
<PolicyARN>{{ policy.arn }}</PolicyARN>
|
||||||
761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/my-test-asg:policyName/MyScaleDownPolicy</PolicyARN>
|
|
||||||
<AdjustmentType>{{ policy.adjustment_type }}</AdjustmentType>
|
<AdjustmentType>{{ policy.adjustment_type }}</AdjustmentType>
|
||||||
|
{% if policy.scaling_adjustment %}
|
||||||
<ScalingAdjustment>{{ policy.scaling_adjustment }}</ScalingAdjustment>
|
<ScalingAdjustment>{{ policy.scaling_adjustment }}</ScalingAdjustment>
|
||||||
|
{% endif %}
|
||||||
<PolicyName>{{ policy.name }}</PolicyName>
|
<PolicyName>{{ policy.name }}</PolicyName>
|
||||||
<PolicyType>{{ policy.policy_type }}</PolicyType>
|
<PolicyType>{{ policy.policy_type }}</PolicyType>
|
||||||
<AutoScalingGroupName>{{ policy.as_name }}</AutoScalingGroupName>
|
<AutoScalingGroupName>{{ policy.as_name }}</AutoScalingGroupName>
|
||||||
|
{% if policy.policy_type == 'SimpleScaling' %}
|
||||||
<Cooldown>{{ policy.cooldown }}</Cooldown>
|
<Cooldown>{{ policy.cooldown }}</Cooldown>
|
||||||
|
{% endif %}
|
||||||
|
{% if policy.policy_type == 'TargetTrackingScaling' %}
|
||||||
|
<TargetTrackingConfiguration>
|
||||||
|
<PredefinedMetricSpecification>
|
||||||
|
<PredefinedMetricType>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("PredefinedMetricType", "") }}</PredefinedMetricType>
|
||||||
|
{% if policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") %}
|
||||||
|
<ResourceLabel>{{ policy.target_tracking_config.get("PredefinedMetricSpecification", {}).get("ResourceLabel") }}</ResourceLabel>
|
||||||
|
{% endif %}
|
||||||
|
</PredefinedMetricSpecification>
|
||||||
|
<TargetValue>{{ policy.target_tracking_config.get("TargetValue") }}</TargetValue>
|
||||||
|
</TargetTrackingConfiguration>
|
||||||
|
{% endif %}
|
||||||
|
{% if policy.policy_type == 'StepScaling' %}
|
||||||
|
<StepAdjustments>
|
||||||
|
{% for step in policy.step_adjustments %}
|
||||||
|
<entry>
|
||||||
|
<MetricIntervalLowerBound>{{ step.get("MetricIntervalLowerBound") }}</MetricIntervalLowerBound>
|
||||||
|
<MetricIntervalUpperBound>{{ step.get("MetricIntervalUpperBound") }}</MetricIntervalUpperBound>
|
||||||
|
<ScalingAdjustment>{{ step.get("ScalingAdjustment") }}</ScalingAdjustment>
|
||||||
|
</entry>
|
||||||
|
{% endfor %}
|
||||||
|
</StepAdjustments>
|
||||||
|
{% endif %}
|
||||||
<Alarms/>
|
<Alarms/>
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -17,6 +17,7 @@ from moto import (
|
|||||||
mock_autoscaling_deprecated,
|
mock_autoscaling_deprecated,
|
||||||
mock_ec2,
|
mock_ec2,
|
||||||
)
|
)
|
||||||
|
from moto.core import ACCOUNT_ID
|
||||||
from tests.helpers import requires_boto_gte
|
from tests.helpers import requires_boto_gte
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@ -1597,7 +1598,16 @@ def test_autoscaling_describe_policies_boto3():
|
|||||||
PolicyTypes=["SimpleScaling"],
|
PolicyTypes=["SimpleScaling"],
|
||||||
)
|
)
|
||||||
response["ScalingPolicies"].should.have.length_of(1)
|
response["ScalingPolicies"].should.have.length_of(1)
|
||||||
response["ScalingPolicies"][0]["PolicyName"].should.equal("test_policy_down")
|
policy = response["ScalingPolicies"][0]
|
||||||
|
policy["PolicyType"].should.equal("SimpleScaling")
|
||||||
|
policy["AdjustmentType"].should.equal("PercentChangeInCapacity")
|
||||||
|
policy["ScalingAdjustment"].should.equal(-10)
|
||||||
|
policy["Cooldown"].should.equal(60)
|
||||||
|
policy["PolicyARN"].should.equal(
|
||||||
|
f"arn:aws:autoscaling:us-east-1:{ACCOUNT_ID}:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/test_asg:policyName/test_policy_down"
|
||||||
|
)
|
||||||
|
policy["PolicyName"].should.equal("test_policy_down")
|
||||||
|
policy.shouldnt.have.key("TargetTrackingConfiguration")
|
||||||
|
|
||||||
|
|
||||||
@mock_elb
|
@mock_elb
|
||||||
@ -1677,6 +1687,114 @@ def test_detach_one_instance_decrement():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_autoscaling
|
||||||
|
@mock_ec2
|
||||||
|
def test_create_autoscaling_policy_with_policytype__targettrackingscaling():
|
||||||
|
mocked_networking = setup_networking(region_name="us-west-1")
|
||||||
|
client = boto3.client("autoscaling", region_name="us-west-1")
|
||||||
|
configuration_name = "test"
|
||||||
|
asg_name = "asg_test"
|
||||||
|
|
||||||
|
client.create_launch_configuration(
|
||||||
|
LaunchConfigurationName=configuration_name,
|
||||||
|
ImageId=EXAMPLE_AMI_ID,
|
||||||
|
InstanceType="m1.small",
|
||||||
|
)
|
||||||
|
client.create_auto_scaling_group(
|
||||||
|
LaunchConfigurationName=configuration_name,
|
||||||
|
AutoScalingGroupName=asg_name,
|
||||||
|
MinSize=1,
|
||||||
|
MaxSize=2,
|
||||||
|
VPCZoneIdentifier=mocked_networking["subnet1"],
|
||||||
|
)
|
||||||
|
|
||||||
|
client.put_scaling_policy(
|
||||||
|
AutoScalingGroupName=asg_name,
|
||||||
|
PolicyName=configuration_name,
|
||||||
|
PolicyType="TargetTrackingScaling",
|
||||||
|
EstimatedInstanceWarmup=100,
|
||||||
|
TargetTrackingConfiguration={
|
||||||
|
"PredefinedMetricSpecification": {
|
||||||
|
"PredefinedMetricType": "ASGAverageNetworkIn",
|
||||||
|
},
|
||||||
|
"TargetValue": 1000000.0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_policies(AutoScalingGroupName=asg_name)
|
||||||
|
policy = resp["ScalingPolicies"][0]
|
||||||
|
policy.should.have.key("PolicyName").equals(configuration_name)
|
||||||
|
policy.should.have.key("PolicyARN").equals(
|
||||||
|
f"arn:aws:autoscaling:us-west-1:{ACCOUNT_ID}:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/{asg_name}:policyName/{configuration_name}"
|
||||||
|
)
|
||||||
|
policy.should.have.key("PolicyType").equals("TargetTrackingScaling")
|
||||||
|
policy.should.have.key("TargetTrackingConfiguration").should.equal(
|
||||||
|
{
|
||||||
|
"PredefinedMetricSpecification": {
|
||||||
|
"PredefinedMetricType": "ASGAverageNetworkIn",
|
||||||
|
},
|
||||||
|
"TargetValue": 1000000.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
policy.shouldnt.have.key("ScalingAdjustment")
|
||||||
|
policy.shouldnt.have.key("Cooldown")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_autoscaling
|
||||||
|
@mock_ec2
|
||||||
|
def test_create_autoscaling_policy_with_policytype__stepscaling():
|
||||||
|
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="StepScaling",
|
||||||
|
StepAdjustments=[
|
||||||
|
{
|
||||||
|
"MetricIntervalLowerBound": 2,
|
||||||
|
"MetricIntervalUpperBound": 8,
|
||||||
|
"ScalingAdjustment": 1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_policies(AutoScalingGroupName=asg_name)
|
||||||
|
policy = resp["ScalingPolicies"][0]
|
||||||
|
policy.should.have.key("PolicyName").equals(launch_config_name)
|
||||||
|
policy.should.have.key("PolicyARN").equals(
|
||||||
|
f"arn:aws:autoscaling:eu-west-1:{ACCOUNT_ID}:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/{asg_name}:policyName/{launch_config_name}"
|
||||||
|
)
|
||||||
|
policy.should.have.key("PolicyType").equals("StepScaling")
|
||||||
|
policy.should.have.key("StepAdjustments").equal(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"MetricIntervalLowerBound": 2,
|
||||||
|
"MetricIntervalUpperBound": 8,
|
||||||
|
"ScalingAdjustment": 1,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
policy.shouldnt.have.key("TargetTrackingConfiguration")
|
||||||
|
policy.shouldnt.have.key("ScalingAdjustment")
|
||||||
|
policy.shouldnt.have.key("Cooldown")
|
||||||
|
|
||||||
|
|
||||||
@mock_elb
|
@mock_elb
|
||||||
@mock_autoscaling
|
@mock_autoscaling
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
|
@ -4,14 +4,14 @@ from moto import mock_ec2, mock_ec2_deprecated
|
|||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
def setup_networking():
|
def setup_networking(region_name="us-east-1"):
|
||||||
ec2 = boto3.resource("ec2", region_name="us-east-1")
|
ec2 = boto3.resource("ec2", region_name=region_name)
|
||||||
vpc = ec2.create_vpc(CidrBlock="10.11.0.0/16")
|
vpc = ec2.create_vpc(CidrBlock="10.11.0.0/16")
|
||||||
subnet1 = ec2.create_subnet(
|
subnet1 = ec2.create_subnet(
|
||||||
VpcId=vpc.id, CidrBlock="10.11.1.0/24", AvailabilityZone="us-east-1a"
|
VpcId=vpc.id, CidrBlock="10.11.1.0/24", AvailabilityZone=f"{region_name}a"
|
||||||
)
|
)
|
||||||
subnet2 = ec2.create_subnet(
|
subnet2 = ec2.create_subnet(
|
||||||
VpcId=vpc.id, CidrBlock="10.11.2.0/24", AvailabilityZone="us-east-1b"
|
VpcId=vpc.id, CidrBlock="10.11.2.0/24", AvailabilityZone=f"{region_name}b"
|
||||||
)
|
)
|
||||||
return {"vpc": vpc.id, "subnet1": subnet1.id, "subnet2": subnet2.id}
|
return {"vpc": vpc.id, "subnet1": subnet1.id, "subnet2": subnet2.id}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user