Error in retrieving public dns name of ec2 instance - python

I am trying to retrieve public dns name of an ec2 instance.
Here is my python3 script.
import sys
import boto3
from botocore.exceptions import ClientError
instance_id = "i-03e7f6391a0f523ee"
action = 'ON'
ec2 = boto3.client('ec2')
if action == 'ON':
# Do a dryrun first to verify permissions
try:
ec2.start_instances(InstanceIds=[instance_id], DryRun=True)
except ClientError as e:
if 'DryRunOperation' not in str(e):
raise
# Dry run succeeded, run start_instances without dryrun
try:
response = ec2.start_instances(InstanceIds=[instance_id], DryRun=False)
print(response)
except ClientError as e:
print(e)
else:
# Do a dryrun first to verify permissions
try:
ec2.stop_instances(InstanceIds=[instance_id], DryRun=True)
except ClientError as e:
if 'DryRunOperation' not in str(e):
raise
# Dry run succeeded, call stop_instances without dryrun
try:
response = ec2.stop_instances(InstanceIds=[instance_id], DryRun=False)
print(response)
except ClientError as e:
print(e)
instance = ec2.Instance('i-1234567890123456')
while instance.state['Name'] not in ('running', 'stopped'):
sleep(5)
print("the instance is initializing")
#pubdns=instance.PublicDnsName
#print ("public dns name"+pubdns)
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(instance_id)
print (foo)
If I use
ec2 = boto3.client('ec2')
in the above code, I get the following error:
AttributeError: 'EC2' object has no attribute 'Instance'
and if I use
ec2 = boto3.resource('ec2')
then I get this error instead:
AttributeError: 'ec2.ServiceResource' object has no attribute 'start_instances'
what I want to do is to be able to connect to an ec2 instance and retrieve its publicdns name.
I have changed the code now based on below suggestions
import sys
import boto3
instance_id = "i-03e7f6391a0f523ee"
action = 'ON'
ec2 = boto3.client('ec2')
#instance = ec2.resource('ec2').instance(instance_id)
if action == 'ON':
response = ec2.start_instances(InstanceIds=[instance_id], DryRun=False)
else:
response = ec2.stop_instances(InstanceIds=[instance_id], DryRun=False)
print(response)
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(instance_id)
print (foo)
but now I get error
in get_name
response = client.describe_instances(InstanceIds = [inst[0].instance_id])
AttributeError: 'str' object has no attribute 'instance_id'

You're conflating two ideas in one.
boto3.client creates an object through which you look up resources like ec2.
Once you have a resource, you can begin to manipulate it.
Use
ec2 = boto3.client('ec2')
and then
instance = ec2.resource('ec2').instance(instance_id)
The second looks up your ec2 instance from the ec2 resource, not the boto3 ec2 client.

Here is a working code in case any one hits here in future I am posting it.This will print public DNS name of all of your instances after switching them on and then shutdown them.
import boto3
from pprint import pprint
ec2=boto3.client('ec2')
response=ec2.describe_instances()
print (response)
instancelist = []
for reservation in (response["Reservations"]):
for instance in reservation["Instances"]:
instancelist.append(instance["InstanceId"])
print (instancelist)
action ='ON'
if action == 'ON':
response = ec2.start_instances(InstanceIds=instancelist, DryRun=False)
ec2client = boto3.resource('ec2')
#response = ec2client.describe_instances()
instances = ec2client.instances.filter(Filters=[{'Name': 'instance-state-name', 'Values': ['running','stopped']}])
ids = []
for instance in instances:
print(instance.id, instance.instance_type)
ids.append(instance.id)
resp=ec2.describe_network_interfaces();
print ("printing pub dns name")
print(resp['NetworkInterfaces'][0]['Association']['PublicDnsName'])
ec2client.instances.filter(InstanceIds=ids).stop()

Related

AWS Lambda function signal success or failure of the execution

I created a aws lambda function and trying to integrate it with AWS Connect.
The lambda function resets the directory password. AWS Connect triggers the lambda function, the function reset the password and signal AWS Connect success or failed. How do I include signal in the code?
import logging
import json
import boto3
client = boto3.client('ds')
def lambda_handler(event, context):
response = reset_user_password()
return event
def reset_user_password():
response = client.reset_user_password(
DirectoryId='d-xxxxxxxxxx',
UserName='username',
NewPassword='Password'
)
Unclear what you mean by signal, but you can add visibility into the response or error message with something like this for your reset function:
def reset_user_password():
try:
response = client.reset_user_password(
DirectoryId='d-xxxxxxxxxx',
UserName='username',
NewPassword='Password'
)
print(response)
except Exception as e:
print(e)
response = str(e)
return response
Also, you are calling the reset function in the lambda handler before it is defined, which will throw an error. You need to update the code like this:
import logging
import json
import boto3
client = boto3.client('ds')
def reset_user_password():
try:
response = client.reset_user_password(
DirectoryId='d-xxxxxxxxxx',
UserName='username',
NewPassword='Password'
)
print(response)
except Exception as e:
print(e)
response = str(e)
return response
def lambda_handler(event, context):
response = reset_user_password()
return response

AWS - Print details on instance that the lambda launches

I'm new to AWS and have been creating some scripts for automation.
This script is launching an EC2 instance. What I would like it to do is also return and print the 'instance ID' and 'public IP' of the instance that the code itself is launching.
import boto3
ec2 = boto3.resource('ec2')
def lambda_handler(event, context):
# create a new EC2 instance
instances = ec2.create_instances(
ImageId='ami-*******',
MinCount=1,
MaxCount=1,
InstanceType='t2.micro',
KeyName='*****'
)
return
The tricky bit here is that public IP may be not immediately available after execution of create_instances. Thus to overcome this timing problem, you can implement basic while loop to wait for the IP.
import json
from time import sleep
import boto3
ec2 = boto3.resource('ec2')
ec2r = boto3.resource('ec2')
def lambda_handler(event, context):
instances = ec2.create_instances(
ImageId='ami-0c94855ba95c71c99',
MinCount=1,
MaxCount=1,
InstanceType='t2.micro',
KeyName='xxxxxxx'
)
instance = instances[0]
while instance.public_ip_address is None:
print('Wait 2 seconds and check again for public ip')
sleep(2)
instance = ec2r.Instance(instance.instance_id)
print('Public IP available')
return [instance.instance_id, instance.public_ip_address]

Boto3 upload_file is silently failing

I am trying to upload a file in s3 bucket and the following code i have used to achieve the same.
Code
accessKey = ''
secretKey = ''
session = boto3.Session(aws_access_key_id = accessKey, aws_secret_access_key = secretKey,)
s3 = session.resource('s3')
try:
response =s3.Object(bucket_name,'sample.docx').upload_file(Filename='C:/Users/Anushka/Desktop/sample.docx')
except Exception as e:
return e
The code does not do anything not even raising any error and if I print "response", "None" gets printed on the shell. I am not able to understand what is the problem with the code.

Create AWS SG using python boto3

I'm trying to create a security group within a specific vpc by passing the variables during the code execution but I get the following errors, when I run the following command with the variables.
./create_sg.py vpc-e79569b2 dev_test_sg testing tcp 22 22 0.0.0.0/0
An error occurred (InvalidVpcID.NotFound) when calling the CreateSecurityGroup operation: The vpc ID 'VPC_ID' does not exist
#!/usr/bin/env python
import sys
import boto3
from botocore.exceptions import ClientError
region = "us-west-1"
VPC_ID=sys.argv[0]
SECURITY_GROUP_NAME=sys.argv[1]
DESCRIPTION=sys.argv[2]
IP_PROTOCOL_1=sys.argv[3]
FROM_PORT_1=sys.argv[4]
TO_PORT_1=sys.argv[5]
CIDR_IP_1=sys.argv[6]
ec2 = boto3.client('ec2')
response = ec2.describe_vpcs()
vpc_id = 'VPC_ID'
try:
response = ec2.create_security_group(GroupName='SECURITY_GROUP_NAME',Description='DESCRIPTION',VpcId=vpc_id)
security_group_id = response['GroupId']
print('Security Group Created %s in vpc %s.' % (security_group_id, vpc_id))
data = ec2.authorize_security_group_ingress(
GroupId=security_group_id,
IpPermissions=[
{'IpProtocol': 'IP_PROTOCOL_1',
'FromPort': FROM_PORT_1,
'ToPort': TO_PORT_1,
'IpRanges': [{'CidrIp': 'CIDR_IP_1'}]}
])
print('Ingress Successfully Set %s' % data)
except ClientError as e:
print(e)
Please review the code and let me know if I need to change something in there to successfully create a security group.
This line is all wrong...
response = ec2.create_security_group(GroupName='SECURITY_GROUP_NAME',Description='DESCRIPTION',VpcId=vpc_id)
IMO it should be:
response = ec2.create_security_group(GroupName=SECURITY_GROUP_NAME,Description=DESCRIPTION,VpcId=VPC_ID)
Ok, here is the complete code with corrections made to the string literals:
#!/usr/bin/env python
import sys
import boto3
from botocore.exceptions import ClientError
region = "us-west-1"
VPC_ID=sys.argv[0]
SECURITY_GROUP_NAME=sys.argv[1]
DESCRIPTION=sys.argv[2]
IP_PROTOCOL_1=sys.argv[3]
FROM_PORT_1=sys.argv[4]
TO_PORT_1=sys.argv[5]
CIDR_IP_1=sys.argv[6]
ec2 = boto3.client('ec2')
response = ec2.describe_vpcs()
try:
response = ec2.create_security_group(GroupName=SECURITY_GROUP_NAME,Description=DESCRIPTION,VpcId=VPC_ID)
security_group_id = response['GroupId']
print('Security Group Created %s in vpc %s.' % (security_group_id, VPC_ID))
data = ec2.authorize_security_group_ingress(
GroupId=security_group_id,
IpPermissions=[
{'IpProtocol': IP_PROTOCOL_1,
'FromPort': int(FROM_PORT_1),
'ToPort': int(TO_PORT_1),
'IpRanges': [{'CidrIp': CIDR_IP_1}]}
])
print('Ingress Successfully Set %s' % data)
except ClientError as e:
print(e)
Try removing the quotes around 'VPC_ID':
vpc_id = VPC_ID

Retrieving public dns of EC2 instance with BOTO3

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.
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)
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 dns of any of your actives 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"
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:
Change this profile with your AWS profile name profile_name='aws_dev'
This code is working for Python3

Categories

Resources