Asg mixed instance types (#67045)

* merge from origin pr 55067

* handle update existing asg with mixed-instance-policy

* fix documentation and append output

* update output documentation

* update documentation version added

* add integration test for mixed instance policy using launch template

* add changelog fragment

* Update lib/ansible/modules/cloud/amazon/ec2_asg.py

Co-Authored-By: Mark Chappell <mchappel@redhat.com>

* Update lib/ansible/modules/cloud/amazon/ec2_asg.py

Co-Authored-By: Mark Chappell <mchappel@redhat.com>

* Update lib/ansible/modules/cloud/amazon/ec2_asg.py

Co-Authored-By: Jill R <4121322+jillr@users.noreply.github.com>

* add warning about botocore version and add expand example documentation

* Update changelogs/fragments/67045-ec2_asg_mixed_instance_policy.yml

Co-Authored-By: Mark Chappell <mchappel@redhat.com>

* Update lib/ansible/modules/cloud/amazon/ec2_asg.py

Co-Authored-By: Mark Chappell <mchappel@redhat.com>

* Update lib/ansible/modules/cloud/amazon/ec2_asg.py

Co-Authored-By: Mark Chappell <mchappel@redhat.com>

* remove useless line

Co-authored-by: Yi-Tse Hong <yitse.hong@soocii.me>
Co-authored-by: Mark Chappell <mchappel@redhat.com>
Co-authored-by: Jill R <4121322+jillr@users.noreply.github.com>
This commit is contained in:
Markus Bergholz 2020-02-05 09:04:15 +01:00 committed by GitHub
parent f23cee2145
commit 822077fefd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 3 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- ec2_asg - Add the ability to use mixed_instance_policy in launch template driven autoscaling groups

View file

@ -81,6 +81,20 @@ options:
description:
- Maximum number of instances in group, if unspecified then the current group value will be used.
type: int
mixed_instances_policy:
description:
- A mixed instance policy to use for the ASG.
- Only used when the ASG is configured to use a Launch Template (I(launch_template)).
- 'See also U(https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-autoscaling-autoscalinggroup-mixedinstancespolicy.html)'
required: false
version_added: "2.10"
suboptions:
instance_types:
description:
- A list of instance_types.
type: list
elements: str
type: dict
placement_group:
description:
- Physical location of your cluster placement group created in Amazon EC2.
@ -329,6 +343,28 @@ EXAMPLES = '''
- environment: production
propagate_at_launch: no
# Basic Configuration with Launch Template using mixed instance policy
- ec2_asg:
name: special
load_balancers: [ 'lb1', 'lb2' ]
availability_zones: [ 'eu-west-1a', 'eu-west-1b' ]
launch_template:
version: '1'
launch_template_name: 'lt-example'
launch_template_id: 'lt-123456'
mixed_instances_policy:
instance_types:
- t3a.large
- t3.large
- t2.large
min_size: 1
max_size: 10
desired_capacity: 5
vpc_zone_identifier: [ 'subnet-abcd1234', 'subnet-1a2b3c4d' ]
tags:
- environment: production
propagate_at_launch: no
'''
@ -426,6 +462,11 @@ min_size:
returned: success
type: int
sample: 1
mixed_instance_policy:
description: Returns the list of instance types if a mixed instance policy is set.
returned: success
type: list
sample: ["t3.micro", "t3a.micro"]
pending_instances:
description: Number of instances in pending state
returned: success
@ -511,6 +552,8 @@ try:
except ImportError:
pass # will be detected by imported HAS_BOTO3
from ansible.module_utils.aws.core import AnsibleAWSModule
ASG_ATTRIBUTES = ('AvailabilityZones', 'DefaultCooldown', 'DesiredCapacity',
'HealthCheckGracePeriod', 'HealthCheckType', 'LaunchConfigurationName',
'LoadBalancerNames', 'MaxSize', 'MinSize', 'AutoScalingGroupName', 'PlacementGroup',
@ -711,6 +754,10 @@ def get_properties(autoscaling_group):
properties['termination_policies'] = autoscaling_group.get('TerminationPolicies')
properties['target_group_arns'] = autoscaling_group.get('TargetGroupARNs')
properties['vpc_zone_identifier'] = autoscaling_group.get('VPCZoneIdentifier')
raw_mixed_instance_object = autoscaling_group.get('MixedInstancesPolicy')
if raw_mixed_instance_object:
properties['mixed_instances_policy'] = [x['InstanceType'] for x in raw_mixed_instance_object.get('LaunchTemplate').get('Overrides')]
metrics = autoscaling_group.get('EnabledMetrics')
if metrics:
metrics.sort(key=lambda x: x["Metric"])
@ -738,6 +785,7 @@ def get_launch_object(connection, ec2_connection):
launch_object = dict()
launch_config_name = module.params.get('launch_config_name')
launch_template = module.params.get('launch_template')
mixed_instances_policy = module.params.get('mixed_instances_policy')
if launch_config_name is None and launch_template is None:
return launch_object
elif launch_config_name:
@ -756,6 +804,20 @@ def get_launch_object(connection, ec2_connection):
launch_object = {"LaunchTemplate": {"LaunchTemplateId": lt['LaunchTemplateId'], "Version": launch_template['version']}}
else:
launch_object = {"LaunchTemplate": {"LaunchTemplateId": lt['LaunchTemplateId'], "Version": str(lt['LatestVersionNumber'])}}
if mixed_instances_policy:
instance_types = mixed_instances_policy.get('instance_types', [])
policy = {
'LaunchTemplate': {
'LaunchTemplateSpecification': launch_object['LaunchTemplate']
}
}
if instance_types:
policy['LaunchTemplate']['Overrides'] = []
for instance_type in instance_types:
instance_type_dict = {'InstanceType': instance_type}
policy['LaunchTemplate']['Overrides'].append(instance_type_dict)
launch_object['MixedInstancesPolicy'] = policy
return launch_object
@ -951,6 +1013,7 @@ def create_autoscaling_group(connection):
availability_zones = module.params['availability_zones']
launch_config_name = module.params.get('launch_config_name')
launch_template = module.params.get('launch_template')
mixed_instances_policy = module.params.get('mixed_instances_policy')
min_size = module.params['min_size']
max_size = module.params['max_size']
placement_group = module.params.get('placement_group')
@ -1028,7 +1091,10 @@ def create_autoscaling_group(connection):
if 'LaunchConfigurationName' in launch_object:
ag['LaunchConfigurationName'] = launch_object['LaunchConfigurationName']
elif 'LaunchTemplate' in launch_object:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
if 'MixedInstancesPolicy' in launch_object:
ag['MixedInstancesPolicy'] = launch_object['MixedInstancesPolicy']
else:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
else:
module.fail_json(msg="Missing LaunchConfigurationName or LaunchTemplate",
exception=traceback.format_exc())
@ -1201,7 +1267,10 @@ def create_autoscaling_group(connection):
if 'LaunchConfigurationName' in launch_object:
ag['LaunchConfigurationName'] = launch_object['LaunchConfigurationName']
elif 'LaunchTemplate' in launch_object:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
if 'MixedInstancesPolicy' in launch_object:
ag['MixedInstancesPolicy'] = launch_object['MixedInstancesPolicy']
else:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
else:
try:
ag['LaunchConfigurationName'] = as_group['LaunchConfigurationName']
@ -1639,6 +1708,11 @@ def main():
launch_template_id=dict(type='str'),
),
),
mixed_instances_policy=dict(type='dict',
default=None,
options=dict(
instance_types=dict(type='list', elements='str'),
)),
min_size=dict(type='int'),
max_size=dict(type='int'),
placement_group=dict(type='str'),
@ -1681,7 +1755,7 @@ def main():
)
global module
module = AnsibleModule(
module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=[
['replace_all_instances', 'replace_instances'],
@ -1691,6 +1765,9 @@ def main():
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
if module.params.get('mixed_instance_type') and not module.botocore_at_least('1.12.45'):
module.fail_json(msg="mixed_instance_type is only supported with botocore >= 1.12.45")
state = module.params.get('state')
replace_instances = module.params.get('replace_instances')
replace_all_instances = module.params.get('replace_all_instances')

View file

@ -585,6 +585,44 @@
until: status is finished
retries: 200
delay: 15
# we need a launch template, otherwise we cannot test the mixed instance policy
- name: create launch template for autoscaling group to test its mixed instance policy
ec2_launch_template:
template_name: "{{ resource_prefix }}-lt"
image_id: "{{ ec2_ami_image }}"
instance_type: t3.micro
credit_specification:
cpu_credits: standard
network_interfaces:
- associate_public_ip_address: yes
delete_on_termination: yes
device_index: 0
groups:
- "{{ sg.group_id }}"
- name: update autoscaling group with mixed-instance policy
ec2_asg:
name: "{{ resource_prefix }}-asg"
launch_template:
launch_template_name: "{{ resource_prefix }}-lt"
desired_capacity: 1
min_size: 1
max_size: 1
vpc_zone_identifier: "{{ testing_subnet.subnet.id }}"
state: present
mixed_instances_policy:
instance_types:
- t3.micro
- t3a.micro
wait_for_instances: yes
register: output
- assert:
that:
- "output.mixed_instances_policy | length == 2"
- "output.mixed_instances_policy[0] == 't3.micro'"
- "output.mixed_instances_policy[1] == 't3a.micro'"
# ============================================================
@ -639,6 +677,15 @@
- "{{ resource_prefix }}-lc"
- "{{ resource_prefix }}-lc-2"
- name: delete launch template
ec2_launch_template:
name: "{{ resource_prefix }}-lt"
state: absent
register: del_lt
retries: 10
until: del_lt is not failed
ignore_errors: true
- name: remove the security group
ec2_group:
name: "{{ resource_prefix }}-sg"