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:
parent
d7604844c2
commit
b8650c0a50
4 changed files with 114 additions and 12 deletions
3
changelogs/fragments/61284-ec2_asg-idempotency.yml
Normal file
3
changelogs/fragments/61284-ec2_asg-idempotency.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
bugfixes:
|
||||||
|
- aws_ec2 - fix idempotency when managing tags
|
||||||
|
- aws_ec2 - fix idempotency when metrics are enable
|
|
@ -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": "*"
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue