Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully support mixed instance policy #232

Merged
merged 6 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ec2_asg module - add support for all mixed_instances_policy parameters (https://github.com/ansible-collections/community.aws/issues/231).
108 changes: 106 additions & 2 deletions plugins/modules/ec2_asg.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,60 @@
- A list of instance_types.
type: list
elements: str
required: false
instances_distribution:
description:
- >-
Specifies the distribution of On-Demand Instances and Spot Instances, the maximum price
to pay for Spot Instances, and how the Auto Scaling group allocates instance types
to fulfill On-Demand and Spot capacity.
- 'See also U(https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_InstancesDistribution.html)'
required: false
type: dict
tremble marked this conversation as resolved.
Show resolved Hide resolved
suboptions:
on_demand_allocation_strategy:
description:
- Indicates how to allocate instance types to fulfill On-Demand capacity.
type: str
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
on_demand_base_capacity:
description:
- >-
The minimum amount of the Auto Scaling group's capacity that must be fulfilled by On-Demand
Instances. This base portion is provisioned first as your group scales.
- >-
Default if not set is 0. If you leave it set to 0, On-Demand Instances are launched as a
percentage of the Auto Scaling group's desired capacity, per the OnDemandPercentageAboveBaseCapacity setting.
type: int
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
on_demand_percentage_above_base_capacity:
description:
- Controls the percentages of On-Demand Instances and Spot Instances for your additional capacity beyond OnDemandBaseCapacity.
- Default if not set is 100. If you leave it set to 100, the percentages are 100% for On-Demand Instances and 0% for Spot Instances.
- 'Valid range: 0 to 100'
type: int
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
spot_allocation_strategy:
description:
- Indicates how to allocate instances across Spot Instance pools.
type: str
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
spot_instance_pools:
description:
- >-
The number of Spot Instance pools across which to allocate your Spot Instances. The Spot pools are determined from
the different instance types in the Overrides array of LaunchTemplate. Default if not set is 2.
- Used only when the Spot allocation strategy is lowest-price.
- 'Valid Range: Minimum value of 1. Maximum value of 20.'
type: int
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
spot_max_price:
description:
- The maximum price per unit hour that you are willing to pay for a Spot Instance.
- If you leave the value of this parameter blank (which is the default), the maximum Spot price is set at the On-Demand price.
- To remove a value that you previously set, include the parameter but leave the value blank.
type: str
required: false
tremble marked this conversation as resolved.
Show resolved Hide resolved
type: dict
placement_group:
description:
Expand Down Expand Up @@ -339,6 +393,9 @@
- t3a.large
- t3.large
- t2.large
instances_distribution:
on_demand_percentage_above_base_capacity: 0
spot_allocation_strategy: capacity-optimized
min_size: 1
max_size: 10
desired_capacity: 5
Expand Down Expand Up @@ -447,11 +504,38 @@
returned: success
type: int
sample: 1
mixed_instance_policy:
description: Returns the list of instance types if a mixed instance policy is set.
mixed_instances_policy:
description: Returns the list of instance types if a mixed instances policy is set.
returned: success
type: list
sample: ["t3.micro", "t3a.micro"]
mixed_instances_policy_full:
description: Returns the full dictionary representation of the mixed instances policy if a mixed instances policy is set.
returned: success
type: dict
sample: {
"instances_distribution": {
"on_demand_allocation_strategy": "prioritized",
"on_demand_base_capacity": 0,
"on_demand_percentage_above_base_capacity": 0,
"spot_allocation_strategy": "capacity-optimized"
},
"launch_template": {
"launch_template_specification": {
"launch_template_id": "lt-53c2425cffa544c23",
"launch_template_name": "random-LaunchTemplate",
"version": "2"
},
"overrides": [
{
"instance_type": "m5.xlarge"
},
{
"instance_type": "m5a.xlarge"
},
]
}
}
pending_instances:
description: Number of instances in pending state
returned: success
Expand Down Expand Up @@ -536,7 +620,10 @@

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
tremble marked this conversation as resolved.
Show resolved Hide resolved
from ansible_collections.amazon.aws.plugins.module_utils.core import scrub_none_parameters
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict
tremble marked this conversation as resolved.
Show resolved Hide resolved
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict

ASG_ATTRIBUTES = ('AvailabilityZones', 'DefaultCooldown', 'DesiredCapacity',
'HealthCheckGracePeriod', 'HealthCheckType', 'LaunchConfigurationName',
Expand Down Expand Up @@ -742,6 +829,7 @@ def get_properties(autoscaling_group):
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_full'] = camel_dict_to_snake_dict(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')
Expand Down Expand Up @@ -792,6 +880,7 @@ def get_launch_object(connection, ec2_connection):

if mixed_instances_policy:
instance_types = mixed_instances_policy.get('instance_types', [])
instances_distribution = mixed_instances_policy.get('instances_distribution', {})
policy = {
'LaunchTemplate': {
'LaunchTemplateSpecification': launch_object['LaunchTemplate']
Expand All @@ -802,6 +891,9 @@ def get_launch_object(connection, ec2_connection):
for instance_type in instance_types:
instance_type_dict = {'InstanceType': instance_type}
policy['LaunchTemplate']['Overrides'].append(instance_type_dict)
if instances_distribution:
instances_distribution_params = scrub_none_parameters(instances_distribution)
policy['InstancesDistribution'] = snake_dict_to_camel_dict(instances_distribution_params, capitalize_first=True)
launch_object['MixedInstancesPolicy'] = policy
return launch_object

Expand Down Expand Up @@ -1661,6 +1753,18 @@ def main():
type='list',
elements='str'
),
instances_distribution=dict(
type='dict',
default=None,
options=dict(
on_demand_allocation_strategy=dict(type='str'),
on_demand_base_capacity=dict(type='int'),
on_demand_percentage_above_base_capacity=dict(type='int'),
spot_allocation_strategy=dict(type='str'),
spot_instance_pools=dict(type='int'),
spot_max_price=dict(type='str'),
)
)
)
),
placement_group=dict(type='str'),
Expand Down
35 changes: 31 additions & 4 deletions tests/integration/targets/ec2_asg/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,9 @@
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
- name: create launch template for autoscaling group to test its mixed instances policy
ec2_launch_template:
template_name: "{{ resource_prefix }}-lt"
image_id: "{{ ec2_ami_image }}"
Expand All @@ -645,10 +645,10 @@
groups:
- "{{ sg.group_id }}"

- name: update autoscaling group with mixed-instance policy
- name: update autoscaling group with mixed-instances policy with mixed instances types
ec2_asg:
name: "{{ resource_prefix }}-asg"
launch_template:
launch_template:
launch_template_name: "{{ resource_prefix }}-lt"
desired_capacity: 1
min_size: 1
Expand All @@ -668,6 +668,33 @@
- "output.mixed_instances_policy[0] == 't3.micro'"
- "output.mixed_instances_policy[1] == 't3a.micro'"

- name: update autoscaling group with mixed-instances policy with instances_distribution
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
instances_distribution:
on_demand_percentage_above_base_capacity: 0
spot_allocation_strategy: capacity-optimized
wait_for_instances: yes
register: output

- assert:
that:
- "output.mixed_instances_policy_full['launch_template']['overrides'][0]['instance_type'] == 't3.micro'"
- "output.mixed_instances_policy_full['launch_template']['overrides'][1]['instance_type'] == 't3a.micro'"
- "output.mixed_instances_policy_full['instances_distribution']['on_demand_percentage_above_base_capacity'] == 0"
- "output.mixed_instances_policy_full['instances_distribution']['spot_allocation_strategy'] == 'capacity-optimized'"

# ============================================================

always:
Expand Down