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 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.ec2 import ec2_backends
 | 
			
		||||
from moto.elb import elb_backends
 | 
			
		||||
@ -70,6 +70,8 @@ class FakeScalingPolicy(BaseModel):
 | 
			
		||||
        as_name,
 | 
			
		||||
        scaling_adjustment,
 | 
			
		||||
        cooldown,
 | 
			
		||||
        target_tracking_config,
 | 
			
		||||
        step_adjustments,
 | 
			
		||||
        autoscaling_backend,
 | 
			
		||||
    ):
 | 
			
		||||
        self.name = name
 | 
			
		||||
@ -81,8 +83,14 @@ class FakeScalingPolicy(BaseModel):
 | 
			
		||||
            self.cooldown = cooldown
 | 
			
		||||
        else:
 | 
			
		||||
            self.cooldown = DEFAULT_COOLDOWN
 | 
			
		||||
        self.target_tracking_config = target_tracking_config
 | 
			
		||||
        self.step_adjustments = step_adjustments
 | 
			
		||||
        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):
 | 
			
		||||
        if self.adjustment_type == "ExactCapacity":
 | 
			
		||||
            self.autoscaling_backend.set_desired_capacity(
 | 
			
		||||
@ -612,6 +620,7 @@ class AutoScalingBackend(BaseBackend):
 | 
			
		||||
        self.ec2_backend = ec2_backend
 | 
			
		||||
        self.elb_backend = elb_backend
 | 
			
		||||
        self.elbv2_backend = elbv2_backend
 | 
			
		||||
        self.region = self.elbv2_backend.region_name
 | 
			
		||||
 | 
			
		||||
    def reset(self):
 | 
			
		||||
        ec2_backend = self.ec2_backend
 | 
			
		||||
@ -943,7 +952,15 @@ class AutoScalingBackend(BaseBackend):
 | 
			
		||||
        self.lifecycle_hooks.pop("%s_%s" % (as_name, name), None)
 | 
			
		||||
 | 
			
		||||
    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(
 | 
			
		||||
            name,
 | 
			
		||||
@ -952,6 +969,8 @@ class AutoScalingBackend(BaseBackend):
 | 
			
		||||
            as_name,
 | 
			
		||||
            scaling_adjustment,
 | 
			
		||||
            cooldown,
 | 
			
		||||
            target_tracking_config,
 | 
			
		||||
            step_adjustments,
 | 
			
		||||
            self,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -273,13 +273,16 @@ class AutoScalingResponse(BaseResponse):
 | 
			
		||||
        return template.render()
 | 
			
		||||
 | 
			
		||||
    def put_scaling_policy(self):
 | 
			
		||||
        params = self._get_params()
 | 
			
		||||
        policy = self.autoscaling_backend.create_autoscaling_policy(
 | 
			
		||||
            name=self._get_param("PolicyName"),
 | 
			
		||||
            policy_type=self._get_param("PolicyType"),
 | 
			
		||||
            adjustment_type=self._get_param("AdjustmentType"),
 | 
			
		||||
            as_name=self._get_param("AutoScalingGroupName"),
 | 
			
		||||
            name=params.get("PolicyName"),
 | 
			
		||||
            policy_type=params.get("PolicyType", "SimpleScaling"),
 | 
			
		||||
            adjustment_type=params.get("AdjustmentType"),
 | 
			
		||||
            as_name=params.get("AutoScalingGroupName"),
 | 
			
		||||
            scaling_adjustment=self._get_int_param("ScalingAdjustment"),
 | 
			
		||||
            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)
 | 
			
		||||
        return template.render(policy=policy)
 | 
			
		||||
@ -801,14 +804,39 @@ DESCRIBE_SCALING_POLICIES_TEMPLATE = """<DescribePoliciesResponse xmlns="http://
 | 
			
		||||
    <ScalingPolicies>
 | 
			
		||||
      {% for policy in policies %}
 | 
			
		||||
      <member>
 | 
			
		||||
        <PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c322
 | 
			
		||||
761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/my-test-asg:policyName/MyScaleDownPolicy</PolicyARN>
 | 
			
		||||
        <PolicyARN>{{ policy.arn }}</PolicyARN>
 | 
			
		||||
        <AdjustmentType>{{ policy.adjustment_type }}</AdjustmentType>
 | 
			
		||||
        {% if policy.scaling_adjustment %}
 | 
			
		||||
        <ScalingAdjustment>{{ policy.scaling_adjustment }}</ScalingAdjustment>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        <PolicyName>{{ policy.name }}</PolicyName>
 | 
			
		||||
        <PolicyType>{{ policy.policy_type }}</PolicyType>
 | 
			
		||||
        <AutoScalingGroupName>{{ policy.as_name }}</AutoScalingGroupName>
 | 
			
		||||
        {% if policy.policy_type == 'SimpleScaling' %}
 | 
			
		||||
        <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/>
 | 
			
		||||
      </member>
 | 
			
		||||
      {% endfor %}
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ from moto import (
 | 
			
		||||
    mock_autoscaling_deprecated,
 | 
			
		||||
    mock_ec2,
 | 
			
		||||
)
 | 
			
		||||
from moto.core import ACCOUNT_ID
 | 
			
		||||
from tests.helpers import requires_boto_gte
 | 
			
		||||
 | 
			
		||||
from .utils import (
 | 
			
		||||
@ -1597,7 +1598,16 @@ def test_autoscaling_describe_policies_boto3():
 | 
			
		||||
        PolicyTypes=["SimpleScaling"],
 | 
			
		||||
    )
 | 
			
		||||
    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
 | 
			
		||||
@ -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_autoscaling
 | 
			
		||||
@mock_ec2
 | 
			
		||||
 | 
			
		||||
@ -4,14 +4,14 @@ from moto import mock_ec2, mock_ec2_deprecated
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@mock_ec2
 | 
			
		||||
def setup_networking():
 | 
			
		||||
    ec2 = boto3.resource("ec2", region_name="us-east-1")
 | 
			
		||||
def setup_networking(region_name="us-east-1"):
 | 
			
		||||
    ec2 = boto3.resource("ec2", region_name=region_name)
 | 
			
		||||
    vpc = ec2.create_vpc(CidrBlock="10.11.0.0/16")
 | 
			
		||||
    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(
 | 
			
		||||
        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}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user