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
Related
I have the below code it is working very well in local for stopping EC2 Instance but while I am trying to move its production it is stopping only the first instance not the second one/nth one
import boto3
import json
access_key = "AKIAJSVXXXXXXXXXX"
secret_key = "mSvhX5q7uw8dTZ543qtC6OXXXXXXXXXXXX"
client = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name='us-east-1')
file1 = open("Myfile.txt", "r").read().split("\n")
print(file1)
ec2_result = client.describe_instances(
Filters=[
{
'Name': 'tag:Name',
'Values': file1
}
]
)
ids = [ec2_result['Reservations'][0]['Instances'][i]['InstanceId'] for i in
range(len(ec2_result['Reservations'][0]['Instances']))]
print(ids)
response = client.stop_instances(
InstanceIds=ids
)
print("stooped now")
Myfile.txt
instanceonename
instance2name
It is working very well in my local system but in production, it is stopping only the first EC2 instance
not second one
It stops only one instance, because your list comprehension iterates only over one instance. You need double for:
ids = [instance['InstanceId'] \
for reservation in ec2_result['Reservations'] \
for instance in reservation['Instances']]
I have tried to create user credential in AWS EC2 Windows Instance using Boto3 AWS-RunPowerShellScript. But when i trying to run this below code, getting error "AttributeError: 'ec2.ServiceResource' object has no attribute 'send_command'".
import boto3
import os
import subprocess
ssm_client = boto3.resource('ec2',aws_access_key_id='xxxxxx',aws_secret_access_key='yyyyy', region_name='us-west-2')
session = boto3.Session (profile_name='exampleaws')
response = ssm_client.send_command(
InstanceIds=[
"i-xxxxxx" # use instance id on which you want to execute, even multiple is allowd
],
DocumentName="AWS-RunPowerShellScript",
Parameters={
'commands':[
'New-LocalUser "Latchu" -Password "ABCD123" -FullName "LakshmiNarayanan" -Description "User-Details'
]
},
)
command_id = response['Command']['CommandId']
output = ssm_client.get_command_invocation(
CommandId=command_id,
InstanceId='i-xxxxxx',
)
print(output)```
Your ssm_client is incorrect as send_command is property of ssm, not ec2. Thus, it should be:
ssm_client = boto3.client('ssm', aws_access_key_id='xxxxxx', aws_secret_access_key='yyyyy', region_name='us-west-2')
Also your session is not used at all. There still could be other errors which are not apparent yet.
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]
I am working on executing an AWS Lambda code from Code-pipeline. I have given the lambda role full access to EC2 and code-deploy. The commands generally work when I am not triggering them from code-pipeline. When Triggered from code-pipeline, they just keep on running, even though success is sent. What am i doing wrong?
Code :
import boto3
import json
def lambda_handler(event, context):
reservations = boto3.client('ec2').describe_instances()['Reservations']
instances_list = []
process_instance_list = []
command = 'COMMAND TO EXECUTE ON SERVER'
ssm = boto3.client('ssm')
for res in reservations:
instances = res['Instances']
for inst in res['Instances']:
for tag in inst['Tags']:
#print("Tag value is {}".format(tag['Value']))
if tag['Value']=='Ubuntu_Magento':
print("{} {} {}".format(tag['Value'], inst['InstanceId'], inst['LaunchTime']))
instances_list.append(inst)
instances_list.sort(key=lambda x: x['LaunchTime'])
instance_id = instances_list[0]['InstanceId']
ssmresponse = ssm.send_command(InstanceIds=[instance_id], DocumentName='AWS-RunShellScript', Parameters= { 'commands': [command]})
code_pipeline = boto3.client('codepipeline')
job_id = event['CodePipeline.job']['id']
code_pipeline.put_job_success_result(jobId=job_Id)
Any lambda by default has lifespan of 15 mins only, after that it exits no matter what. I think it has something to do with the way you are trigger it.
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()