Added delete_on_termination option for volume attachment

This commit is contained in:
Constantin07 2016-01-07 12:14:10 +00:00 committed by Matt Clay
parent 2dd53a8d91
commit f36c567022

View file

@ -67,6 +67,12 @@ options:
- device id to override device mapping. Assumes /dev/sdf for Linux/UNIX and /dev/xvdf for Windows. - device id to override device mapping. Assumes /dev/sdf for Linux/UNIX and /dev/xvdf for Windows.
required: false required: false
default: null default: null
delete_on_termination:
description:
- When set to "yes", the volume will be deleted upon instance termination.
required: false
default: "no"
choices: ["yes", "no"]
zone: zone:
description: description:
- zone in which to create the volume, if unset uses the zone the instance is in (if set) - zone in which to create the volume, if unset uses the zone the instance is in (if set)
@ -171,6 +177,56 @@ EXAMPLES = '''
volume_size: 50 volume_size: 50
volume_type: gp2 volume_type: gp2
device_name: /dev/xvdf device_name: /dev/xvdf
# Attach an existing volume to instance. The volume will be deleted upon instance termination.
- ec2_vol:
instance: XXXXXX
id: XXXXXX
device_name: /dev/sdf
delete_on_termination: yes
'''
RETURN = '''
device:
description: device name of attached volume
returned: when success
type: string
sample: "/def/sdf"
volume_id:
description: the id of volume
returned: when success
type: string
sample: "vol-35b333d9"
volume_type:
description: the volume type
returned: when success
type: string
sample: "standard"
volume:
description: a dictionary containing detailed attributes of the volume
returned: when success
type: string
sample: {
"attachment_set": {
"attach_time": "2015-10-23T00:22:29.000Z",
"deleteOnTermination": "false",
"device": "/dev/sdf",
"instance_id": "i-8356263c",
"status": "attached"
},
"create_time": "2015-10-21T14:36:08.870Z",
"encrypted": false,
"id": "vol-35b333d9",
"iops": null,
"size": 1,
"snapshot_id": "",
"status": "in-use",
"tags": {
"env": "dev"
},
"type": "standard",
"zone": "us-east-1b"
}
''' '''
import time import time
@ -180,6 +236,7 @@ from distutils.version import LooseVersion
try: try:
import boto.ec2 import boto.ec2
from boto.exception import BotoServerError from boto.exception import BotoServerError
from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
HAS_BOTO = True HAS_BOTO = True
except ImportError: except ImportError:
HAS_BOTO = False HAS_BOTO = False
@ -220,6 +277,7 @@ def get_volume(module, ec2):
module.fail_json(msg="Found more than one volume in zone (if specified) with name: %s" % name) module.fail_json(msg="Found more than one volume in zone (if specified) with name: %s" % name)
return vols[0] return vols[0]
def get_volumes(module, ec2): def get_volumes(module, ec2):
instance = module.params.get('instance') instance = module.params.get('instance')
@ -233,6 +291,7 @@ def get_volumes(module, ec2):
module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message)) module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message))
return vols return vols
def delete_volume(module, ec2): def delete_volume(module, ec2):
volume_id = module.params['id'] volume_id = module.params['id']
try: try:
@ -243,6 +302,7 @@ def delete_volume(module, ec2):
module.exit_json(changed=False) module.exit_json(changed=False)
module.fail_json(msg=ec2_error.message) module.fail_json(msg=ec2_error.message)
def boto_supports_volume_encryption(): def boto_supports_volume_encryption():
""" """
Check if Boto library supports encryption of EBS volumes (added in 2.29.0) Check if Boto library supports encryption of EBS volumes (added in 2.29.0)
@ -290,6 +350,7 @@ def create_volume(module, ec2, zone):
def attach_volume(module, ec2, volume, instance): def attach_volume(module, ec2, volume, instance):
device_name = module.params.get('device_name') device_name = module.params.get('device_name')
delete_on_termination = module.params.get('delete_on_termination')
changed = False changed = False
# If device_name isn't set, make a choice based on best practices here: # If device_name isn't set, make a choice based on best practices here:
@ -313,6 +374,9 @@ def attach_volume(module, ec2, volume, instance):
if adata.instance_id != instance.id: if adata.instance_id != instance.id:
module.fail_json(msg = "Volume %s is already attached to another instance: %s" module.fail_json(msg = "Volume %s is already attached to another instance: %s"
% (volume.id, adata.instance_id)) % (volume.id, adata.instance_id))
else:
# Volume is already attached to right instance
changed = modify_dot_attribute(module, ec2, instance, device_name)
else: else:
try: try:
volume.attach(instance.id, device_name) volume.attach(instance.id, device_name)
@ -323,8 +387,41 @@ def attach_volume(module, ec2, volume, instance):
except boto.exception.BotoServerError, e: except boto.exception.BotoServerError, e:
module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message)) module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message))
modify_dot_attribute(module, ec2, instance, device_name)
return volume, changed return volume, changed
def modify_dot_attribute(module, ec2, instance, device_name):
""" Modify delete_on_termination attribute """
delete_on_termination = module.params.get('delete_on_termination')
changed = False
try:
instance.update()
dot = instance.block_device_mapping[device_name].delete_on_termination
except boto.exception.BotoServerError, e:
module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message))
if delete_on_termination != dot:
try:
bdt = BlockDeviceType(delete_on_termination=delete_on_termination)
bdm = BlockDeviceMapping()
bdm[device_name] = bdt
ec2.modify_instance_attribute(instance_id=instance.id, attribute='blockDeviceMapping', value=bdm)
while instance.block_device_mapping[device_name].delete_on_termination != delete_on_termination:
time.sleep(3)
instance.update()
changed = True
except boto.exception.BotoServerError, e:
module.fail_json(msg = "%s: %s" % (e.error_code, e.error_message))
return changed
def detach_volume(module, ec2, volume): def detach_volume(module, ec2, volume):
changed = False changed = False
@ -339,6 +436,7 @@ def detach_volume(module, ec2, volume):
return volume, changed return volume, changed
def get_volume_info(volume, state): def get_volume_info(volume, state):
# If we're just listing volumes then do nothing, else get the latest update for the volume # If we're just listing volumes then do nothing, else get the latest update for the volume
@ -350,6 +448,7 @@ def get_volume_info(volume, state):
volume_info = { volume_info = {
'create_time': volume.create_time, 'create_time': volume.create_time,
'encrypted': volume.encrypted,
'id': volume.id, 'id': volume.id,
'iops': volume.iops, 'iops': volume.iops,
'size': volume.size, 'size': volume.size,
@ -365,9 +464,12 @@ def get_volume_info(volume, state):
}, },
'tags': volume.tags 'tags': volume.tags
} }
if hasattr(attachment, 'deleteOnTermination'):
volume_info['attachment_set']['deleteOnTermination'] = attachment.deleteOnTermination
return volume_info return volume_info
def main(): def main():
argument_spec = ec2_argument_spec() argument_spec = ec2_argument_spec()
argument_spec.update(dict( argument_spec.update(dict(
@ -379,6 +481,7 @@ def main():
iops = dict(), iops = dict(),
encrypted = dict(type='bool', default=False), encrypted = dict(type='bool', default=False),
device_name = dict(), device_name = dict(),
delete_on_termination = dict(type='bool', default=False),
zone = dict(aliases=['availability_zone', 'aws_zone', 'ec2_zone']), zone = dict(aliases=['availability_zone', 'aws_zone', 'ec2_zone']),
snapshot = dict(), snapshot = dict(),
state = dict(choices=['absent', 'present', 'list'], default='present') state = dict(choices=['absent', 'present', 'list'], default='present')