diff --git a/changelogs/fragments/102_module_at_add_chdir_option.yml b/changelogs/fragments/102_module_at_add_chdir_option.yml new file mode 100644 index 0000000000..e4724ed092 --- /dev/null +++ b/changelogs/fragments/102_module_at_add_chdir_option.yml @@ -0,0 +1,2 @@ +minor_changes: + - at - add option ``chdir`` to permit to launch the ``at`` command from a specific directory (https://github.com/ansible-collections/ansible.posix/issues/13). diff --git a/plugins/modules/at.py b/plugins/modules/at.py index a35ec4e98e..9c7b02e109 100644 --- a/plugins/modules/at.py +++ b/plugins/modules/at.py @@ -17,6 +17,12 @@ - All jobs are executed in the 'a' queue. version_added: "1.0.0" options: + chdir: + description: + - An optional location from where to run the command C(at). + - Useful for instance when running a playbook using ansible-pull with C(purge) option. + type: path + version_added: 1.3.0 command: description: - A command to be executed in the future. @@ -78,32 +84,32 @@ from ansible.module_utils.basic import AnsibleModule -def add_job(module, result, at_cmd, count, units, command, script_file): +def add_job(module, result, at_cmd, count, units, command, script_file, chdir=None): at_command = "%s -f %s now + %s %s" % (at_cmd, script_file, count, units) - rc, out, err = module.run_command(at_command, check_rc=True) + rc, out, err = module.run_command(at_command, cwd=chdir, check_rc=True) if command: os.unlink(script_file) result['changed'] = True -def delete_job(module, result, at_cmd, command, script_file): +def delete_job(module, result, at_cmd, command, script_file, chdir=None): for matching_job in get_matching_jobs(module, at_cmd, script_file): at_command = "%s -r %s" % (at_cmd, matching_job) - rc, out, err = module.run_command(at_command, check_rc=True) + rc, out, err = module.run_command(at_command, cwd=chdir, check_rc=True) result['changed'] = True if command: os.unlink(script_file) module.exit_json(**result) -def get_matching_jobs(module, at_cmd, script_file): +def get_matching_jobs(module, at_cmd, script_file, chdir=None): matching_jobs = [] atq_cmd = module.get_bin_path('atq', True) # Get list of job numbers for the user. atq_command = "%s" % atq_cmd - rc, out, err = module.run_command(atq_command, check_rc=True) + rc, out, err = module.run_command(atq_command, cwd=chdir, check_rc=True) current_jobs = out.splitlines() if len(current_jobs) == 0: return matching_jobs @@ -118,7 +124,7 @@ def get_matching_jobs(module, at_cmd, script_file): split_current_job = current_job.split() at_opt = '-c' if platform.system() != 'AIX' else '-lv' at_command = "%s %s %s" % (at_cmd, at_opt, split_current_job[0]) - rc, out, err = module.run_command(at_command, check_rc=True) + rc, out, err = module.run_command(at_command, cwd=chdir, check_rc=True) if script_file_string in out: matching_jobs.append(split_current_job[0]) @@ -139,6 +145,7 @@ def main(): module = AnsibleModule( argument_spec=dict( command=dict(type='str'), + chdir=dict(type='path'), script_file=dict(type='str'), count=dict(type='int'), units=dict(type='str', choices=['minutes', 'hours', 'days', 'weeks']), @@ -152,6 +159,7 @@ def main(): at_cmd = module.get_bin_path('at', True) + chdir = module.params['chdir'] command = module.params['command'] script_file = module.params['script_file'] count = module.params['count'] @@ -173,7 +181,7 @@ def main(): # if absent remove existing and return if state == 'absent': - delete_job(module, result, at_cmd, command, script_file) + delete_job(module, result, at_cmd, command, script_file, chdir=chdir) # if unique if existing return unchanged if unique: @@ -186,7 +194,7 @@ def main(): result['count'] = count result['units'] = units - add_job(module, result, at_cmd, count, units, command, script_file) + add_job(module, result, at_cmd, count, units, command, script_file, chdir=chdir) module.exit_json(**result) diff --git a/tests/integration/targets/at/aliases b/tests/integration/targets/at/aliases index 85f744a596..6eae8bd8dd 100644 --- a/tests/integration/targets/at/aliases +++ b/tests/integration/targets/at/aliases @@ -1,3 +1,2 @@ shippable/posix/group1 destructive -disabled # fixme package diff --git a/tests/integration/targets/at/tasks/main.yml b/tests/integration/targets/at/tasks/main.yml index cd09e11850..436b787a7f 100644 --- a/tests/integration/targets/at/tasks/main.yml +++ b/tests/integration/targets/at/tasks/main.yml @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . + - set_fact: output_dir_test={{output_dir}}/at - name: make sure our testing sub-directory does not exist @@ -28,35 +29,103 @@ ## at ## -- name: define distros to attempt installing at on - set_fact: - package_distros: - - RedHat - - CentOS - - ScientificLinux - - Fedora - - Ubuntu - - Debian - - openSUSE Leap - -- name: ensure at is installed - package: - name: at - state: present - when: ansible_distribution in package_distros - -- name: run the first example - at: - command: "ls -d / > /dev/null" - count: 20 - units: minutes - register: at_test0 -- debug: var=at_test0 -- name: validate results - assert: - that: +- name: Run At tests + block: + - name: define distros to attempt installing at on + set_fact: + package_distros: + - RedHat + - CentOS + - ScientificLinux + - Fedora + - Ubuntu + - Debian + - openSUSE Leap + + - name: ensure at is installed + package: + name: at + state: present + when: ansible_distribution in package_distros + + - name: run the first example + at: + command: "ls -d / > /dev/null" + count: 20 + units: minutes + register: at_test0 + + - debug: var=at_test0 + + - name: validate results + assert: + that: - 'at_test0.changed is defined' - 'at_test0.count is defined' - 'at_test0.script_file is defined' - 'at_test0.state is defined' - 'at_test0.units is defined' + + - name: Add a useless command using at + at: + command: /bin/logger 'AT task ran from Ansible' + count: 1 + units: minutes + unique: yes + register: at_add + + - debug: var=at_add + + - name: Wait for at to run the previous command + pause: + minutes: 1 + + - name: Add a useless command + at: + command: /bin/logger 'AT task ran from Ansible' + count: 1 + units: minutes + unique: true + state: absent + register: at_removal + + - debug: var=at_removal + + - name: Wait for at to run the previous command + pause: + minutes: 1 + + - name: Validate results + assert: + that: + - at_add is changed + - at_removal is changed + + - name: Create an at command with chdir with valid value + at: + command: /bin/logger 'AT task ran from Ansible with chdir' + count: 1 + units: minutes + chdir: /tmp + register: at_chdir_valid + - debug: var=at_chdir_valid + + - name: Create an at command with chdir with invalid value + at: + command: /bin/logger 'AT task ran from Ansible with chdir' + count: 1 + units: minutes + chdir: /invalid + register: at_chdir_invalid + ignore_errors: true + + - debug: var=at_chdir_invalid + + - name: Validate results + assert: + that: + - at_chdir_valid is changed + - at_chdir_invalid is changed + when: + - not (ansible_facts['distribution'] in ('Ubuntu','FreeBSD')) + - not (ansible_distribution == "CentOS" and ansible_distribution_version is version('6', '==')) \ No newline at end of file