Skip to content

Commit

Permalink
merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
abikouo committed Jun 21, 2021
1 parent dbec0b0 commit 0b794ad
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ec2_vol - add parameter ``multi_attach`` to support Multi-Attach on volume creation/update (https://github.com/ansible-collections/amazon.aws/pull/362).
85 changes: 58 additions & 27 deletions plugins/modules/ec2_vol.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@
- Requires at least botocore version 1.19.27.
type: int
version_added: 1.4.0
multi_attach:
description:
- If set to C(yes), Multi-Attach will be enabled when creating the volume.
- When you create a new volume, Multi-Attach is disabled by default.
type: bool
version_added: 2.0.0
author: "Lester Wade (@lwade)"
extends_documentation_fragment:
- amazon.aws.aws
Expand Down Expand Up @@ -189,6 +195,13 @@
volume_type: gp2
device_name: /dev/xvdf
# Create new volume with multi-attach enabled
- amazon.aws.ec2_vol:
instance: XXXXXX
volume_size: 50
device_name: sdd
multi_attach: true
# Attach an existing volume to instance. The volume will be deleted upon instance termination.
- amazon.aws.ec2_vol:
instance: XXXXXX
Expand Down Expand Up @@ -218,13 +231,13 @@
returned: when success
type: str
sample: {
"attachment_set": {
"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",
Expand Down Expand Up @@ -408,14 +421,23 @@ def update_volume(module, ec2_conn, volume):
throughput_changed = True
req_obj['Throughput'] = target_throughput

changed = iops_changed or size_changed or type_changed or throughput_changed
target_multi_attach = module.params.get('multi_attach')
multi_attach_changed = False
if target_multi_attach:
original_multi_attach = volume['multi_attach_enabled']
if target_multi_attach != original_multi_attach:
multi_attach_changed = True
req_obj['MultiAttachEnabled'] = target_multi_attach

changed = iops_changed or size_changed or type_changed or throughput_changed or multi_attach_changed

if changed:
response = ec2_conn.modify_volume(**req_obj)

volume['size'] = response.get('VolumeModification').get('TargetSize')
volume['volume_type'] = response.get('VolumeModification').get('TargetVolumeType')
volume['iops'] = response.get('VolumeModification').get('TargetIops')
volume['multi_attach_enabled'] = response.get('VolumeModification').get('TargetMultiAttachEnabled')
if module.botocore_at_least("1.19.27"):
volume['throughput'] = response.get('VolumeModification').get('TargetThroughput')

Expand All @@ -431,6 +453,10 @@ def create_volume(module, ec2_conn, zone):
volume_type = module.params.get('volume_type')
snapshot = module.params.get('snapshot')
throughput = module.params.get('throughput')
multi_attach = module.params.get('multi_attach')
# If custom iops is defined we use volume_type "io1" rather than the default of "standard"
if iops:
volume_type = 'io1'

volume = get_volume(module, ec2_conn)

Expand Down Expand Up @@ -458,6 +484,8 @@ def create_volume(module, ec2_conn, zone):

if throughput:
additional_params['Throughput'] = int(throughput)
if multi_attach:
additional_params['MultiAttachEnabled'] = multi_attach

create_vol_response = ec2_conn.create_volume(
aws_retry=True,
Expand Down Expand Up @@ -489,11 +517,13 @@ def attach_volume(module, ec2_conn, volume_dict, instance_dict, device_name):

attachment_data = get_attachment_data(volume_dict, wanted_state='attached')
if attachment_data:
if attachment_data.get('instance_id', None) != instance_dict['instance_id']:
module.fail_json(msg="Volume {0} is already attached to another instance: {1}".format(volume_dict['volume_id'],
attachment_data.get('instance_id', None)))
else:
return volume_dict, changed
if not volume_dict['multi_attach']:
# volumes without MultiAttach Enabled can be attached to 1 instance only
if attachment_data[0].get('instance_id', None) != instance_dict['instance_id']:
module.fail_json(msg="Volume {0} is already attached to another instance: {1}".format(volume_dict['volume_id'],
attachment_data[0].get('instance_id', None)))
else:
return volume_dict, changed

try:
attach_response = ec2_conn.attach_volume(aws_retry=True, Device=device_name,
Expand Down Expand Up @@ -557,17 +587,22 @@ def modify_dot_attribute(module, ec2_conn, instance_dict, device_name):
def get_attachment_data(volume_dict, wanted_state=None):
changed = False

attachment_data = {}
attachment_data = []
if not volume_dict:
return attachment_data
for data in volume_dict.get('attachments', []):
if wanted_state and wanted_state == data['state']:
attachment_data = data
break
else:
# No filter, return first
attachment_data = data
break
resource = volume_dict.get('attachments', [])
if wanted_state:
# filter 'state', return attachment matching wanted state
resource = [data for data in resource if data['state'] == wanted_state]

for data in resource:
attachment_data.append({
'attach_time': data.get('attach_time', None),
'device': data.get('device', None),
'instance_id': data.get('instance_id', None),
'status': data.get('state', None),
'deleteOnTermination': data.get('delete_on_termination', None)
})

return attachment_data

Expand All @@ -576,8 +611,9 @@ def detach_volume(module, ec2_conn, volume_dict):
changed = False

attachment_data = get_attachment_data(volume_dict, wanted_state='attached')
if attachment_data:
ec2_conn.detach_volume(aws_retry=True, VolumeId=volume_dict['volume_id'])
# The ID of the instance must be specified iff you are detaching a Multi-Attach enabled volume.
for attachment in attachment_data:
ec2_conn.detach_volume(aws_retry=True, InstanceId=attachment['instance_id'], VolumeId=volume_dict['volume_id'])
waiter = ec2_conn.get_waiter('volume_available')
waiter.wait(
VolumeIds=[volume_dict['volume_id']],
Expand All @@ -602,13 +638,7 @@ def get_volume_info(module, volume, tags=None):
'status': volume.get('state'),
'type': volume.get('volume_type'),
'zone': volume.get('availability_zone'),
'attachment_set': {
'attach_time': attachment_data.get('attach_time', None),
'device': attachment_data.get('device', None),
'instance_id': attachment_data.get('instance_id', None),
'status': attachment_data.get('state', None),
'deleteOnTermination': attachment_data.get('delete_on_termination', None)
},
'attachment_set': attachment_data,
'tags': tags
}

Expand Down Expand Up @@ -659,6 +689,7 @@ def main():
modify_volume=dict(default=False, type='bool'),
throughput=dict(type='int'),
purge_tags=dict(type='bool', default=False),
multi_attach=dict(type='bool'),
)

module = AnsibleAWSModule(
Expand Down Expand Up @@ -799,7 +830,7 @@ def main():
if tags_changed:
changed = True

module.exit_json(changed=changed, volume=volume_info, device=volume_info['attachment_set']['device'],
module.exit_json(changed=changed, volume=volume_info, device=device_name,
volume_id=volume_info['id'], volume_type=volume_info['type'])
elif state == 'absent':
if not name and not param_id:
Expand Down
31 changes: 15 additions & 16 deletions tests/integration/targets/ec2_vol/tasks/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@
- volume1.volume.status == 'available'
- volume1.volume_type == 'standard'
- "'attachment_set' in volume1.volume"
- "'instance_id' in volume1.volume.attachment_set"
- not volume1.volume.attachment_set.instance_id
- volume1.volume.attachment_set | length == 0
- not ("Name" in volume1.volume.tags)
- not volume1.volume.encrypted
- volume1.volume.tags.ResourcePrefix == "{{ resource_prefix }}"
Expand Down Expand Up @@ -185,9 +184,9 @@
- vol_attach_result.changed
- "'device' in vol_attach_result and vol_attach_result.device == '/dev/sdg'"
- "'volume' in vol_attach_result"
- vol_attach_result.volume.attachment_set.status in ['attached', 'attaching']
- vol_attach_result.volume.attachment_set.instance_id == test_instance.instance_ids[0]
- vol_attach_result.volume.attachment_set.device == '/dev/sdg'
- vol_attach_result.volume.attachment_set[0].status in ['attached', 'attaching']
- vol_attach_result.volume.attachment_set[0].instance_id == test_instance.instance_ids[0]
- vol_attach_result.volume.attachment_set[0].device == '/dev/sdg'

# Failing
# - "vol_attach_result.volume.attachment_set.deleteOnTermination"
Expand All @@ -204,7 +203,7 @@
assert:
that:
- "not vol_attach_result.changed"
- vol_attach_result.volume.attachment_set.status in ['attached', 'attaching']
- vol_attach_result.volume.attachment_set[0].status in ['attached', 'attaching']

- name: attach a new volume to an instance
ec2_vol:
Expand All @@ -227,9 +226,9 @@
- new_vol_attach_result.changed
- "'device' in new_vol_attach_result and new_vol_attach_result.device == '/dev/sdh'"
- "'volume' in new_vol_attach_result"
- new_vol_attach_result.volume.attachment_set.status in ['attached', 'attaching']
- new_vol_attach_result.volume.attachment_set.instance_id == test_instance.instance_ids[0]
- new_vol_attach_result.volume.attachment_set.device == '/dev/sdh'
- new_vol_attach_result.volume.attachment_set[0].status in ['attached', 'attaching']
- new_vol_attach_result.volume.attachment_set[0].instance_id == test_instance.instance_ids[0]
- new_vol_attach_result.volume.attachment_set[0].device == '/dev/sdh'
- new_vol_attach_result.volume.tags["lowercase spaced"] == 'hello cruel world'
- new_vol_attach_result.volume.tags["Title Case"] == 'Hello Cruel World'
- new_vol_attach_result.volume.tags["CamelCase"] == 'SimpleCamelCase'
Expand Down Expand Up @@ -306,8 +305,8 @@
- attach_new_vol_from_snapshot_result.changed
- "'device' in attach_new_vol_from_snapshot_result and attach_new_vol_from_snapshot_result.device == '/dev/sdi'"
- "'volume' in attach_new_vol_from_snapshot_result"
- attach_new_vol_from_snapshot_result.volume.attachment_set.status in ['attached', 'attaching']
- attach_new_vol_from_snapshot_result.volume.attachment_set.instance_id == test_instance.instance_ids[0]
- attach_new_vol_from_snapshot_result.volume.attachment_set[0].status in ['attached', 'attaching']
- attach_new_vol_from_snapshot_result.volume.attachment_set[0].instance_id == test_instance.instance_ids[0]

- name: list volumes attached to instance
ec2_vol:
Expand Down Expand Up @@ -537,10 +536,10 @@
assert:
that:
- "volume_info.volumes|length == 1"
- "v.attachment_set.attach_time is defined"
- "v.attachment_set.device is defined and v.attachment_set.device == dot_volume.device"
- "v.attachment_set.instance_id is defined and v.attachment_set.instance_id == test_instance.instance_ids[0]"
- "v.attachment_set.status is defined and v.attachment_set.status == 'attached'"
- "v.attachment_set[0].attach_time is defined"
- "v.attachment_set[0].device is defined and v.attachment_set[0].device == dot_volume.device"
- "v.attachment_set[0].instance_id is defined and v.attachment_set[0].instance_id == test_instance.instance_ids[0]"
- "v.attachment_set[0].status is defined and v.attachment_set[0].status == 'attached'"
- "v.create_time is defined"
- "v.encrypted is defined and v.encrypted == false"
- "v.id is defined and v.id == dot_volume.volume_id"
Expand All @@ -559,7 +558,7 @@
- name: New format check
assert:
that:
- "v.attachment_set.delete_on_termination is defined"
- "v.attachment_set[0].delete_on_termination is defined"
vars:
v: "{{ volume_info.volumes[0] }}"
when: ansible_version.full is version('2.7', '>=')
Expand Down

0 comments on commit 0b794ad

Please sign in to comment.