Merge branch 'ansible-collections:main' into patch-2

This commit is contained in:
Baptiste Mille-Mathias 2022-03-27 19:28:11 +02:00 committed by GitHub
commit 4174f53c6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 611 additions and 73 deletions

View file

@ -50,13 +50,31 @@ stages:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
testFormat: devel/linux/{0}/1 testFormat: devel/linux/{0}/1
targets:
- name: CentOS 7
test: centos7
- name: Fedora 34
test: fedora34
- name: Fedora 35
test: fedora35
- name: openSUSE 15 py3
test: opensuse15
- name: Ubuntu 18.04
test: ubuntu1804
- name: Ubuntu 20.04
test: ubuntu2004
- stage: Docker_2_12
displayName: Docker 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/linux/{0}/1
targets: targets:
- name: CentOS 6 - name: CentOS 6
test: centos6 test: centos6
- name: CentOS 7 - name: CentOS 7
test: centos7 test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 33 - name: Fedora 33
test: fedora33 test: fedora33
- name: Fedora 34 - name: Fedora 34
@ -81,8 +99,6 @@ stages:
test: centos6 test: centos6
- name: CentOS 7 - name: CentOS 7
test: centos7 test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 32 - name: Fedora 32
test: fedora32 test: fedora32
- name: Fedora 33 - name: Fedora 33
@ -107,8 +123,6 @@ stages:
test: centos6 test: centos6
- name: CentOS 7 - name: CentOS 7
test: centos7 test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 30 - name: Fedora 30
test: fedora30 test: fedora30
- name: Fedora 31 - name: Fedora 31
@ -133,8 +147,6 @@ stages:
test: centos6 test: centos6
- name: CentOS 7 - name: CentOS 7
test: centos7 test: centos7
- name: CentOS 8
test: centos8
- name: Fedora 30 - name: Fedora 30
test: fedora30 test: fedora30
- name: Fedora 31 - name: Fedora 31
@ -156,6 +168,24 @@ stages:
- template: templates/matrix.yml - template: templates/matrix.yml
parameters: parameters:
testFormat: devel/{0}/1 testFormat: devel/{0}/1
targets:
- name: MacOS 12.0
test: macos/12.0
- name: RHEL 7.9
test: rhel/7.9
- name: RHEL 8.5
test: rhel/8.5
- name: FreeBSD 12.3
test: freebsd/12.3
- name: FreeBSD 13.0
test: freebsd/13.0
- stage: Remote_2_12
displayName: Remote 2.12
dependsOn: []
jobs:
- template: templates/matrix.yml
parameters:
testFormat: 2.12/{0}/1
targets: targets:
- name: MacOS 11.1 - name: MacOS 11.1
test: macos/11.1 test: macos/11.1
@ -195,8 +225,8 @@ stages:
targets: targets:
- name: OS X 10.11 - name: OS X 10.11
test: osx/10.11 test: osx/10.11
- name: RHEL 7.6 - name: RHEL 7.9
test: rhel/7.6 test: rhel/7.9
- name: RHEL 8.2 - name: RHEL 8.2
test: rhel/8.2 test: rhel/8.2
- name: FreeBSD 11.1 - name: FreeBSD 11.1
@ -214,8 +244,8 @@ stages:
targets: targets:
- name: OS X 10.11 - name: OS X 10.11
test: osx/10.11 test: osx/10.11
- name: RHEL 7.6 - name: RHEL 7.9
test: rhel/7.6 test: rhel/7.9
- name: RHEL 8.1 - name: RHEL 8.1
test: rhel/8.1 test: rhel/8.1
- name: FreeBSD 11.1 - name: FreeBSD 11.1
@ -230,9 +260,11 @@ stages:
- Remote_2_9 - Remote_2_9
- Docker_2_9 - Docker_2_9
- Remote_2_10 - Remote_2_10
- Remote_2_11
- Docker_2_10 - Docker_2_10
- Remote_2_11
- Docker_2_11 - Docker_2_11
- Remote_2_12
- Docker_2_12
- Remote_devel - Remote_devel
- Docker_devel - Docker_devel
jobs: jobs:

View file

@ -86,7 +86,8 @@ None
<!-- List the versions of Ansible the collection has been tested with. Must match what is in galaxy.yml. --> <!-- List the versions of Ansible the collection has been tested with. Must match what is in galaxy.yml. -->
* ansible-core 2.12 (devel) * ansible-core 2.13 (devel)
* ansible-core 2.12 (stable)
* ansible-core 2.11 (stable) * ansible-core 2.11 (stable)
* ansible-base 2.10 (stable) * ansible-base 2.10 (stable)
* ansible 2.9 (stable) * ansible 2.9 (stable)

View file

@ -1,4 +1,4 @@
# This is a cross-platform list tracking distribution packages needed by tests; # This is a cross-platform list tracking distribution packages needed by tests;
# see https://docs.openstack.org/infra/bindep/ for additional information. # see https://docs.openstack.org/infra/bindep/ for additional information.
rsync [platform:centos-8 platform:rhel-8] rsync [platform:rhel-8]

View file

@ -0,0 +1,3 @@
---
trivial:
- Copy ignore-2.12.txt to ignore-2.13.txt.

View file

@ -0,0 +1,3 @@
---
trivial:
- Fix integration tests of synchronize and sysctl to address chaging behavior on devel branch (https://github.com/ansible-collections/overview/issues/45).

View file

@ -0,0 +1,3 @@
---
trivial:
- Fix unit tests of synchronize action plugin to use yaml.safe_load().

View file

@ -0,0 +1,3 @@
---
trivial:
- firewalld - add python-firewall to requirements (https://github.com/ansible-collections/ansible.posix/issues/286).

View file

@ -0,0 +1,3 @@
---
trivial:
- mount - remove deprecated option from nfs example

View file

@ -0,0 +1,3 @@
---
bugfixes:
- firewalld - Refine the handling of exclusive options (https://github.com/ansible-collections/ansible.posix/issues/255).

View file

@ -0,0 +1,3 @@
---
bugfixes:
- seboolean - add ``python3-libsemanage`` package dependency for RHEL8+ systems.

View file

@ -0,0 +1,3 @@
---
trivial:
- CI tests - fix exit code to address shellckeck test issue (https://github.com/ansible-collections/ansible.posix/issues/301).

View file

@ -0,0 +1,3 @@
---
bugfixes:
- Use vendored version of ``distutils.version`` instead of the deprecated Python standard library to address PEP 632 (https://github.com/ansible-collections/ansible.posix/issues/303).

View file

@ -0,0 +1,3 @@
---
bugfixes:
- Fix for whitespace in source full path causing error ```code 23) at main.c(1330) [sender=3.2.3]``` (https://github.com/ansible-collections/ansible.posix/pull/278)

1
codecov.yml Normal file
View file

@ -0,0 +1 @@
comment: false

View file

@ -0,0 +1,344 @@
# Vendored copy of distutils/version.py from CPython 3.9.5
#
# Implements multiple version numbering conventions for the
# Python Module Distribution Utilities.
#
# PSF License (see licenses/PSF-license.txt or https://opensource.org/licenses/Python-2.0)
#
"""Provides classes to represent module version numbers (one class for
each style of version numbering). There are currently two such classes
implemented: StrictVersion and LooseVersion.
Every version number class implements the following interface:
* the 'parse' method takes a string and parses it to some internal
representation; if the string is an invalid version number,
'parse' raises a ValueError exception
* the class constructor takes an optional string argument which,
if supplied, is passed to 'parse'
* __str__ reconstructs the string that was passed to 'parse' (or
an equivalent string -- ie. one that will generate an equivalent
version number instance)
* __repr__ generates Python code to recreate the version number instance
* _cmp compares the current instance with either another instance
of the same class or a string (which will be parsed to an instance
of the same class, thus must follow the same rules)
"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import re
try:
RE_FLAGS = re.VERBOSE | re.ASCII
except AttributeError:
RE_FLAGS = re.VERBOSE
class Version:
"""Abstract base class for version numbering classes. Just provides
constructor (__init__) and reproducer (__repr__), because those
seem to be the same for all version numbering classes; and route
rich comparisons to _cmp.
"""
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def __repr__(self):
return "%s ('%s')" % (self.__class__.__name__, str(self))
def __eq__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c == 0
def __lt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c >= 0
# Interface for version-number classes -- must be implemented
# by the following classes (the concrete ones -- Version should
# be treated as an abstract class).
# __init__ (string) - create and take same action as 'parse'
# (string parameter is optional)
# parse (string) - convert a string representation to whatever
# internal representation is appropriate for
# this style of version numbering
# __str__ (self) - convert back to a string; should be very similar
# (if not identical to) the string supplied to parse
# __repr__ (self) - generate Python code to recreate
# the instance
# _cmp (self, other) - compare two version numbers ('other' may
# be an unparsed version string, or another
# instance of your version class)
class StrictVersion(Version):
"""Version numbering for anal retentives and software idealists.
Implements the standard interface for version number classes as
described above. A version number consists of two or three
dot-separated numeric components, with an optional "pre-release" tag
on the end. The pre-release tag consists of the letter 'a' or 'b'
followed by a number. If the numeric components of two version
numbers are equal, then one with a pre-release tag will always
be deemed earlier (lesser) than one without.
The following are valid version numbers (shown in the order that
would be obtained by sorting according to the supplied cmp function):
0.4 0.4.0 (these two are equivalent)
0.4.1
0.5a1
0.5b3
0.5
0.9.6
1.0
1.0.4a3
1.0.4b1
1.0.4
The following are examples of invalid version numbers:
1
2.7.2.2
1.3.a4
1.3pl1
1.3c4
The rationale for this version numbering system will be explained
in the distutils documentation.
"""
version_re = re.compile(r"^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$", RE_FLAGS)
def parse(self, vstring):
match = self.version_re.match(vstring)
if not match:
raise ValueError("invalid version number '%s'" % vstring)
(major, minor, patch, prerelease, prerelease_num) = match.group(1, 2, 4, 5, 6)
if patch:
self.version = tuple(map(int, [major, minor, patch]))
else:
self.version = tuple(map(int, [major, minor])) + (0,)
if prerelease:
self.prerelease = (prerelease[0], int(prerelease_num))
else:
self.prerelease = None
def __str__(self):
if self.version[2] == 0:
vstring = ".".join(map(str, self.version[0:2]))
else:
vstring = ".".join(map(str, self.version))
if self.prerelease:
vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
return vstring
def _cmp(self, other):
if isinstance(other, str):
other = StrictVersion(other)
elif not isinstance(other, StrictVersion):
return NotImplemented
if self.version != other.version:
# numeric versions don't match
# prerelease stuff doesn't matter
if self.version < other.version:
return -1
else:
return 1
# have to compare prerelease
# case 1: neither has prerelease; they're equal
# case 2: self has prerelease, other doesn't; other is greater
# case 3: self doesn't have prerelease, other does: self is greater
# case 4: both have prerelease: must compare them!
if not self.prerelease and not other.prerelease:
return 0
elif self.prerelease and not other.prerelease:
return -1
elif not self.prerelease and other.prerelease:
return 1
elif self.prerelease and other.prerelease:
if self.prerelease == other.prerelease:
return 0
elif self.prerelease < other.prerelease:
return -1
else:
return 1
else:
raise AssertionError("never get here")
# end class StrictVersion
# The rules according to Greg Stein:
# 1) a version number has 1 or more numbers separated by a period or by
# sequences of letters. If only periods, then these are compared
# left-to-right to determine an ordering.
# 2) sequences of letters are part of the tuple for comparison and are
# compared lexicographically
# 3) recognize the numeric components may have leading zeroes
#
# The LooseVersion class below implements these rules: a version number
# string is split up into a tuple of integer and string components, and
# comparison is a simple tuple comparison. This means that version
# numbers behave in a predictable and obvious way, but a way that might
# not necessarily be how people *want* version numbers to behave. There
# wouldn't be a problem if people could stick to purely numeric version
# numbers: just split on period and compare the numbers as tuples.
# However, people insist on putting letters into their version numbers;
# the most common purpose seems to be:
# - indicating a "pre-release" version
# ('alpha', 'beta', 'a', 'b', 'pre', 'p')
# - indicating a post-release patch ('p', 'pl', 'patch')
# but of course this can't cover all version number schemes, and there's
# no way to know what a programmer means without asking him.
#
# The problem is what to do with letters (and other non-numeric
# characters) in a version number. The current implementation does the
# obvious and predictable thing: keep them as strings and compare
# lexically within a tuple comparison. This has the desired effect if
# an appended letter sequence implies something "post-release":
# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
#
# However, if letters in a version number imply a pre-release version,
# the "obvious" thing isn't correct. Eg. you would expect that
# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
# implemented here, this just isn't so.
#
# Two possible solutions come to mind. The first is to tie the
# comparison algorithm to a particular set of semantic rules, as has
# been done in the StrictVersion class above. This works great as long
# as everyone can go along with bondage and discipline. Hopefully a
# (large) subset of Python module programmers will agree that the
# particular flavour of bondage and discipline provided by StrictVersion
# provides enough benefit to be worth using, and will submit their
# version numbering scheme to its domination. The free-thinking
# anarchists in the lot will never give in, though, and something needs
# to be done to accommodate them.
#
# Perhaps a "moderately strict" version class could be implemented that
# lets almost anything slide (syntactically), and makes some heuristic
# assumptions about non-digits in version number strings. This could
# sink into special-case-hell, though; if I was as talented and
# idiosyncratic as Larry Wall, I'd go ahead and implement a class that
# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
# just as happy dealing with things like "2g6" and "1.13++". I don't
# think I'm smart enough to do it right though.
#
# In any case, I've coded the test suite for this module (see
# ../test/test_version.py) specifically to fail on things like comparing
# "1.2a2" and "1.2". That's not because the *code* is doing anything
# wrong, it's because the simple, obvious design doesn't match my
# complicated, hairy expectations for real-world version numbers. It
# would be a snap to fix the test suite to say, "Yep, LooseVersion does
# the Right Thing" (ie. the code matches the conception). But I'd rather
# have a conception that matches common notions about version numbers.
class LooseVersion(Version):
"""Version numbering for anarchists and software realists.
Implements the standard interface for version number classes as
described above. A version number consists of a series of numbers,
separated by either periods or strings of letters. When comparing
version numbers, the numeric components will be compared
numerically, and the alphabetic components lexically. The following
are all valid version numbers, in no particular order:
1.5.1
1.5.2b2
161
3.10a
8.02
3.4j
1996.07.12
3.2.pl0
3.1.1.6
2g6
11g
0.960923
2.2beta29
1.13++
5.5.kw
2.0b1pl0
In fact, there is no such thing as an invalid version number under
this scheme; the rules for comparison are simple and predictable,
but may not always give the results you want (for some definition
of "want").
"""
component_re = re.compile(r"(\d+ | [a-z]+ | \.)", re.VERBOSE)
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def parse(self, vstring):
# I've given up on thinking I can reconstruct the version string
# from the parsed tuple -- so I just store the string here for
# use by __str__
self.vstring = vstring
components = [x for x in self.component_re.split(vstring) if x and x != "."]
for i, obj in enumerate(components):
try:
components[i] = int(obj)
except ValueError:
pass
self.version = components
def __str__(self):
return self.vstring
def __repr__(self):
return "LooseVersion ('%s')" % str(self)
def _cmp(self, other):
if isinstance(other, str):
other = LooseVersion(other)
elif not isinstance(other, LooseVersion):
return NotImplemented
if self.version == other.version:
return 0
if self.version < other.version:
return -1
if self.version > other.version:
return 1
# end class LooseVersion

View file

@ -4,11 +4,10 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # 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 from __future__ import absolute_import, division, print_function
from ansible_collections.ansible.posix.plugins.module_utils.version import LooseVersion
__metaclass__ = type __metaclass__ = type
# Imports and info for sanity checking
from distutils.version import LooseVersion
FW_VERSION = None FW_VERSION = None
fw = None fw = None

View file

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
# Once we drop support for Ansible 2.9, ansible-base 2.10, and ansible-core 2.11, we can
# remove the _version.py file, and replace the following import by
#
# from ansible.module_utils.compat.version import LooseVersion
from ._version import LooseVersion, StrictVersion

View file

@ -128,8 +128,11 @@ notes:
The module will not take care of this for you implicitly because that would undo any previously performed immediate actions which were not The module will not take care of this for you implicitly because that would undo any previously performed immediate actions which were not
permanent. Therefore, if you require immediate access to a newly created zone it is recommended you reload firewalld immediately after the zone permanent. Therefore, if you require immediate access to a newly created zone it is recommended you reload firewalld immediately after the zone
creation returns with a changed state and before you perform any other immediate, non-permanent actions on that zone. creation returns with a changed state and before you perform any other immediate, non-permanent actions on that zone.
- This module needs C(python-firewall) or C(python3-firewall) on managed nodes.
It is usually provided as a subset with C(firewalld) from the OS distributor for the OS default Python interpreter.
requirements: requirements:
- firewalld >= 0.2.11 - firewalld >= 0.2.11
- python-firewall >= 0.2.11
author: author:
- Adam Miller (@maxamillion) - Adam Miller (@maxamillion)
''' '''
@ -757,6 +760,10 @@ def main():
target=('zone',), target=('zone',),
source=('permanent',), source=('permanent',),
), ),
mutually_exclusive=[
['icmp_block', 'icmp_block_inversion', 'service', 'port', 'port_forward', 'rich_rule',
'interface', 'masquerade', 'source', 'target']
],
) )
permanent = module.params['permanent'] permanent = module.params['permanent']
@ -813,33 +820,11 @@ def main():
if 'toaddr' in port_forward: if 'toaddr' in port_forward:
port_forward_toaddr = port_forward['toaddr'] port_forward_toaddr = port_forward['toaddr']
modification_count = 0 modification = False
if icmp_block is not None: if any([icmp_block, icmp_block_inversion, service, port, port_forward, rich_rule,
modification_count += 1 interface, masquerade, source, target]):
if icmp_block_inversion is not None: modification = True
modification_count += 1 if modification and desired_state in ['absent', 'present'] and target is None:
if service is not None:
modification_count += 1
if port is not None:
modification_count += 1
if port_forward is not None:
modification_count += 1
if rich_rule is not None:
modification_count += 1
if interface is not None:
modification_count += 1
if masquerade is not None:
modification_count += 1
if source is not None:
modification_count += 1
if target is not None:
modification_count += 1
if modification_count > 1:
module.fail_json(
msg='can only operate on port, service, rich_rule, masquerade, icmp_block, icmp_block_inversion, interface or source at once'
)
elif (modification_count > 0) and (desired_state in ['absent', 'present']) and (target is None):
module.fail_json( module.fail_json(
msg='absent and present state can only be used in zone level operations' msg='absent and present state can only be used in zone level operations'
) )
@ -1024,7 +1009,7 @@ def main():
msgs = msgs + transaction_msgs msgs = msgs + transaction_msgs
''' If there are no changes within the zone we are operating on the zone itself ''' ''' If there are no changes within the zone we are operating on the zone itself '''
if modification_count == 0 and desired_state in ['absent', 'present']: if not modification and desired_state in ['absent', 'present']:
transaction = ZoneTransaction( transaction = ZoneTransaction(
module, module,

View file

@ -204,8 +204,9 @@ 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.six import raise_from
from ansible.module_utils._text import to_native from ansible.module_utils._text import to_native
from distutils.version import StrictVersion from ansible_collections.ansible.posix.plugins.module_utils.version import StrictVersion
try: try:

View file

@ -172,7 +172,7 @@ EXAMPLES = r'''
ansible.posix.mount: ansible.posix.mount:
src: 192.168.1.100:/nfs/ssd/shared_data src: 192.168.1.100:/nfs/ssd/shared_data
path: /mnt/shared_data path: /mnt/shared_data
opts: rw,sync,hard,intr opts: rw,sync,hard
state: mounted state: mounted
fstype: nfs fstype: nfs
@ -180,7 +180,7 @@ EXAMPLES = r'''
ansible.posix.mount: ansible.posix.mount:
src: 192.168.1.100:/nfs/ssd/shared_data src: 192.168.1.100:/nfs/ssd/shared_data
path: /mnt/shared_data path: /mnt/shared_data
opts: rw,sync,hard,intr opts: rw,sync,hard
boot: no boot: no
state: mounted state: mounted
fstype: nfs fstype: nfs

View file

@ -40,6 +40,7 @@ notes:
requirements: requirements:
- libselinux-python - libselinux-python
- libsemanage-python - libsemanage-python
- python3-libsemanage
author: author:
- Stephen Fromm (@sfromm) - Stephen Fromm (@sfromm)
''' '''
@ -284,7 +285,7 @@ def main():
module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR) module.fail_json(msg=missing_required_lib('libselinux-python'), exception=SELINUX_IMP_ERR)
if not HAVE_SEMANAGE: if not HAVE_SEMANAGE:
module.fail_json(msg=missing_required_lib('libsemanage-python'), exception=SEMANAGE_IMP_ERR) module.fail_json(msg=missing_required_lib('libsemanage-python or python3-libsemanage'), exception=SEMANAGE_IMP_ERR)
ignore_selinux_state = module.params['ignore_selinux_state'] ignore_selinux_state = module.params['ignore_selinux_state']

View file

@ -586,8 +586,8 @@ def main():
if '@' not in dest: if '@' not in dest:
dest = os.path.expanduser(dest) dest = os.path.expanduser(dest)
cmd.append(source) cmd.append(shlex_quote(source))
cmd.append(dest) cmd.append(shlex_quote(dest))
cmdstr = ' '.join(cmd) cmdstr = ' '.join(cmd)
# If we are using password authentication, write the password into the pipe # If we are using password authentication, write the password into the pipe

View file

@ -15,7 +15,7 @@ matrix:
- env: T=2.9/freebsd/12.0/1 - env: T=2.9/freebsd/12.0/1
- env: T=2.9/linux/centos6/1 - env: T=2.9/linux/centos6/1
- env: T=2.9/linux/centos7/1 - env: T=2.9/linux/centos7/1
- env: T=2.9/linux/centos8/1 # - env: T=2.9/linux/centos8/1
- env: T=2.9/linux/fedora30/1 - env: T=2.9/linux/fedora30/1
- env: T=2.9/linux/fedora31/1 - env: T=2.9/linux/fedora31/1
- env: T=2.9/linux/opensuse15py2/1 - env: T=2.9/linux/opensuse15py2/1
@ -30,7 +30,7 @@ matrix:
- env: T=2.10/freebsd/12.1/1 - env: T=2.10/freebsd/12.1/1
- env: T=2.10/linux/centos6/1 - env: T=2.10/linux/centos6/1
- env: T=2.10/linux/centos7/1 - env: T=2.10/linux/centos7/1
- env: T=2.10/linux/centos8/1 # - env: T=2.10/linux/centos8/1
- env: T=2.10/linux/fedora30/1 - env: T=2.10/linux/fedora30/1
- env: T=2.10/linux/fedora31/1 - env: T=2.10/linux/fedora31/1
- env: T=2.10/linux/opensuse15py2/1 - env: T=2.10/linux/opensuse15py2/1
@ -45,7 +45,7 @@ matrix:
- env: T=devel/freebsd/12.1/1 - env: T=devel/freebsd/12.1/1
- env: T=devel/linux/centos6/1 - env: T=devel/linux/centos6/1
- env: T=devel/linux/centos7/1 - env: T=devel/linux/centos7/1
- env: T=devel/linux/centos8/1 # - env: T=devel/linux/centos8/1
- env: T=devel/linux/fedora30/1 - env: T=devel/linux/fedora30/1
- env: T=devel/linux/fedora31/1 - env: T=devel/linux/fedora31/1
- env: T=devel/linux/opensuse15py2/1 - env: T=devel/linux/opensuse15py2/1

View file

@ -23,6 +23,16 @@
group: group:
name: "{{ test_group }}" name: "{{ test_group }}"
- name: Clean up working directory and files
file:
path: "{{ output_dir }}"
state: absent
- name: Create working directory
file:
path: "{{ output_dir }}"
state: directory
- name: Create ansible file - name: Create ansible file
file: file:
path: "{{ test_file }}" path: "{{ test_file }}"

View file

@ -82,4 +82,4 @@
assert: assert:
that: that:
- result is not changed - result is not changed
- "result.msg == 'can only operate on port, service, rich_rule, masquerade, icmp_block, icmp_block_inversion, interface or source at once'" - "result.msg == 'parameters are mutually exclusive: icmp_block|icmp_block_inversion|service|port|port_forward|rich_rule|interface|masquerade|source|target'"

View file

@ -26,10 +26,19 @@
state: present state: present
- name: TEST 1 | Get current SELinux config file contents - name: TEST 1 | Get current SELinux config file contents
slurp:
src: /etc/sysconfig/selinux
register: selinux_config_original_base64
- name: TEST 1 | Register SELinux config and SELinux status
set_fact: set_fact:
selinux_config_original: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}" selinux_config_original_raw: "{{ selinux_config_original_base64.content | b64decode }}"
before_test_sestatus: "{{ ansible_selinux }}" before_test_sestatus: "{{ ansible_selinux }}"
- name: TEST 1 | Split by line and register original config
set_fact:
selinux_config_original: "{{ selinux_config_original_raw.split('\n') }}"
- debug: - debug:
var: "{{ item }}" var: "{{ item }}"
verbosity: 1 verbosity: 1
@ -95,8 +104,17 @@
- _disable_test2.reboot_required - _disable_test2.reboot_required
- name: TEST 1 | Get modified config file - name: TEST 1 | Get modified config file
slurp:
src: /etc/sysconfig/selinux
register: selinux_config_after_base64
- name: TEST 1 | Register modified config
set_fact: set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}" selinux_config_after_raw: "{{ selinux_config_after_base64.content | b64decode }}"
- name: TEST 1 | Split by line and register modified config
set_fact:
selinux_config_after: "{{ selinux_config_after_raw.split('\n') }}"
- debug: - debug:
var: selinux_config_after var: selinux_config_after
@ -209,8 +227,17 @@
- not _state_test2.reboot_required - not _state_test2.reboot_required
- name: TEST 2 | Get modified config file - name: TEST 2 | Get modified config file
slurp:
src: /etc/sysconfig/selinux
register: selinux_config_after_base64
- name: TEST 2 | Register modified config
set_fact: set_fact:
selinux_config_after: "{{ lookup('file', '/etc/sysconfig/selinux').split('\n') }}" selinux_config_after_raw: "{{ selinux_config_after_base64.content | b64decode }}"
- name: TEST 2 | Split by line and register modified config
set_fact:
selinux_config_after: "{{ selinux_config_after_raw.split('\n') }}"
- debug: - debug:
var: selinux_config_after var: selinux_config_after

View file

@ -2,16 +2,29 @@
package: package:
name: rsync name: rsync
when: ansible_distribution != "MacOSX" when: ansible_distribution != "MacOSX"
- name: cleanup old files - name: Clean up the working directory and files
shell: rm -rf {{output_dir}}/* file:
path: '{{ output_dir }}'
state: absent
- name: Create the working directory
file:
path: '{{ output_dir }}'
state: directory
- name: create test new files - name: create test new files
copy: dest={{output_dir}}/{{item}} mode=0644 content="hello world" copy:
dest: '{{output_dir}}/{{item}}'
mode: '0644'
content: 'hello world'
with_items: with_items:
- foo.txt - foo.txt
- bar.txt - bar.txt
- name: synchronize file to new filename - name: synchronize file to new filename
synchronize: src={{output_dir}}/foo.txt dest={{output_dir}}/foo.result synchronize:
src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.result'
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- '''changed'' in sync_result' - '''changed'' in sync_result'
@ -31,9 +44,13 @@
that: that:
- stat_result.stat.exists == True - stat_result.stat.exists == True
- stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' - stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
- name: test that the file is not copied a second time - name: test that the file is not copied a second time
synchronize: src={{output_dir}}/foo.txt dest={{output_dir}}/foo.result synchronize:
src='{{output_dir}}/foo.txt'
dest='{{output_dir}}/foo.result'
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- sync_result.changed == False - sync_result.changed == False
@ -44,12 +61,14 @@
with_items: with_items:
- foo.result - foo.result
- bar.result - bar.result
- name: Synchronize using the mode=push param - name: Synchronize using the mode=push param
synchronize: synchronize:
src: '{{output_dir}}/foo.txt' src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.result' dest: '{{output_dir}}/foo.result'
mode: push mode: push
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- '''changed'' in sync_result' - '''changed'' in sync_result'
@ -69,12 +88,14 @@
that: that:
- stat_result.stat.exists == True - stat_result.stat.exists == True
- stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' - stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
- name: test that the file is not copied a second time - name: test that the file is not copied a second time
synchronize: synchronize:
src: '{{output_dir}}/foo.txt' src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.result' dest: '{{output_dir}}/foo.result'
mode: push mode: push
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- sync_result.changed == False - sync_result.changed == False
@ -85,12 +106,14 @@
with_items: with_items:
- foo.result - foo.result
- bar.result - bar.result
- name: Synchronize using the mode=pull param - name: Synchronize using the mode=pull param
synchronize: synchronize:
src: '{{output_dir}}/foo.txt' src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.result' dest: '{{output_dir}}/foo.result'
mode: pull mode: pull
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- '''changed'' in sync_result' - '''changed'' in sync_result'
@ -110,12 +133,14 @@
that: that:
- stat_result.stat.exists == True - stat_result.stat.exists == True
- stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' - stat_result.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
- name: test that the file is not copied a second time - name: test that the file is not copied a second time
synchronize: synchronize:
src: '{{output_dir}}/foo.txt' src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.result' dest: '{{output_dir}}/foo.result'
mode: pull mode: pull
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- sync_result.changed == False - sync_result.changed == False
@ -126,12 +151,16 @@
with_items: with_items:
- foo.result - foo.result
- bar.result - bar.result
- name: synchronize files using with_items (issue#5965) - name: synchronize files using with_items (issue#5965)
synchronize: src={{output_dir}}/{{item}} dest={{output_dir}}/{{item}}.result synchronize:
src: '{{output_dir}}/{{item}}'
dest: '{{output_dir}}/{{item}}.result'
with_items: with_items:
- foo.txt - foo.txt
- bar.txt - bar.txt
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- sync_result.changed - sync_result.changed
@ -151,9 +180,14 @@
with_items: with_items:
- foo.txt - foo.txt
- bar.txt - bar.txt
- name: synchronize files using rsync_path (issue#7182) - name: synchronize files using rsync_path (issue#7182)
synchronize: src={{output_dir}}/foo.txt dest={{output_dir}}/foo.rsync_path rsync_path="sudo rsync" synchronize:
src: '{{output_dir}}/foo.txt'
dest: '{{output_dir}}/foo.rsync_path'
rsync_path: 'sudo rsync'
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- '''changed'' in sync_result' - '''changed'' in sync_result'
@ -186,6 +220,7 @@
dest: '{{output_dir}}/{{item}}/foo.txt' dest: '{{output_dir}}/{{item}}/foo.txt'
with_items: with_items:
- directory_a - directory_a
delegate_to: '{{ inventory_hostname }}'
- name: synchronize files using link_dest - name: synchronize files using link_dest
synchronize: synchronize:
src: '{{output_dir}}/directory_a/foo.txt' src: '{{output_dir}}/directory_a/foo.txt'
@ -193,6 +228,7 @@
link_dest: link_dest:
- '{{output_dir}}/directory_a' - '{{output_dir}}/directory_a'
register: sync_result register: sync_result
delegate_to: '{{ inventory_hostname }}'
- name: get stat information for directory_a - name: get stat information for directory_a
stat: stat:
path: '{{ output_dir }}/directory_a/foo.txt' path: '{{ output_dir }}/directory_a/foo.txt'
@ -214,6 +250,8 @@
- '{{output_dir}}' - '{{output_dir}}'
register: sync_result register: sync_result
ignore_errors: true ignore_errors: true
delegate_to: '{{ inventory_hostname }}'
- assert: - assert:
that: that:
- sync_result is not changed - sync_result is not changed
@ -227,3 +265,46 @@
- directory_a/foo.txt - directory_a/foo.txt
- directory_a - directory_a
- directory_b - directory_b
- name: setup - test for source with working dir with spaces in path
file:
state: directory
path: '{{output_dir}}/{{item}}'
delegate_to: '{{ inventory_hostname }}'
with_items:
- 'directory a'
- 'directory b'
- name: setup - create test new files
copy:
dest: '{{output_dir}}/directory a/{{item}}'
mode: '0644'
content: 'hello world'
with_items:
- foo.txt
delegate_to: '{{ inventory_hostname }}'
- name: copy source with spaces in dir path
synchronize:
src: '{{output_dir}}/directory a/foo.txt'
dest: '{{output_dir}}/directory b/'
delegate_to: '{{ inventory_hostname }}'
register: sync_result
ignore_errors: true
- name: get stat information for directory_b
stat:
path: '{{ output_dir }}/directory b/foo.txt'
register: stat_result_b
- assert:
that:
- '''changed'' in sync_result'
- sync_result.changed == true
- stat_result_b.stat.exists == True
- stat_result_b.stat.checksum == '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
- name: Cleanup
file:
state: absent
path: '{{output_dir}}/{{item}}'
with_items:
- 'directory b/foo.txt'
- 'directory a/foo.txt'
- 'directory a'
- 'directory b'

View file

@ -123,10 +123,10 @@
that: that:
- sysctl_test2_change_test is not changed - sysctl_test2_change_test is not changed
- name: Try sysctl with an invalid value - name: Try sysctl with an invalid name
sysctl: sysctl:
name: net.ipv4.ip_forward name: test.invalid
value: foo value: 1
register: sysctl_test3 register: sysctl_test3
ignore_errors: yes ignore_errors: yes
@ -196,10 +196,10 @@
- sysctl_no_value is failed - sysctl_no_value is failed
- "sysctl_no_value.msg == 'value cannot be None'" - "sysctl_no_value.msg == 'value cannot be None'"
- name: Try sysctl with an invalid value - name: Try sysctl with an invalid name
sysctl: sysctl:
name: net.ipv4.ip_forward name: test.invalid
value: foo value: 1
sysctl_set: yes sysctl_set: yes
register: sysctl_test4 register: sysctl_test4
ignore_errors: yes ignore_errors: yes

View file

@ -0,0 +1,8 @@
plugins/modules/synchronize.py pylint:disallowed-name
plugins/modules/synchronize.py use-argspec-type-path
plugins/modules/synchronize.py validate-modules:doc-default-does-not-match-spec
plugins/modules/synchronize.py validate-modules:nonexistent-parameter-documented
plugins/modules/synchronize.py validate-modules:parameter-type-not-in-doc
plugins/modules/synchronize.py validate-modules:undocumented-parameter
tests/utils/shippable/check_matrix.py replace-urlopen
tests/utils/shippable/timing.py shebang

View file

@ -125,7 +125,7 @@ class SynchronizeTester(object):
metapath = os.path.join(fixturepath, 'meta.yaml') metapath = os.path.join(fixturepath, 'meta.yaml')
with open(metapath, 'rb') as f: with open(metapath, 'rb') as f:
fdata = f.read() fdata = f.read()
test_meta = yaml.load(fdata) test_meta = yaml.safe_load(fdata)
# load initial play context vars # load initial play context vars
if '_play_context' in test_meta: if '_play_context' in test_meta:

View file

@ -50,7 +50,7 @@ function retry
echo "@* -> ${result}" echo "@* -> ${result}"
done done
echo "Command '@*' failed 3 times!" echo "Command '@*' failed 3 times!"
exit -1 exit 255
} }
command -v pip command -v pip