EC2_ASG: Enable support for launch_templates (#45647)

* Enable support for launch_templates in ec2_asg

* Fix asg create with LT and no version number

* Update mutually exclusive list

* Better function names
This commit is contained in:
Nathan Webster 2018-09-25 21:39:34 +01:00 committed by Ryan Brown
commit 3b786acb86

View file

@ -24,7 +24,7 @@ module: ec2_asg
short_description: Create or delete AWS Autoscaling Groups short_description: Create or delete AWS Autoscaling Groups
description: description:
- Can create or delete AWS Autoscaling Groups - Can create or delete AWS Autoscaling Groups
- Works with the ec2_lc module to manage Launch Configurations - Can be used with the ec2_lc module to manage Launch Configurations
version_added: "1.6" version_added: "1.6"
author: "Gareth Rushgrove (@garethr)" author: "Gareth Rushgrove (@garethr)"
requirements: [ "boto3", "botocore" ] requirements: [ "boto3", "botocore" ]
@ -51,8 +51,22 @@ options:
launch_config_name: launch_config_name:
description: description:
- Name of the Launch configuration to use for the group. See the ec2_lc module for managing these. - Name of the Launch configuration to use for the group. See the ec2_lc module for managing these.
If unspecified then the current group value will be used. If unspecified then the current group value will be used. One of launch_config_name or launch_template must be provided.
required: true launch_template:
description:
- Dictionary describing the Launch Template to use
suboptions:
version:
description:
- The version number of the launch template to use. Defaults to latest version if not provided.
default: "latest"
launch_template_name:
description:
- The name of the launch template. Only one of launch_template_name or launch_template_id is required.
launch_template_id:
description:
- The id of the launch template. Only one of launch_template_name or launch_template_id is required.
version_added: "2.8"
min_size: min_size:
description: description:
- Minimum number of instances in group, if unspecified then the current group value will be used. - Minimum number of instances in group, if unspecified then the current group value will be used.
@ -87,6 +101,11 @@ options:
- Check to make sure instances that are being replaced with replace_instances do not already have the current launch_config. - Check to make sure instances that are being replaced with replace_instances do not already have the current launch_config.
version_added: "1.8" version_added: "1.8"
default: 'yes' default: 'yes'
lt_check:
description:
- Check to make sure instances that are being replaced with replace_instances do not already have the current launch_template or launch_template version.
version_added: "2.8"
default: 'yes'
vpc_zone_identifier: vpc_zone_identifier:
description: description:
- List of VPC subnets to use - List of VPC subnets to use
@ -182,7 +201,7 @@ extends_documentation_fragment:
""" """
EXAMPLES = ''' EXAMPLES = '''
# Basic configuration # Basic configuration with Launch Configuration
- ec2_asg: - ec2_asg:
name: special name: special
@ -245,6 +264,26 @@ EXAMPLES = '''
max_size: 5 max_size: 5
desired_capacity: 5 desired_capacity: 5
region: us-east-1 region: us-east-1
# Basic Configuration with Launch Template
- 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'
min_size: 1
max_size: 10
desired_capacity: 5
vpc_zone_identifier: [ 'subnet-abcd1234', 'subnet-1a2b3c4d' ]
tags:
- environment: production
propagate_at_launch: no
''' '''
RETURN = ''' RETURN = '''
@ -476,6 +515,22 @@ def describe_launch_configurations(connection, launch_config_name):
return pg.paginate(LaunchConfigurationNames=[launch_config_name]).build_full_result() return pg.paginate(LaunchConfigurationNames=[launch_config_name]).build_full_result()
@AWSRetry.backoff(**backoff_params)
def describe_launch_templates(connection, launch_template):
if launch_template['launch_template_id'] is not None:
try:
lt = connection.describe_launch_templates(LaunchTemplateIds=[launch_template['launch_template_id']])
return lt
except (botocore.exceptions.ClientError) as e:
module.fail_json(msg="No launch template found matching: %s" % launch_template)
else:
try:
lt = connection.describe_launch_templates(LaunchTemplateNames=[launch_template['launch_template_name']])
return lt
except (botocore.exceptions.ClientError) as e:
module.fail_json(msg="No launch template found matching: %s" % launch_template)
@AWSRetry.backoff(**backoff_params) @AWSRetry.backoff(**backoff_params)
def create_asg(connection, **params): def create_asg(connection, **params):
connection.create_auto_scaling_group(**params) connection.create_auto_scaling_group(**params)
@ -534,16 +589,18 @@ def terminate_asg_instance(connection, instance_id, decrement_capacity):
ShouldDecrementDesiredCapacity=decrement_capacity) ShouldDecrementDesiredCapacity=decrement_capacity)
def enforce_required_arguments(): def enforce_required_arguments_for_create():
''' As many arguments are not required for autoscale group deletion ''' As many arguments are not required for autoscale group deletion
they cannot be mandatory arguments for the module, so we enforce they cannot be mandatory arguments for the module, so we enforce
them here ''' them here '''
missing_args = [] missing_args = []
for arg in ('min_size', 'max_size', 'launch_config_name'): if module.params.get('launch_config_name') is None and module.params.get('launch_template') is None:
module.fail_json(msg="Missing either launch_config_name or launch_template for autoscaling group create")
for arg in ('min_size', 'max_size'):
if module.params[arg] is None: if module.params[arg] is None:
missing_args.append(arg) missing_args.append(arg)
if missing_args: if missing_args:
module.fail_json(msg="Missing required arguments for autoscaling group create/update: %s" % ",".join(missing_args)) module.fail_json(msg="Missing required arguments for autoscaling group create: %s" % ",".join(missing_args))
def get_properties(autoscaling_group): def get_properties(autoscaling_group):
@ -558,11 +615,17 @@ def get_properties(autoscaling_group):
instance_facts = dict() instance_facts = dict()
autoscaling_group_instances = autoscaling_group.get('Instances') autoscaling_group_instances = autoscaling_group.get('Instances')
if autoscaling_group_instances: if autoscaling_group_instances:
properties['instances'] = [i['InstanceId'] for i in autoscaling_group_instances] properties['instances'] = [i['InstanceId'] for i in autoscaling_group_instances]
for i in autoscaling_group_instances: for i in autoscaling_group_instances:
instance_facts[i['InstanceId']] = {'health_status': i['HealthStatus'], if i.get('LaunchConfigurationName'):
'lifecycle_state': i['LifecycleState'], instance_facts[i['InstanceId']] = {'health_status': i['HealthStatus'],
'launch_config_name': i.get('LaunchConfigurationName')} 'lifecycle_state': i['LifecycleState'],
'launch_config_name': i['LaunchConfigurationName']}
else:
instance_facts[i['InstanceId']] = {'health_status': i['HealthStatus'],
'lifecycle_state': i['LifecycleState'],
'launch_template': i['LaunchTemplate']}
if i['HealthStatus'] == 'Healthy' and i['LifecycleState'] == 'InService': if i['HealthStatus'] == 'Healthy' and i['LifecycleState'] == 'InService':
properties['viable_instances'] += 1 properties['viable_instances'] += 1
if i['HealthStatus'] == 'Healthy': if i['HealthStatus'] == 'Healthy':
@ -584,7 +647,10 @@ def get_properties(autoscaling_group):
properties['created_time'] = autoscaling_group.get('CreatedTime') properties['created_time'] = autoscaling_group.get('CreatedTime')
properties['instance_facts'] = instance_facts properties['instance_facts'] = instance_facts
properties['load_balancers'] = autoscaling_group.get('LoadBalancerNames') properties['load_balancers'] = autoscaling_group.get('LoadBalancerNames')
properties['launch_config_name'] = autoscaling_group.get('LaunchConfigurationName') if autoscaling_group.get('LaunchConfigurationName'):
properties['launch_config_name'] = autoscaling_group.get('LaunchConfigurationName')
else:
properties['launch_template'] = autoscaling_group.get('LaunchTemplate')
properties['tags'] = autoscaling_group.get('Tags') properties['tags'] = autoscaling_group.get('Tags')
properties['min_size'] = autoscaling_group.get('MinSize') properties['min_size'] = autoscaling_group.get('MinSize')
properties['max_size'] = autoscaling_group.get('MaxSize') properties['max_size'] = autoscaling_group.get('MaxSize')
@ -616,6 +682,31 @@ def get_properties(autoscaling_group):
return properties return properties
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')
if launch_config_name is None and launch_template is None:
return launch_object
elif launch_config_name:
try:
launch_configs = describe_launch_configurations(connection, launch_config_name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json(msg="Failed to describe launch configurations",
exception=traceback.format_exc())
if len(launch_configs['LaunchConfigurations']) == 0:
module.fail_json(msg="No launch config found with name %s" % launch_config_name)
launch_object = {"LaunchConfigurationName": launch_configs['LaunchConfigurations'][0]['LaunchConfigurationName']}
return launch_object
elif launch_template:
lt = describe_launch_templates(ec2_connection, launch_template)['LaunchTemplates'][0]
if launch_template['version'] is not None:
launch_object = {"LaunchTemplate": {"LaunchTemplateId": lt['LaunchTemplateId'], "Version": launch_template['version']}}
else:
launch_object = {"LaunchTemplate": {"LaunchTemplateId": lt['LaunchTemplateId'], "Version": str(lt['LatestVersionNumber'])}}
return launch_object
def elb_dreg(asg_connection, group_name, instance_id): def elb_dreg(asg_connection, group_name, instance_id):
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)
as_group = describe_autoscaling_groups(asg_connection, group_name)[0] as_group = describe_autoscaling_groups(asg_connection, group_name)[0]
@ -807,6 +898,7 @@ def create_autoscaling_group(connection):
target_group_arns = module.params['target_group_arns'] target_group_arns = module.params['target_group_arns']
availability_zones = module.params['availability_zones'] availability_zones = module.params['availability_zones']
launch_config_name = module.params.get('launch_config_name') launch_config_name = module.params.get('launch_config_name')
launch_template = module.params.get('launch_template')
min_size = module.params['min_size'] min_size = module.params['min_size']
max_size = module.params['max_size'] max_size = module.params['max_size']
placement_group = module.params.get('placement_group') placement_group = module.params.get('placement_group')
@ -830,15 +922,15 @@ def create_autoscaling_group(connection):
module.fail_json(msg="Failed to describe auto scaling groups.", module.fail_json(msg="Failed to describe auto scaling groups.",
exception=traceback.format_exc()) exception=traceback.format_exc())
if not vpc_zone_identifier and not availability_zones: 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) ec2_connection = boto3_conn(module,
ec2_connection = boto3_conn(module, conn_type='client',
conn_type='client', resource='ec2',
resource='ec2', region=region,
region=region, endpoint=ec2_url,
endpoint=ec2_url, **aws_connect_params)
**aws_connect_params)
elif vpc_zone_identifier: if vpc_zone_identifier:
vpc_zone_identifier = ','.join(vpc_zone_identifier) vpc_zone_identifier = ','.join(vpc_zone_identifier)
asg_tags = [] asg_tags = []
@ -854,19 +946,13 @@ def create_autoscaling_group(connection):
if not vpc_zone_identifier and not availability_zones: if not vpc_zone_identifier and not availability_zones:
availability_zones = module.params['availability_zones'] = [zone['ZoneName'] for availability_zones = module.params['availability_zones'] = [zone['ZoneName'] for
zone in ec2_connection.describe_availability_zones()['AvailabilityZones']] zone in ec2_connection.describe_availability_zones()['AvailabilityZones']]
enforce_required_arguments()
try: enforce_required_arguments_for_create()
launch_configs = describe_launch_configurations(connection, launch_config_name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json(msg="Failed to describe launch configurations",
exception=traceback.format_exc())
if len(launch_configs['LaunchConfigurations']) == 0:
module.fail_json(msg="No launch config found with name %s" % launch_config_name)
if desired_capacity is None: if desired_capacity is None:
desired_capacity = min_size desired_capacity = min_size
ag = dict( ag = dict(
AutoScalingGroupName=group_name, AutoScalingGroupName=group_name,
LaunchConfigurationName=launch_configs['LaunchConfigurations'][0]['LaunchConfigurationName'],
MinSize=min_size, MinSize=min_size,
MaxSize=max_size, MaxSize=max_size,
DesiredCapacity=desired_capacity, DesiredCapacity=desired_capacity,
@ -886,6 +972,15 @@ def create_autoscaling_group(connection):
if target_group_arns: if target_group_arns:
ag['TargetGroupARNs'] = target_group_arns ag['TargetGroupARNs'] = target_group_arns
launch_object = get_launch_object(connection, ec2_connection)
if 'LaunchConfigurationName' in launch_object:
ag['LaunchConfigurationName'] = launch_object['LaunchConfigurationName']
elif 'LaunchTemplate' in launch_object:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
else:
module.fail_json(msg="Missing LaunchConfigurationName or LaunchTemplate",
exception=traceback.format_exc())
try: try:
create_asg(connection, **ag) create_asg(connection, **ag)
if metrics_collection: if metrics_collection:
@ -1035,18 +1130,8 @@ def create_autoscaling_group(connection):
max_size = as_group['MaxSize'] max_size = as_group['MaxSize']
if desired_capacity is None: if desired_capacity is None:
desired_capacity = as_group['DesiredCapacity'] desired_capacity = as_group['DesiredCapacity']
launch_config_name = launch_config_name or as_group['LaunchConfigurationName']
try:
launch_configs = describe_launch_configurations(connection, launch_config_name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json(msg="Failed to describe launch configurations",
exception=traceback.format_exc())
if len(launch_configs['LaunchConfigurations']) == 0:
module.fail_json(msg="No launch config found with name %s" % launch_config_name)
ag = dict( ag = dict(
AutoScalingGroupName=group_name, AutoScalingGroupName=group_name,
LaunchConfigurationName=launch_configs['LaunchConfigurations'][0]['LaunchConfigurationName'],
MinSize=min_size, MinSize=min_size,
MaxSize=max_size, MaxSize=max_size,
DesiredCapacity=desired_capacity, DesiredCapacity=desired_capacity,
@ -1054,6 +1139,21 @@ def create_autoscaling_group(connection):
HealthCheckType=health_check_type, HealthCheckType=health_check_type,
DefaultCooldown=default_cooldown, DefaultCooldown=default_cooldown,
TerminationPolicies=termination_policies) TerminationPolicies=termination_policies)
# Get the launch object (config or template) if one is provided in args or use the existing one attached to ASG if not.
launch_object = get_launch_object(connection, ec2_connection)
if 'LaunchConfigurationName' in launch_object:
ag['LaunchConfigurationName'] = launch_object['LaunchConfigurationName']
elif 'LaunchTemplate' in launch_object:
ag['LaunchTemplate'] = launch_object['LaunchTemplate']
else:
try:
ag['LaunchConfigurationName'] = as_group['LaunchConfigurationName']
except:
launch_template = as_group['LaunchTemplate']
# Prefer LaunchTemplateId over Name as it's more specific. Only one can be used for update_asg.
ag['LaunchTemplate'] = {"LaunchTemplateId": launch_template['LaunchTemplateId'], "Version": launch_template['Version']}
if availability_zones: if availability_zones:
ag['AvailabilityZones'] = availability_zones ag['AvailabilityZones'] = availability_zones
if vpc_zone_identifier: if vpc_zone_identifier:
@ -1168,7 +1268,18 @@ def replace(connection):
max_size = module.params.get('max_size') max_size = module.params.get('max_size')
min_size = module.params.get('min_size') min_size = module.params.get('min_size')
desired_capacity = module.params.get('desired_capacity') desired_capacity = module.params.get('desired_capacity')
lc_check = module.params.get('lc_check') launch_config_name = module.params.get('launch_config_name')
# Required to maintain the default value being set to 'true'
if launch_config_name:
lc_check = module.params.get('lc_check')
else:
lc_check = False
# Mirror above behaviour for Launch Templates
launch_template = module.params.get('launch_template')
if launch_template:
lt_check = module.params.get('lt_check')
else:
lt_check = False
replace_instances = module.params.get('replace_instances') replace_instances = module.params.get('replace_instances')
replace_all_instances = module.params.get('replace_all_instances') replace_all_instances = module.params.get('replace_all_instances')
@ -1185,12 +1296,16 @@ def replace(connection):
replace_instances = instances replace_instances = instances
if replace_instances: if replace_instances:
instances = replace_instances instances = replace_instances
# check to see if instances are replaceable if checking launch configs
new_instances, old_instances = get_instances_by_lc(props, lc_check, instances) # check to see if instances are replaceable if checking launch configs
if launch_config_name:
new_instances, old_instances = get_instances_by_launch_config(props, lc_check, instances)
elif launch_template:
new_instances, old_instances = get_instances_by_launch_template(props, lt_check, instances)
num_new_inst_needed = desired_capacity - len(new_instances) num_new_inst_needed = desired_capacity - len(new_instances)
if lc_check: if lc_check or lt_check:
if num_new_inst_needed == 0 and old_instances: if num_new_inst_needed == 0 and old_instances:
module.debug("No new instances needed, but old instances are present. Removing old instances") module.debug("No new instances needed, but old instances are present. Removing old instances")
terminate_batch(connection, old_instances, instances, True) terminate_batch(connection, old_instances, instances, True)
@ -1247,14 +1362,17 @@ def replace(connection):
return(changed, asg_properties) return(changed, asg_properties)
def get_instances_by_lc(props, lc_check, initial_instances): def get_instances_by_launch_config(props, lc_check, initial_instances):
new_instances = [] new_instances = []
old_instances = [] old_instances = []
# old instances are those that have the old launch config # old instances are those that have the old launch config
if lc_check: if lc_check:
for i in props['instances']: for i in props['instances']:
if props['instance_facts'][i]['launch_config_name'] == props['launch_config_name']: # Check if migrating from launch_template to launch_config first
if 'launch_template' in props['instance_facts'][i]:
old_instances.append(i)
elif props['instance_facts'][i]['launch_config_name'] == props['launch_config_name']:
new_instances.append(i) new_instances.append(i)
else: else:
old_instances.append(i) old_instances.append(i)
@ -1272,20 +1390,60 @@ def get_instances_by_lc(props, lc_check, initial_instances):
return new_instances, old_instances return new_instances, old_instances
def list_purgeable_instances(props, lc_check, replace_instances, initial_instances): def get_instances_by_launch_template(props, lt_check, initial_instances):
new_instances = []
old_instances = []
# old instances are those that have the old launch template or version of the same launch templatec
if lt_check:
for i in props['instances']:
# Check if migrating from launch_config_name to launch_template_name first
if 'launch_config_name' in props['instance_facts'][i]:
old_instances.append(i)
elif props['instance_facts'][i]['launch_template'] == props['launch_template']:
new_instances.append(i)
else:
old_instances.append(i)
else:
module.debug("Comparing initial instances with current: %s" % initial_instances)
for i in props['instances']:
if i not in initial_instances:
new_instances.append(i)
else:
old_instances.append(i)
module.debug("New instances: %s, %s" % (len(new_instances), new_instances))
module.debug("Old instances: %s, %s" % (len(old_instances), old_instances))
return new_instances, old_instances
def list_purgeable_instances(props, lc_check, lt_check, replace_instances, initial_instances):
instances_to_terminate = [] instances_to_terminate = []
instances = (inst_id for inst_id in replace_instances if inst_id in props['instances']) instances = (inst_id for inst_id in replace_instances if inst_id in props['instances'])
# check to make sure instances given are actually in the given ASG # check to make sure instances given are actually in the given ASG
# and they have a non-current launch config # and they have a non-current launch config
if lc_check: if module.params.get('launch_config_name'):
for i in instances: if lc_check:
if props['instance_facts'][i]['launch_config_name'] != props['launch_config_name']: for i in instances:
instances_to_terminate.append(i) if 'launch_template' in props['instance_facts'][i]:
else: instances_to_terminate.append(i)
for i in instances: elif props['instance_facts'][i]['launch_config_name'] != props['launch_config_name']:
if i in initial_instances: instances_to_terminate.append(i)
instances_to_terminate.append(i) else:
for i in instances:
if i in initial_instances:
instances_to_terminate.append(i)
elif module.params.get('launch_template'):
if lt_check:
for i in instances:
if 'launch_config_name' in props['instance_facts'][i]:
instances_to_terminate.append(i)
elif props['instance_facts'][i]['launch_template'] != props['launch_template']:
instances_to_terminate.append(i)
else:
for i in instances:
if i in initial_instances:
instances_to_terminate.append(i)
return instances_to_terminate return instances_to_terminate
@ -1295,6 +1453,7 @@ def terminate_batch(connection, replace_instances, initial_instances, leftovers=
desired_capacity = module.params.get('desired_capacity') desired_capacity = module.params.get('desired_capacity')
group_name = module.params.get('name') group_name = module.params.get('name')
lc_check = module.params.get('lc_check') lc_check = module.params.get('lc_check')
lt_check = module.params.get('lt_check')
decrement_capacity = False decrement_capacity = False
break_loop = False break_loop = False
@ -1304,13 +1463,15 @@ def terminate_batch(connection, replace_instances, initial_instances, leftovers=
props = get_properties(as_group) props = get_properties(as_group)
desired_size = as_group['MinSize'] desired_size = as_group['MinSize']
if module.params.get('launch_config_name'):
new_instances, old_instances = get_instances_by_lc(props, lc_check, initial_instances) new_instances, old_instances = get_instances_by_launch_config(props, lc_check, initial_instances)
else:
new_instances, old_instances = get_instances_by_launch_template(props, lt_check, initial_instances)
num_new_inst_needed = desired_capacity - len(new_instances) num_new_inst_needed = desired_capacity - len(new_instances)
# check to make sure instances given are actually in the given ASG # check to make sure instances given are actually in the given ASG
# and they have a non-current launch config # and they have a non-current launch config
instances_to_terminate = list_purgeable_instances(props, lc_check, replace_instances, initial_instances) instances_to_terminate = list_purgeable_instances(props, lc_check, lt_check, replace_instances, initial_instances)
module.debug("new instances needed: %s" % num_new_inst_needed) module.debug("new instances needed: %s" % num_new_inst_needed)
module.debug("new instances: %s" % new_instances) module.debug("new instances: %s" % new_instances)
@ -1412,6 +1573,14 @@ def main():
target_group_arns=dict(type='list'), target_group_arns=dict(type='list'),
availability_zones=dict(type='list'), availability_zones=dict(type='list'),
launch_config_name=dict(type='str'), launch_config_name=dict(type='str'),
launch_template=dict(type='dict',
default=None,
options=dict(
version=dict(type='str'),
launch_template_name=dict(type='str'),
launch_template_id=dict(type='str'),
),
),
min_size=dict(type='int'), min_size=dict(type='int'),
max_size=dict(type='int'), max_size=dict(type='int'),
placement_group=dict(type='str'), placement_group=dict(type='str'),
@ -1421,6 +1590,7 @@ def main():
replace_all_instances=dict(type='bool', default=False), replace_all_instances=dict(type='bool', default=False),
replace_instances=dict(type='list', default=[]), replace_instances=dict(type='list', default=[]),
lc_check=dict(type='bool', default=True), lc_check=dict(type='bool', default=True),
lt_check=dict(type='bool', default=True),
wait_timeout=dict(type='int', default=300), wait_timeout=dict(type='int', default=300),
state=dict(default='present', choices=['present', 'absent']), state=dict(default='present', choices=['present', 'absent']),
tags=dict(type='list', default=[]), tags=dict(type='list', default=[]),
@ -1455,7 +1625,9 @@ def main():
global module global module
module = AnsibleModule( module = AnsibleModule(
argument_spec=argument_spec, argument_spec=argument_spec,
mutually_exclusive=[['replace_all_instances', 'replace_instances']] mutually_exclusive=[
['replace_all_instances', 'replace_instances'],
['launch_config_name', 'launch_template']]
) )
if not HAS_BOTO3: if not HAS_BOTO3:
@ -1464,6 +1636,7 @@ def main():
state = module.params.get('state') state = module.params.get('state')
replace_instances = module.params.get('replace_instances') replace_instances = module.params.get('replace_instances')
replace_all_instances = module.params.get('replace_all_instances') replace_all_instances = module.params.get('replace_all_instances')
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)
connection = boto3_conn(module, connection = boto3_conn(module,
conn_type='client', conn_type='client',
@ -1481,7 +1654,7 @@ def main():
module.exit_json(changed=changed) module.exit_json(changed=changed)
# Only replace instances if asg existed at start of call # Only replace instances if asg existed at start of call
if exists and (replace_all_instances or replace_instances): if exists and (replace_all_instances or replace_instances) and (module.params.get('launch_config_name') or module.params.get('launch_template')):
replace_changed, asg_properties = replace(connection) replace_changed, asg_properties = replace(connection)
if create_changed or replace_changed: if create_changed or replace_changed:
changed = True changed = True