Archive

Archive for October, 2021

Boto3 Script to create and attach an EBS Volume to an EC2

October 22, 2021 Leave a comment

import boto3
import logging
import datetime
import argparse
import time
from datetime import datetime
from botocore.exceptions import ClientError

logger = logging.getLogger()
logger.setLevel(logging.INFO)

VolumeList=[]

expirationDate = expiration_Date = ""

DEFAULT_AWS_Account_ID = "1111222222"
DEFAULT_REGION = "us-east-1"

def parse_commandline_arguments():

    global REGION
    global AWS_Account_ID
    global instance_id
    global server_name
    global size_of_volume
    global kms_key

    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                                     description='Boto 2 Scritp to create and attach volume to a given Ec2 Instance.')
    parser.add_argument("-accountID", "--ownerID", dest="aws_ID", type=str, default=DEFAULT_AWS_Account_ID,
                        help="The AWS Account ID where volume tagging is  to be done")
    parser.add_argument("-r", "--region", dest="region", type=str,
                        default=DEFAULT_REGION, help="Specify the region of the AWS Account")
    parser.add_argument("-server_name", "--ServerName", dest="servername", type=str,
                        help="Specify the Instance Name to be terminated")
    parser.add_argument("-volume_size","--Volume_Size",dest="volumesize", type=int,
                        help="Specify the size of new volume to be created and attached")
    parser.add_argument("-kmsId","--KMS_ID",dest="kms_key_id",type=str,
                        help="Specify the KMS Key ID  to encrypt the volume")

    args = parser.parse_args()
    REGION = args.region
    AWS_Account_ID = args.aws_ID
    server_name = args.servername
    size_of_volume = args.volumesize
    kms_key = args.kms_key_id


def ec2_client(region):
    """
    Connects to EC2, returns a connection object
    """
    try:
        conn = boto3.client('ec2', region_name=region)

    except Exception as e:
        sys.stderr.write(
            'Could not connect to region: %s. Exception: %s\n' % (region, e))
        conn = None

    return conn



def wait_for_state (instance, target_state):
    # Waits for instance to move to desired state
    # Vol Creation State: 'creating'|'available'|'in-use'|'deleting'|'deleted'|'error'
    # Vol Attachment State: 'attaching'|'attached'|'detaching'|'detached'
    status = ec2.Instance(instance).state['Name']
    while status != target_state:
        print("Waiting for Instance - {} to come in {} state" .format(instance,target_state))
        time.sleep (5)
        status = ec2.Instance(instance).state['Name']



def create_and_attach_volume(client,serverName,volSize,kmsId):
    global VolumeList
    device = "/dev/sdh"
    print(serverName)
    # Get Instance ID from the given Instance Name
    filters = [ {'Name': 'tag:Name',
                'Values': [serverName]}
                ]
    for attempt in range(5):
        try:
            response = client.describe_instances(Filters=filters)["Reservations"]
            #response = client.describe_instances()
            instanceid = response[0]['Instances'][0]['InstanceId']
            avaialbilityZone = response[0]['Instances'][0]['Placement']['AvailabilityZone']
            print(instanceid + ":" + avaialbilityZone)
        except BaseException as err:
            logger.error(err)
            logger.info("*** ERROR *** during EC2 Describe proceess - retry...")
            time.sleep(0.5)
        else:
            logger.info("--> Done")
            break
    else:
        logger.error("*** ERROR *** - All attempt to describe instance failed - exit with error")
        raise Exception("*** ERROR *** - Can't describe instance")

    # Create volume
    for attempt in range(5):
        try:
            response = client.create_volume(
                            AvailabilityZone=avaialbilityZone,
                            Encrypted=True,
                            KmsKeyId=kmsId,
                            Size=volSize,
                            VolumeType='gp3' ## Default Volume Type
                        )
            #print(response)
        except BaseException as err:
            logger.error(err)
            logger.info("*** ERROR *** during EC2 Volume creation proceess - retry...")
            time.sleep(0.5)
        else:
            logger.info("--> Done")
            break
    else:
        logger.error("*** ERROR *** - All attempt to create EC2 Volume failed - exit with error")
        raise Exception("*** ERROR *** - Can't create EBS Volume")


    if response['ResponseMetadata']['HTTPStatusCode']== 200:
        volume_id= response['VolumeId']
        print('***volume:', volume_id)
        client.get_waiter('volume_available').wait(
                VolumeIds=[volume_id]
                )
        print('***Success!! volume:', volume_id, 'created...')

    VolumeList.append(volume_id)
    print(VolumeList)

    # Add tag on newly created Volumes
    logger.info("Tagging for deletion following Volumes:")
    for volume in VolumeToDelList:
        logger.info("- " + volume)
    for attempt in range(5):
        try:
            print("creating Tag for Volume ID {}" .format(VolumeToDelList))
            client.create_tags(
                    Resources=VolumeToDelList,
                    Tags=[
                        {
                            'Key': 'InsntanceId',
                            'Value': instanceid
                        }
                    ]
            )
        except BaseException as err:
            logger.error(err)
            logger.error("*** ERROR *** during tagging Volumes - retry...")
            time.sleep(0.6)
        else:
            logger.info("--> Done")
            break
    else:
        logger.error("*** ERROR *** - All attempt to tagging volumes - exit with error")
        raise Exception("*** ERROR *** - Can't tagging Volumes")

    # Attach Volume to EC2 Instance
    logger.info("--> Attaching volume to EC2")
    for attempt in range(5):
        try:
            if volume_id:
                print('***attaching volume:', volume_id, 'to:', instanceid)
                response = client.attach_volume(
                            Device=device,
                            InstanceId=instanceid,
                            VolumeId=volume_id,
                            DryRun=False
                            )
                if response['ResponseMetadata']['HTTPStatusCode']== 200:
                    client.get_waiter('volume_in_use').wait(
                            VolumeIds=[volume_id],
                            DryRun=False
                            )
                    print('***Success!! volume:', volume_id, 'is attached to instance:', instanceid)

        except BaseException as err:
            logger.error(err)
            logger.error("*** ERROR *** during EC2 Volume attachment process - retry...")
            time.sleep(0.6) # second
        else:
            logger.info("--> Done")
            break
    else:
        logger.error("*** ERROR *** - All attempt to attach volume to instance failed - exit with error")
        raise Exception("*** ERROR *** - Can't attach volume to EC2")





if __name__ == '__main__':
    try:
        parse_commandline_arguments()
        client=ec2_client(REGION)
        create_and_attach_volume(client,server_name,size_of_volume,kms_key)
    except Exception as error:
        logging.error(error)
        print(str(error))

Happy Reading !!!!

-Anand M

Categories: AWS/Boto3/Python