Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ec2_snapshot_info add option for paginated requests #321

Merged
merged 12 commits into from
Apr 14, 2021
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 this parameter is used, `ec2_snapshot_facts` only returns results in a single page along with a C(next_token_id) response element.
- 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 C(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 C(snapshot_ids)
abikouo marked this conversation as resolved.
Show resolved Hide resolved
required: False
type: int
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.
tremble marked this conversation as resolved.
Show resolved Hide resolved
- Pagination continues from the end of the previous results that returned the C(next_token_id) value.
tremble marked this conversation as resolved.
Show resolved Hide resolved
- This parameter is mutually exclusive with C(snapshot_ids)
required: false
abikouo marked this conversation as resolved.
Show resolved Hide resolved
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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For anyone else who sees this: this PR didn't change the results here, it's been this way since at least 2.9

Given support for 2.8 is about to be dropped I don't think it's worth adding a shim layer

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