Skip to content

Commit

Permalink
rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
abikouo committed Jun 21, 2021
2 parents 0b794ad + 77a60f1 commit 129665d
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
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).
- ec2_vol_info - return ``attachment_set`` is now a list of attachments with Multi-Attach support on disk. (https://github.com/ansible-collections/amazon.aws/pull/362)
34 changes: 22 additions & 12 deletions plugins/modules/ec2_vol.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
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.
- This parameter is supported with io1 and io2 volumes only.
type: bool
version_added: 2.0.0
author: "Lester Wade (@lwade)"
Expand Down Expand Up @@ -197,10 +198,11 @@
# Create new volume with multi-attach enabled
- amazon.aws.ec2_vol:
instance: XXXXXX
volume_size: 50
device_name: sdd
zone: XXXXXX
multi_attach: true
volume_size: 4
volume_type: io1
iops: 102
# Attach an existing volume to instance. The volume will be deleted upon instance termination.
- amazon.aws.ec2_vol:
Expand Down Expand Up @@ -423,11 +425,14 @@ def update_volume(module, ec2_conn, volume):

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
if target_multi_attach is not None:
if "io1" in [target_type, original_type] or "io2" in [target_type, original_type]:
original_multi_attach = volume['multi_attach_enabled']
if target_multi_attach != original_multi_attach:
multi_attach_changed = True
req_obj['MultiAttachEnabled'] = target_multi_attach
else:
module.warn("multi_attach is supported with io1 and io2 volumes only.")

changed = iops_changed or size_changed or type_changed or throughput_changed or multi_attach_changed

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

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

if multi_attach is True:
if volume_type not in ("io1", "io2"):
module.warn("multi_attach is supported with io1 and io2 volumes only.")
else:
additional_params['MultiAttachEnabled'] = multi_attach

create_vol_response = ec2_conn.create_volume(
aws_retry=True,
Expand Down Expand Up @@ -517,7 +526,7 @@ 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 not volume_dict['multi_attach']:
if not volume_dict['multi_attach_enabled']:
# 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'],
Expand Down Expand Up @@ -601,7 +610,7 @@ def get_attachment_data(volume_dict, wanted_state=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)
'delete_on_termination': data.get('delete_on_termination', None)
})

return attachment_data
Expand Down Expand Up @@ -639,6 +648,7 @@ def get_volume_info(module, volume, tags=None):
'type': volume.get('volume_type'),
'zone': volume.get('availability_zone'),
'attachment_set': attachment_data,
'multi_attach_enabled': volume.get('multi_attach_enabled'),
'tags': tags
}

Expand Down
25 changes: 18 additions & 7 deletions plugins/modules/ec2_vol_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
description: The Availability Zone of the volume.
type: str
sample: "us-east-1b"
throughput:
description: The throughput that the volume supports, in MiB/s.
type: int
sample: 131
'''

try:
Expand All @@ -128,6 +132,16 @@ def get_volume_info(volume, region):

attachment = volume["attachments"]

attachment_data = []
for data in volume["attachments"]:
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),
'delete_on_termination': data.get('delete_on_termination', None)
})

volume_info = {
'create_time': volume["create_time"],
'id': volume["volume_id"],
Expand All @@ -139,16 +153,13 @@ def get_volume_info(volume, region):
'type': volume["volume_type"],
'zone': volume["availability_zone"],
'region': region,
'attachment_set': {
'attach_time': attachment[0]["attach_time"] if len(attachment) > 0 else None,
'device': attachment[0]["device"] if len(attachment) > 0 else None,
'instance_id': attachment[0]["instance_id"] if len(attachment) > 0 else None,
'status': attachment[0]["state"] if len(attachment) > 0 else None,
'delete_on_termination': attachment[0]["delete_on_termination"] if len(attachment) > 0 else None
},
'attachment_set': attachment_data,
'tags': boto3_tag_list_to_ansible_dict(volume['tags']) if "tags" in volume else None
}

if 'throughput' in volume:
volume_info['throughput'] = volume["throughput"]

return volume_info


Expand Down
114 changes: 94 additions & 20 deletions tests/integration/targets/ec2_vol/tasks/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
set_fact:
ec2_ami_image: '{{ latest_ami.image_id }}'

# ==== ec2_vol tests ===============================================
# # ==== ec2_vol tests ===============================================

- name: create a volume (validate module defaults)
ec2_vol:
Expand Down Expand Up @@ -187,9 +187,7 @@
- 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"
- not vol_attach_result.volume.attachment_set[0].delete_on_termination

- name: attach existing volume to an instance (idempotent)
ec2_vol:
Expand All @@ -203,7 +201,7 @@
assert:
that:
- "not vol_attach_result.changed"
- vol_attach_result.volume.attachment_set[0].status in ['attached', 'attaching']
- "vol_attach_result.volume.attachment_set[0].status == 'attached'"

- name: attach a new volume to an instance
ec2_vol:
Expand Down Expand Up @@ -453,7 +451,7 @@
- name: volume type must be gp3
assert:
that:
- v.type == 'gp3'
- v.type == 'gp3'
vars:
v: "{{ verify_gp3_change.volumes[0] }}"

Expand Down Expand Up @@ -500,8 +498,7 @@
that:
- dot_volume.changed
- "'attachment_set' in dot_volume.volume"
- "'deleteOnTermination' in dot_volume.volume.attachment_set"
- "dot_volume.volume.attachment_set.deleteOnTermination is defined"
- "'delete_on_termination' in dot_volume.volume.attachment_set[0]"
- "'create_time' in dot_volume.volume"
- "'id' in dot_volume.volume"
- "'size' in dot_volume.volume"
Expand Down Expand Up @@ -569,7 +566,7 @@
zone: "{{ availability_zone }}"
volume_type: gp3
throughput: 130
iops: 3001
iops: 300
name: "GP3-TEST-{{ resource_prefix }}"
tags:
ResourcePrefix: "{{ resource_prefix }}"
Expand All @@ -580,22 +577,38 @@
that:
- gp3_volume.changed
- "'attachment_set' in gp3_volume.volume"
- "'deleteOnTermination' in gp3_volume.volume.attachment_set"
- gp3_volume.volume.attachment_set.deleteOnTermination == none
- "'delete_on_termination' in gp3_volume.volume.attachment_set[0]"
- "'create_time' in gp3_volume.volume"
- "'id' in gp3_volume.volume"
- "'size' in gp3_volume.volume"
- gp3_volume.volume.size == 7
- "'volume_type' in gp3_volume"
- gp3_volume.volume_type == 'gp3'
- "'iops' in gp3_volume.volume"
- gp3_volume.volume.iops == 3001
- gp3_volume.volume.iops == 300
- "'throughput' in gp3_volume.volume"
- gp3_volume.volume.throughput == 130
- "'tags' in gp3_volume.volume"
- (gp3_volume.volume.tags | length ) == 2
- gp3_volume.volume.tags["ResourcePrefix"] == "{{ resource_prefix }}"

- name: Read volume information to validate throughput
ec2_vol_info:
filters:
volume-id: "{{ gp3_volume.volume_id }}"
register: verify_throughput

- name: throughput must be equal to 130
assert:
that:
- v.throughput == 130
vars:
v: "{{ verify_throughput.volumes[0] }}"

- name: print out facts
debug:
var: vol_facts

- name: increase throughput
ec2_vol:
volume_size: 7
Expand All @@ -613,31 +626,88 @@
that:
- gp3_volume.changed
- "'attachment_set' in gp3_volume.volume"
- "'deleteOnTermination' in gp3_volume.volume.attachment_set"
- gp3_volume.volume.attachment_set.deleteOnTermination == none
- "'delete_on_termination' in gp3_volume.volume.attachment_set[0]"
- "'create_time' in gp3_volume.volume"
- "'id' in gp3_volume.volume"
- "'size' in gp3_volume.volume"
- gp3_volume.volume.size == 7
- "'volume_type' in gp3_volume"
- gp3_volume.volume_type == 'gp3'
- "'iops' in gp3_volume.volume"
- gp3_volume.volume.iops == 3001
- gp3_volume.volume.iops == 300
- "'throughput' in gp3_volume.volume"
- gp3_volume.volume.throughput == 131
- "'tags' in gp3_volume.volume"
- (gp3_volume.volume.tags | length ) == 2
- gp3_volume.volume.tags["ResourcePrefix"] == "{{ resource_prefix }}"

# Multi-Attach disk
- name: create disk with multi-attach enabled
ec2_vol:
volume_size: 4
volume_type: io1
iops: 102
zone: "{{ availability_zone }}"
multi_attach: yes
tags:
ResourcePrefix: "{{ resource_prefix }}"
register: multi_attach_disk

- name: check volume creation
assert:
that:
- multi_attach_disk.changed
- "'volume' in multi_attach_disk"
- multi_attach_disk.volume.multi_attach_enabled

- name: attach existing volume to an instance
ec2_vol:
id: "{{ multi_attach_disk.volume_id }}"
instance: "{{ test_instance.instance_ids[0] }}"
device_name: /dev/sdk
delete_on_termination: no
register: vol_attach_result

- name: create another ec2 instance
ec2_instance:
name: "{{ resource_prefix }}-2"
vpc_subnet_id: "{{ testing_subnet.subnet.id }}"
instance_type: t3.nano
image_id: "{{ ec2_ami_image }}"
tags:
ResourcePrefix: "{{ resource_prefix }}"
register: test_instance_2

- name: check task return attributes
assert:
that:
- test_instance_2.changed

- name: attach existing volume to second instance
ec2_vol:
id: "{{ multi_attach_disk.volume_id }}"
instance: "{{ test_instance_2.instance_ids[0] }}"
device_name: /dev/sdg
delete_on_termination: no
register: vol_attach_result

- name: check task return attributes
assert:
that:
- vol_attach_result.changed
- "'volume' in vol_attach_result"
- vol_attach_result.volume.attachment_set | length == 2
- 'test_instance.instance_ids[0] in vol_attach_result.volume.attachment_set | map(attribute="instance_id") | list'
- 'test_instance_2.instance_ids[0] in vol_attach_result.volume.attachment_set | map(attribute="instance_id") | list'

# ==== Cleanup ============================================================

always:
- name: Describe the instance before we delete it
ec2_instance_info:
instance_ids:
- "{{ test_instance.instance_ids[0] }}"
- "{{ item }}"
ignore_errors: yes
with_items:
- "{{ test_instance.instance_ids[0] }}"
- "{{ test_instance_2.instance_ids[0] }}"
register: pre_delete

- debug:
Expand All @@ -646,8 +716,11 @@
- name: delete test instance
ec2_instance:
instance_ids:
- "{{ test_instance.instance_ids[0] }}"
- "{{ item }}"
state: terminated
with_items:
- "{{ test_instance.instance_ids[0] }}"
- "{{ test_instance_2.instance_ids[0] }}"
ignore_errors: yes

- name: delete volumes
Expand All @@ -663,6 +736,7 @@
- "{{ attach_new_vol_from_snapshot_result }}"
- "{{ dot_volume }}"
- "{{ gp3_volume }}"
- "{{ multi_attach_disk }}"

- name: delete snapshot
ec2_snapshot:
Expand Down

0 comments on commit 129665d

Please sign in to comment.