16
votes

I'm using ipython to get an understanding of Boto3 and interacting with EC2 instances. Here is the code I'm using to create an instance:

import boto3

ec2 = boto3.resource('ec2')
client = boto3.client('ec2')


new_instance = ec2.create_instances(
    ImageId='ami-d05e75b8',
    MinCount=1,
    MaxCount=1,
    InstanceType='t2.micro',
    KeyName=<name_of_my_key>,
    SecurityGroups=['<security_group_name>'],
    DryRun = False
    )

This starts an EC2 instance fine, and I can get the public DNS name, ip and other info from the AWS console. But, when I try to get the public DNS using Boto, by doing this:

new_instance[0].public_dns_name

Returns blank quotes. Yet, other instance details, such as:

new_instance[0].instance_type

Returns the correct information.

Any ideas? Thanks.

EDIT:

So if I do:

def get_name(inst):
    client = boto3.client('ec2')
    response = client.describe_instances(InstanceIds = [inst[0].instance_id])
    foo = response['Reservations'][0]['Instances'][0]['NetworkInterfaces'][0]['Association']['PublicDnsName']
    return foo


foo = get_name(new_instance)
print foo

Then it will return the public DNS. But it doesn't make sense to me why I need to do all of this.

3

3 Answers

27
votes

The Instance object you get back is only hydrated with the response attributes from the create_instances call. Since the DNS name is not available until the instance has reached the running state [1], it will not be immediately present. I imagine the time between you creating the instance and calling describe instances is long enough for the micro instance to start.

import boto3

ec2 = boto3.resource('ec2')
instances = ec2.create_instances(
    ImageId='ami-f0091d91',
    MinCount=1,
    MaxCount=1,
    InstanceType='t2.micro',
    KeyName='<KEY-NAME>',
    SecurityGroups=['<GROUP-NAME>'])
instance = instances[0]

# Wait for the instance to enter the running state
instance.wait_until_running()

# Reload the instance attributes
instance.load()
print(instance.public_dns_name)
1
votes
import boto3
import pandas as pd
session = boto3.Session(profile_name='aws_dev')
dev_ec2_client = session.client('ec2')
response = dev_ec2_client.describe_instances()
df = pd.DataFrame(columns=['InstanceId', 'InstanceType', 'PrivateIpAddress','PublicDnsName'])
i = 0
for res in response['Reservations']:
    df.loc[i, 'InstanceId'] = res['Instances'][0]['InstanceId']
    df.loc[i, 'InstanceType'] = res['Instances'][0]['InstanceType']
    df.loc[i, 'PrivateIpAddress'] = res['Instances'][0]['PrivateIpAddress']
    df.loc[i, 'PublicDnsName'] = res['Instances'][0]['PublicDnsName']
    i += 1
print df

Note:

  1. Change this profile with your AWS profile name profile_name='aws_dev'
  2. This code is working for Python3
1
votes

Here my wrapper:

import boto3
from boto3.session import Session

def credentials():
    """Credentials:"""
    session = Session(aws_access_key_id= 'XXXXXXXXX',
                      aws_secret_access_key= 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
    ec2 = boto3.resource('ec2', region_name='us-east-2')
    return ec2

def get_public_dns(instance_id):
    """having the instance_id, gives you the public DNS"""
    ec2 = credentials()
    instance = ec2.Instance(instance_id)
    instancePublicDNS = instance.public_dns_name
    return instancePublicDNS

Then you just need to use your instance_id to get public id of any of your active ec2:

dns = get_public_dns(instance_id)

Remember to change "region_name" to your zone and add your "aws_access_key_id" and "aws_secret_access_key"