1

I need some help here.

I'm trying to obtain a public IP from a network interface using boto3, for some reason I'm getting the following error:

ec2 = boto3.resource('ec2')
nia = ec2.NetworkInterfaceAssociation('eni-r2d2')
nia.id  # I can obtain the id without any issue
# 'eni-r2d2'
nia.public_ip
# /usr/local/lib/python3.6/site-packages/boto3/resources/factory.py in property_loader(self)
#     343                             self.__class__.__name__))
#     344
# --> 345             return self.meta.data.get(name)
#     346
#     347         property_loader.__name__ = str(snake_cased)
# 
# AttributeError: 'NoneType' object has no attribute 'get'

Note: The network interface belongs to an ECS task, launch type is FARGATE and the network mode is awsvpc. Can someone help me please?

Thanks!

Manre
  • 921
  • 7
  • 12
  • Are you sure eni-r2d2 exists? nia.id could just return what you have given it. It doesn’t have to do a network call and not be any proof it’s valid. – Sam Jul 11 '18 at 02:48
  • @Sam Yes of course, the resource exists, but for some reason the response is still blank. I could solve it using another method, if you're interested check the solution below. Thanks for your response! – Manre Jul 12 '18 at 02:58

2 Answers2

4

I could solve it! Here's the code:

import boto3

session = boto3.Session(
  aws_access_key_id='...',
  aws_secret_access_key='...',
  region_name='...',
)
ec2 = session.client('ec2')
response = ec2.describe_network_interfaces(
    NetworkInterfaceIds=['eni-r2d2'],
)
interface = response['NetworkInterfaces'][0]
interface['Association']['PublicIp']
# '1.2.3.4'
Manre
  • 921
  • 7
  • 12
1

I don't think you can do this purely with boto3 (Edit: OP proved otherwise!), so unless you have a requirement to use it, use the metadata service.

AWS docs would tell you to invoke the metadata service from within the container and parse the json response for the public IP. Documentation here. Note ECS "classic" has a different metadata endpoint when the ecs-agent version < 1.17.0.

Something like this should work from inside a container in Fargate:

import requests

try:
    response = requests.get('http://169.254.170.2/v2/metadata').json()  
    for container in response.get('Containers', []):
        if 'Networks' in container:
            for network in container.get('Networks', []):
                if 'IPv4Addresses' in network:
                    for ipv4address in network.get('IPv4Addresses', []):
                        print ipv4address # or do something else
except requests.exceptions.RequestException:
    # parse the smoldering remains of the response object
bluescores
  • 4,437
  • 1
  • 20
  • 34