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

Add method to automatically clean up after an action plugin #65509

Merged
merged 5 commits into from Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelogs/fragments/action-plugin-always-cleanup.yml
@@ -0,0 +1,7 @@
bugfixes:
- ActionBase - Add new ``cleanup`` method that is explicitly run by the
``TaskExecutor`` to ensure that the shell plugins ``tmpdir`` is always
removed. This change means that individual action plugins need not be
responsible for removing the temporary directory, which ensures that
we don't have code paths that accidentally leave behind the temporary
directory.
3 changes: 3 additions & 0 deletions lib/ansible/executor/task_executor.py
Expand Up @@ -649,6 +649,8 @@ def _execute(self, variables=None):
return dict(failed=True, msg=to_text(e))
except AnsibleConnectionFailure as e:
return dict(unreachable=True, msg=to_text(e))
finally:
self._handler.cleanup()
display.debug("handler run complete")

# preserve no log
Expand Down Expand Up @@ -853,6 +855,7 @@ def _poll_async_result(self, result, templar, task_vars=None):
else:
return dict(failed=True, msg="async task produced unparseable results", async_result=async_result)
else:
async_handler.cleanup(force=True)
return async_result

def _get_become(self, name):
Expand Down
12 changes: 12 additions & 0 deletions lib/ansible/plugins/action/__init__.py
Expand Up @@ -115,6 +115,18 @@ def run(self, tmp=None, task_vars=None):

return result

def cleanup(self, force=False):
"""Method to perform a clean up at the end of an action plugin execution

By default this is designed to clean up the shell tmpdir, and is toggled based on whether
async is in use

Action plugins may override this if they deem necessary, but should still call this method
via super
"""
if force or not self._task.async_val:
self._remove_tmp_path(self._connection._shell.tmpdir)

def get_plugin_option(self, plugin, option, default=None):
"""Helper to get an option from a plugin without having to use
the try/except dance everywhere to set a default
Expand Down
6 changes: 6 additions & 0 deletions test/integration/targets/listen_ports_facts/tasks/main.yml
Expand Up @@ -77,3 +77,9 @@
assert:
that: 5555 in ansible_facts.udp_listen | map(attribute='port') | sort | list
when: (ansible_os_family == "RedHat" and ansible_distribution_major_version|int >= 7) or ansible_os_family == "Debian"

- name: kill all async commands
command: "kill -9 {{ item.pid }}"
loop: "{{ [tcp_listen, udp_listen]|flatten }}"
when: item.name == 'nc'
ignore_errors: true
29 changes: 29 additions & 0 deletions test/integration/targets/remote_tmp/playbook.yml
Expand Up @@ -24,3 +24,32 @@
- name: clean up test user
user: name=tmptest state=absent
become_user: root

- name: Test tempdir is removed
hosts: testhost
gather_facts: false
tasks:
- file:
state: touch
path: "/{{ output_dir }}/65393"

- copy:
src: "/{{ output_dir }}/65393"
dest: "/{{ output_dir }}/65393.2"
remote_src: true

- find:
path: "~/.ansible/tmp"
use_regex: yes
patterns: 'AnsiballZ_.+\.py'
recurse: true
register: result

- debug:
var: result

- assert:
that:
# Should only be AnsiballZ_find.py because find is actively running
- result.files|length == 1
- result.files[0].path.endswith('/AnsiballZ_find.py')
2 changes: 1 addition & 1 deletion test/integration/targets/remote_tmp/runme.sh
Expand Up @@ -2,4 +2,4 @@

set -ux

ansible-playbook -i ../../inventory playbook.yml -v "$@"
ansible-playbook -i ../../inventory playbook.yml -e "output_dir=${OUTPUT_DIR}" -v "$@"