Skip to content

Commit

Permalink
Merge pull request #681 from tremble/aws_secret/deletion_idempotency
Browse files Browse the repository at this point in the history
aws_secret - fix deletion idempotency when not using instant deletion

SUMMARY
If you try to delete a secret that's already pending deletion the aws_secret threw an exception because result hadn't been defined.
Also enables basic tests for aws_secret.  note: "something" is broken with the rotation tests, so these are skipped for now.  Better that we have partial test coverage than none.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
aws_secret
ADDITIONAL INFORMATION
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: UnboundLocalError: local variable 'result' referenced before assignment
fatal: [testhost]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/root/.ansible/tmp/ansible-tmp-1628676235.3853-364-73867477372190/AnsiballZ_aws_secret.py\", line 114, in <module>\n    _ansiballz_main()\n  File \"/root/.ansible/tmp/ansible-tmp-1628676235.3853-364-73867477372190/AnsiballZ_aws_secret.py\", line 106, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/root/.ansible/tmp/ansible-tmp-1628676235.3853-364-73867477372190/AnsiballZ_aws_secret.py\", line 54, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.community.aws.plugins.modules.aws_secret', init_globals=dict(_module_fqn='ansible_collections.community.aws.plugins.modules.aws_secret', _modlib_path=modlib_path),\n  File \"/usr/lib/python3.9/runpy.py\", line 210, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/lib/python3.9/runpy.py\", line 97, in _run_module_code\n    _run_code(code, mod_globals, init_globals,\n  File \"/usr/lib/python3.9/runpy.py\", line 87, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_aws_secret_payload_6xlyxr1u/ansible_aws_secret_payload.zip/ansible_collections/community/aws/plugins/modules/aws_secret.py\", line 401, in <module>\n  File \"/tmp/ansible_aws_secret_payload_6xlyxr1u/ansible_aws_secret_payload.zip/ansible_collections/community/aws/plugins/modules/aws_secret.py\", line 397, in main\nUnboundLocalError: local variable 'result' referenced before assignment\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error

Depends-On: #686

Reviewed-by: Alina Buzachis <None>
Reviewed-by: None <None>
  • Loading branch information
ansible-zuul[bot] committed Aug 13, 2021
2 parents d78b08c + 371222f commit 9ac1717
Show file tree
Hide file tree
Showing 6 changed files with 359 additions and 247 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/681-aws_secret-deletion-idempotency.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- aws_secret - fix deletion idempotency when not using instant deletion (https://github.com/ansible-collections/community.aws/pull/681).
3 changes: 3 additions & 0 deletions plugins/modules/aws_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ def main():
elif current_secret.get("DeletedDate") and recovery_window == 0:
result = camel_dict_to_snake_dict(secrets_mgr.delete_secret(secret.name, recovery_window=recovery_window))
changed = True
else:
result = "secret already scheduled for deletion"
else:
result = "secret does not exist"
if state == 'present':
Expand All @@ -393,6 +395,7 @@ def main():
changed = True
result = camel_dict_to_snake_dict(secrets_mgr.get_secret(secret.name))
result.pop("response_metadata")

module.exit_json(changed=changed, secret=result)


Expand Down
5 changes: 0 additions & 5 deletions tests/integration/targets/aws_secret/aliases
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
# reason: missing-policy
# reason: broken
# The tests for configuring secret rotation seem to be missing a permission
disabled

cloud/aws
160 changes: 160 additions & 0 deletions tests/integration/targets/aws_secret/tasks/basic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
- block:
# ============================================================
# Module parameter testing
# ============================================================
- name: test with no parameters
aws_secret:
register: result
ignore_errors: true
check_mode: true

- name: assert failure when called with no parameters
assert:
that:
- result.failed
- 'result.msg.startswith("missing required arguments:")'

# ============================================================
# Creation/Deletion testing
# ============================================================
- name: add secret to AWS Secrets Manager
aws_secret:
name: "{{ secret_name }}"
state: present
secret_type: 'string'
secret: "{{ super_secret_string }}"
register: result

- name: assert correct keys are returned
assert:
that:
- result.changed
- result.arn is not none
- result.name is not none
- result.tags is not none
- result.version_ids_to_stages is not none

- name: no changes to secret
aws_secret:
name: "{{ secret_name }}"
state: present
secret_type: 'string'
secret: "{{ super_secret_string }}"
register: result

- name: assert correct keys are returned
assert:
that:
- not result.changed
- result.arn is not none

- name: make change to secret
aws_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
secret_type: 'string'
secret: "{{ super_secret_string }}"
register: result

- debug:
var: result

- name: assert correct keys are returned
assert:
that:
- result.changed
- result.arn is not none
- result.name is not none
- result.tags is not none
- result.version_ids_to_stages is not none

- name: add tags to secret
aws_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
secret_type: 'string'
secret: "{{ super_secret_string }}"
tags:
Foo: 'Bar'
Test: 'Tag'
register: result

- name: assert correct keys are returned
assert:
that:
- result.changed

- name: remove tags from secret
aws_secret:
name: "{{ secret_name }}"
description: 'this is a change to this secret'
state: present
secret_type: 'string'
secret: "{{ super_secret_string }}"
register: result

- name: assert correct keys are returned
assert:
that:
- result.changed

- name: remove secret
aws_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 7
register: result

- name: assert key is deleted
assert:
that:
- result.changed

- name: remove secret (idempotency)
aws_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 7
register: result

- name: assert no change happened
assert:
that:
- not result.changed

- name: immediate secret removal
aws_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
register: result

- name: assert key is deleted
assert:
that:
- result.changed

# AWS Doesn't expose when the secret will be removed, all we can do is
# check that we didn't throw an error
- name: immediate secret removal
aws_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
register: result

- name: assert no change happened
assert:
that:
- not result.failed

always:
- name: remove secret
aws_secret:
name: "{{ secret_name }}"
state: absent
recovery_window: 0
ignore_errors: yes
Loading

0 comments on commit 9ac1717

Please sign in to comment.