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 (#1606) (#1687)

[PR #1606/3391b27d backport][stable-5] s3_lifecycle - ability to set the number of newest noncurrent versions to retain

This is a backport of PR #1606 as merged into main (3391b27).
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: Mark Chappell <None>
  • Loading branch information
patchback[bot] authored Feb 1, 2023
1 parent 5c39343 commit 68c0ac4
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 68c0ac4

Please sign in to comment.