Reputation: 403
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
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
Reputation: 3387
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.
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