1
0
Fork 0
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:
patchback[bot] 2023-09-10 09:00:14 +02:00 committed by GitHub
parent 2fa17c32a3
commit c94fa6132d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 162 additions and 13 deletions

View 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).

View file

@ -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

View file

@ -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'])

View 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

View file

@ -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

View file

@ -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 }}"

View file

@ -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