aws_asg: Fix idempotency when using tags and metrics (#61284)

* Update AWS hacking policy to enable ASG Tagging management

* aws_asg: Add tests for ASG Tagging (including idempotency)

* aws_asg: ignore sort order when comparing tags on the ASG (fix idempotency)

* ec2_asg: (integration tests) test for idempotency when managing metrics collection

* ec2_asg: sort list of enabled metrics to ensure clean comparisons.
This commit is contained in:
Mark Chappell 2019-09-06 20:48:40 +01:00 committed by Jill R
parent d7604844c2
commit b8650c0a50
4 changed files with 114 additions and 12 deletions

View file

@ -0,0 +1,3 @@
bugfixes:
- aws_ec2 - fix idempotency when managing tags
- aws_ec2 - fix idempotency when metrics are enable

View file

@ -18,10 +18,12 @@
"Effect": "Allow", "Effect": "Allow",
"Action": [ "Action": [
"autoscaling:*LaunchConfiguration", "autoscaling:*LaunchConfiguration",
"autoscaling:*LoadBalancers",
"autoscaling:*AutoScalingGroup", "autoscaling:*AutoScalingGroup",
"autoscaling:*MetricsCollection", "autoscaling:*MetricsCollection",
"autoscaling:PutScalingPolicy", "autoscaling:PutScalingPolicy",
"autoscaling:DeletePolicy" "autoscaling:DeletePolicy",
"autoscaling:*Tags"
], ],
"Resource": [ "Resource": [
"arn:aws:autoscaling:{{aws_region}}:{{aws_account}}:*" "arn:aws:autoscaling:{{aws_region}}:{{aws_account}}:*"
@ -128,28 +130,22 @@
"Sid": "AllowLoadBalancerOperations", "Sid": "AllowLoadBalancerOperations",
"Effect": "Allow", "Effect": "Allow",
"Action": [ "Action": [
"elasticloadbalancing:*LoadBalancer",
"elasticloadbalancing:*LoadBalancers",
"elasticloadbalancing:*LoadBalancerListeners",
"elasticloadbalancing:*TargetGroup",
"elasticloadbalancing:AddTags", "elasticloadbalancing:AddTags",
"elasticloadbalancing:ConfigureHealthCheck", "elasticloadbalancing:ConfigureHealthCheck",
"elasticloadbalancing:CreateListener", "elasticloadbalancing:CreateListener",
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateLoadBalancerListeners",
"elasticloadbalancing:CreateRule", "elasticloadbalancing:CreateRule",
"elasticloadbalancing:CreateTargetGroup",
"elasticloadbalancing:DeleteListener", "elasticloadbalancing:DeleteListener",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:DeleteLoadBalancerListeners",
"elasticloadbalancing:DeleteRule", "elasticloadbalancing:DeleteRule",
"elasticloadbalancing:DeleteTargetGroup",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:DescribeInstanceHealth", "elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:DescribeLoadBalancer*", "elasticloadbalancing:DescribeLoadBalancer*",
"elasticloadbalancing:DescribeTags", "elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DisableAvailabilityZonesForLoadBalancer",
"elasticloadbalancing:EnableAvailabilityZonesForLoadBalancer",
"elasticloadbalancing:ModifyListener", "elasticloadbalancing:ModifyListener",
"elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:ModifyRule", "elasticloadbalancing:ModifyRule",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"elasticloadbalancing:RemoveTags" "elasticloadbalancing:RemoveTags"
], ],
"Resource": "*" "Resource": "*"

View file

@ -672,7 +672,10 @@ def get_properties(autoscaling_group):
properties['termination_policies'] = autoscaling_group.get('TerminationPolicies') properties['termination_policies'] = autoscaling_group.get('TerminationPolicies')
properties['target_group_arns'] = autoscaling_group.get('TargetGroupARNs') properties['target_group_arns'] = autoscaling_group.get('TargetGroupARNs')
properties['vpc_zone_identifier'] = autoscaling_group.get('VPCZoneIdentifier') properties['vpc_zone_identifier'] = autoscaling_group.get('VPCZoneIdentifier')
properties['metrics_collection'] = autoscaling_group.get('EnabledMetrics') metrics = autoscaling_group.get('EnabledMetrics')
if metrics:
metrics.sort(key=lambda x: x["Metric"])
properties['metrics_collection'] = metrics
if properties['target_group_arns']: if properties['target_group_arns']:
region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
@ -1032,6 +1035,10 @@ def create_autoscaling_group(connection):
if len(set_tags) > 0: if len(set_tags) > 0:
have_tags = as_group.get('Tags') have_tags = as_group.get('Tags')
want_tags = asg_tags want_tags = asg_tags
if have_tags:
have_tags.sort(key=lambda x: x["Key"])
if want_tags:
want_tags.sort(key=lambda x: x["Key"])
dead_tags = [] dead_tags = []
have_tag_keyvals = [x['Key'] for x in have_tags] have_tag_keyvals = [x['Key'] for x in have_tags]
want_tag_keyvals = [x['Key'] for x in want_tags] want_tag_keyvals = [x['Key'] for x in want_tags]

View file

@ -186,6 +186,102 @@
that: that:
- "output.viable_instances == 1" - "output.viable_instances == 1"
- name: Tag asg
ec2_asg:
name: "{{ resource_prefix }}-asg"
tags:
- tag_a: 'value 1'
propagate_at_launch: no
- tag_b: 'value 2'
propagate_at_launch: yes
register: output
- assert:
that:
- "output.tags | length == 2"
- output is changed
- name: Re-Tag asg (different order)
ec2_asg:
name: "{{ resource_prefix }}-asg"
tags:
- tag_b: 'value 2'
propagate_at_launch: yes
- tag_a: 'value 1'
propagate_at_launch: no
register: output
- assert:
that:
- "output.tags | length == 2"
- output is not changed
- name: Re-Tag asg new tags
ec2_asg:
name: "{{ resource_prefix }}-asg"
tags:
- tag_c: 'value 3'
propagate_at_launch: no
register: output
- assert:
that:
- "output.tags | length == 1"
- output is changed
- name: Re-Tag asg update propagate_at_launch
ec2_asg:
name: "{{ resource_prefix }}-asg"
tags:
- tag_c: 'value 3'
propagate_at_launch: yes
register: output
- assert:
that:
- "output.tags | length == 1"
- output is changed
- name: Enable metrics collection
ec2_asg:
name: "{{ resource_prefix }}-asg"
metrics_collection: yes
register: output
- assert:
that:
- output is changed
- name: Enable metrics collection (check idempotency)
ec2_asg:
name: "{{ resource_prefix }}-asg"
metrics_collection: yes
register: output
- assert:
that:
- output is not changed
- name: Disable metrics collection
ec2_asg:
name: "{{ resource_prefix }}-asg"
metrics_collection: no
register: output
- assert:
that:
- output is changed
- name: Disable metrics collection (check idempotency)
ec2_asg:
name: "{{ resource_prefix }}-asg"
metrics_collection: no
register: output
- assert:
that:
- output is not changed
# - name: pause for a bit to make sure that the group can't be trivially deleted # - name: pause for a bit to make sure that the group can't be trivially deleted
# pause: seconds=30 # pause: seconds=30
- name: kill asg - name: kill asg