From 325aa7281caef2b5765a0a42015fb9ed6e546bd7 Mon Sep 17 00:00:00 2001 From: Patrick Michael Kane Date: Wed, 20 Feb 2019 16:39:01 +0000 Subject: [PATCH 1/3] First pass at using boto3. --- aws_ec2_assign_elastic_ip/__init__.py | 76 +++++++++++++-------------- requirements.txt | 3 +- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/aws_ec2_assign_elastic_ip/__init__.py b/aws_ec2_assign_elastic_ip/__init__.py index 3e46357..7087097 100644 --- a/aws_ec2_assign_elastic_ip/__init__.py +++ b/aws_ec2_assign_elastic_ip/__init__.py @@ -8,10 +8,10 @@ else: import os.path as ospath -import boto.utils from netaddr import IPNetwork, AddrFormatError, AddrConversionError -from boto.ec2 import connect_to_region -from boto.utils import get_instance_metadata + +from ec2_metadata import ec2_metadata +import boto3 from aws_ec2_assign_elastic_ip.command_line_options import ARGS as args @@ -23,38 +23,36 @@ region = args.region -# Fetch instance metadata -metadata = get_instance_metadata(timeout=1, num_retries=1) -if metadata: - try: - region = metadata['placement']['availability-zone'][:-1] - except KeyError: - pass +try: + region = ec2_metadata.region +except KeyError: + pass # Connect to AWS EC2 if args.access_key or args.secret_key: # Use command line credentials - connection = connect_to_region( - region, - aws_access_key_id=args.access_key, - aws_secret_access_key=args.secret_key) + connection = boto3.client('ec2', + region_name=region, + aws_access_key_id=args.access_key, + aws_secret_access_key=args.secret_key) else: # Use environment vars or global boto configuration or instance metadata - connection = connect_to_region(region) + connection = boto3.client('ec2', + region_name=region) logger.info('Connected to AWS EC2 in {0}'.format(region)) def main(): """ Main function """ # Get our instance name - instance_id = boto.utils.get_instance_metadata()['instance-id'] + instance_id = ec2_metadata.instance_id # Check if the instance already has an Elastic IP # If so, exit if _has_associated_address(instance_id): logger.warning('{0} is already assigned an Elastic IP. Exiting.'.format( instance_id)) - sys.exit(0) +# sys.exit(0) # Get an unassigned Elastic IP address = _get_unassociated_address() @@ -65,7 +63,7 @@ def main(): # Assign the Elastic IP to our instance if args.dry_run: - logger.info('Would assign IP {0}'.format(address.public_ip)) + logger.info('Would assign IP {0}'.format(address['PublicIp'])) else: _assign_address(instance_id, address) @@ -80,27 +78,29 @@ def _assign_address(instance_id, address): :returns: None """ logger.debug('Trying to associate {0} with {1}'.format( - instance_id, address.public_ip)) + instance_id, address['PublicIp'])) # Check if this is an VPC or standard allocation try: - if address.domain == 'standard': - # EC2 classic association - connection.associate_address( - instance_id, - public_ip=address.public_ip) + if address['Domain'] == 'standard': + # EC2 classic association + connection.associate_address( + InstanceId=instance_id, + PublicIp=address['PublicIp'], + AllowReassocation=False) else: - # EC2 VPC association + # EC2 VPC association connection.associate_address( - instance_id, - allocation_id=address.allocation_id) + InstanceId=instance_id, + allocation_id=address['AllocationId'], + AllowReassocation=False) except Exception as error: logger.error('Failed to associate {0} with {1}. Reason: {2}'.format( - instance_id, address.public_ip, error)) + instance_id, address['PublicIp'], error)) sys.exit(1) logger.info('Successfully associated Elastic IP {0} with {1}'.format( - address.public_ip, instance_id)) + address['PublicIp'], instance_id)) def _get_unassociated_address(): @@ -110,30 +110,30 @@ def _get_unassociated_address(): """ eip = None - for address in connection.get_all_addresses(): + for address in connection.describe_addresses()['Addresses']: # Check if the address is associated - if address.instance_id: + if address['InstanceId']: logger.debug('{0} is already associated with {1}'.format( - address.public_ip, address.instance_id)) + address['PublicIp'], address['InstanceId'])) continue # Check if the address is attached to an ENI - if address.network_interface_id: + if address['NetworkInterfaceId']: logger.debug('{0} is already attached to {1}'.format( - address.public_ip, address.network_interface_id)) + address['PublicIp'], address['NetworkInterfaceId'])) continue # Check if the address is in the valid IP's list - if _is_valid(address.public_ip): + if _is_valid(address['PublicIp']): logger.debug('{0} is unassociated and OK for us to take'.format( - address.public_ip)) + address['PublicIp'])) eip = address break else: logger.debug( '{0} is unassociated, but not in the valid IPs list'.format( - address.public_ip, address.instance_id)) + address['PublicIp'], address['InstanceId'])) if not eip: logger.error('No unassociated Elastic IP found!') @@ -148,7 +148,7 @@ def _has_associated_address(instance_id): :param instance_id: Instances ID :returns: bool -- True if the instance has an Elastic IP associated """ - if connection.get_all_addresses(filters={'instance-id': instance_id}): + if connection.describe_addresses(Filters=[{'Name': 'instance-id', 'Values': [ec2_metadata.instance_id]}])['Addresses']: return True return False diff --git a/requirements.txt b/requirements.txt index f532ab0..e815995 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -boto>=2.29.1 +boto3>=1.0.0 +ec2-metadata>=1.8.0 netaddr>=0.7.12 From 3d3c43b49998d9a65628f0ae6e6c273cca41f5e6 Mon Sep 17 00:00:00 2001 From: Patrick Michael Kane Date: Wed, 20 Feb 2019 16:46:07 +0000 Subject: [PATCH 2/3] bring back exit if already assigned fix detecting associated addresses fix two spelling errors --- aws_ec2_assign_elastic_ip/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws_ec2_assign_elastic_ip/__init__.py b/aws_ec2_assign_elastic_ip/__init__.py index 7087097..168140a 100644 --- a/aws_ec2_assign_elastic_ip/__init__.py +++ b/aws_ec2_assign_elastic_ip/__init__.py @@ -52,7 +52,7 @@ def main(): if _has_associated_address(instance_id): logger.warning('{0} is already assigned an Elastic IP. Exiting.'.format( instance_id)) -# sys.exit(0) + sys.exit(0) # Get an unassigned Elastic IP address = _get_unassociated_address() @@ -87,13 +87,13 @@ def _assign_address(instance_id, address): connection.associate_address( InstanceId=instance_id, PublicIp=address['PublicIp'], - AllowReassocation=False) + AllowReassociation=False) else: # EC2 VPC association connection.associate_address( InstanceId=instance_id, - allocation_id=address['AllocationId'], - AllowReassocation=False) + AllocationId=address['AllocationId'], + AllowReassociation=False) except Exception as error: logger.error('Failed to associate {0} with {1}. Reason: {2}'.format( instance_id, address['PublicIp'], error)) @@ -112,13 +112,13 @@ def _get_unassociated_address(): for address in connection.describe_addresses()['Addresses']: # Check if the address is associated - if address['InstanceId']: + if 'InstanceId' in address.keys(): logger.debug('{0} is already associated with {1}'.format( address['PublicIp'], address['InstanceId'])) continue # Check if the address is attached to an ENI - if address['NetworkInterfaceId']: + if 'NetworkInterfaceId' in address.keys(): logger.debug('{0} is already attached to {1}'.format( address['PublicIp'], address['NetworkInterfaceId'])) continue From 0ad47be08bdbb573ce2db98c57ddb1f6962c64ff Mon Sep 17 00:00:00 2001 From: Patrick Michael Kane Date: Wed, 20 Feb 2019 16:48:30 +0000 Subject: [PATCH 3/3] fix copy pasta bug. --- aws_ec2_assign_elastic_ip/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws_ec2_assign_elastic_ip/__init__.py b/aws_ec2_assign_elastic_ip/__init__.py index 168140a..7c266d1 100644 --- a/aws_ec2_assign_elastic_ip/__init__.py +++ b/aws_ec2_assign_elastic_ip/__init__.py @@ -133,7 +133,7 @@ def _get_unassociated_address(): else: logger.debug( '{0} is unassociated, but not in the valid IPs list'.format( - address['PublicIp'], address['InstanceId'])) + address['PublicIp'])) if not eip: logger.error('No unassociated Elastic IP found!')