From 957ef6efb3a5197ebee896c862ba51010622a7c2 Mon Sep 17 00:00:00 2001 From: Scott Armit Date: Fri, 11 Oct 2013 13:13:04 -0400 Subject: [PATCH] If an AWS account does not have a default subnet in their VPC configuration, then creating instances in that VPC will not automatically provide a public IP/DNS. Boto added this functionality in 2.13.0 (NetworkInterfaceSpecification.associate_public_ip_address). This change adds assign_pubic_ip as a parameter to the ec2 module, ensuring that it is not set to one of BOOLEANS_TRUE if vpc_subnet_id is not also set, and if Boto is less than 2.13.0. --- cloud/ec2 | 56 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/cloud/ec2 b/cloud/ec2 index fc284c14a67..73c6d489133 100644 --- a/cloud/ec2 +++ b/cloud/ec2 @@ -156,6 +156,13 @@ options: required: false default: null aliases: [] + assign_public_ip: + version_added: "1.4" + description: + - when provisioning within vpc, assign a public IP address. Boto library must be 2.13.0+ + required: false + default: null + aliases: [] private_ip: version_added: "1.2" description: @@ -238,7 +245,7 @@ local_action: image: ami-6e649707 wait: yes vpc_subnet_id: subnet-29e63245 - + assign_public_ip: yes # Launch instances, runs some tasks # and then terminate them @@ -336,6 +343,24 @@ def get_instance_info(inst): return instance_info +def boto_supports_associate_public_ip_address(ec2): + """ + Check if Boto library has associate_public_ip_address in the NetworkInterfaceSpecification + class. Added in Boto 2.13.0 + + ec2: authenticated ec2 connection object + + Returns: + True if Boto library accepts associate_public_ip_address argument, else false + """ + + try: + network_interface = boto.ec2.networkinterface.NetworkInterfaceSpecification() + getattr(network_interface, "associate_public_ip_address") + return True + except AttributeError: + return False + def boto_supports_profile_name_arg(ec2): """ Check if Boto library has instance_profile_name argument. instance_profile_name has been added in Boto 2.5.0 @@ -378,10 +403,10 @@ def create_instances(module, ec2): user_data = module.params.get('user_data') instance_tags = module.params.get('instance_tags') vpc_subnet_id = module.params.get('vpc_subnet_id') + assign_public_ip = module.boolean(module.params.get('assign_public_ip')) private_ip = module.params.get('private_ip') instance_profile_name = module.params.get('instance_profile_name') - # group_id and group_name are exclusive of each other if group_id and group_name: module.fail_json(msg = str("Use only one type of parameter (group_name) or (group_id)")) @@ -442,7 +467,6 @@ def create_instances(module, ec2): 'instance_type': instance_type, 'kernel_id': kernel, 'ramdisk_id': ramdisk, - 'subnet_id': vpc_subnet_id, 'private_ip_address': private_ip, 'user_data': user_data} @@ -453,10 +477,28 @@ def create_instances(module, ec2): module.fail_json( msg="instance_profile_name parameter requires Boto version 2.5.0 or higher") - if vpc_subnet_id: - params['security_group_ids'] = group_id + if assign_public_ip: + if not boto_supports_associate_public_ip_address(ec2): + module.fail_json( + msg="assign_public_ip parameter requires Boto version 2.13.0 or higher.") + elif not vpc_subnet_id: + module.fail_json( + msg="assign_public_ip only available with vpc_subnet_id") + + else: + interface = boto.ec2.networkinterface.NetworkInterfaceSpecification( + subnet_id=vpc_subnet_id, + groups=group_id, + associate_public_ip_address=assign_public_ip) + interfaces = boto.ec2.networkinterface.NetworkInterfaceCollection(interface) + params['network_interfaces'] = interfaces + else: - params['security_groups'] = group_name + params['subnet_id'] = vpc_subnet_id + if vpc_subnet_id: + params['security_group_ids'] = group_id + else: + params['security_groups'] = group_name res = ec2.run_instances(**params) except boto.exception.BotoServerError, e: @@ -579,6 +621,7 @@ def main(): user_data = dict(), instance_tags = dict(), vpc_subnet_id = dict(), + assign_public_ip = dict(type='bool', default=False), private_ip = dict(), instance_profile_name = dict(), instance_ids = dict(type='list'), @@ -591,7 +634,6 @@ def main(): aws_access_key = module.params.get('aws_access_key') region = module.params.get('region') - # allow eucarc environment variables to be used if ansible vars aren't set if not ec2_url and 'EC2_URL' in os.environ: ec2_url = os.environ['EC2_URL']