Skip to content

Commit

Permalink
s3_lifecycle - ability to set the number of newest noncurrent version…
Browse files Browse the repository at this point in the history
…s to retain (ansible-collections#1606)

s3_lifecycle - ability to set the number of newest noncurrent versions to retain

SUMMARY
Adds the ability to set "Number of newer versions to retain"

ISSUE TYPE


Feature Pull Request

COMPONENT NAME
s3_lifecycle
ADDITIONAL INFORMATION
See: https://docs.aws.amazon.com/AmazonS3/latest/API/API_NoncurrentVersionExpiration.html
Previously only the NoncurrentDays parameter was supported, this PR adds support for NewerNoncurrentVersions

Reviewed-by: Markus Bergholz <[email protected]>
Reviewed-by: Mark Chappell <None>
  • Loading branch information
davejames authored Feb 1, 2023
1 parent dbb482c commit 3391b27
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- s3_lifecycle - add parameter `noncurrent_version_keep_newer` to set the number of newest noncurrent versions to retain
51 changes: 38 additions & 13 deletions plugins/modules/s3_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,17 @@
noncurrent_version_expiration_days:
description:
- The number of days after which non-current versions should be deleted.
- Must be set if I(noncurrent_version_keep_newer) is set.
required: false
type: int
noncurrent_version_keep_newer:
description:
- The minimum number of non-current versions to retain.
- Requires C(botocore >= 1.23.12)
- Requres I(noncurrent_version_expiration_days).
required: false
type: int
version_added: 5.3.0
noncurrent_version_storage_class:
description:
- The storage class to which non-current versions are transitioned.
Expand Down Expand Up @@ -269,6 +278,7 @@ def build_rule(client, module):
noncurrent_version_transition_days = module.params.get("noncurrent_version_transition_days")
noncurrent_version_transitions = module.params.get("noncurrent_version_transitions")
noncurrent_version_storage_class = module.params.get("noncurrent_version_storage_class")
noncurrent_version_keep_newer = module.params.get("noncurrent_version_keep_newer")
prefix = module.params.get("prefix") or ""
rule_id = module.params.get("rule_id")
status = module.params.get("status")
Expand All @@ -294,10 +304,12 @@ def build_rule(client, module):
rule['Expiration'] = dict(Date=expiration_date.isoformat())
elif expire_object_delete_marker is not None:
rule['Expiration'] = dict(ExpiredObjectDeleteMarker=expire_object_delete_marker)

if noncurrent_version_expiration_days or noncurrent_version_keep_newer:
rule['NoncurrentVersionExpiration'] = dict()
if noncurrent_version_expiration_days is not None:
rule['NoncurrentVersionExpiration'] = dict(NoncurrentDays=noncurrent_version_expiration_days)

rule['NoncurrentVersionExpiration']['NoncurrentDays'] = noncurrent_version_expiration_days
if noncurrent_version_keep_newer is not None:
rule['NoncurrentVersionExpiration']['NewerNoncurrentVersions'] = noncurrent_version_keep_newer
if transition_days is not None:
rule['Transitions'] = [dict(Days=transition_days, StorageClass=storage_class.upper()), ]

Expand Down Expand Up @@ -572,6 +584,7 @@ def main():
expiration_date=dict(),
expire_object_delete_marker=dict(type='bool'),
noncurrent_version_expiration_days=dict(type='int'),
noncurrent_version_keep_newer=dict(type='int'),
noncurrent_version_storage_class=dict(default='glacier', type='str', choices=s3_storage_class),
noncurrent_version_transition_days=dict(type='int'),
noncurrent_version_transitions=dict(type='list', elements='dict'),
Expand All @@ -587,29 +600,41 @@ def main():
wait=dict(type='bool', default=False)
)

module = AnsibleAWSModule(argument_spec=argument_spec,
mutually_exclusive=[
['expiration_days', 'expiration_date', 'expire_object_delete_marker'],
['expiration_days', 'transition_date'],
['transition_days', 'transition_date'],
['transition_days', 'expiration_date'],
['transition_days', 'transitions'],
['transition_date', 'transitions'],
['noncurrent_version_transition_days', 'noncurrent_version_transitions'],
],)
module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=[
["expiration_days", "expiration_date", "expire_object_delete_marker"],
["expiration_days", "transition_date"],
["transition_days", "transition_date"],
["transition_days", "expiration_date"],
["transition_days", "transitions"],
["transition_date", "transitions"],
["noncurrent_version_transition_days", "noncurrent_version_transitions"],
],
required_by={
"noncurrent_version_keep_newer": ["noncurrent_version_expiration_days"],
},
)

client = module.client('s3', retry_decorator=AWSRetry.jittered_backoff())

expiration_date = module.params.get("expiration_date")
transition_date = module.params.get("transition_date")
state = module.params.get("state")

if module.params.get("noncurrent_version_keep_newer"):
module.require_botocore_at_least(
"1.23.12",
reason="to set number of versions to keep with noncurrent_version_keep_newer"
)

if state == 'present' and module.params["status"] == "enabled": # allow deleting/disabling a rule by id/prefix

required_when_present = ('abort_incomplete_multipart_upload_days',
'expiration_date', 'expiration_days', 'expire_object_delete_marker',
'transition_date', 'transition_days', 'transitions',
'noncurrent_version_expiration_days',
'noncurrent_version_keep_newer',
'noncurrent_version_transition_days',
'noncurrent_version_transitions')
for param in required_when_present:
Expand Down
5 changes: 4 additions & 1 deletion tests/integration/targets/s3_lifecycle/meta/main.yml
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
dependencies: []
dependencies:
- role: setup_botocore_pip
vars:
botocore_version: "1.23.12"
53 changes: 52 additions & 1 deletion tests/integration/targets/s3_lifecycle/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,6 @@
that:
- output is changed

# ============================================================
- name: Create a lifecycle policy, with expired_object_delete_marker (idempotency)
s3_lifecycle:
name: '{{ bucket_name }}'
Expand All @@ -435,6 +434,58 @@
that:
- output is not changed

# ============================================================
- name: Update lifecycle policy, with noncurrent_version_expiration_days
s3_lifecycle:
name: '{{ bucket_name }}'
noncurrent_version_expiration_days: 5
prefix: /something
register: output

- assert:
that:
- output is changed

- name: Update lifecycle policy, with noncurrent_version_expiration_days (idempotency)
s3_lifecycle:
name: '{{ bucket_name }}'
noncurrent_version_expiration_days: 5
prefix: /something
register: output

- assert:
that:
- output is not changed

# ============================================================
- name: Update lifecycle policy, with noncurrent_version_keep_newer
s3_lifecycle:
name: '{{ bucket_name }}'
noncurrent_version_expiration_days: 10
noncurrent_version_keep_newer: 6
prefix: /something
register: output
vars:
ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"

- assert:
that:
- output is changed

- name: Update lifecycle policy, with noncurrent_version_keep_newer (idempotency)
s3_lifecycle:
name: '{{ bucket_name }}'
noncurrent_version_expiration_days: 10
noncurrent_version_keep_newer: 6
prefix: /something
register: output
vars:
ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"

- assert:
that:
- output is not changed

# ============================================================
# test all the examples
# Configure a lifecycle rule on a bucket to expire (delete) items with a prefix of /logs/ after 30 days
Expand Down

0 comments on commit 3391b27

Please sign in to comment.