Repository URL to install this package:
Version:
6.0.0 ▾
|
#!/usr/bin/python
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
module: ec2_scaling_policy
short_description: Create or delete AWS scaling policies for Autoscaling groups
version_added: 1.0.0
description:
- Can create or delete scaling policies for autoscaling groups.
- Referenced autoscaling groups must already exist.
author:
- Zacharie Eakin (@zeekin)
- Will Thames (@willthames)
options:
state:
type: str
description:
- Register or deregister the policy.
choices: ['present', 'absent']
default: 'present'
name:
type: str
description:
- Unique name for the scaling policy.
required: true
asg_name:
type: str
description:
- Name of the associated autoscaling group.
- Required if I(state) is C(present).
adjustment_type:
type: str
description:
- The type of change in capacity of the autoscaling group.
- Required if I(state) is C(present).
choices:
- ChangeInCapacity
- ExactCapacity
- PercentChangeInCapacity
scaling_adjustment:
type: int
description:
- The amount by which the autoscaling group is adjusted by the policy.
- A negative number has the effect of scaling down the ASG.
- Units are numbers of instances for C(ExactCapacity) or C(ChangeInCapacity) or percent
of existing instances for C(PercentChangeInCapacity).
- Required when I(policy_type) is C(SimpleScaling).
min_adjustment_step:
type: int
description:
- Minimum amount of adjustment when policy is triggered.
- Only used when I(adjustment_type) is C(PercentChangeInCapacity).
cooldown:
type: int
description:
- The minimum period of time (in seconds) between which autoscaling actions can take place.
- Only used when I(policy_type) is C(SimpleScaling).
policy_type:
type: str
description:
- Auto scaling adjustment policy.
choices:
- StepScaling
- SimpleScaling
default: SimpleScaling
metric_aggregation:
type: str
description:
- The aggregation type for the CloudWatch metrics.
- Only used when I(policy_type) is not C(SimpleScaling).
choices:
- Minimum
- Maximum
- Average
default: Average
step_adjustments:
type: list
description:
- list of dicts containing I(lower_bound), I(upper_bound) and I(scaling_adjustment)
- Intervals must not overlap or have a gap between them.
- At most, one item can have an undefined I(lower_bound).
If any item has a negative lower_bound, then there must be a step adjustment with an undefined I(lower_bound).
- At most, one item can have an undefined I(upper_bound).
If any item has a positive upper_bound, then there must be a step adjustment with an undefined I(upper_bound).
- The bounds are the amount over the alarm threshold at which the adjustment will trigger.
This means that for an alarm threshold of 50, triggering at 75 requires a lower bound of 25.
See U(http://docs.aws.amazon.com/AutoScaling/latest/APIReference/API_StepAdjustment.html).
elements: dict
suboptions:
lower_bound:
type: int
description:
- The lower bound for the difference between the alarm threshold and
the CloudWatch metric.
upper_bound:
type: int
description:
- The upper bound for the difference between the alarm threshold and
the CloudWatch metric.
scaling_adjustment:
type: int
description:
- The amount by which to scale.
required: true
estimated_instance_warmup:
type: int
description:
- The estimated time, in seconds, until a newly launched instance can contribute to the CloudWatch metrics.
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
'''
EXAMPLES = '''
- name: Simple Scale Down policy
community.aws.ec2_scaling_policy:
state: present
region: US-XXX
name: "scaledown-policy"
adjustment_type: "ChangeInCapacity"
asg_name: "application-asg"
scaling_adjustment: -1
min_adjustment_step: 1
cooldown: 300
# For an alarm with a breach threshold of 20, the
# following creates a stepped policy:
# From 20-40 (0-20 above threshold), increase by 50% of existing capacity
# From 41-infinity, increase by 100% of existing capacity
- community.aws.ec2_scaling_policy:
state: present
region: US-XXX
name: "step-scale-up-policy"
policy_type: StepScaling
metric_aggregation: Maximum
step_adjustments:
- upper_bound: 20
scaling_adjustment: 50
- lower_bound: 20
scaling_adjustment: 100
adjustment_type: "PercentChangeInCapacity"
asg_name: "application-asg"
'''
RETURN = '''
adjustment_type:
description: Scaling policy adjustment type
returned: always
type: str
sample: PercentChangeInCapacity
alarms:
description: Cloudwatch alarms related to the policy
returned: always
type: complex
contains:
alarm_name:
description: name of the Cloudwatch alarm
returned: always
type: str
sample: cpu-very-high
alarm_arn:
description: ARN of the Cloudwatch alarm
returned: always
type: str
sample: arn:aws:cloudwatch:us-east-2:1234567890:alarm:cpu-very-high
arn:
description: ARN of the scaling policy. Provided for backward compatibility, value is the same as I(policy_arn)
returned: always
type: str
sample: arn:aws:autoscaling:us-east-2:123456789012:scalingPolicy:59e37526-bd27-42cf-adca-5cd3d90bc3b9:autoScalingGroupName/app-asg:policyName/app-policy
as_name:
description: Auto Scaling Group name. Provided for backward compatibility, value is the same as I(auto_scaling_group_name)
returned: always
type: str
sample: app-asg
auto_scaling_group_name:
description: Name of Auto Scaling Group
returned: always
type: str
sample: app-asg
metric_aggregation_type:
description: Method used to aggregate metrics
returned: when I(policy_type) is C(StepScaling)
type: str
sample: Maximum
name:
description: Name of the scaling policy. Provided for backward compatibility, value is the same as I(policy_name)
returned: always
type: str
sample: app-policy
policy_arn:
description: ARN of scaling policy.
returned: always
type: str
sample: arn:aws:autoscaling:us-east-2:123456789012:scalingPolicy:59e37526-bd27-42cf-adca-5cd3d90bc3b9:autoScalingGroupName/app-asg:policyName/app-policy
policy_name:
description: Name of scaling policy
returned: always
type: str
sample: app-policy
policy_type:
description: Type of auto scaling policy
returned: always
type: str
sample: StepScaling
scaling_adjustment:
description: Adjustment to make when alarm is triggered
returned: When I(policy_type) is C(SimpleScaling)
type: int
sample: 1
step_adjustments:
description: List of step adjustments
returned: always
type: complex
contains:
metric_interval_lower_bound:
description: Lower bound for metric interval
returned: if step has a lower bound
type: float
sample: 20.0
metric_interval_upper_bound:
description: Upper bound for metric interval
returned: if step has an upper bound
type: float
sample: 40.0
scaling_adjustment:
description: Adjustment to make if this step is reached
returned: always
type: int
sample: 50
'''
try:
import botocore
except ImportError:
pass # caught by imported AnsibleAWSModule
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
def create_scaling_policy(connection, module):
changed = False
asg_name = module.params['asg_name']
policy_type = module.params['policy_type']
policy_name = module.params['name']
params = dict(PolicyName=policy_name,
PolicyType=policy_type,
AutoScalingGroupName=asg_name,
AdjustmentType=module.params['adjustment_type'])
# min_adjustment_step attribute is only relevant if the adjustment_type
# is set to percentage change in capacity, so it is a special case
if module.params['adjustment_type'] == 'PercentChangeInCapacity':
if module.params['min_adjustment_step']:
params['MinAdjustmentMagnitude'] = module.params['min_adjustment_step']
if policy_type == 'SimpleScaling':
# can't use required_if because it doesn't allow multiple criteria -
# it's only required if policy is SimpleScaling and state is present
if not module.params['scaling_adjustment']:
module.fail_json(msg='scaling_adjustment is required when policy_type is SimpleScaling '
'and state is present')
params['ScalingAdjustment'] = module.params['scaling_adjustment']
if module.params['cooldown']:
params['Cooldown'] = module.params['cooldown']
if policy_type == 'StepScaling':
if not module.params['step_adjustments']:
module.fail_json(msg='step_adjustments is required when policy_type is StepScaling '
'and state is present')
params['StepAdjustments'] = []
for step_adjustment in module.params['step_adjustments']:
step_adjust_params = dict(ScalingAdjustment=step_adjustment['scaling_adjustment'])
if step_adjustment.get('lower_bound'):
step_adjust_params['MetricIntervalLowerBound'] = step_adjustment['lower_bound']
if step_adjustment.get('upper_bound'):
step_adjust_params['MetricIntervalUpperBound'] = step_adjustment['upper_bound']
params['StepAdjustments'].append(step_adjust_params)
if module.params['metric_aggregation']:
params['MetricAggregationType'] = module.params['metric_aggregation']
if module.params['estimated_instance_warmup']:
params['EstimatedInstanceWarmup'] = module.params['estimated_instance_warmup']
try:
policies = connection.describe_policies(aws_retry=True,
AutoScalingGroupName=asg_name,
PolicyNames=[policy_name])['ScalingPolicies']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to obtain autoscaling policy %s" % policy_name)
before = after = {}
if not policies:
changed = True
else:
policy = policies[0]
for key in params:
if params[key] != policy.get(key):
changed = True
before[key] = params[key]
after[key] = policy.get(key)
if changed:
try:
connection.put_scaling_policy(aws_retry=True, **params)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create autoscaling policy")
try:
policies = connection.describe_policies(aws_retry=True,
AutoScalingGroupName=asg_name,
PolicyNames=[policy_name])['ScalingPolicies']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to obtain autoscaling policy %s" % policy_name)
policy = camel_dict_to_snake_dict(policies[0])
# Backward compatible return values
policy['arn'] = policy['policy_arn']
policy['as_name'] = policy['auto_scaling_group_name']
policy['name'] = policy['policy_name']
if before and after:
module.exit_json(changed=changed, diff=dict(before=before, after=after), **policy)
else:
module.exit_json(changed=changed, **policy)
def delete_scaling_policy(connection, module):
policy_name = module.params.get('name')
try:
policy = connection.describe_policies(aws_retry=True, PolicyNames=[policy_name])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to obtain autoscaling policy %s" % policy_name)
if policy['ScalingPolicies']:
try:
connection.delete_policy(aws_retry=True,
AutoScalingGroupName=policy['ScalingPolicies'][0]['AutoScalingGroupName'],
PolicyName=policy_name)
module.exit_json(changed=True)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to delete autoscaling policy")
module.exit_json(changed=False)
def main():
step_adjustment_spec = dict(
lower_bound=dict(type='int'),
upper_bound=dict(type='int'),
scaling_adjustment=dict(type='int', required=True))
argument_spec = dict(
name=dict(required=True),
adjustment_type=dict(choices=['ChangeInCapacity', 'ExactCapacity', 'PercentChangeInCapacity']),
asg_name=dict(),
scaling_adjustment=dict(type='int'),
min_adjustment_step=dict(type='int'),
cooldown=dict(type='int'),
state=dict(default='present', choices=['present', 'absent']),
metric_aggregation=dict(default='Average', choices=['Minimum', 'Maximum', 'Average']),
policy_type=dict(default='SimpleScaling', choices=['SimpleScaling', 'StepScaling']),
step_adjustments=dict(type='list', options=step_adjustment_spec, elements='dict'),
estimated_instance_warmup=dict(type='int')
)
module = AnsibleAWSModule(argument_spec=argument_spec,
required_if=[['state', 'present', ['asg_name', 'adjustment_type']]])
connection = module.client('autoscaling', retry_decorator=AWSRetry.jittered_backoff())
state = module.params.get('state')
if state == 'present':
create_scaling_policy(connection, module)
elif state == 'absent':
delete_scaling_policy(connection, module)
if __name__ == '__main__':
main()