Skip to content

Commit

Permalink
ec2_snapshot_info add option for paginated requests (ansible-collecti…
Browse files Browse the repository at this point in the history
…ons#321)

ec2_snapshot_info add option for paginated requests

Reviewed-by: https://github.com/apps/ansible-zuul
  • Loading branch information
abikouo authored Apr 14, 2021
1 parent 9130653 commit 8011d3a
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- ec2_snapshot_info - add the ``max_results`` along with ``next_token_id`` option (https://github.com/ansible-collections/amazon.aws/pull/321).
206 changes: 127 additions & 79 deletions plugins/modules/ec2_snapshot_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
- Gather information about ec2 volume snapshots in AWS.
- This module was called C(ec2_snapshot_facts) before Ansible 2.9. The usage did not change.
requirements: [ boto3 ]
author: "Rob White (@wimnat)"
author:
- "Rob White (@wimnat)"
- Aubin Bikouo (@abikouo)
options:
snapshot_ids:
description:
Expand Down Expand Up @@ -48,6 +50,23 @@
required: false
type: dict
default: {}
max_results:
description:
- The maximum number of snapshot results returned in paginated output.
- When used only a single page along with a C(next_token_id) response element will be returned.
- The remaining results of the initial request can be seen by sending another request with the returned C(next_token_id) value.
- This value can be between 5 and 1000; if I(next_token_id) is given a value larger than 1000, only 1000 results are returned.
- If this parameter is not used, then DescribeSnapshots returns all results.
- This parameter is mutually exclusive with I(snapshot_ids).
required: False
type: int
next_token_id:
description:
- Contains the value returned from a previous paginated request where I(max_results) was used and the results exceeded the value of that parameter.
- Pagination continues from the end of the previous results that returned the I(next_token_id) value.
- This parameter is mutually exclusive with I(snapshot_ids)
required: false
type: str
notes:
- By default, the module will return all snapshots, including public ones. To limit results to snapshots owned by
the account use the filter 'owner-id'.
Expand Down Expand Up @@ -97,81 +116,92 @@
'''

RETURN = '''
snapshot_id:
description: The ID of the snapshot. Each snapshot receives a unique identifier when it is created.
type: str
returned: always
sample: snap-01234567
volume_id:
description: The ID of the volume that was used to create the snapshot.
type: str
returned: always
sample: vol-01234567
state:
description: The snapshot state (completed, pending or error).
type: str
returned: always
sample: completed
state_message:
description: Encrypted Amazon EBS snapshots are copied asynchronously. If a snapshot copy operation fails (for example, if the proper
AWS Key Management Service (AWS KMS) permissions are not obtained) this field displays error state details to help you diagnose why the
error occurred.
type: str
returned: always
sample:
start_time:
description: The time stamp when the snapshot was initiated.
type: str
returned: always
sample: "2015-02-12T02:14:02+00:00"
progress:
description: The progress of the snapshot, as a percentage.
type: str
returned: always
sample: "100%"
owner_id:
description: The AWS account ID of the EBS snapshot owner.
type: str
returned: always
sample: "099720109477"
description:
description: The description for the snapshot.
type: str
returned: always
sample: "My important backup"
volume_size:
description: The size of the volume, in GiB.
type: int
returned: always
sample: 8
owner_alias:
description: The AWS account alias (for example, amazon, self) or AWS account ID that owns the snapshot.
type: str
returned: always
sample: "033440102211"
tags:
description: Any tags assigned to the snapshot.
type: dict
returned: always
sample: "{ 'my_tag_key': 'my_tag_value' }"
encrypted:
description: Indicates whether the snapshot is encrypted.
type: bool
returned: always
sample: "True"
kms_key_id:
description: The full ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to \
protect the volume encryption key for the parent volume.
type: str
returned: always
sample: "74c9742a-a1b2-45cb-b3fe-abcdef123456"
data_encryption_key_id:
description: The data encryption key identifier for the snapshot. This value is a unique identifier that \
corresponds to the data encryption key that was used to encrypt the original volume or snapshot copy.
snapshots:
description: snapshots retrieved
type: list
returned: success
elements: dict
contains:
snapshot_id:
description: The ID of the snapshot. Each snapshot receives a unique identifier when it is created.
type: str
returned: always
sample: snap-01234567
volume_id:
description: The ID of the volume that was used to create the snapshot.
type: str
returned: always
sample: vol-01234567
state:
description: The snapshot state (completed, pending or error).
type: str
returned: always
sample: completed
state_message:
description: Encrypted Amazon EBS snapshots are copied asynchronously. If a snapshot copy operation fails (for example, if the proper
AWS Key Management Service (AWS KMS) permissions are not obtained) this field displays error state details to help you diagnose why the
error occurred.
type: str
returned: always
sample:
start_time:
description: The time stamp when the snapshot was initiated.
type: str
returned: always
sample: "2015-02-12T02:14:02+00:00"
progress:
description: The progress of the snapshot, as a percentage.
type: str
returned: always
sample: "100%"
owner_id:
description: The AWS account ID of the EBS snapshot owner.
type: str
returned: always
sample: "099720109477"
description:
description: The description for the snapshot.
type: str
returned: always
sample: "My important backup"
volume_size:
description: The size of the volume, in GiB.
type: int
returned: always
sample: 8
owner_alias:
description: The AWS account alias (for example, amazon, self) or AWS account ID that owns the snapshot.
type: str
returned: always
sample: "033440102211"
tags:
description: Any tags assigned to the snapshot.
type: dict
returned: always
sample: "{ 'my_tag_key': 'my_tag_value' }"
encrypted:
description: Indicates whether the snapshot is encrypted.
type: bool
returned: always
sample: "True"
kms_key_id:
description: The full ARN of the AWS Key Management Service (AWS KMS) customer master key (CMK) that was used to \
protect the volume encryption key for the parent volume.
type: str
returned: always
sample: "74c9742a-a1b2-45cb-b3fe-abcdef123456"
data_encryption_key_id:
description: The data encryption key identifier for the snapshot. This value is a unique identifier that \
corresponds to the data encryption key that was used to encrypt the original volume or snapshot copy.
type: str
returned: always
sample: "arn:aws:kms:ap-southeast-2:012345678900:key/74c9742a-a1b2-45cb-b3fe-abcdef123456"
next_token_id:
description:
- Contains the value returned from a previous paginated request where C(max_results) was used and the results exceeded the value of that parameter.
- This value is null when there are no more results to return.
type: str
returned: always
sample: "arn:aws:kms:ap-southeast-2:012345678900:key/74c9742a-a1b2-45cb-b3fe-abcdef123456"
returned: when option C(max_results) is set in input
'''

try:
Expand All @@ -194,19 +224,28 @@ def list_ec2_snapshots(connection, module):
owner_ids = [str(owner_id) for owner_id in module.params.get("owner_ids")]
restorable_by_user_ids = [str(user_id) for user_id in module.params.get("restorable_by_user_ids")]
filters = ansible_dict_to_boto3_filter_list(module.params.get("filters"))
max_results = module.params.get('max_results')
next_token = module.params.get('next_token_id')
optional_param = {}
if max_results:
optional_param['MaxResults'] = max_results
if next_token:
optional_param['NextToken'] = next_token

try:
snapshots = connection.describe_snapshots(
aws_retry=True,
SnapshotIds=snapshot_ids, OwnerIds=owner_ids,
RestorableByUserIds=restorable_by_user_ids, Filters=filters)
RestorableByUserIds=restorable_by_user_ids, Filters=filters,
**optional_param)
except is_boto3_error_code('InvalidSnapshot.NotFound') as e:
if len(snapshot_ids) > 1:
module.warn("Some of your snapshots may exist, but %s" % str(e))
snapshots = {'Snapshots': []}
except ClientError as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg='Failed to describe snapshots')

result = {}
# Turn the boto3 result in to ansible_friendly_snaked_names
snaked_snapshots = []
for snapshot in snapshots['Snapshots']:
Expand All @@ -217,7 +256,12 @@ def list_ec2_snapshots(connection, module):
if 'tags' in snapshot:
snapshot['tags'] = boto3_tag_list_to_ansible_dict(snapshot['tags'], 'key', 'value')

module.exit_json(snapshots=snaked_snapshots)
result['snapshots'] = snaked_snapshots

if snapshots.get('NextToken'):
result.update(camel_dict_to_snake_dict({'NextTokenId': snapshots.get('NextToken')}))

module.exit_json(**result)


def main():
Expand All @@ -226,13 +270,17 @@ def main():
snapshot_ids=dict(default=[], type='list', elements='str'),
owner_ids=dict(default=[], type='list', elements='str'),
restorable_by_user_ids=dict(default=[], type='list', elements='str'),
filters=dict(default={}, type='dict')
filters=dict(default={}, type='dict'),
max_results=dict(type='int'),
next_token_id=dict(type='str')
)

module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=[
['snapshot_ids', 'owner_ids', 'restorable_by_user_ids', 'filters']
['snapshot_ids', 'owner_ids', 'restorable_by_user_ids', 'filters'],
['snapshot_ids', 'max_results'],
['snapshot_ids', 'next_token_id']
],
supports_check_mode=True
)
Expand Down
55 changes: 55 additions & 0 deletions tests/integration/targets/ec2_snapshot/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,61 @@
that:
- info_result.snapshots| length == 3

# check that snapshot_ids and max_results are mutually exclusive
- name: Check that max_results and snapshot_ids are mutually exclusive
ec2_snapshot_info:
snapshot_ids:
- '{{ tagged_snapshot_id }}'
max_results: 1
ignore_errors: true
register: info_result

- name: assert that operation failed
assert:
that:
- info_result is failed

# check that snapshot_ids and next_token_id are mutually exclusive
- name: Check that snapshot_ids and next_token_id are mutually exclusive
ec2_snapshot_info:
snapshot_ids:
- '{{ tagged_snapshot_id }}'
next_token_id: 'random_value_token'
ignore_errors: true
register: info_result

- name: assert that operation failed
assert:
that:
- info_result is failed

# Retrieve snapshots in paginated mode
- name: Get snapshots in paginated mode using max_results option
ec2_snapshot_info:
filters:
"tag:Name": '{{ resource_prefix }}'
max_results: 1
register: info_result

- assert:
that:
- info_result.snapshots | length == 1
- info_result.next_token_id is defined

# Pagination : 2nd request
- name: Get snapshots for a second paginated request
ec2_snapshot_info:
filters:
"tag:Name": '{{ resource_prefix }}'
next_token_id: "{{ info_result.next_token_id }}"
register: info_result

- assert:
that:
- info_result.snapshots | length == 2
- info_result.next_token_id is defined

# delete the tagged snapshot
- name: Delete the tagged snapshot
ec2_snapshot:
state: absent
Expand Down

0 comments on commit 8011d3a

Please sign in to comment.