mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
[PR #7200/8fa667ee backport][stable-7] CmdRunner bugfix (#7228)
CmdRunner bugfix (#7200)
* cmd_runner module utils: fix bug when passing absolute path not in standard search paths
* improved tests
* changed /usr/bin/echo to /bin/echo for the sake of alpine
* fixed error messaging for last testcase
* add condition to test cases, and remove macos from troubling ones
* fix templating
* fix templating
* exclude centos 6 from testcases copying echo to tmp dir
* try different way of specifying version
* trying trick for old jinjas
* use os.path.isabs() to determine if path is absolute
* add changelog frag
* Update plugins/module_utils/cmd_runner.py
Co-authored-by: Felix Fontein <felix@fontein.de>
* Update changelogs/fragments/7200-cmd-runner-abs-path.yml
Co-authored-by: Felix Fontein <felix@fontein.de>
---------
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 8fa667eeb7
)
Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
This commit is contained in:
parent
2fa17c32a3
commit
c94fa6132d
7 changed files with 162 additions and 13 deletions
2
changelogs/fragments/7200-cmd-runner-abs-path.yml
Normal file
2
changelogs/fragments/7200-cmd-runner-abs-path.yml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- CmdRunner module utils - does not attempt to resolve path if executable is a relative or absolute path (https://github.com/ansible-collections/community.general/pull/7200).
|
|
@ -6,6 +6,7 @@
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import os
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from ansible.module_utils.common.collections import is_sequence
|
from ansible.module_utils.common.collections import is_sequence
|
||||||
|
@ -204,12 +205,17 @@ class CmdRunner(object):
|
||||||
environ_update = {}
|
environ_update = {}
|
||||||
self.environ_update = environ_update
|
self.environ_update = environ_update
|
||||||
|
|
||||||
self.command[0] = module.get_bin_path(self.command[0], opt_dirs=path_prefix, required=True)
|
_cmd = self.command[0]
|
||||||
|
self.command[0] = _cmd if (os.path.isabs(_cmd) or '/' in _cmd) else module.get_bin_path(_cmd, opt_dirs=path_prefix, required=True)
|
||||||
|
|
||||||
for mod_param_name, spec in iteritems(module.argument_spec):
|
for mod_param_name, spec in iteritems(module.argument_spec):
|
||||||
if mod_param_name not in self.arg_formats:
|
if mod_param_name not in self.arg_formats:
|
||||||
self.arg_formats[mod_param_name] = _Format.as_default_type(spec.get('type', 'str'), mod_param_name)
|
self.arg_formats[mod_param_name] = _Format.as_default_type(spec.get('type', 'str'), mod_param_name)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def binary(self):
|
||||||
|
return self.command[0]
|
||||||
|
|
||||||
def __call__(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
|
def __call__(self, args_order=None, output_process=None, ignore_value_none=True, check_mode_skip=False, check_mode_return=None, **kwargs):
|
||||||
if output_process is None:
|
if output_process is None:
|
||||||
output_process = _process_as_is
|
output_process = _process_as_is
|
||||||
|
|
|
@ -21,6 +21,8 @@ from ansible_collections.community.general.plugins.module_utils.cmd_runner impor
|
||||||
def main():
|
def main():
|
||||||
module = AnsibleModule(
|
module = AnsibleModule(
|
||||||
argument_spec=dict(
|
argument_spec=dict(
|
||||||
|
cmd=dict(type="str", default="echo"),
|
||||||
|
path_prefix=dict(type="str"),
|
||||||
arg_formats=dict(type="dict", default={}),
|
arg_formats=dict(type="dict", default={}),
|
||||||
arg_order=dict(type="raw", required=True),
|
arg_order=dict(type="raw", required=True),
|
||||||
arg_values=dict(type="dict", default={}),
|
arg_values=dict(type="dict", default={}),
|
||||||
|
@ -41,7 +43,7 @@ def main():
|
||||||
|
|
||||||
arg_formats[arg] = func(*args)
|
arg_formats[arg] = func(*args)
|
||||||
|
|
||||||
runner = CmdRunner(module, ['echo', '--'], arg_formats=arg_formats)
|
runner = CmdRunner(module, [module.params["cmd"], '--'], arg_formats=arg_formats, path_prefix=module.params["path_prefix"])
|
||||||
|
|
||||||
with runner.context(p['arg_order'], check_mode_skip=p['check_mode_skip']) as ctx:
|
with runner.context(p['arg_order'], check_mode_skip=p['check_mode_skip']) as ctx:
|
||||||
result = ctx.run(**p['arg_values'])
|
result = ctx.run(**p['arg_values'])
|
||||||
|
|
7
tests/integration/targets/cmd_runner/meta/main.yml
Normal file
7
tests/integration/targets/cmd_runner/meta/main.yml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
# Copyright (c) Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- setup_remote_tmp_dir
|
|
@ -6,3 +6,4 @@
|
||||||
ansible.builtin.include_tasks:
|
ansible.builtin.include_tasks:
|
||||||
file: test_cmd_echo.yml
|
file: test_cmd_echo.yml
|
||||||
loop: "{{ cmd_echo_tests }}"
|
loop: "{{ cmd_echo_tests }}"
|
||||||
|
when: item.condition | default(true) | bool
|
||||||
|
|
|
@ -3,17 +3,26 @@
|
||||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
- name: test cmd_echo [{{ item.name }}]
|
- name: create copy of /bin/echo ({{ item.name }})
|
||||||
cmd_echo:
|
ansible.builtin.copy:
|
||||||
arg_formats: "{{ item.arg_formats|default(omit) }}"
|
src: /bin/echo
|
||||||
arg_order: "{{ item.arg_order }}"
|
dest: "{{ item.copy_to }}/echo"
|
||||||
arg_values: "{{ item.arg_values|default(omit) }}"
|
mode: "755"
|
||||||
check_mode_skip: "{{ item.check_mode_skip|default(omit) }}"
|
when: item.copy_to is defined
|
||||||
aa: "{{ item.aa|default(omit) }}"
|
|
||||||
register: test_result
|
|
||||||
check_mode: "{{ item.check_mode|default(omit) }}"
|
|
||||||
ignore_errors: "{{ item.expect_error|default(omit) }}"
|
|
||||||
|
|
||||||
- name: check results [{{ item.name }}]
|
- name: test cmd_echo module ({{ item.name }})
|
||||||
|
cmd_echo:
|
||||||
|
cmd: "{{ item.cmd | default(omit) }}"
|
||||||
|
path_prefix: "{{ item.path_prefix | default(omit) }}"
|
||||||
|
arg_formats: "{{ item.arg_formats | default(omit) }}"
|
||||||
|
arg_order: "{{ item.arg_order }}"
|
||||||
|
arg_values: "{{ item.arg_values | default(omit) }}"
|
||||||
|
check_mode_skip: "{{ item.check_mode_skip | default(omit) }}"
|
||||||
|
aa: "{{ item.aa | default(omit) }}"
|
||||||
|
register: test_result
|
||||||
|
check_mode: "{{ item.check_mode | default(omit) }}"
|
||||||
|
ignore_errors: "{{ item.expect_error | default(omit) }}"
|
||||||
|
|
||||||
|
- name: check results ({{ item.name }})
|
||||||
assert:
|
assert:
|
||||||
that: "{{ item.assertions }}"
|
that: "{{ item.assertions }}"
|
||||||
|
|
|
@ -138,3 +138,125 @@ cmd_echo_tests:
|
||||||
- test_result.rc == 0
|
- test_result.rc == 0
|
||||||
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
||||||
- test_result.err == ""
|
- test_result.err == ""
|
||||||
|
|
||||||
|
- name: use cmd echo
|
||||||
|
cmd: echo
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
assertions:
|
||||||
|
- test_result.rc == 0
|
||||||
|
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
||||||
|
- test_result.err == ""
|
||||||
|
|
||||||
|
- name: use cmd /bin/echo
|
||||||
|
cmd: /bin/echo
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
assertions:
|
||||||
|
- test_result.rc == 0
|
||||||
|
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
||||||
|
- test_result.err == ""
|
||||||
|
|
||||||
|
# this will not be in the regular set of paths get_bin_path() searches
|
||||||
|
- name: use cmd {{ remote_tmp_dir }}/echo
|
||||||
|
condition: >
|
||||||
|
{{
|
||||||
|
ansible_distribution != "MacOSX" and
|
||||||
|
not (ansible_distribution == "CentOS" and ansible_distribution_major_version is version('7.0', '<'))
|
||||||
|
}}
|
||||||
|
copy_to: "{{ remote_tmp_dir }}"
|
||||||
|
cmd: "{{ remote_tmp_dir }}/echo"
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
assertions:
|
||||||
|
- test_result.rc == 0
|
||||||
|
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
||||||
|
- test_result.err == ""
|
||||||
|
|
||||||
|
- name: use cmd echo with path_prefix {{ remote_tmp_dir }}
|
||||||
|
cmd: echo
|
||||||
|
condition: >
|
||||||
|
{{
|
||||||
|
ansible_distribution != "MacOSX" and
|
||||||
|
not (ansible_distribution == "CentOS" and ansible_distribution_major_version is version('7.0', '<'))
|
||||||
|
}}
|
||||||
|
copy_to: "{{ remote_tmp_dir }}"
|
||||||
|
path_prefix: "{{ remote_tmp_dir }}"
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
assertions:
|
||||||
|
- test_result.rc == 0
|
||||||
|
- test_result.out == "-- --answer=11 --tt-arg potatoes\n"
|
||||||
|
- test_result.err == ""
|
||||||
|
|
||||||
|
- name: use cmd never-existed
|
||||||
|
cmd: never-existed
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
expect_error: true
|
||||||
|
assertions:
|
||||||
|
- >
|
||||||
|
"Failed to find required executable" in test_result.msg
|
||||||
|
|
||||||
|
- name: use cmd /usr/bin/never-existed
|
||||||
|
cmd: /usr/bin/never-existed
|
||||||
|
arg_formats:
|
||||||
|
aa:
|
||||||
|
func: as_opt_eq_val
|
||||||
|
args: [--answer]
|
||||||
|
tt:
|
||||||
|
func: as_opt_val
|
||||||
|
args: [--tt-arg]
|
||||||
|
arg_order: 'aa tt'
|
||||||
|
arg_values:
|
||||||
|
tt: potatoes
|
||||||
|
aa: 11
|
||||||
|
expect_error: true
|
||||||
|
assertions:
|
||||||
|
- >
|
||||||
|
"No such file or directory" in test_result.msg
|
||||||
|
|
Loading…
Reference in a new issue