jmoorhead
jmoorhead

Reputation: 403

AWS - How to get boto3 detach volume state

I have a script that is encrypting instance volumes that are not currently encrypted. The last two steps are to detach the unencrypted volume and attach the new encrypted volume. It works if I use time.sleep(180) to create a wait period before the attach volume process starts. This would be more efficient if it could ensure the previous step completed successfully. That is why I am using a while statement.

import boto3, json, sys, time
from botocore.exceptions import ClientError

if len(sys.argv) < 2:
    print("A profile parameter is required.")
    profile = input("Enter a profile name: ")
    boto3.setup_default_session(profile_name=profile)
else:
    profile = (sys.argv[1])
    boto3.setup_default_session(profile_name=profile)

ec2 = boto3.resource('ec2')
instances = ec2.instances.filter(InstanceIds=[sys.argv[2]])

for i in instances:
    i_name = "unnamed"
    r = i.root_device_name
    i_az = i.placement['AvailabilityZone']
    if i.tags is None:
        continue
    for tag in i.tags:
        if tag['Key'] == "Name":
            i_name = tag['Value']
        if tag["Key"] == 'Costcenter':
            i_div = tag['Value']
    print('\n')
    print(' {}'.format(i.id))
    for x in i.block_device_mappings:
        volumes = i.volumes.all()
        d = x.get('DeviceName')
        e = x.get('Ebs')
        g = e.get('VolumeId')
        for v in volumes:
            if v.id == g:
                f = v.size
                h = v.encrypted
                if h == False:
                    snap_name = i_name + "_" + d
                    ec2.instances.filter(InstanceIds=[i.id]).stop()
                    while i.state['Name'] != 'stopped':
                        time.sleep(10)
                        i.load()
                    snap = ec2.create_snapshot(
                        VolumeId = g,
                        TagSpecifications=[
                            {
                                'ResourceType': 'snapshot',
                                'Tags' : [
                                    {
                                        'Key': 'Name',
                                        'Value': snap_name
                                    },
                                    {
                                        'Key': 'Backup',
                                        'Value': 'Daily'
                                    },
                                    {
                                        'Key': 'Costcenter',
                                        'Value': i_div
                                    },
                                ],
                            },
                        ],
                    Description = 'Snapshot of volume ({})'.format(v.id)
                    )
                    snap.load()
                    while snap.state != 'completed':
                        time.sleep(10)
                        snap.load()
                    snap_id = snap.id
                    vol = ec2.create_volume(
                        AvailabilityZone = i_az,
                        Encrypted = True,
                        SnapshotId = snap_id,
                        VolumeType = 'gp3',
                        TagSpecifications=[
                            {
                                'ResourceType': 'volume',
                                'Tags': [
                                    {
                                        'Key': 'Name',
                                        'Value': i_name
                                    },
                                    {
                                        'Key': 'Backup',
                                        'Value': 'Daily'
                                    },
                                    {
                                        'Key': 'Costcenter',
                                        'Value': i_div
                                    },
                                ],
                            },
                        ]
                    )
                    while vol.state != 'available':
                        time.sleep(10)
                        vol.load()
                    vol_id = vol.id
                    volume = ec2.Volume(v.id)
                    detach_vol = volume.detach_from_instance(
                        Device = d,
                        Force = False,
                        InstanceId = i.id,
                        VolumeId = v.id,
                        DryRun = False
                    )
                    while detach_vol != 'detached':
                        time.sleep(10)
                        detach_vol.load()
                    
                    vol_id = vol.id
                    attach_vol = volume.attach_to_instance(
                        VolumeId = vol_id,
                        Device = d,
                        InstanceId = i.id,
                        DryRun = False
                    )
                    
                    while attach_vol.state != 'attached':
                        time.sleep(10)
                        attach_vol.load()

I am trying to capture the state of a volume being detached and attached. The last section of the script is where I am getting an error.

                detach_vol = volume.detach_from_instance(
                    Device = d,
                    Force = False,
                    InstanceId = i.id,
                    VolumeId = v.id,
                    DryRun = False
                )
                while detach_vol.state != 'detached':
                    time.sleep(10)
                    detach_vol.load()
                
                vol_id = vol.id
                attach_vol = volume.attach_to_instance(
                    VolumeId = vol_id,
                    Device = d,
                    InstanceId = i.id,
                    DryRun = False
                )
                
                while attach_vol.state != 'attached':
                    time.sleep(10)
                    attach_vol.load()

This is the error I am getting for the detach section. If I comment out the while statement and use time.sleep(180) it will get to the attach section and essentially get the same error as the detach block.

Traceback (most recent call last):
  File "C:\Users\jmoorhead\bin\EC2-Vol-Encryption.py", line 131, in <module>
    while detach_vol.state != 'detached':
AttributeError: 'dict' object has no attribute 'state'

I have tried using response['responsemetadata']['httpstatuscode'] instead of the while statement but haven't been able to get that to work either. Any help could give would be greatly appreicated.

Upvotes: 2

Views: 1453

Answers (2)

jmoorhead
jmoorhead

Reputation: 403

I was able to create a functional while statement for the detach and attach blocks of code.

volume = ec2.Volume(v.id)
detach_vol = volume.detach_from_instance(
    Device = d,
    Force = False,
    InstanceId = i.id,
    VolumeId = v.id,
    DryRun = False
),
while volume.state != "available":
    time.sleep(10)
    volume.load()
volume = ec2.Volume(vol_id)
attach_vol = volume.attach_to_instance(
    VolumeId = vol_id,
    Device = d,
    InstanceId = i.id,
    DryRun = False
)
while volume.state != "in-use":
    time.sleep(10)
    volume.load()

Upvotes: 0

alexis-donoghue
alexis-donoghue

Reputation: 3387

  1. Volume.detach_from_instance() returns dict, not Volume object. You should use detach_vol["state"] instead of detach_vol.state, that's what error is indicating.

  2. boto3 provides waiters for use cases like these. In this case you might use EC2.Waiter.VolumeAvailable or EC2.Waiter.VolumeInUse, depending on your logic (there is no dedicated "volume is detached" waiter): https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Waiter.VolumeAvailable

Upvotes: 1

Related Questions