DevOps with Boto Python - Part III
Monty: The Firefighter!
Monty the Firefighter! That's right. In this tutorial we will see how to start, stop and list EC2 instances. I say: fire up or cool down an EC2 instance, and that is why Monty is a Firefighter.
By the end of this tutorial you will learn how to,
- Create a generic AWS Connection class
- List EC2 Instances
- List EC2 Instance MetaData
- Start an EC2 Instance
- Stop an EC2 Instance
In previous tutorial we configured a skeleton of DevOps project. Now, let's put it to use, shall we?
Boto: Make a Connection
First and foremost we need to make a connection to AWS. Therefore, I will add a file for the Connection class under "aws" folder. We will use Connection class to create an EC2 connection. Remember, for the AWS connection the credentials and secret key information is retrieved from the .boto config file. Review this article to create a boto configuration file.
#import boto ec2
import boto.ec2
class Connection:
def __init__(self):
''' Connection Instance '''
self.region = 'us-east-1'
def ec2Connection(self):
''' Create and return an EC2 Connection '''
conn = boto.ec2.connect_to_region(self.region)
return conn
Modify "init.py" file under "aws" package to import the Connection class.
from Connection import Connection
Next, we will add an executable python script file. We will use this file extensively during our tutorial series to accomplish various tasks. Let's call this file "DevOpsMain.py".
Riteshs-MacBook-Pro-2:~ rpatel$ cd DevOps
#create DevOpsMain file
Riteshs-MacBook-Pro-2:DevOps rpatel$ touch DevOpsMain.py
Now, let's add python code to make an EC2 Connection to this file.
#!/usr/bin/Python
#Import classes from aws package
from aws import Connection
#Instantiate Connection
connInst = Connection()
#Create an EC2 Connection
conn = connInst.ec2Connection()
#print connection
print conn
Finally, we test our script. Execute the script using Python interpreter.
Riteshs-MacBook-Pro-2:DevOps rpatel$ python DevOpsMain.py
EC2Connection:ec2.us-east-1.amazonaws.com
Voila! Python Interpreter outputs an EC2 Connection.
Boto: List my fires...Instances!
Our project is equipped with the AWS connection. Now let's do some meaningful work with it. We will add a file called "EC2Instance" to the "aws" package. This file will hold functions for listing, starting and stopping instances.
Riteshs-MacBook-Pro-2:DevOps rpatel$ cd aws
#create EC2Instance file
Riteshs-MacBook-Pro-2:aws rpatel$ touch EC2Instance.py
Next we will add a script to list instances associated with the AWS account.
#import EC2
import boto.ec2
class EC2Instance:
def __init__(self):
''' EC2Instance Constructor '''
def list_instances(self,conn):
''' List EC2 Instances '''
# get all instance reservations associated with this AWS account
reservations = conn.get_all_reservations()
# loop through reservations and extract instance information
for r in reservations:
#get all instances from the reservation
instances = r.instances
# loop through instances and print instance information
for i in instances:
# get instance name from the tags object
tags = i.tags
instancename = 'Default EC2 Instance Name'
#check for Name property in tags object
if 'Name' in tags:
instancename = tags['Name']
#print instance information
print 'Instance Name:', instancename, ' Instance Id:', i.id, ' State:', i.state
Now let's modify DevOpsMain.py to accommodate EC2 Instance listing.
#import EC2Instance class
from aws import EC2Instance
#add the lines below to DevOpsMain.py script
ec2 = EC2Instance()
ec2.list_instances(conn)
Entire DevOpsMain.py should look like below.
#!/usr/bin/Python
#Import classes from aws package
from aws import Connection
from aws import EC2Instance
connInst = Connection()
conn = connInst.ec2Connection()
ec2 = EC2Instance()
ec2.listInstances(conn)
Now back to Python Interpreter. Executing DevOpsMain.py should list all instances associated with the AWS account.
Riteshs-MacBook-Pro-2:DevOps rpatel$ python DevOpsMain.py
Instance Name: rpatel_testbox Id: i-1234f1e1 Instance Type: t2.micro State: running
Quite precisely, the output on my terminal shows Instance Name, Instance Id, Instance Type & the State of the instance. We see only 1 instance in the output and that is because my account is running only 1 instance. But you get the gist. It should list all EC2 instances tied with your AWS account.
Boto: Show me Da'MetaData
So, we listed the instance information. But a million dollar question is: how do I know the field names before I start printing the values, right? Well, let's meet "dict". It is a dictionary of object's properties.
In other words, "dict" will simply list the properties tied with the object: In our case an object is the EC2 instance! To print the metadata tied with each instance just add print.dict to your code and boom! script will print metadata for each instance.
#looping through instances
for i in instances:
print i.__dict__
Below is the sample output of "dict" for my instance.
{
'kernel': u'aki-1234590',
'instance_profile': 'instance profile',
'root_device_type': u'instance-store',
'private_dns_name': u'ip-12-12-12-334.rpatel.local',
'_state': running(16),
'group_name': None,
'public_dns_name': '',
'id': u'i-1234e90',
'state_reason': None,
'monitored': False,
'item': u'\n',
'subnet_id': u'subnet-efd123b2',
'block_device_mapping': {
u'/dev/sda1': <boto.ec2.blockdevicemapping.BlockDeviceTypeobjectat0x101153590>
},
'platform': None,
'eventsSet': None,
'ebs_optimized': False,
'client_token': '',
'_in_monitoring_element': False,
'virtualization_type': u'paravirtual',
'architecture': u'x86_64',
'ramdisk': None,
'_previous_state': None,
'tags': {
u'Name': u'rpatel_testbox'
},
'key_name': u'rpatel',
'interfaces': [
NetworkInterface: eni-1e2ea345
],
'sourceDestCheck': u'true',
'image_id': u'ami-be1300d0',
'reason': '',
'groups': [
<boto.ec2.group.Groupobjectat0x101153550>
],
'spot_instance_request_id': None,
'monitoring': u'\n',
'requester_id': None,
'ip_address': u'12.123.111.100',
'monitoring_state': u'disabled',
'_placement': us-east-1c,
'ami_launch_index': u'0',
'dns_name': '',
'region': RegionInfo: us-east-1,
'launch_time': u'2015-01-12T19: 36: 25.000Z',
'persistent': False,
'instance_type': u'm1.large',
'connection': EC2Connection: ec2.us-east-1.amazonaws.com,
'root_device_name': None,
'hypervisor': u'xen',
'private_ip_address': u'10.1.10.200',
'vpc_id': u'vpc-e0123b0d',
'product_codes': [
]
}
Now can you print the launch_time & the instance ip addresses? I am sure you can!
Boto: Start A Fire...Instance
Let's see how to fire up a stopped instance. We will add a function start_instance to our EC2Instance class. You may loop through EC2 Instances to find stopped instances or simply pass in the instance id to start a specific instance. I will use "i-1234e90" as my instance id. For the demonstration I am hardcoding the instance_id. In most cases instance_id will be supplied dynamically.
#import EC2
import boto.ec2
import time
class EC2Instance:
def __init__(self):
''' EC2Instance Constructor '''
def list_instances(self,conn):
''' list instances '''
def start_instance(self,conn,instance_id):
''' Starts a stopped instance '''
#Filter reservations for a specific instance
reservations = conn.get_all_reservations(filters={'instance-id':instance_id})
if(reservations):
instance = reservations[0].instances[0]
#start the instance if it's in a stopped state
if(instance and instance.state == 'stopped'):
print 'Attempting to start instance ', instance_id
instance.start()
#wait till instance is up and running...
while not instance.update() == 'running':
#sleep for 10 seconds, before checking the status again
time.sleep(10)
print 'Instance ', instance_id, ' is ', instance.state, ' now!
Now let's modify the DevOpsMain script to append start_instance and supply the instance_id.
#!/usr/bin/Python
#Import classes from aws package
from aws import Connection
from aws import EC2Instance
connInst = Connection()
conn = connInst.ec2Connection()
ec2 = EC2Instance()
#call start_instance with the Id of an instance
ec2.start_instance(conn, 'i-1234e90')
Back to Python Interpreter. Let's execute the script.
Riteshs-MacBook-Pro-2:DevOps rpatel$ python DevOpsMain.py
Attempting to start instance i-1234e90
Instance i-1234e90 is running now!
And I have successfully started a stopped instance.
Boto: Cool down my fire...Instance
I have an instance up and running. Now let's stop it. Pretty much the exact same steps. I will add stop_instance function to EC2Instance class, modify DevOpsMain to make a call to stop_instance and execute the script.
Let's take a look at the stop_instance function.
#import EC2
import boto.ec2
import time
class EC2Instance:
def __init__(self):
''' EC2Instance Constructor '''
def list_instances(self,conn):
''' list instances '''
def stop_instance(self,conn,instance_id):
''' Stops a running instance'''
#Filter reservations for a specific instance
reservations = conn.get_all_reservations(filters={'instance-id':instance_id})
if(reservations):
instance = reservations[0].instances[0]
#start the instance if it's in a running state
if(instance and instance.state == 'running'):
print 'Attempting to stop the instance ', instance_id
instance.stop()
#wait till instance is completely stopped...
while not instance.update() == 'stopped':
#sleep for 10 seconds, before checking the status again
time.sleep(10)
print 'Instance ', instance_id, ' is ', instance.state, ' now!
Next we modify DevOpsMain.py script.
#!/usr/bin/Python
#Import classes from aws package
from aws import Connection
from aws import EC2Instance
connInst = Connection()
conn = connInst.ec2Connection()
ec2 = EC2Instance()
#call stop_instance with the Id of an instance
ec2.stop_instance(conn, 'i-1234e90')
Back to Python Interpreter. Let's execute the script.
Riteshs-MacBook-Pro-2:DevOps rpatel$ python DevOpsMain.py
Attempting to stop instance i-1234e90
Instance i-1234e90 is stopped now!
In the next article we will see how to extend this code to retrieve volume(s) attached with the instance(s). I say Monty: The Weight Watcher!
Project files are located @ github. Fork and enjoy!
See you then!
Hi, I am Ritesh Patel. I live in a beautiful town surrounded by the mountains. C&O Canal is few miles away. State parks are only a distance away & bike trails galore. It is home sweet home Frederick, MD. A passionate developer. Love to cook. Enjoy playing "Bollywood Tunes" on my harmonica. Apart from that just a normal guy.