mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-07-25 00:44:46 +00:00
Compare commits
12 Commits
947dacff6a
...
2.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9af430396 | ||
|
|
9cf6a06ca7 | ||
|
|
1009d5cb28 | ||
|
|
42feec22c7 | ||
|
|
ec51a15f69 | ||
|
|
0b197ad440 | ||
|
|
165babdd69 | ||
|
|
8b5bba6fa1 | ||
|
|
714c50bdb7 | ||
|
|
c163fb089e | ||
|
|
e29860f4d2 | ||
|
|
668015a48c |
@@ -4,6 +4,50 @@ ansible.posix Release Notes
|
|||||||
|
|
||||||
.. contents:: Topics
|
.. contents:: Topics
|
||||||
|
|
||||||
|
v2.2.0
|
||||||
|
======
|
||||||
|
|
||||||
|
Release Summary
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This is the minor release of the ``ansible.posix`` collection.
|
||||||
|
This changelog contains all changes to the modules and plugins
|
||||||
|
in the stable-2 branch that have been added after the release of
|
||||||
|
``ansible.posix`` 2.1.0
|
||||||
|
|
||||||
|
Minor Changes
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- acl - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- authorized_key - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- cgroup_perf_recap callback - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- csh shell plugin - fix deprecated ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- firewalld_info - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- firewalld_info - use module.warn instead of passing ``warnings`` to ``exit_json`` (https://github.com/ansible-collections/ansible.posix/issues/710).
|
||||||
|
- fish shell plugin - fix deprecated ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- json callback - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- jsonl callback - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- mount - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- patch - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- profile_roles callback - fix deprecated ``ansible.module_utils.six`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- profile_tasks - Add option to provide a different date/time format (https://github.com/ansible-collections/ansible.posix/issues/279).
|
||||||
|
- profile_tasks callback - fix deprecated ``ansible.module_utils.six`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- removed ANSIBLE_METADATA from remaining plugins.
|
||||||
|
- rhel_rpm_ostree - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- rpm_ostree_upgrade - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- seboolean - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- synchronize - fix deprecated ``ansible.module_utils._text``, ``ansible.module_utils.common._collections_compat``, and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- sysctl - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
|
||||||
|
Bugfixes
|
||||||
|
--------
|
||||||
|
|
||||||
|
- acl - correctly assert needed changes when pointing to a directory and recursive is set to true.
|
||||||
|
- ansible.posix.authorized_key - fixes error on permission denied in authorized_key module (https://github.com/ansible-collections/ansible.posix/issues/462).
|
||||||
|
- firewalld_info - stop returning warnings as return values; this has been deprecated by ansible-core (https://github.com/ansible-collections/ansible.posix/pull/670).
|
||||||
|
- mount - stop returning warnings as return values; this has been deprecated by ansible-core (https://github.com/ansible-collections/ansible.posix/pull/670).
|
||||||
|
- patch - removed use of deprecated ``_AnsibleActionDone`` API (https://github.com/ansible-collections/ansible.posix/pull/687).
|
||||||
|
|
||||||
v2.1.0
|
v2.1.0
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<!-- Add CI and code coverage badges here. Samples included below. -->
|
<!-- Add CI and code coverage badges here. Samples included below. -->
|
||||||
[](https://dev.azure.com/ansible/ansible.posix/_build?definitionId=26)
|
https://dev.azure.com/ansible/ansible.posix/_apis/build/status/CI?branchName=main)](https://dev.azure.com/ansible/ansible.posix/_build?definitionId=26)
|
||||||
[]() <!--[](https://codecov.io/gh/ansible-collections/ansible.posix)-->
|
[](https://codecov.io/gh/ansible-collections/ansible.posix)
|
||||||
|
|
||||||
## Communication
|
## Communication
|
||||||
|
|
||||||
|
|||||||
@@ -512,3 +512,69 @@ releases:
|
|||||||
- 650-profile_tasks_roles.yml
|
- 650-profile_tasks_roles.yml
|
||||||
- 654_ci_bump_core_version.yml
|
- 654_ci_bump_core_version.yml
|
||||||
release_date: '2025-07-16'
|
release_date: '2025-07-16'
|
||||||
|
2.2.0:
|
||||||
|
changes:
|
||||||
|
bugfixes:
|
||||||
|
- acl - correctly assert needed changes when pointing to a directory and recursive
|
||||||
|
is set to true.
|
||||||
|
- ansible.posix.authorized_key - fixes error on permission denied in authorized_key
|
||||||
|
module (https://github.com/ansible-collections/ansible.posix/issues/462).
|
||||||
|
- firewalld_info - stop returning warnings as return values; this has been deprecated
|
||||||
|
by ansible-core (https://github.com/ansible-collections/ansible.posix/pull/670).
|
||||||
|
- mount - stop returning warnings as return values; this has been deprecated
|
||||||
|
by ansible-core (https://github.com/ansible-collections/ansible.posix/pull/670).
|
||||||
|
- patch - removed use of deprecated ``_AnsibleActionDone`` API (https://github.com/ansible-collections/ansible.posix/pull/687).
|
||||||
|
minor_changes:
|
||||||
|
- acl - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- authorized_key - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six``
|
||||||
|
imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- cgroup_perf_recap callback - fix deprecated ``ansible.module_utils._text``
|
||||||
|
and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- csh shell plugin - fix deprecated ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- firewalld_info - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- firewalld_info - use module.warn instead of passing ``warnings`` to ``exit_json``
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/issues/710).
|
||||||
|
- fish shell plugin - fix deprecated ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- json callback - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- jsonl callback - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- mount - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six``
|
||||||
|
imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- patch - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- profile_roles callback - fix deprecated ``ansible.module_utils.six`` import
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- profile_tasks - Add option to provide a different date/time format (https://github.com/ansible-collections/ansible.posix/issues/279).
|
||||||
|
- profile_tasks callback - fix deprecated ``ansible.module_utils.six`` import
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- removed ANSIBLE_METADATA from remaining plugins.
|
||||||
|
- rhel_rpm_ostree - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- rpm_ostree_upgrade - fix deprecated ``ansible.module_utils._text`` import
|
||||||
|
(https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- seboolean - fix deprecated ``ansible.module_utils._text`` import (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- synchronize - fix deprecated ``ansible.module_utils._text``, ``ansible.module_utils.common._collections_compat``,
|
||||||
|
and ``ansible.module_utils.six`` imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
- sysctl - fix deprecated ``ansible.module_utils._text`` and ``ansible.module_utils.six``
|
||||||
|
imports (https://github.com/ansible-collections/ansible.posix/issues/686).
|
||||||
|
release_summary: 'This is the minor release of the ``ansible.posix`` collection.
|
||||||
|
|
||||||
|
This changelog contains all changes to the modules and plugins
|
||||||
|
|
||||||
|
in the stable-2 branch that have been added after the release of
|
||||||
|
|
||||||
|
``ansible.posix`` 2.1.0'
|
||||||
|
fragments:
|
||||||
|
- 2.2.0.yml
|
||||||
|
- 626_profile_tasks_datetime_format.yml
|
||||||
|
- 638_fix_recursive_acl.yml
|
||||||
|
- 639_fix_authorized_key.yml
|
||||||
|
- 660_ci_azp_syntax.yml
|
||||||
|
- 665_update_readme_20250728.yml
|
||||||
|
- 666_azp_update_20250728.yml
|
||||||
|
- 670-deprecations.yml
|
||||||
|
- 673_update_ci_20250805.yml
|
||||||
|
- 682_update_ci_20250929.yml
|
||||||
|
- 686_fix_deprecated_imports.yml
|
||||||
|
- 693_azp_update_20251205.yml
|
||||||
|
- ansible_metadata_removed.yml
|
||||||
|
- firewalld_info_warnings.yml
|
||||||
|
- patch_removed.yml
|
||||||
|
release_date: '2026-05-18'
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
trivial:
|
|
||||||
- AZP - fixed syntax error in CI test.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
trivial:
|
|
||||||
- README - Update README to reflect Ansible Core 2.19 release.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
trivial:
|
|
||||||
- AZP - Update AZP matrix to follow ansible-test changes.
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
trivial:
|
|
||||||
- Update AZP CI matrix (https://github.com/ansible-collections/ansible.posix/issues/673).
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
trivial:
|
|
||||||
- Updatng AZP CI matrix to ignore ansible-bad-import-from on six(https://github.com/ansible-collections/ansible.posix/pull/682).
|
|
||||||
- Skipped sanity[cannot-ignore] to keep backward compatibility with Python2.
|
|
||||||
- Consolidate all ansible-lint option locations into .ansible-lint file.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
trivial:
|
|
||||||
- AZP - Update AZP matrix to follow ansible-test changes.
|
|
||||||
- Add ignore file for Ansible Core 2.21.
|
|
||||||
- Remove ignore lines for ansible-bad-import-from in 2.20 sanity tests.
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
namespace: ansible
|
namespace: ansible
|
||||||
name: posix
|
name: posix
|
||||||
version: 2.1.0
|
version: 2.2.0
|
||||||
readme: README.md
|
readme: README.md
|
||||||
authors:
|
authors:
|
||||||
- Ansible (github.com/ansible)
|
- Ansible (github.com/ansible)
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ __metaclass__ = type
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleAction, _AnsibleActionDone, AnsibleActionFail
|
from ansible.errors import AnsibleError, AnsibleAction, AnsibleActionFail
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
|
|
||||||
@@ -46,7 +46,8 @@ class ActionModule(ActionBase):
|
|||||||
elif remote_src:
|
elif remote_src:
|
||||||
# everything is remote, so we just execute the module
|
# everything is remote, so we just execute the module
|
||||||
# without changing any of the module arguments
|
# without changing any of the module arguments
|
||||||
raise _AnsibleActionDone(result=self._execute_module(task_vars=task_vars))
|
result.update(self._execute_module(task_vars=task_vars))
|
||||||
|
return result
|
||||||
|
|
||||||
try:
|
try:
|
||||||
src = self._find_needle('files', src)
|
src = self._find_needle('files', src)
|
||||||
|
|||||||
@@ -18,12 +18,11 @@ from __future__ import (absolute_import, division, print_function)
|
|||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
from collections.abc import MutableSequence
|
||||||
|
from shlex import quote as shlex_quote
|
||||||
|
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
from ansible.module_utils.six import string_types
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
from ansible.module_utils.six.moves import shlex_quote
|
|
||||||
from ansible.module_utils._text import to_text
|
|
||||||
from ansible.module_utils.common._collections_compat import MutableSequence
|
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.plugins.loader import connection_loader
|
from ansible.plugins.loader import connection_loader
|
||||||
@@ -417,7 +416,7 @@ class ActionModule(ActionBase):
|
|||||||
# Replicate what we do in the module argumentspec handling for lists
|
# Replicate what we do in the module argumentspec handling for lists
|
||||||
if not isinstance(_tmp_args.get('rsync_opts'), MutableSequence):
|
if not isinstance(_tmp_args.get('rsync_opts'), MutableSequence):
|
||||||
tmp_rsync_opts = _tmp_args.get('rsync_opts', [])
|
tmp_rsync_opts = _tmp_args.get('rsync_opts', [])
|
||||||
if isinstance(tmp_rsync_opts, string_types):
|
if isinstance(tmp_rsync_opts, str):
|
||||||
tmp_rsync_opts = tmp_rsync_opts.split(',')
|
tmp_rsync_opts = tmp_rsync_opts.split(',')
|
||||||
elif isinstance(tmp_rsync_opts, (int, float)):
|
elif isinstance(tmp_rsync_opts, (int, float)):
|
||||||
tmp_rsync_opts = [to_text(tmp_rsync_opts)]
|
tmp_rsync_opts = [to_text(tmp_rsync_opts)]
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
name: cgroup_perf_recap
|
name: cgroup_perf_recap
|
||||||
@@ -141,8 +138,7 @@ from abc import ABCMeta, abstractmethod
|
|||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
||||||
from ansible.module_utils.six import with_metaclass
|
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
@@ -158,7 +154,7 @@ def dict_fromkeys(keys, default=None):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
class BaseProf(with_metaclass(ABCMeta, threading.Thread)):
|
class BaseProf(threading.Thread, metaclass=ABCMeta):
|
||||||
def __init__(self, path, obj=None, writer=None):
|
def __init__(self, path, obj=None, writer=None):
|
||||||
threading.Thread.__init__(self) # pylint: disable=non-parent-init-called
|
threading.Thread.__init__(self) # pylint: disable=non-parent-init-called
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import json
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import copy
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from ansible.inventory.host import Host
|
from ansible.inventory.host import Host
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import collections
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.module_utils.six.moves import reduce
|
from functools import reduce
|
||||||
|
|
||||||
# define start time
|
# define start time
|
||||||
t0 = tn = time.time()
|
t0 = tn = time.time()
|
||||||
|
|||||||
@@ -52,6 +52,17 @@ DOCUMENTATION = '''
|
|||||||
- section: callback_profile_tasks
|
- section: callback_profile_tasks
|
||||||
key: summary_only
|
key: summary_only
|
||||||
version_added: 1.5.0
|
version_added: 1.5.0
|
||||||
|
datetime_format:
|
||||||
|
description:
|
||||||
|
- Datetime format, as expected by the C(strftime) and C(strptime) methods.
|
||||||
|
An C(iso8601) alias will be translated to C('%Y-%m-%dT%H:%M:%S.%f') if that datetime standard wants to be used.
|
||||||
|
default: '%A %d %B %Y %H:%M:%S %z'
|
||||||
|
env:
|
||||||
|
- name: PROFILE_TASKS_DATETIME_FORMAT
|
||||||
|
ini:
|
||||||
|
- section: callback_profile_tasks
|
||||||
|
key: datetime_format
|
||||||
|
version_added: 3.0.0
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = '''
|
EXAMPLES = '''
|
||||||
@@ -72,14 +83,15 @@ sample output: >
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import time
|
|
||||||
|
|
||||||
from ansible.module_utils.six.moves import reduce
|
from datetime import datetime
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
|
|
||||||
|
|
||||||
# define start time
|
# define start time
|
||||||
t0 = tn = time.time()
|
dt0 = dtn = datetime.now().astimezone()
|
||||||
|
|
||||||
|
|
||||||
def secondsToStr(t):
|
def secondsToStr(t):
|
||||||
@@ -104,17 +116,18 @@ def filled(msg, fchar="*"):
|
|||||||
|
|
||||||
def timestamp(self):
|
def timestamp(self):
|
||||||
if self.current is not None:
|
if self.current is not None:
|
||||||
elapsed = time.time() - self.stats[self.current]['started']
|
elapsed = (datetime.now().astimezone() - self.stats[self.current]['started']).total_seconds()
|
||||||
self.stats[self.current]['elapsed'] += elapsed
|
self.stats[self.current]['elapsed'] += elapsed
|
||||||
|
|
||||||
|
|
||||||
def tasktime():
|
def tasktime(self):
|
||||||
global tn
|
global dtn
|
||||||
time_current = time.strftime('%A %d %B %Y %H:%M:%S %z')
|
cdtn = datetime.now().astimezone()
|
||||||
time_elapsed = secondsToStr(time.time() - tn)
|
datetime_current = cdtn.strftime(self.datetime_format)
|
||||||
time_total_elapsed = secondsToStr(time.time() - t0)
|
time_elapsed = secondsToStr((cdtn - dtn).total_seconds())
|
||||||
tn = time.time()
|
time_total_elapsed = secondsToStr((cdtn - dt0).total_seconds())
|
||||||
return filled('%s (%s)%s%s' % (time_current, time_elapsed, ' ' * 7, time_total_elapsed))
|
dtn = cdtn
|
||||||
|
return filled('%s (%s)%s%s' % (datetime_current, time_elapsed, ' ' * 7, time_total_elapsed))
|
||||||
|
|
||||||
|
|
||||||
class CallbackModule(CallbackBase):
|
class CallbackModule(CallbackBase):
|
||||||
@@ -134,6 +147,7 @@ class CallbackModule(CallbackBase):
|
|||||||
self.sort_order = None
|
self.sort_order = None
|
||||||
self.summary_only = None
|
self.summary_only = None
|
||||||
self.task_output_limit = None
|
self.task_output_limit = None
|
||||||
|
self.datetime_format = None
|
||||||
|
|
||||||
super(CallbackModule, self).__init__()
|
super(CallbackModule, self).__init__()
|
||||||
|
|
||||||
@@ -159,9 +173,14 @@ class CallbackModule(CallbackBase):
|
|||||||
else:
|
else:
|
||||||
self.task_output_limit = int(self.task_output_limit)
|
self.task_output_limit = int(self.task_output_limit)
|
||||||
|
|
||||||
|
self.datetime_format = self.get_option('datetime_format')
|
||||||
|
if self.datetime_format is not None:
|
||||||
|
if self.datetime_format == 'iso8601':
|
||||||
|
self.datetime_format = '%Y-%m-%dT%H:%M:%S.%f'
|
||||||
|
|
||||||
def _display_tasktime(self):
|
def _display_tasktime(self):
|
||||||
if not self.summary_only:
|
if not self.summary_only:
|
||||||
self._display.display(tasktime())
|
self._display.display(tasktime(self))
|
||||||
|
|
||||||
def _record_task(self, task):
|
def _record_task(self, task):
|
||||||
"""
|
"""
|
||||||
@@ -176,10 +195,11 @@ class CallbackModule(CallbackBase):
|
|||||||
# with the same UUID is executed when `serial` is specified in a playbook.
|
# with the same UUID is executed when `serial` is specified in a playbook.
|
||||||
# elapsed: Elapsed time since the first serialized task was started
|
# elapsed: Elapsed time since the first serialized task was started
|
||||||
self.current = task._uuid
|
self.current = task._uuid
|
||||||
|
dtn = datetime.now().astimezone()
|
||||||
if self.current not in self.stats:
|
if self.current not in self.stats:
|
||||||
self.stats[self.current] = {'started': time.time(), 'elapsed': 0.0, 'name': task.get_name()}
|
self.stats[self.current] = {'started': dtn, 'elapsed': 0.0, 'name': task.get_name()}
|
||||||
else:
|
else:
|
||||||
self.stats[self.current]['started'] = time.time()
|
self.stats[self.current]['started'] = dtn
|
||||||
if self._display.verbosity >= 2:
|
if self._display.verbosity >= 2:
|
||||||
self.stats[self.current]['path'] = task.get_path()
|
self.stats[self.current]['path'] = task.get_path()
|
||||||
|
|
||||||
@@ -193,7 +213,7 @@ class CallbackModule(CallbackBase):
|
|||||||
# Align summary report header with other callback plugin summary
|
# Align summary report header with other callback plugin summary
|
||||||
self._display.banner("TASKS RECAP")
|
self._display.banner("TASKS RECAP")
|
||||||
|
|
||||||
self._display.display(tasktime())
|
self._display.display(tasktime(self))
|
||||||
self._display.display(filled("", fchar="="))
|
self._display.display(filled("", fchar="="))
|
||||||
|
|
||||||
timestamp(self)
|
timestamp(self)
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
|
|
||||||
|
|
||||||
def split_entry(entry):
|
def split_entry(entry):
|
||||||
@@ -244,16 +244,16 @@ def acl_changed(module, cmd, entry, use_nfsv4_acls=False):
|
|||||||
lines = run_acl(module, cmd)
|
lines = run_acl(module, cmd)
|
||||||
counter = 0
|
counter = 0
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line.endswith('*,*') and not use_nfsv4_acls:
|
if not use_nfsv4_acls and not line.endswith('*,*'):
|
||||||
return False
|
return True
|
||||||
# if use_nfsv4_acls and entry is listed
|
# if use_nfsv4_acls and entry is listed
|
||||||
if use_nfsv4_acls and entry == line:
|
if use_nfsv4_acls and entry == line:
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
# The current 'nfs4_setfacl --test' lists a new entry,
|
# The current 'nfs4_setfacl --test' lists a new entry,
|
||||||
# which will be added at the top of list, followed by the existing entries.
|
# which will be added at the top of the list, followed by the existing entries.
|
||||||
# So if the entry has already been registered, the entry should be find twice.
|
# So if the entry has already been registered, the entry should be found twice.
|
||||||
if counter == 2:
|
if not use_nfsv4_acls or counter == 2:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -225,12 +225,21 @@ import os.path
|
|||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
import errno
|
||||||
|
import traceback
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from ansible.module_utils._text import to_native
|
# TODO(Python2): urllib.parse is available in Python 3. This module may run on
|
||||||
|
# target hosts with Python 2.7 (e.g., older RHEL systems in CI integration tests).
|
||||||
|
# Remove the try/except fallback to urlparse when Python 2 support is dropped.
|
||||||
|
try:
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
except ImportError:
|
||||||
|
from urlparse import urlparse
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
from ansible.module_utils.urls import fetch_url
|
from ansible.module_utils.urls import fetch_url
|
||||||
from ansible.module_utils.six.moves.urllib.parse import urlparse
|
|
||||||
|
|
||||||
|
|
||||||
class keydict(dict):
|
class keydict(dict):
|
||||||
@@ -475,16 +484,18 @@ def parsekey(module, raw_key, rank=None):
|
|||||||
return (key, key_type, options, comment, rank)
|
return (key, key_type, options, comment, rank)
|
||||||
|
|
||||||
|
|
||||||
def readfile(filename):
|
def readfile(module, filename):
|
||||||
|
|
||||||
if not os.path.isfile(filename):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
f = open(filename)
|
|
||||||
try:
|
try:
|
||||||
return f.read()
|
with open(filename, 'r') as f:
|
||||||
finally:
|
return f.read()
|
||||||
f.close()
|
except IOError as e:
|
||||||
|
if e.errno == errno.EACCES:
|
||||||
|
module.fail_json(msg="Permission denied on file or path for authorized keys file: %s" % filename,
|
||||||
|
exception=traceback.format_exc())
|
||||||
|
elif e.errno == errno.ENOENT:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def parsekeys(module, lines):
|
def parsekeys(module, lines):
|
||||||
@@ -597,7 +608,7 @@ def enforce_state(module, params):
|
|||||||
# check current state -- just get the filename, don't create file
|
# check current state -- just get the filename, don't create file
|
||||||
do_write = False
|
do_write = False
|
||||||
params["keyfile"] = keyfile(module, user, do_write, path, manage_dir)
|
params["keyfile"] = keyfile(module, user, do_write, path, manage_dir)
|
||||||
existing_content = readfile(params["keyfile"])
|
existing_content = readfile(module, params["keyfile"])
|
||||||
existing_keys = parsekeys(module, existing_content)
|
existing_keys = parsekeys(module, existing_content)
|
||||||
|
|
||||||
# Add a place holder for keys that should exist in the state=present and
|
# Add a place holder for keys that should exist in the state=present and
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ firewalld_info:
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
|
from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
|
||||||
|
|
||||||
@@ -319,7 +319,6 @@ def main():
|
|||||||
active_zones=module.params['active_zones'],
|
active_zones=module.params['active_zones'],
|
||||||
collected_zones=list(),
|
collected_zones=list(),
|
||||||
undefined_zones=list(),
|
undefined_zones=list(),
|
||||||
warnings=list(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Exit with failure message if requirements modules are not installed.
|
# Exit with failure message if requirements modules are not installed.
|
||||||
@@ -334,10 +333,6 @@ def main():
|
|||||||
if not HAS_FIREWALLD:
|
if not HAS_FIREWALLD:
|
||||||
module.fail_json(msg=missing_required_lib('python-firewall'))
|
module.fail_json(msg=missing_required_lib('python-firewall'))
|
||||||
|
|
||||||
# If you want to show warning messages in the task running process,
|
|
||||||
# you can append the message to the 'warn' list.
|
|
||||||
warn = list()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = fw_client.FirewallClient()
|
client = fw_client.FirewallClient()
|
||||||
|
|
||||||
@@ -357,8 +352,7 @@ def main():
|
|||||||
collect_zones = list(set(specified_zones) & set(all_zones))
|
collect_zones = list(set(specified_zones) & set(all_zones))
|
||||||
ignore_zones = list(set(specified_zones) - set(collect_zones))
|
ignore_zones = list(set(specified_zones) - set(collect_zones))
|
||||||
if ignore_zones:
|
if ignore_zones:
|
||||||
warn.append(
|
module.warn('Please note: zone:(%s) have been ignored in the gathering process.' % ", ".join(ignore_zones))
|
||||||
'Please note: zone:(%s) have been ignored in the gathering process.' % ','.join(ignore_zones))
|
|
||||||
else:
|
else:
|
||||||
collect_zones = get_all_zones(client)
|
collect_zones = get_all_zones(client)
|
||||||
|
|
||||||
@@ -397,7 +391,6 @@ def main():
|
|||||||
result['collected_zones'] = collect_zones
|
result['collected_zones'] = collect_zones
|
||||||
result['undefined_zones'] = ignore_zones
|
result['undefined_zones'] = ignore_zones
|
||||||
result['firewalld_info'] = firewalld_info
|
result['firewalld_info'] = firewalld_info
|
||||||
result['warnings'] = warn
|
|
||||||
module.exit_json(**result)
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -225,8 +225,7 @@ import platform
|
|||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils.mount import ismount
|
from ansible_collections.ansible.posix.plugins.module_utils.mount import ismount
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
||||||
from ansible.module_utils._text import to_bytes, to_native
|
|
||||||
from ansible.module_utils.parsing.convert_bool import boolean
|
from ansible.module_utils.parsing.convert_bool import boolean
|
||||||
|
|
||||||
|
|
||||||
@@ -279,7 +278,7 @@ def _set_mount_save_old(module, args):
|
|||||||
old_lines = []
|
old_lines = []
|
||||||
exists = False
|
exists = False
|
||||||
changed = False
|
changed = False
|
||||||
escaped_args = dict([(k, _escape_fstab(v)) for k, v in iteritems(args) if k != 'warnings'])
|
escaped_args = dict([(k, _escape_fstab(v)) for k, v in args.items()])
|
||||||
new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n'
|
new_line = '%(src)s %(name)s %(fstype)s %(opts)s %(dump)s %(passno)s\n'
|
||||||
|
|
||||||
if platform.system() == 'SunOS':
|
if platform.system() == 'SunOS':
|
||||||
@@ -804,7 +803,6 @@ def main():
|
|||||||
passno='-',
|
passno='-',
|
||||||
fstab=module.params['fstab'],
|
fstab=module.params['fstab'],
|
||||||
boot='yes' if module.params['boot'] else 'no',
|
boot='yes' if module.params['boot'] else 'no',
|
||||||
warnings=[]
|
|
||||||
)
|
)
|
||||||
if args['fstab'] is None:
|
if args['fstab'] is None:
|
||||||
args['fstab'] = '/etc/vfstab'
|
args['fstab'] = '/etc/vfstab'
|
||||||
@@ -816,7 +814,6 @@ def main():
|
|||||||
passno='0',
|
passno='0',
|
||||||
fstab=module.params['fstab'],
|
fstab=module.params['fstab'],
|
||||||
boot='yes',
|
boot='yes',
|
||||||
warnings=[]
|
|
||||||
)
|
)
|
||||||
if args['fstab'] is None:
|
if args['fstab'] is None:
|
||||||
args['fstab'] = '/etc/fstab'
|
args['fstab'] = '/etc/fstab'
|
||||||
@@ -834,8 +831,7 @@ def main():
|
|||||||
linux_mounts = get_linux_mounts(module)
|
linux_mounts = get_linux_mounts(module)
|
||||||
|
|
||||||
if linux_mounts is None:
|
if linux_mounts is None:
|
||||||
args['warnings'].append('Cannot open file /proc/self/mountinfo.'
|
module.warn('Cannot open file /proc/self/mountinfo. Bind mounts might be misinterpreted.')
|
||||||
' Bind mounts might be misinterpreted.')
|
|
||||||
|
|
||||||
# Override defaults with user specified params
|
# Override defaults with user specified params
|
||||||
for key in ('src', 'fstype', 'passno', 'opts', 'dump', 'fstab'):
|
for key in ('src', 'fstype', 'passno', 'opts', 'dump', 'fstab'):
|
||||||
@@ -847,7 +843,7 @@ def main():
|
|||||||
# specified in 'opts', mount module will ignore 'boot'.
|
# specified in 'opts', mount module will ignore 'boot'.
|
||||||
opts = args['opts'].split(',')
|
opts = args['opts'].split(',')
|
||||||
if module.params['boot'] and 'noauto' in opts:
|
if module.params['boot'] and 'noauto' in opts:
|
||||||
args['warnings'].append("Ignore the 'boot' due to 'opts' contains 'noauto'.")
|
module.warn("Ignore the 'boot' due to 'opts' contains 'noauto'.")
|
||||||
elif not module.params['boot']:
|
elif not module.params['boot']:
|
||||||
args['boot'] = 'no'
|
args['boot'] = 'no'
|
||||||
opts.append('noauto')
|
opts.append('noauto')
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
|
|
||||||
|
|
||||||
class PatchError(Exception):
|
class PatchError(Exception):
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
@@ -73,7 +70,7 @@ import os
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
|
|
||||||
|
|
||||||
def locally_installed(module, pkgname):
|
def locally_installed(module, pkgname):
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
@@ -71,7 +68,7 @@ import os
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils.common.text.converters import to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
def rpm_ostree_transaction(module):
|
def rpm_ostree_transaction(module):
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ except ImportError:
|
|||||||
HAVE_SEMANAGE = False
|
HAVE_SEMANAGE = False
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils.common.text.converters import to_text
|
||||||
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
from ansible_collections.ansible.posix.plugins.module_utils._respawn import respawn_module, HAS_RESPAWN_UTIL
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -367,9 +367,16 @@ EXAMPLES = r'''
|
|||||||
import os
|
import os
|
||||||
import errno
|
import errno
|
||||||
|
|
||||||
|
# TODO(Python2): shlex.quote was added in Python 3.3. This module may run on
|
||||||
|
# target hosts with Python 2.7 (e.g., older RHEL systems in CI integration tests).
|
||||||
|
# Remove the try/except fallback to pipes.quote when Python 2 support is dropped.
|
||||||
|
try:
|
||||||
|
from shlex import quote as shlex_quote
|
||||||
|
except ImportError:
|
||||||
|
from pipes import quote as shlex_quote
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils._text import to_bytes, to_native
|
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
||||||
from ansible.module_utils.six.moves import shlex_quote
|
|
||||||
|
|
||||||
|
|
||||||
client_addr = None
|
client_addr = None
|
||||||
|
|||||||
@@ -80,6 +80,13 @@ EXAMPLES = r'''
|
|||||||
sysctl_file: /tmp/test_sysctl.conf
|
sysctl_file: /tmp/test_sysctl.conf
|
||||||
reload: false
|
reload: false
|
||||||
|
|
||||||
|
# Enable resource limits management in FreeBSD
|
||||||
|
- ansible.posix.sysctl:
|
||||||
|
name: kern.racct.enable
|
||||||
|
value: '1'
|
||||||
|
sysctl_file: /boot/loader.conf
|
||||||
|
reload: false
|
||||||
|
|
||||||
# Set ip forwarding on in /proc and verify token value with the sysctl command
|
# Set ip forwarding on in /proc and verify token value with the sysctl command
|
||||||
- ansible.posix.sysctl:
|
- ansible.posix.sysctl:
|
||||||
name: net.ipv4.ip_forward
|
name: net.ipv4.ip_forward
|
||||||
@@ -100,12 +107,20 @@ EXAMPLES = r'''
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
# TODO(Python2): On Python 2, string_types is basestring (str + unicode).
|
||||||
|
# This module may run on target hosts with Python 2.7.
|
||||||
|
# Remove the Python 2 branch when Python 2 support is dropped.
|
||||||
|
if sys.version_info >= (3, 0):
|
||||||
|
string_types = str
|
||||||
|
else:
|
||||||
|
string_types = basestring # pylint: disable=undefined-variable
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils.six import string_types
|
from ansible.module_utils.common.text.converters import to_native
|
||||||
from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE, BOOLEANS_TRUE
|
from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE, BOOLEANS_TRUE
|
||||||
from ansible.module_utils._text import to_native
|
|
||||||
|
|
||||||
|
|
||||||
class SysctlModule(object):
|
class SysctlModule(object):
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ DOCUMENTATION = '''
|
|||||||
- shell_common
|
- shell_common
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ansible.module_utils.six import text_type
|
from shlex import quote as shlex_quote
|
||||||
from ansible.module_utils.six.moves import shlex_quote
|
|
||||||
from ansible.plugins.shell import ShellBase
|
from ansible.plugins.shell import ShellBase
|
||||||
|
|
||||||
|
|
||||||
@@ -43,5 +42,5 @@ class ShellModule(ShellBase):
|
|||||||
ret = []
|
ret = []
|
||||||
# All the -u options must be first, so we process them first
|
# All the -u options must be first, so we process them first
|
||||||
ret += ['-u %s' % k for k, v in kwargs.items() if v is None]
|
ret += ['-u %s' % k for k, v in kwargs.items() if v is None]
|
||||||
ret += ['%s=%s' % (k, shlex_quote(text_type(v))) for k, v in kwargs.items() if v is not None]
|
ret += ['%s=%s' % (k, shlex_quote(str(v))) for k, v in kwargs.items() if v is not None]
|
||||||
return 'env %s' % ' '.join(ret)
|
return 'env %s' % ' '.join(ret)
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ DOCUMENTATION = '''
|
|||||||
- shell_common
|
- shell_common
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from ansible.module_utils.six import text_type
|
from shlex import quote as shlex_quote
|
||||||
from ansible.module_utils.six.moves import shlex_quote
|
|
||||||
from ansible.plugins.shell.sh import ShellModule as ShModule
|
from ansible.plugins.shell.sh import ShellModule as ShModule
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ class ShellModule(ShModule):
|
|||||||
if v is None:
|
if v is None:
|
||||||
ret.append('set -e %s;' % k)
|
ret.append('set -e %s;' % k)
|
||||||
else:
|
else:
|
||||||
ret.append('set -lx %s %s;' % (k, shlex_quote(text_type(v))))
|
ret.append('set -lx %s %s;' % (k, shlex_quote(str(v))))
|
||||||
return ' '.join(ret)
|
return ' '.join(ret)
|
||||||
|
|
||||||
def build_module_command(self, env_string, shebang, cmd, arg_path=None):
|
def build_module_command(self, env_string, shebang, cmd, arg_path=None):
|
||||||
|
|||||||
@@ -1,20 +1,6 @@
|
|||||||
---
|
---
|
||||||
# (c) 2017, Martin Krizek <mkrizek@redhat.com>
|
# (c) 2017, Martin Krizek <mkrizek@redhat.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
- name: Create ansible user
|
- name: Create ansible user
|
||||||
ansible.builtin.user:
|
ansible.builtin.user:
|
||||||
@@ -43,15 +29,17 @@
|
|||||||
|
|
||||||
- name: Create ansible dir
|
- name: Create ansible dir
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ test_dir }}"
|
path: "{{ item.path }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: "0755"
|
mode: "{{ item.mode }}"
|
||||||
|
loop:
|
||||||
|
- { path: "{{ test_dir }}", mode: "0755" }
|
||||||
|
- { path: "{{ test_recursive_dir }}", mode: "0755" }
|
||||||
|
|
||||||
- name: Install acl package
|
- name: Install acl package
|
||||||
ansible.builtin.package:
|
ansible.builtin.package:
|
||||||
name: acl
|
name: acl
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
- name: Grant ansible user read access to a file
|
- name: Grant ansible user read access to a file
|
||||||
ansible.posix.acl:
|
ansible.posix.acl:
|
||||||
@@ -249,3 +237,38 @@
|
|||||||
- "'default:mask::rwx' in getfacl_output.stdout_lines"
|
- "'default:mask::rwx' in getfacl_output.stdout_lines"
|
||||||
- "'default:other::r-x' in getfacl_output.stdout_lines"
|
- "'default:other::r-x' in getfacl_output.stdout_lines"
|
||||||
- "'default:group:{{ test_group }}:rw-' not in getfacl_output.stdout_lines"
|
- "'default:group:{{ test_group }}:rw-' not in getfacl_output.stdout_lines"
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
- name: create file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ test_recursive_dir }}/txt.txt"
|
||||||
|
mode: '0440'
|
||||||
|
content: "hw"
|
||||||
|
|
||||||
|
- name: Change ACLs recursively
|
||||||
|
ansible.posix.acl:
|
||||||
|
path: "{{ test_recursive_dir }}"
|
||||||
|
entity: "{{ test_user }}"
|
||||||
|
etype: user
|
||||||
|
permissions: rX
|
||||||
|
state: present
|
||||||
|
recursive: true
|
||||||
|
register: output_acl_change
|
||||||
|
|
||||||
|
- name: Remove ACLs recursively again
|
||||||
|
ansible.posix.acl:
|
||||||
|
path: "{{ test_recursive_dir }}"
|
||||||
|
entity: "{{ test_user }}"
|
||||||
|
etype: user
|
||||||
|
permissions: r
|
||||||
|
state: present
|
||||||
|
recursive: true
|
||||||
|
register: output_acl_remove
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- output_acl_change is changed
|
||||||
|
- output_acl_change is not failed
|
||||||
|
- output_acl_remove is changed
|
||||||
|
- output_acl_remove is not failed
|
||||||
|
|||||||
@@ -1,20 +1,6 @@
|
|||||||
---
|
---
|
||||||
# (c) 2017, Martin Krizek <mkrizek@redhat.com>
|
# (c) 2017, Martin Krizek <mkrizek@redhat.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
- name: Test ACL
|
- name: Test ACL
|
||||||
vars:
|
vars:
|
||||||
@@ -22,6 +8,7 @@
|
|||||||
test_group: ansible_group
|
test_group: ansible_group
|
||||||
test_file: "{{ output_dir }}/ansible file"
|
test_file: "{{ output_dir }}/ansible file"
|
||||||
test_dir: "{{ output_dir }}/ansible_dir/with some space"
|
test_dir: "{{ output_dir }}/ansible_dir/with some space"
|
||||||
|
test_recursive_dir: "{{ output_dir }}/recursive_dir"
|
||||||
block:
|
block:
|
||||||
- name: Include tests task file
|
- name: Include tests task file
|
||||||
ansible.builtin.include_tasks: acl.yml
|
ansible.builtin.include_tasks: acl.yml
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# check permissions
|
||||||
|
|
||||||
|
- name: Create a file that is not accessible
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: touch
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
owner: root
|
||||||
|
mode: '0000'
|
||||||
|
|
||||||
|
- name: Create unprivileged user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: nopriv
|
||||||
|
create_home: true
|
||||||
|
|
||||||
|
- name: Try to delete a key from an unreadable file
|
||||||
|
become: true
|
||||||
|
become_user: nopriv
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: root
|
||||||
|
key: "{{ dss_key_basic }}"
|
||||||
|
state: absent
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
register: result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Assert that the key deletion has failed
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Remove the file
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
|
||||||
|
- name: Remove the user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: nopriv
|
||||||
|
state: absent
|
||||||
@@ -34,3 +34,6 @@
|
|||||||
|
|
||||||
- name: Test for specifying key as a path
|
- name: Test for specifying key as a path
|
||||||
ansible.builtin.import_tasks: check_path.yml
|
ansible.builtin.import_tasks: check_path.yml
|
||||||
|
|
||||||
|
- name: Test for permission denied files
|
||||||
|
ansible.builtin.import_tasks: check_permissions.yml
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
- name: Assert turn active_zones true
|
- name: Assert turn active_zones true
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
|
- result.collected_zones == ['public']
|
||||||
|
|
||||||
- name: Ensure firewalld_zones with zone list
|
- name: Ensure firewalld_zones with zone list
|
||||||
ansible.posix.firewalld_info:
|
ansible.posix.firewalld_info:
|
||||||
@@ -31,3 +32,6 @@
|
|||||||
- name: Assert specified zones
|
- name: Assert specified zones
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
|
- result.collected_zones == ['public']
|
||||||
|
- result.undefined_zones == ['invalid_zone']
|
||||||
|
- '"invalid_zone" in result.warnings[0]'
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
plugins/action/synchronize.py pylint:ansible-bad-import-from
|
|
||||||
plugins/callback/cgroup_perf_recap.py pylint:ansible-bad-import-from
|
|
||||||
plugins/modules/mount.py pylint:ansible-bad-import-from
|
|
||||||
plugins/modules/sysctl.py pylint:ansible-bad-import-from
|
|
||||||
plugins/shell/csh.py pylint:ansible-bad-import-from
|
|
||||||
plugins/shell/fish.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/mock/procenv.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/mock/yaml_helper.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/modules/conftest.py pylint:ansible-bad-import-from
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
plugins/action/synchronize.py pylint:ansible-bad-import-from
|
|
||||||
plugins/callback/cgroup_perf_recap.py pylint:ansible-bad-import-from
|
|
||||||
plugins/modules/mount.py pylint:ansible-bad-import-from
|
|
||||||
plugins/modules/sysctl.py pylint:ansible-bad-import-from
|
|
||||||
plugins/shell/csh.py pylint:ansible-bad-import-from
|
|
||||||
plugins/shell/fish.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/mock/procenv.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/mock/yaml_helper.py pylint:ansible-bad-import-from
|
|
||||||
tests/unit/modules/conftest.py pylint:ansible-bad-import-from
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Make coding more python3-ish
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
#
|
|
||||||
# Compat for python2.7
|
|
||||||
#
|
|
||||||
|
|
||||||
# One unittest needs to import builtins via __import__() so we need to have
|
|
||||||
# the string that represents it
|
|
||||||
try:
|
|
||||||
import __builtin__
|
|
||||||
except ImportError:
|
|
||||||
BUILTINS = 'builtins'
|
|
||||||
else:
|
|
||||||
BUILTINS = '__builtin__'
|
|
||||||
__all__ = ['__builtin__']
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Make coding more python3-ish
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleParserError
|
|
||||||
from ansible.parsing.dataloader import DataLoader
|
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
|
||||||
|
|
||||||
|
|
||||||
class DictDataLoader(DataLoader):
|
|
||||||
|
|
||||||
def __init__(self, file_mapping=None):
|
|
||||||
file_mapping = {} if file_mapping is None else file_mapping
|
|
||||||
assert isinstance(file_mapping, dict)
|
|
||||||
|
|
||||||
super(DictDataLoader, self).__init__()
|
|
||||||
|
|
||||||
self._file_mapping = file_mapping
|
|
||||||
self._build_known_directories()
|
|
||||||
self._vault_secrets = None
|
|
||||||
|
|
||||||
def load_from_file(self, path, cache=True, unsafe=False):
|
|
||||||
path = to_text(path)
|
|
||||||
if path in self._file_mapping:
|
|
||||||
return self.load(self._file_mapping[path], path)
|
|
||||||
return None
|
|
||||||
|
|
||||||
# TODO: the real _get_file_contents returns a bytestring, so we actually convert the
|
|
||||||
# unicode/text it's created with to utf-8
|
|
||||||
def _get_file_contents(self, file_name):
|
|
||||||
path = to_text(file_name)
|
|
||||||
if path in self._file_mapping:
|
|
||||||
return (to_bytes(self._file_mapping[path]), False)
|
|
||||||
else:
|
|
||||||
raise AnsibleParserError("file not found: %s" % path)
|
|
||||||
|
|
||||||
def path_exists(self, path):
|
|
||||||
path = to_text(path)
|
|
||||||
return path in self._file_mapping or path in self._known_directories
|
|
||||||
|
|
||||||
def is_file(self, path):
|
|
||||||
path = to_text(path)
|
|
||||||
return path in self._file_mapping
|
|
||||||
|
|
||||||
def is_directory(self, path):
|
|
||||||
path = to_text(path)
|
|
||||||
return path in self._known_directories
|
|
||||||
|
|
||||||
def list_directory(self, path):
|
|
||||||
ret = []
|
|
||||||
path = to_text(path)
|
|
||||||
for x in (list(self._file_mapping.keys()) + self._known_directories):
|
|
||||||
if x.startswith(path):
|
|
||||||
if os.path.dirname(x) == path:
|
|
||||||
ret.append(os.path.basename(x))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def is_executable(self, path):
|
|
||||||
# FIXME: figure out a way to make paths return true for this
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _add_known_directory(self, directory):
|
|
||||||
if directory not in self._known_directories:
|
|
||||||
self._known_directories.append(directory)
|
|
||||||
|
|
||||||
def _build_known_directories(self):
|
|
||||||
self._known_directories = []
|
|
||||||
for path in self._file_mapping:
|
|
||||||
dirname = os.path.dirname(path)
|
|
||||||
while dirname not in ('/', ''):
|
|
||||||
self._add_known_directory(dirname)
|
|
||||||
dirname = os.path.dirname(dirname)
|
|
||||||
|
|
||||||
def push(self, path, content):
|
|
||||||
rebuild_dirs = False
|
|
||||||
if path not in self._file_mapping:
|
|
||||||
rebuild_dirs = True
|
|
||||||
|
|
||||||
self._file_mapping[path] = content
|
|
||||||
|
|
||||||
if rebuild_dirs:
|
|
||||||
self._build_known_directories()
|
|
||||||
|
|
||||||
def pop(self, path):
|
|
||||||
if path in self._file_mapping:
|
|
||||||
del self._file_mapping[path]
|
|
||||||
self._build_known_directories()
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self._file_mapping = dict()
|
|
||||||
self._known_directories = []
|
|
||||||
|
|
||||||
def get_basedir(self):
|
|
||||||
return os.getcwd()
|
|
||||||
|
|
||||||
def set_vault_secrets(self, vault_secrets):
|
|
||||||
self._vault_secrets = vault_secrets
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat.mock import MagicMock
|
|
||||||
from ansible.utils.path import unfrackpath
|
|
||||||
|
|
||||||
|
|
||||||
mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x)
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
# (c) 2016, Matt Davis <mdavis@ansible.com>
|
|
||||||
# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
|
|
||||||
#
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Make coding more python3-ish
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
|
|
||||||
from contextlib import contextmanager
|
|
||||||
from io import BytesIO, StringIO
|
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat import unittest
|
|
||||||
from ansible.module_utils.six import PY3
|
|
||||||
from ansible.module_utils._text import to_bytes
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
|
|
||||||
"""
|
|
||||||
context manager that temporarily masks the test runner's values for stdin and argv
|
|
||||||
"""
|
|
||||||
real_stdin = sys.stdin
|
|
||||||
real_argv = sys.argv
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
fake_stream = StringIO(stdin_data)
|
|
||||||
fake_stream.buffer = BytesIO(to_bytes(stdin_data))
|
|
||||||
else:
|
|
||||||
fake_stream = BytesIO(to_bytes(stdin_data))
|
|
||||||
|
|
||||||
try:
|
|
||||||
sys.stdin = fake_stream
|
|
||||||
sys.argv = argv_data
|
|
||||||
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
sys.stdin = real_stdin
|
|
||||||
sys.argv = real_argv
|
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def swap_stdout():
|
|
||||||
"""
|
|
||||||
context manager that temporarily replaces stdout for tests that need to verify output
|
|
||||||
"""
|
|
||||||
old_stdout = sys.stdout
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
fake_stream = StringIO()
|
|
||||||
else:
|
|
||||||
fake_stream = BytesIO()
|
|
||||||
|
|
||||||
try:
|
|
||||||
sys.stdout = fake_stream
|
|
||||||
|
|
||||||
yield fake_stream
|
|
||||||
finally:
|
|
||||||
sys.stdout = old_stdout
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleTestCase(unittest.TestCase):
|
|
||||||
def setUp(self, module_args=None):
|
|
||||||
if module_args is None:
|
|
||||||
module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False}
|
|
||||||
|
|
||||||
args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
|
|
||||||
|
|
||||||
# unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
|
|
||||||
self.stdin_swap = swap_stdin_and_argv(stdin_data=args)
|
|
||||||
self.stdin_swap.__enter__()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
# unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
|
|
||||||
self.stdin_swap.__exit__(None, None, None)
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Make coding more python3-ish
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
from ansible.module_utils._text import to_bytes
|
|
||||||
|
|
||||||
from ansible.parsing.vault import VaultSecret
|
|
||||||
|
|
||||||
|
|
||||||
class TextVaultSecret(VaultSecret):
|
|
||||||
'''A secret piece of text. ie, a password. Tracks text encoding.
|
|
||||||
|
|
||||||
The text encoding of the text may not be the default text encoding so
|
|
||||||
we keep track of the encoding so we encode it to the same bytes.'''
|
|
||||||
|
|
||||||
def __init__(self, text, encoding=None, errors=None, _bytes=None):
|
|
||||||
super(TextVaultSecret, self).__init__()
|
|
||||||
self.text = text
|
|
||||||
self.encoding = encoding or 'utf-8'
|
|
||||||
self._bytes = _bytes
|
|
||||||
self.errors = errors or 'strict'
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bytes(self):
|
|
||||||
'''The text encoded with encoding, unless we specifically set _bytes.'''
|
|
||||||
return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors)
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
import io
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from ansible.module_utils.six import PY3
|
|
||||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
|
||||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
|
||||||
|
|
||||||
|
|
||||||
class YamlTestUtils(object):
|
|
||||||
"""Mixin class to combine with a unittest.TestCase subclass."""
|
|
||||||
def _loader(self, stream):
|
|
||||||
"""Vault related tests will want to override this.
|
|
||||||
|
|
||||||
Vault cases should setup a AnsibleLoader that has the vault password."""
|
|
||||||
return AnsibleLoader(stream)
|
|
||||||
|
|
||||||
def _dump_stream(self, obj, stream, dumper=None):
|
|
||||||
"""Dump to a py2-unicode or py3-string stream."""
|
|
||||||
if PY3:
|
|
||||||
return yaml.dump(obj, stream, Dumper=dumper)
|
|
||||||
else:
|
|
||||||
return yaml.dump(obj, stream, Dumper=dumper, encoding=None)
|
|
||||||
|
|
||||||
def _dump_string(self, obj, dumper=None):
|
|
||||||
"""Dump to a py2-unicode or py3-string"""
|
|
||||||
if PY3:
|
|
||||||
return yaml.dump(obj, Dumper=dumper)
|
|
||||||
else:
|
|
||||||
return yaml.dump(obj, Dumper=dumper, encoding=None)
|
|
||||||
|
|
||||||
def _dump_load_cycle(self, obj):
|
|
||||||
# Each pass though a dump or load revs the 'generation'
|
|
||||||
# obj to yaml string
|
|
||||||
string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper)
|
|
||||||
|
|
||||||
# wrap a stream/file like StringIO around that yaml
|
|
||||||
stream_from_object_dump = io.StringIO(string_from_object_dump)
|
|
||||||
loader = self._loader(stream_from_object_dump)
|
|
||||||
# load the yaml stream to create a new instance of the object (gen 2)
|
|
||||||
obj_2 = loader.get_data()
|
|
||||||
|
|
||||||
# dump the gen 2 objects directory to strings
|
|
||||||
string_from_object_dump_2 = self._dump_string(obj_2,
|
|
||||||
dumper=AnsibleDumper)
|
|
||||||
|
|
||||||
# The gen 1 and gen 2 yaml strings
|
|
||||||
self.assertEqual(string_from_object_dump, string_from_object_dump_2)
|
|
||||||
# the gen 1 (orig) and gen 2 py object
|
|
||||||
self.assertEqual(obj, obj_2)
|
|
||||||
|
|
||||||
# again! gen 3... load strings into py objects
|
|
||||||
stream_3 = io.StringIO(string_from_object_dump_2)
|
|
||||||
loader_3 = self._loader(stream_3)
|
|
||||||
obj_3 = loader_3.get_data()
|
|
||||||
|
|
||||||
string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper)
|
|
||||||
|
|
||||||
self.assertEqual(obj, obj_3)
|
|
||||||
# should be transitive, but...
|
|
||||||
self.assertEqual(obj_2, obj_3)
|
|
||||||
self.assertEqual(string_from_object_dump, string_from_object_dump_3)
|
|
||||||
|
|
||||||
def _old_dump_load_cycle(self, obj):
|
|
||||||
'''Dump the passed in object to yaml, load it back up, dump again, compare.'''
|
|
||||||
stream = io.StringIO()
|
|
||||||
|
|
||||||
yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
|
|
||||||
self._dump_stream(obj, stream, dumper=AnsibleDumper)
|
|
||||||
|
|
||||||
yaml_string_from_stream = stream.getvalue()
|
|
||||||
|
|
||||||
# reset stream
|
|
||||||
stream.seek(0)
|
|
||||||
|
|
||||||
loader = self._loader(stream)
|
|
||||||
# loader = AnsibleLoader(stream, vault_password=self.vault_password)
|
|
||||||
obj_from_stream = loader.get_data()
|
|
||||||
|
|
||||||
stream_from_string = io.StringIO(yaml_string)
|
|
||||||
loader2 = self._loader(stream_from_string)
|
|
||||||
# loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password)
|
|
||||||
obj_from_string = loader2.get_data()
|
|
||||||
|
|
||||||
stream_obj_from_stream = io.StringIO()
|
|
||||||
stream_obj_from_string = io.StringIO()
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper)
|
|
||||||
yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper)
|
|
||||||
else:
|
|
||||||
yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None)
|
|
||||||
yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None)
|
|
||||||
|
|
||||||
yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue()
|
|
||||||
yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue()
|
|
||||||
|
|
||||||
stream_obj_from_stream.seek(0)
|
|
||||||
stream_obj_from_string.seek(0)
|
|
||||||
|
|
||||||
if PY3:
|
|
||||||
yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper)
|
|
||||||
yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper)
|
|
||||||
else:
|
|
||||||
yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None)
|
|
||||||
yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None)
|
|
||||||
|
|
||||||
assert yaml_string == yaml_string_obj_from_stream
|
|
||||||
assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
|
|
||||||
assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream ==
|
|
||||||
yaml_string_stream_obj_from_string)
|
|
||||||
assert obj == obj_from_stream
|
|
||||||
assert obj == obj_from_string
|
|
||||||
assert obj == yaml_string_obj_from_stream
|
|
||||||
assert obj == yaml_string_obj_from_string
|
|
||||||
assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
|
|
||||||
return {'obj': obj,
|
|
||||||
'yaml_string': yaml_string,
|
|
||||||
'yaml_string_from_stream': yaml_string_from_stream,
|
|
||||||
'obj_from_stream': obj_from_stream,
|
|
||||||
'obj_from_string': obj_from_string,
|
|
||||||
'yaml_string_obj_from_string': yaml_string_obj_from_string}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Copyright (c) 2017 Ansible Project
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from ansible.module_utils.six import string_types
|
|
||||||
from ansible.module_utils._text import to_bytes
|
|
||||||
from ansible.module_utils.common._collections_compat import MutableMapping
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def patch_ansible_module(request, mocker):
|
|
||||||
if isinstance(request.param, string_types):
|
|
||||||
args = request.param
|
|
||||||
elif isinstance(request.param, MutableMapping):
|
|
||||||
if 'ANSIBLE_MODULE_ARGS' not in request.param:
|
|
||||||
request.param = {'ANSIBLE_MODULE_ARGS': request.param}
|
|
||||||
if '_ansible_remote_tmp' not in request.param['ANSIBLE_MODULE_ARGS']:
|
|
||||||
request.param['ANSIBLE_MODULE_ARGS']['_ansible_remote_tmp'] = '/tmp'
|
|
||||||
if '_ansible_keep_remote_files' not in request.param['ANSIBLE_MODULE_ARGS']:
|
|
||||||
request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = False
|
|
||||||
args = json.dumps(request.param)
|
|
||||||
else:
|
|
||||||
raise Exception('Malformed data to the patch_ansible_module pytest fixture')
|
|
||||||
|
|
||||||
mocker.patch('ansible.module_utils.basic._ANSIBLE_ARGS', to_bytes(args))
|
|
||||||
@@ -7,7 +7,7 @@ import tempfile
|
|||||||
|
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat import unittest
|
from ansible_collections.ansible.posix.tests.unit.compat import unittest
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat.mock import MagicMock
|
from ansible_collections.ansible.posix.tests.unit.compat.mock import MagicMock
|
||||||
from ansible.module_utils._text import to_bytes
|
from ansible.module_utils.common.text.converters import to_bytes
|
||||||
|
|
||||||
from ansible_collections.ansible.posix.plugins.modules.mount import (
|
from ansible_collections.ansible.posix.plugins.modules.mount import (
|
||||||
get_linux_mounts,
|
get_linux_mounts,
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat import unittest
|
|
||||||
from ansible_collections.ansible.posix.tests.unit.compat.mock import patch
|
|
||||||
from ansible.module_utils import basic
|
|
||||||
from ansible.module_utils._text import to_bytes
|
|
||||||
|
|
||||||
|
|
||||||
def set_module_args(args):
|
|
||||||
if '_ansible_remote_tmp' not in args:
|
|
||||||
args['_ansible_remote_tmp'] = '/tmp'
|
|
||||||
if '_ansible_keep_remote_files' not in args:
|
|
||||||
args['_ansible_keep_remote_files'] = False
|
|
||||||
|
|
||||||
args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
|
|
||||||
basic._ANSIBLE_ARGS = to_bytes(args)
|
|
||||||
|
|
||||||
|
|
||||||
class AnsibleExitJson(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class AnsibleFailJson(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def exit_json(*args, **kwargs):
|
|
||||||
if 'changed' not in kwargs:
|
|
||||||
kwargs['changed'] = False
|
|
||||||
raise AnsibleExitJson(kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def fail_json(*args, **kwargs):
|
|
||||||
kwargs['failed'] = True
|
|
||||||
raise AnsibleFailJson(kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleTestCase(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
|
|
||||||
self.mock_module.start()
|
|
||||||
self.mock_sleep = patch('time.sleep')
|
|
||||||
self.mock_sleep.start()
|
|
||||||
set_module_args({})
|
|
||||||
self.addCleanup(self.mock_module.stop)
|
|
||||||
self.addCleanup(self.mock_sleep.stop)
|
|
||||||
Reference in New Issue
Block a user