import boto3
from botocore.exceptions import ClientError
import time

# A script to create an EBS volume and attach it to an existing EC2 instance
# using Boto3.

# --- Configuration ---
REGION = "us-east-1"
VOLUME_SIZE = 10 # GB
VOLUME_TYPE = "gp3"
VOLUME_NAME = "MyBoto3EBSVolume"
DEVICE_NAME = "/dev/sdf" # Common device name for Linux instances

ec2_client = boto3.client('ec2', region_name=REGION)
ec2_resource = boto3.resource('ec2', region_name=REGION)

def get_instance_az(instance_id):
    """Validates EC2 instance ID and gets its Availability Zone."""
    print(f"Validating EC2 instance ID '{instance_id}' and getting its Availability Zone...")
    try:
        response = ec2_client.describe_instances(InstanceIds=[instance_id])
        instance_az = response['Reservations'][0]['Instances'][0]['Placement']['AvailabilityZone']
        print(f"EC2 instance '{instance_id}' is in Availability Zone: {instance_az}")
        return instance_az
    except ClientError as e:
        if e.response['Error']['Code'] == 'InvalidInstanceID.NotFound':
            print(f"Error: EC2 instance '{instance_id}' not found in region '{REGION}'.")
        else:
            print(f"Error describing instance: {e}")
        raise

def create_ebs_volume(instance_az):
    """Creates a new EBS volume."""
    print(f"\n--- Creating EBS Volume: {VOLUME_NAME} in {instance_az} ---")
    try:
        volume = ec2_resource.create_volume(
            AvailabilityZone=instance_az,
            Size=VOLUME_SIZE,
            VolumeType=VOLUME_TYPE,
            TagSpecifications=[{'ResourceType': 'volume', 'Tags': [{'Key': 'Name', 'Value': VOLUME_NAME}]}]
        )
        print(f"EBS Volume created with ID: {volume.id}. Waiting for it to be available...")
        volume.wait_until_available()
        print("EBS Volume is available.")
        return volume
    except ClientError as e:
        print(f"Error creating volume: {e}")
        raise

def attach_ebs_volume(volume, instance_id):
    """Attaches the EBS volume to the EC2 instance."""
    print(f"\n--- Attaching EBS Volume '{volume.id}' to EC2 Instance '{instance_id}' ---")
    try:
        ec2_client.attach_volume(
            VolumeId=volume.id,
            InstanceId=instance_id,
            Device=DEVICE_NAME
        )
        print("EBS Volume attached. It may take a moment for the OS to recognize the new device.")
        print("You can now SSH into your EC2 instance and format/mount the new volume.")
    except ClientError as e:
        print(f"Error attaching volume: {e}")
        raise

def detach_ebs_volume(volume, instance_id):
    """Detaches the EBS volume from the EC2 instance."""
    print(f"\n--- Detaching EBS Volume '{volume.id}' from EC2 Instance '{instance_id}' ---")
    try:
        ec2_client.detach_volume(
            VolumeId=volume.id,
            InstanceId=instance_id
        )
        print("Waiting for volume to be available (detached)...")
        volume.wait_until_available()
        print("EBS Volume detached.")
    except ClientError as e:
        print(f"Error detaching volume: {e}")
        raise

def delete_ebs_volume(volume):
    """Deletes the EBS volume."""
    print(f"\n--- Deleting EBS Volume '{volume.id}' ---")
    try:
        volume.delete()
        print("EBS Volume deleted.")
    except ClientError as e:
        print(f"Error deleting volume: {e}")
        raise

def main():
    ec2_instance_id = input("Enter the ID of an existing EC2 instance to attach the EBS volume to: ")
    if not ec2_instance_id:
        print("EC2 Instance ID cannot be empty. Exiting.")
        return

    volume = None
    try:
        instance_az = get_instance_az(ec2_instance_id)
        volume = create_ebs_volume(instance_az)
        attach_ebs_volume(volume, ec2_instance_id)

        input("Press Enter to detach and delete the EBS volume...")

    except ClientError as e:
        print(f"An AWS client error occurred: {e}")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
    finally:
        if volume:
            try:
                detach_ebs_volume(volume, ec2_instance_id)
            except ClientError as e:
                print(f"Could not detach volume: {e}. Attempting to delete anyway.")
            delete_ebs_volume(volume)
        print("\n--- EBS volume demonstration and cleanup complete ---")

if __name__ == "__main__":
    main()
