Backend Helpers | Automation and Software Development for Cloud Applicationses

Introduction to AWS EC2 Using Python

Amazon EC2 is a service that provides computer power in the cloud. In our previous post we cover the basis of this service. Today we are going to demonstrate how to use python to access AWS EC2 functionality.

Python Boto3

Boto3 is a Python3 client library for Amazon Web Services. The following command installs this library in your local system:

pip3 install boto3

Boto3 AWS Credentials Configuration

There are two options for configuring boto. The first one is to define the environment variables AWS_ACCESS_KEY_ID ,AWS_SECRET_ACCESS_KEY and AWS_DEFAULT_REGION


export AWS_ACCESS_KEY_ID="MY_KEY"
export AWS_SECRET_ACCESS_KEY="MY_AWS_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="eu-west1"

The second one is to create a ~/.boto file and copy the following content:


[Credentials]
aws_access_key_id = YOURACCESSKEY
aws_secret_access_key = YOURSECRETKEY
region = eu-west1

Getting started with boto

The following code shows some basic examples of using AWS EC2 using python:


# Lists all ec2 regions
import boto3

ec2 = boto3.client('ec2')

result = ec2.describe_regions()

result.keys()

for region in result['Regions']:
    print(region)


# Lists availability zones for a given region
import boto3

ec2 = boto3.client('ec2', region_name='us-west-2')

result = ec2.describe_availability_zones()

result.keys()

for zone in result['AvailabilityZones']:
    print(zone)


Example 1: Get or Create a Security Group

The following code uses the create_security_group function to create a new group:




from botocore.exceptions import ClientError
import boto3

import argparse


def get_or_create_security_group(name, description):
    """
    Search by group_name, if doesn't exits, it is created
    """
    try:
        ec2 = boto3.client('ec2')
        return ec2.describe_security_groups(GroupNames=[name])
    except ClientError as e:
        if e.response['Error']['Code']  == 'InvalidGroup.NotFound':
            group_id = ec2.create_security_group(GroupName=name, Description=description)['GroupId']
            return group_id
        else:
            raise

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--name', required=True)
    parser.add_argument('--description', required=True)
    args = parser.parse_args()
    result = get_or_create_security_group(args.name, args.description)
    for group in result['SecurityGroups']:
        print('keys: {}'.format(', '.join(group.keys()) ))
        print('GroupName: {}'.format(group['GroupName']))
        print('Description: {}'.format(group['Description']))


if __name__ == '__main__':
    main()



python get_or_create_security_group.py --name=my-group-test \
  --description='example security group with ec2 access'

Example 2: Grant SSH Access to a Security Group

The following example uses the authorize_ingress function to grant ssh access to a security group:



import boto3

import argparse


def authorize_security_group(
        ip_protocol='tcp', region='us-west-2', name=None, from_port=None,
        to_port=None, cidr_ip=None):
    """
    Authorize cidr_ip access to a security group
    """
    response = boto3.client('ec2').describe_security_groups(GroupNames=[name])
    group_id = response['SecurityGroups'][0]['GroupId']
    security_group = boto3.resource('ec2').SecurityGroup(group_id)

    return security_group.authorize_ingress(
        IpProtocol=ip_protocol, FromPort=from_port, ToPort=to_port, CidrIp=cidr_ip)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--name', required=True)
    parser.add_argument('--region',  default='us-west-2')
    parser.add_argument('--ip_protocol', default='tcp')
    parser.add_argument('--from_port', required=True, type=int)
    parser.add_argument('--to_port', required=True, type=int)
    parser.add_argument('--cidr_ip', required=True)
    args = parser.parse_args()
    result = authorize_security_group(
        ip_protocol=args.ip_protocol, region=args.region, name=args.name,
        from_port=args.from_port, to_port=args.to_port, cidr_ip=args.cidr_ip)
    print(result)


if __name__ == '__main__':
    main()


python autorize_security_group.py --name=my-group-test \
  --ip_protocol=tcp --from_port=22 \
  --to_port=22 --cidr_ip=0.0.0.0/32 
Example 3: Revoke SSH Access to a Security Group

The following code uses the revoke_ingress function to revoke SSH to a security group:



import boto3

import argparse


def revoque_from_security_group(
        ip_protocol='tcp', region='us-west-2', name=None, from_port=None,
        to_port=None, cidr_ip=None):
    """
    Revoque cidr_ip access to a security group
    """
    response = boto3.client('ec2').describe_security_groups(GroupNames=[name])
    group_id = response['SecurityGroups'][0]['GroupId']
    security_group = boto3.resource('ec2').SecurityGroup(group_id)

    return security_group.revoke_ingress(
        IpProtocol=ip_protocol, FromPort=from_port, ToPort=to_port, CidrIp=cidr_ip)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--name', required=True)
    parser.add_argument('--region',  default='us-west-2')
    parser.add_argument('--ip_protocol', default='tcp')
    parser.add_argument('--from_port', required=True, type=int)
    parser.add_argument('--to_port', required=True, type=int)
    parser.add_argument('--cidr_ip', required=True)
    args = parser.parse_args()
    result = revoque_from_security_group(
        ip_protocol=args.ip_protocol, region=args.region, name=args.name,
        from_port=args.from_port, to_port=args.to_port, cidr_ip=args.cidr_ip)
    print(result)


if __name__ == '__main__':
    main()



python revoke_security_group.py --name=my-group-test \
  --ip_protocol=tcp --from_port=22 --to_port=22 \
  --cidr_ip=0.0.0.0/32  --region=us-west-2
Example 4: Create SSH Key Pair

The function create_key_pair creates a ssh key pair for a specific region:




import boto3

import argparse
import os


def create_key_pair(key_dir, key_name):
    f_path = os.path.join(key_dir, key_name)
    ec2 = boto3.client('ec2')
    key =  ec2.create_key_pair(KeyName=key_name)
    with open(f_path, 'a+') as f:
        f.write(key['KeyMaterial'])
    return key


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--key_name', required=True)
    parser.add_argument('--key_dir', required=True)
    args = parser.parse_args()
    key = create_key_pair(args.key_dir, args.key_name)
    print(key['KeyFingerprint'])



if __name__ == '__main__':
    main()

python create_key_pair.py --key_name test_key.pem --key_dir ~/.ssh/
Example 5: Creating EBS Volume

The following code shows how to use the function create_volume:



import boto3

import argparse


def create_volume(region, zone, size_gb):
    ec2 = boto3.client('ec2' , region_name=region)
    v = ec2.create_volume(
       Size=size_gb, AvailabilityZone=zone)
    return v


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--size_gb', type=int,required=True)
    parser.add_argument('--region',  required=True)
    parser.add_argument('--zone', required=True)
    args = parser.parse_args()
    result = create_volume(
        args.region, args.zone, args.size_gb)
    print(result)

if __name__ == '__main__':
    main()

python create_ebs_volume.py --region=eu-west-1 --zone=eu-west-1a  --size_gb=1
Example 6: Create a EC2 Instance

The function run_instances may be used to create one or more instances.




import boto3

import argparse
import time


def launch_instance(ami, instance_type, group_name, min_count=1, max_count=1):

    ec2 = boto3.client('ec2')

    response = ec2.describe_security_groups(GroupNames=[group_name])
    group_id = response['SecurityGroups'][0]['GroupId']
    return ec2.run_instances(
        ImageId=ami,SecurityGroupIds=[group_id], InstanceType=instance_type,
        MinCount=min_count, MaxCount=max_count)


def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--ami', required=True)
    parser.add_argument('--instance_type', required=False, default='t1.nano')
    parser.add_argument('--group_name', required=True)

    args = parser.parse_args()

    result = launch_instance(
        ami=args.ami, instance_type=args.instance_type,
        group_name=args.group_name
    )

    print(result)

if __name__ == '__main__':
    main()




python launch_instance.py  --ami ami-047bb4163c506cd98 \
    --instance_type=t2.nano  --group_name=my-group-test --zone=eu-west-1a

Example 7: Attach Volume to an Instance

AWS instances have a root hard drive, but when an instance is stopped the root volume associated to that instance disappears. The following example uses the function attach_volume to append a second hard drive to a ec2 instance. This disk won't be destroyed if the instance is destroyed.


import boto
import boto.ec2

import argparse


def attach_volume(
        region='us-west-2', volume_id=None, instance_id=None,
        device_name='/dev/sdb'):

    ec2 = boto.ec2.connect_to_region(region)
    volume = ec2.get_all_volumes(volume_ids=volume_id)[0]
    volume.attach(instance_id, device_name)
    return volume

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('--region',  default='us-west-2')
    parser.add_argument('--volume_id',  required=True)
    parser.add_argument('--instance_id',  required=True)
    parser.add_argument('--device_name',  default='sdb')

    args = parser.parse_args()
    v = attach_volume(
        region=args.region, volume_id=args.volume_id,
        device_name=args.device_name, instance_id=args.instance_id)
    print(v)

if __name__ == '__main__':
    main()

    python attach_volume.py --volume_id=vol-05457b66dd0389d53 \
      --instance_id=i-073577bf60eea7224 --device_name=/dev/xvdb