Compare commits

..

41 Commits
1.3.1 ... 1.3.4

Author SHA1 Message Date
Felix Fontein
8a9d18cc86 Release 1.3.4. 2021-01-14 16:07:29 +01:00
Felix Fontein
b7b69d918a Add release summary. 2021-01-14 16:06:02 +01:00
patchback[bot]
a3f08377b2 bitbucket_pipeline_variable: Hide secured values in console log (#1635) (#1637)
**SECURITY** - CVE-2021-20180

Hide user sensitive information which is marked as ``secured``
while logging in console.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 1d0c5e2ba4)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-14 16:04:27 +01:00
patchback[bot]
4c9c8e0514 npm - handle json decode exception (#1625) (#1636)
* Provide a user friendly message by handling json decode
  exception rather than providing a stacktrace

Fixes: #1614

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit a9c64655de)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-14 14:40:33 +01:00
Felix Fontein
3911b83145 Next release will be 1.3.4. 2021-01-13 13:19:40 +01:00
Felix Fontein
20e1d7c08b Release 1.3.3. 2021-01-13 12:31:11 +01:00
Felix Fontein
24aa8afde8 Add release summary. 2021-01-13 12:28:33 +01:00
patchback[bot]
71c6ec0b00 init_reconfigure fails on module cloud/misc/terraform.py (#1620) (#1629)
* fix reconfigure option

If `init_reconfigure` is true, the init fails because it is run as:
`terraform init -input=false - r e c o n f i g u r e`

* changelog fragment

* typo

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 9f4fd4c899)

Co-authored-by: christophemorio <49184206+christophemorio@users.noreply.github.com>
2021-01-13 11:12:50 +01:00
patchback[bot]
469e32e15b Remove bigmstone (#1626) (#1627)
Removing bigmstone from BOTMETA.

(cherry picked from commit 19fdb29db7)

Co-authored-by: Matthew Stone <dev@mattstone.io>
2021-01-12 17:52:50 +01:00
patchback[bot]
ebfb46aa78 Updated doc. Module not idempotent. delegate_to not needed. (#1587) (#1622)
(cherry picked from commit 63817f7c1b)

Co-authored-by: Vladimir Botka <vbotka@gmail.com>
2021-01-12 12:08:17 +01:00
patchback[bot]
fa2d2d6971 snmp_facts: Hide user sensitive information in console (#1621) (#1623)
**SECURITY** - CVE-2021-20178

Hide user sensitive information like `privkey` and `authkey`
while logging in console.

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 3560aeb12f)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-12 12:08:03 +01:00
patchback[bot]
a1429d0266 Skip monit tests on RHEL. (#1615) (#1617)
(cherry picked from commit 637571993a)

Co-authored-by: Felix Fontein <felix@fontein.de>
2021-01-12 07:09:04 +01:00
Felix Fontein
3077ac770f chroot: re-enable connection chroot tests (#1591) (#1602)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit e7b16a96b9)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-07 12:20:28 +01:00
patchback[bot]
7813cd751a hg: Re-enable tests (#1599) (#1600)
* Update license boilerplate
* Change mercurial repository links

Fixes: #840

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 126c397d6c)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-07 07:44:20 +01:00
Felix Fontein
4461c18957 Add kubevirt removal announcement. (#1594) 2021-01-05 18:41:02 -05:00
Felix Fontein
34cf93a538 Next release will be 1.3.3. 2021-01-04 18:26:38 +01:00
Felix Fontein
b56539f17e Release 1.3.2. 2021-01-04 18:26:01 +01:00
Felix Fontein
167d4bae90 Add release summary. 2021-01-04 13:36:21 +01:00
Felix Fontein
de85c11bd1 [stable-1] Add OC, hashi_vault and Google removal announcements (#1560)
* Add removal announcements.

* Remove Latin abbrevation.

* Add hashi_vault removal announcement.
2021-01-04 11:06:49 +01:00
patchback[bot]
d0731b111c Re-enable nomad tests (#1582) (#1586)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit d12951b9c7)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-04 09:18:37 +01:00
patchback[bot]
7cd96ef3b6 changed make parameter from --question to -q (#1574) (#1581)
* changed make parameter from --question to -q

* changelog fragment

* Update changelogs/fragments/1574-make-question.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 0bd4b3cbc9)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-01-03 13:55:58 +01:00
patchback[bot]
b7a44a593e fix passwordstore.py to be compatible with gopass versions (#1493) (#1580)
* Be compatible to latest gopass versions.
`gopass show` is deprecated.

* add changelog fragment

* Update changelogs/fragments/1493-fix_passwordstore.py_to_be_compatible_with_gopass_versions.yml

Co-authored-by: Eike Waldt <git@yog.wtf>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 491b622041)

Co-authored-by: Eike Waldt <git@yeoldegrove.de>
2021-01-03 11:48:37 +00:00
patchback[bot]
c413963ecb pamd - fixed bug (#1538) (#1579)
* Fixed bug

- The module was searching back (and forward, in the ``after`` state) for lines that were not comments, assuming it would be a valid rule or an include.

* remove the line, make yamllint happy

* Update changelogs/fragments/1394-pamd-removing-comments.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 325a19d88a)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2021-01-03 11:48:07 +00:00
patchback[bot]
4f7d44aa10 monit: add support for all monit services when checking process state (#1532) (#1578)
* add support for all monit service types

* ignore case when performing check

* add changelog

* Escape special characters before matching

Co-authored-by: Felix Fontein <felix@fontein.de>

* escape each element individually

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit bed1dc479f)

Co-authored-by: Graham Herceg <g.a.herceg@gmail.com>
2021-01-03 11:47:54 +00:00
patchback[bot]
56055d4f1e Remove bridge-slave from list of IP based connections (#1517) (#1577)
* Removed the bridge-slave from list of ip based connections since nmcli does not accept IP options for bridge-slave connections.

* Update changelogs/fragments/1517-bridge-slave-from-list-of-ip-based-connections.yml

Thanks for the tip.

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit fd741ed663)

Co-authored-by: momcilo78 <momcilo@majic.rs>
2021-01-03 12:43:56 +01:00
patchback[bot]
3fa4a9c073 Legacy Python certificate validation fixed (#470) (#1576)
* Legacy Python certificate validation fixed

* added changelog fragment

* removed blank line for sanity checks

* Update changelogs/fragments/470-spacewalk-legacy-python-certificate-validation.yaml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

* Update changelogs/fragments/470-spacewalk-legacy-python-certificate-validation.yaml

Co-authored-by: jpe <petz.johannes@afb.de>
Co-authored-by: Felix Fontein <felix@fontein.de>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit df9f0741b5)

Co-authored-by: Johannes Petz <PetzJohannes@users.noreply.github.com>
2021-01-03 11:37:40 +01:00
patchback[bot]
1552bae77b syslogger - update syslog.openlog API call for older Python (#1572) (#1573)
* syslogger - update syslog.openlog API call for older Python

Fixes: #953

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>

* Update changelogs/fragments/953_syslogger.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit ce83bde742)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-02 21:05:43 +01:00
patchback[bot]
a9cad80a36 lxc_container: update docs (#1544) (#1570)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit eacbf45632)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-01 17:37:11 +01:00
patchback[bot]
fc79283662 snmp_facts: doc update (#1569) (#1571)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit ba50d114d4)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-01 17:36:50 +01:00
patchback[bot]
0d8ea31781 Scaleway: Update documentation (#1567) (#1568)
Online SAS is rebranded as Scaleway in 2015. Updated
inventory documentation for the same.

Fixes: #814

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 7b529c72b3)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-01-01 13:44:09 +01:00
patchback[bot]
7ac14f964b updated deprecated homebrew cask commands (#1481) (#1565)
* updated deprecated homebrew cask commands

* added methods for brew version deprecation check

* added comments and changelog fragment

* added unit test for version comparison

* switch to use disutils LooseVersion for version comparison

* updated changelog message and minor refactor for building brew command based on version

* added caching logic for retrieval of brew version and updated PR changelog yaml

* Update changelogs/fragments/1481-deprecated-brew-cask-command.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/packaging/os/homebrew_cask.py

* Update plugins/modules/packaging/os/homebrew_cask.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* Update plugins/modules/packaging/os/homebrew_cask.py

Co-authored-by: Felix Fontein <felix@fontein.de>

* switch to use subprocess.check_output instead of subprocess.run

* replace subprocess with run_command

* removed unused subprocess import

* removed error handling logic to depend on check_rc=True instead

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit ed813176ce)

Co-authored-by: Jianhao Tan <jianhao@shopback.com>
2020-12-31 23:07:39 +00:00
patchback[bot]
95d725a3cc launchd: Handle deprecated APIs in plistlib (#1554) (#1563)
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 6c88b69d6f)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2020-12-30 09:00:33 +01:00
patchback[bot]
95de8bd39d sendgrid: Update docs (#1557) (#1558)
* Updated docs
* Warn user about required Sendgrid Python library version i.e <=1.6.22

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
(cherry picked from commit 818cafc580)

Co-authored-by: Abhijeet Kasurde <akasurde@redhat.com>
2020-12-29 10:25:40 +01:00
Felix Fontein
ecbdaca971 Backport of 5eef093e99 (#1548) 2020-12-27 15:50:21 +01:00
patchback[bot]
54754f7e81 Add hnakamur to ignore list for LXD modules (see #1543). (#1545) (#1546)
(cherry picked from commit 09e2699d1c)

Co-authored-by: Felix Fontein <felix@fontein.de>
2020-12-27 14:47:40 +01:00
patchback[bot]
bd15741647 jira - some improvements to the module (#1536) (#1547)
* Some improvements to the module

- Fixed examples documentation ().
- Module no longer incorrectly reports change for information gathering operations ().
- Replaced custom parameter validation with ``required_if`` ().
- Added the traceback output to ``fail_json()`` calls deriving from exceptions ().

* added PR URL to changelof frag

* Update changelogs/fragments/jira_improvements.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>

* mentioned issue required for transition in chnagelog

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 5016f402a5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2020-12-27 13:47:33 +00:00
Felix Fontein
fa05ca3f63 Backport of 117f132213 (#1542) 2020-12-26 18:30:07 +00:00
patchback[bot]
29992f1fbf nios_member: fix nios api member_normalize error with python 3 (#1527) (#1534)
* nios_member: fix nios api member_normalize error with python 3

Force a copy of the key to allow change during iteration.

* Update - add changelog fragment

* Update - add changelog fragment

* Update changelogs/fragments/1527-fix-nios-api-member-normalize.yaml

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit c63f3f9956)

Co-authored-by: neatherweb <35084494+neatherweb@users.noreply.github.com>
2020-12-23 08:49:29 +01:00
patchback[bot]
34ab07865f Ensured `changed returns False`. (#1530) (#1531)
* Ensured ``changed`` returns ``False``.

- Added small improvement on the ``_load_scope()`` method.

* yamllint caught it

* Rephrased changelog fragment

(cherry picked from commit 1faf8ef08b)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2020-12-22 16:15:50 +01:00
patchback[bot]
5fa1fc65ca YAML callback: do not remove non-ASCII Unicode from multi-line string output (#1522) (#1529)
* Do not remove non-ASCII Unicode from multi-line string output.

* Added basic tests.

* Add Unicode test.

* Simplify tests, avoid later Jinja features.

* Refactor.

* Make use diy tests use callback test framework as well.

* Remove color codes.

* Work around stable-2.9 bug.

* Simplify again.

(cherry picked from commit 0a7ed3b019)

Co-authored-by: Felix Fontein <felix@fontein.de>
2020-12-22 09:59:57 +00:00
Felix Fontein
c0bb56c454 Next release will be 1.3.2. 2020-12-21 14:57:57 +01:00
44 changed files with 1182 additions and 539 deletions

4
.github/BOTMETA.yml vendored
View File

@@ -259,7 +259,7 @@ files:
$modules/cloud/lxc/lxc_container.py:
maintainers: cloudnull
$modules/cloud/lxd/:
maintainers: hnakamur
ignore: hnakamur
$modules/cloud/memset/:
maintainers: glitchcrab
$modules/cloud/misc/cloud_init_data_facts.py:
@@ -576,7 +576,7 @@ files:
$modules/net_tools/nmcli.py:
maintainers: alcamie101
$modules/net_tools/snmp_facts.py:
maintainers: ogenstad bigmstone ujwalkomarla
maintainers: ogenstad ujwalkomarla
$modules/notification/osx_say.py:
maintainers: ansible mpdehaan
labels: _osx_say

View File

@@ -5,6 +5,117 @@ Community General Release Notes
.. contents:: Topics
v1.3.4
======
Release Summary
---------------
Bugfix/security release that addresses CVE-2021-20180.
Security Fixes
--------------
- bitbucket_pipeline_variable - **CVE-2021-20180** - hide user sensitive information which are marked as ``secured`` from logging into the console (https://github.com/ansible-collections/community.general/pull/1635).
Bugfixes
--------
- npm - handle json decode exception while parsing command line output (https://github.com/ansible-collections/community.general/issues/1614).
v1.3.3
======
Release Summary
---------------
Bugfix/security release that addresses CVE-2021-20178.
Major Changes
-------------
- For community.general 2.0.0, the kubevirt modules will be moved to the `community.kubevirt <https://galaxy.ansible.com/community/kubevirt>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer do not have to change anything.
If you use Ansible 2.9 and explicitly use kubevirt modules from this collection, you will need to adjust your playbooks and roles to use FQCNs starting with ``community.kubevirt.`` instead of ``community.general.``,
for example replace ``community.general.kubevirt_vm`` in a task by ``community.kubevirt.kubevirt_vm``.
If you use ansible-base and installed ``community.general`` manually and rely on the kubevirt modules, you have to make sure to install the ``community.kubevirt`` collection as well.
If you are using FQCNs, for example ``community.general.kubevirt_vm`` instead of ``kubevirt_vm``, it will continue working, but we still recommend to adjust the FQCNs as well.
Security Fixes
--------------
- snmp_facts - **CVE-2021-20178** - hide user sensitive information such as ``privkey`` and ``authkey`` from logging into the console (https://github.com/ansible-collections/community.general/pull/1621).
Bugfixes
--------
- terraform - fix ``init_reconfigure`` option for proper CLI args (https://github.com/ansible-collections/community.general/pull/1620).
v1.3.2
======
Release Summary
---------------
Regular bugfix release.
Major Changes
-------------
- For community.general 2.0.0, the Google modules will be moved to the `community.google <https://galaxy.ansible.com/community/google>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer do not have to change anything.
If you use Ansible 2.9 and explicitly use Google modules from this collection, you will need to adjust your playbooks and roles to use FQCNs starting with ``community.google.`` instead of ``community.general.``,
for example replace ``community.general.gcpubsub`` in a task by ``community.google.gcpubsub``.
If you use ansible-base and installed ``community.general`` manually and rely on the Google modules, you have to make sure to install the ``community.google`` collection as well.
If you are using FQCNs, for example ``community.general.gcpubsub`` instead of ``gcpubsub``, it will continue working, but we still recommend to adjust the FQCNs as well.
- For community.general 2.0.0, the OC connection plugin will be moved to the `community.okd <https://galaxy.ansible.com/community/okd>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer do not have to change anything.
If you use Ansible 2.9 and explicitly use OC connection plugin from this collection, you will need to adjust your playbooks and roles to use FQCNs ``community.okd.oc`` instead of ``community.general.oc``.
If you use ansible-base and installed ``community.general`` manually and rely on the OC connection plugin, you have to make sure to install the ``community.okd`` collection as well.
If you are using FQCNs, in other words ``community.general.oc`` instead of ``oc``, it will continue working, but we still recommend to adjust this FQCN as well.
- For community.general 2.0.0, the hashi_vault lookup plugin will be moved to the `community.hashi_vault <https://galaxy.ansible.com/community/hashi_vault>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer do not have to change anything.
If you use Ansible 2.9 and explicitly use hashi_vault lookup plugin from this collection, you will need to adjust your playbooks and roles to use FQCNs ``community.hashi_vault.hashi_vault`` instead of ``community.general.hashi_vault``.
If you use ansible-base and installed ``community.general`` manually and rely on the hashi_vault lookup plugin, you have to make sure to install the ``community.hashi_vault`` collection as well.
If you are using FQCNs, in other words ``community.general.hashi_vault`` instead of ``hashi_vault``, it will continue working, but we still recommend to adjust this FQCN as well.
Minor Changes
-------------
- homebrew_cask - Homebrew will be deprecating use of ``brew cask`` commands as of version 2.6.0, see https://brew.sh/2020/12/01/homebrew-2.6.0/. Added logic to stop using ``brew cask`` for brew version >= 2.6.0 (https://github.com/ansible-collections/community.general/pull/1481).
- jira - added the traceback output to ``fail_json()`` calls deriving from exceptions (https://github.com/ansible-collections/community.general/pull/1536).
Bugfixes
--------
- docker_image - if ``push=true`` is used with ``repository``, and the image does not need to be tagged, still push. This can happen if ``repository`` and ``name`` are equal (https://github.com/ansible-collections/community.docker/issues/52, https://github.com/ansible-collections/community.docker/pull/53).
- docker_image - report error when loading a broken archive that contains no image (https://github.com/ansible-collections/community.docker/issues/46, https://github.com/ansible-collections/community.docker/pull/55).
- docker_image - report error when the loaded archive does not contain the specified image (https://github.com/ansible-collections/community.docker/issues/41, https://github.com/ansible-collections/community.docker/pull/55).
- jira - ``fetch`` and ``search`` no longer indicate that something changed (https://github.com/ansible-collections/community.general/pull/1536).
- jira - ensured parameter ``issue`` is mandatory for operation ``transition`` (https://github.com/ansible-collections/community.general/pull/1536).
- jira - module no longer incorrectly reports change for information gathering operations (https://github.com/ansible-collections/community.general/pull/1536).
- jira - replaced custom parameter validation with ``required_if`` (https://github.com/ansible-collections/community.general/pull/1536).
- launchd - handle deprecated APIs like ``readPlist`` and ``writePlist`` in ``plistlib`` (https://github.com/ansible-collections/community.general/issues/1552).
- ldap_search - the module no longer incorrectly reports a change (https://github.com/ansible-collections/community.general/issues/1040).
- make - fixed ``make`` parameter used for check mode when running a non-GNU ``make`` (https://github.com/ansible-collections/community.general/pull/1574).
- monit - add support for all monit service checks (https://github.com/ansible-collections/community.general/pull/1532).
- nios_member - fix Python 3 compatibility with nios api ``member_normalize`` function (https://github.com/ansible-collections/community.general/issues/1526).
- nmcli - remove ``bridge-slave`` from list of IP based connections ((https://github.com/ansible-collections/community.general/issues/1500).
- pamd - added logic to retain the comment line (https://github.com/ansible-collections/community.general/issues/1394).
- passwordstore lookup plugin - always use explicit ``show`` command to retrieve password. This ensures compatibility with ``gopass`` and avoids problems when password names equal ``pass`` commands (https://github.com/ansible-collections/community.general/pull/1493).
- rhn_channel - Python 2.7.5 fails if the certificate should not be validated. Fixed this by creating the correct ``ssl_context`` (https://github.com/ansible-collections/community.general/pull/470).
- sendgrid - update documentation and warn user about sendgrid Python library version (https://github.com/ansible-collections/community.general/issues/1553).
- syslogger - update ``syslog.openlog`` API call for older Python versions, and improve error handling (https://github.com/ansible-collections/community.general/issues/953).
- yaml callback plugin - do not remove non-ASCII Unicode characters from multiline string output (https://github.com/ansible-collections/community.general/issues/1519).
v1.3.1
======

View File

@@ -1627,3 +1627,191 @@ releases:
- fix_parsing_array_values_in_osx_defaults.yml
- nios_host_record-fix-aliases-removal.yml
release_date: '2020-12-21'
1.3.2:
changes:
bugfixes:
- docker_image - if ``push=true`` is used with ``repository``, and the image
does not need to be tagged, still push. This can happen if ``repository``
and ``name`` are equal (https://github.com/ansible-collections/community.docker/issues/52,
https://github.com/ansible-collections/community.docker/pull/53).
- docker_image - report error when loading a broken archive that contains no
image (https://github.com/ansible-collections/community.docker/issues/46,
https://github.com/ansible-collections/community.docker/pull/55).
- docker_image - report error when the loaded archive does not contain the specified
image (https://github.com/ansible-collections/community.docker/issues/41,
https://github.com/ansible-collections/community.docker/pull/55).
- jira - ``fetch`` and ``search`` no longer indicate that something changed
(https://github.com/ansible-collections/community.general/pull/1536).
- jira - ensured parameter ``issue`` is mandatory for operation ``transition``
(https://github.com/ansible-collections/community.general/pull/1536).
- jira - module no longer incorrectly reports change for information gathering
operations (https://github.com/ansible-collections/community.general/pull/1536).
- jira - replaced custom parameter validation with ``required_if`` (https://github.com/ansible-collections/community.general/pull/1536).
- launchd - handle deprecated APIs like ``readPlist`` and ``writePlist`` in
``plistlib`` (https://github.com/ansible-collections/community.general/issues/1552).
- ldap_search - the module no longer incorrectly reports a change (https://github.com/ansible-collections/community.general/issues/1040).
- make - fixed ``make`` parameter used for check mode when running a non-GNU
``make`` (https://github.com/ansible-collections/community.general/pull/1574).
- monit - add support for all monit service checks (https://github.com/ansible-collections/community.general/pull/1532).
- nios_member - fix Python 3 compatibility with nios api ``member_normalize``
function (https://github.com/ansible-collections/community.general/issues/1526).
- nmcli - remove ``bridge-slave`` from list of IP based connections ((https://github.com/ansible-collections/community.general/issues/1500).
- pamd - added logic to retain the comment line (https://github.com/ansible-collections/community.general/issues/1394).
- passwordstore lookup plugin - always use explicit ``show`` command to retrieve
password. This ensures compatibility with ``gopass`` and avoids problems when
password names equal ``pass`` commands (https://github.com/ansible-collections/community.general/pull/1493).
- rhn_channel - Python 2.7.5 fails if the certificate should not be validated.
Fixed this by creating the correct ``ssl_context`` (https://github.com/ansible-collections/community.general/pull/470).
- sendgrid - update documentation and warn user about sendgrid Python library
version (https://github.com/ansible-collections/community.general/issues/1553).
- syslogger - update ``syslog.openlog`` API call for older Python versions,
and improve error handling (https://github.com/ansible-collections/community.general/issues/953).
- yaml callback plugin - do not remove non-ASCII Unicode characters from multiline
string output (https://github.com/ansible-collections/community.general/issues/1519).
major_changes:
- 'For community.general 2.0.0, the Google modules will be moved to the `community.google
<https://galaxy.ansible.com/community/google>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer
do not have to change anything.
If you use Ansible 2.9 and explicitly use Google modules from this collection,
you will need to adjust your playbooks and roles to use FQCNs starting with
``community.google.`` instead of ``community.general.``,
for example replace ``community.general.gcpubsub`` in a task by ``community.google.gcpubsub``.
If you use ansible-base and installed ``community.general`` manually and rely
on the Google modules, you have to make sure to install the ``community.google``
collection as well.
If you are using FQCNs, for example ``community.general.gcpubsub`` instead
of ``gcpubsub``, it will continue working, but we still recommend to adjust
the FQCNs as well.
'
- 'For community.general 2.0.0, the OC connection plugin will be moved to the
`community.okd <https://galaxy.ansible.com/community/okd>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer
do not have to change anything.
If you use Ansible 2.9 and explicitly use OC connection plugin from this collection,
you will need to adjust your playbooks and roles to use FQCNs ``community.okd.oc``
instead of ``community.general.oc``.
If you use ansible-base and installed ``community.general`` manually and rely
on the OC connection plugin, you have to make sure to install the ``community.okd``
collection as well.
If you are using FQCNs, in other words ``community.general.oc`` instead of
``oc``, it will continue working, but we still recommend to adjust this FQCN
as well.
'
- 'For community.general 2.0.0, the hashi_vault lookup plugin will be moved
to the `community.hashi_vault <https://galaxy.ansible.com/community/hashi_vault>`_
collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer
do not have to change anything.
If you use Ansible 2.9 and explicitly use hashi_vault lookup plugin from this
collection, you will need to adjust your playbooks and roles to use FQCNs
``community.hashi_vault.hashi_vault`` instead of ``community.general.hashi_vault``.
If you use ansible-base and installed ``community.general`` manually and rely
on the hashi_vault lookup plugin, you have to make sure to install the ``community.hashi_vault``
collection as well.
If you are using FQCNs, in other words ``community.general.hashi_vault`` instead
of ``hashi_vault``, it will continue working, but we still recommend to adjust
this FQCN as well.
'
minor_changes:
- homebrew_cask - Homebrew will be deprecating use of ``brew cask`` commands
as of version 2.6.0, see https://brew.sh/2020/12/01/homebrew-2.6.0/. Added
logic to stop using ``brew cask`` for brew version >= 2.6.0 (https://github.com/ansible-collections/community.general/pull/1481).
- jira - added the traceback output to ``fail_json()`` calls deriving from exceptions
(https://github.com/ansible-collections/community.general/pull/1536).
release_summary: Regular bugfix release.
fragments:
- 1.3.2.yml
- 1040-ldap_search-changed-must-be-false.yaml
- 1394-pamd-removing-comments.yaml
- 1481-deprecated-brew-cask-command.yaml
- 1493-fix_passwordstore.py_to_be_compatible_with_gopass_versions.yml
- 1517-bridge-slave-from-list-of-ip-based-connections.yml
- 1522-yaml-callback-unicode.yml
- 1527-fix-nios-api-member-normalize.yaml
- 1532-monit-support-all-services.yaml
- 1552_launchd.yml
- 1553_sendgrid.yml
- 1574-make-question.yaml
- 470-spacewalk-legacy-python-certificate-validation.yaml
- 953_syslogger.yml
- community.docker-53-docker_image-tag-push.yml
- community.docker-55-docker_image-loading.yml
- google-migration.yml
- hashi_vault-migration.yml
- jira_improvements.yaml
- oc-migration.yml
release_date: '2021-01-04'
1.3.3:
changes:
bugfixes:
- terraform - fix ``init_reconfigure`` option for proper CLI args (https://github.com/ansible-collections/community.general/pull/1620).
major_changes:
- 'For community.general 2.0.0, the kubevirt modules will be moved to the `community.kubevirt
<https://galaxy.ansible.com/community/kubevirt>`_ collection.
A redirection will be inserted so that users using ansible-base 2.10 or newer
do not have to change anything.
If you use Ansible 2.9 and explicitly use kubevirt modules from this collection,
you will need to adjust your playbooks and roles to use FQCNs starting with
``community.kubevirt.`` instead of ``community.general.``,
for example replace ``community.general.kubevirt_vm`` in a task by ``community.kubevirt.kubevirt_vm``.
If you use ansible-base and installed ``community.general`` manually and rely
on the kubevirt modules, you have to make sure to install the ``community.kubevirt``
collection as well.
If you are using FQCNs, for example ``community.general.kubevirt_vm`` instead
of ``kubevirt_vm``, it will continue working, but we still recommend to adjust
the FQCNs as well.
'
release_summary: Bugfix/security release that addresses CVE-2021-20178.
security_fixes:
- snmp_facts - **CVE-2021-20178** - hide user sensitive information such as
``privkey`` and ``authkey`` from logging into the console (https://github.com/ansible-collections/community.general/pull/1621).
fragments:
- 1.3.3.yml
- 1620-terraform_init_reconfigure_fix.yml
- kubevirt-migration.yml
- snmp_facts.yml
release_date: '2021-01-13'
1.3.4:
changes:
bugfixes:
- npm - handle json decode exception while parsing command line output (https://github.com/ansible-collections/community.general/issues/1614).
release_summary: Bugfix/security release that addresses CVE-2021-20180.
security_fixes:
- bitbucket_pipeline_variable - **CVE-2021-20180** - hide user sensitive information
which are marked as ``secured`` from logging into the console (https://github.com/ansible-collections/community.general/pull/1635).
fragments:
- 1.3.4.yml
- 1614_npm.yml
- cve_bitbucket_pipeline_variable.yml
release_date: '2021-01-14'

View File

@@ -1,6 +1,6 @@
namespace: community
name: general
version: 1.3.1
version: 1.3.4
readme: README.md
authors:
- Ansible (https://github.com/ansible)

View File

@@ -50,7 +50,7 @@ def my_represent_scalar(self, tag, value, style=None):
# ...no trailing space
value = value.rstrip()
# ...and non-printable characters
value = ''.join(x for x in value if x in string.printable)
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
# ...tabs prevent blocks from expanding
value = value.expandtabs()
# ...and odd bits of whitespace

View File

@@ -2,18 +2,16 @@
# 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
DOCUMENTATION = '''
DOCUMENTATION = r'''
name: online
plugin_type: inventory
author:
- Remy Leone (@sieben)
short_description: Online inventory source
short_description: Scaleway (previously Online SAS or Online.net) inventory source
description:
- Get inventory hosts from Online
- Get inventory hosts from Scaleway (previously Online SAS or Online.net).
options:
plugin:
description: token that ensures this is a source file for the 'online' plugin.
@@ -45,7 +43,7 @@ DOCUMENTATION = '''
- rpn
'''
EXAMPLES = '''
EXAMPLES = r'''
# online_inventory.yml file in YAML format
# Example command line: ansible-inventory --list -i online_inventory.yml

View File

@@ -204,7 +204,7 @@ class LookupModule(LookupBase):
def check_pass(self):
try:
self.passoutput = to_text(
check_output2(["pass", self.passname], env=self.env),
check_output2(["pass", "show", self.passname], env=self.env),
errors='surrogate_or_strict'
).splitlines()
self.password = self.passoutput[0]

View File

@@ -144,7 +144,7 @@ def member_normalize(member_spec):
'pre_provisioning', 'network_setting', 'v6_network_setting',
'ha_port_setting', 'lan_port_setting', 'lan2_physical_setting',
'lan_ha_port_setting', 'mgmt_network_setting', 'v6_mgmt_network_setting']
for key in member_spec.keys():
for key in list(member_spec.keys()):
if key in member_elements and member_spec[key] is not None:
member_spec[key] = member_spec[key][0]
if isinstance(member_spec[key], dict):

View File

@@ -698,8 +698,8 @@ class ImageManager(DockerBaseClass):
if image and image['Id'] == self.results['image']['Id']:
self.results['changed'] = False
if push:
self.push_image(repo, repo_tag)
if push:
self.push_image(repo, repo_tag)
def build_image(self):
'''
@@ -749,7 +749,7 @@ class ImageManager(DockerBaseClass):
# line = json.loads(line)
self.log(line, pretty_print=True)
if "stream" in line or "status" in line:
build_line = line.get("stream") or line.get("status")
build_line = line.get("stream") or line.get("status") or ''
build_output.append(build_line)
if line.get('error'):
@@ -774,17 +774,45 @@ class ImageManager(DockerBaseClass):
:return: image dict
'''
# Load image(s) from file
load_output = []
try:
self.log("Opening image %s" % self.load_path)
with open(self.load_path, 'rb') as image_tar:
self.log("Loading image from %s" % self.load_path)
self.client.load_image(image_tar)
for line in self.client.load_image(image_tar):
self.log(line, pretty_print=True)
if "stream" in line or "status" in line:
load_line = line.get("stream") or line.get("status") or ''
load_output.append(load_line)
except EnvironmentError as exc:
if exc.errno == errno.ENOENT:
self.fail("Error opening image %s - %s" % (self.load_path, str(exc)))
self.fail("Error loading image %s - %s" % (self.name, str(exc)))
self.client.fail("Error opening image %s - %s" % (self.load_path, str(exc)))
self.client.fail("Error loading image %s - %s" % (self.name, str(exc)), stdout='\n'.join(load_output))
except Exception as exc:
self.fail("Error loading image %s - %s" % (self.name, str(exc)))
self.client.fail("Error loading image %s - %s" % (self.name, str(exc)), stdout='\n'.join(load_output))
# Collect loaded images
loaded_images = set()
for line in load_output:
if line.startswith('Loaded image:'):
loaded_images.add(line[len('Loaded image:'):].strip())
if not loaded_images:
self.client.fail("Detected no loaded images. Archive potentially corrupt?", stdout='\n'.join(load_output))
expected_image = '%s:%s' % (self.name, self.tag)
if expected_image not in loaded_images:
self.client.fail(
"The archive did not contain image '%s'. Instead, found %s." % (
expected_image, ', '.join(["'%s'" % image for image in sorted(loaded_images)])),
stdout='\n'.join(load_output))
loaded_images.remove(expected_image)
if loaded_images:
self.client.module.warn(
"The archive contained more images than specified: %s" % (
', '.join(["'%s'" % image for image in sorted(loaded_images)]), ))
return self.client.find_image(self.name, self.tag)

View File

@@ -1,19 +1,19 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
# Copyright: (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
# 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
DOCUMENTATION = '''
DOCUMENTATION = r'''
---
module: lxc_container
short_description: Manage LXC Containers
description:
- Management of LXC containers
- Management of LXC containers.
author: "Kevin Carter (@cloudnull)"
options:
name:
@@ -53,7 +53,7 @@ options:
type: str
vg_name:
description:
- If Backend store is lvm, specify the name of the volume group.
- If backend store is lvm, specify the name of the volume group.
type: str
default: lxc
thinpool:
@@ -84,7 +84,7 @@ options:
type: str
lxc_path:
description:
- Place container under PATH
- Place container under PATH.
type: path
container_log:
description:
@@ -109,26 +109,26 @@ options:
default: INFO
clone_name:
description:
- Name of the new cloned server. This is only used when state is
clone.
- Name of the new cloned server.
- This is only used when state is clone.
type: str
clone_snapshot:
description:
- Create a snapshot a container when cloning. This is not supported
by all container storage backends. Enabling this may fail if the
backing store does not support snapshots.
- Create a snapshot a container when cloning.
- This is not supported by all container storage backends.
- Enabling this may fail if the backing store does not support snapshots.
type: bool
default: 'no'
archive:
description:
- Create an archive of a container. This will create a tarball of the
running container.
- Create an archive of a container.
- This will create a tarball of the running container.
type: bool
default: 'no'
archive_path:
description:
- Path the save the archived container. If the path does not exist
the archive method will attempt to create it.
- Path the save the archived container.
- If the path does not exist the archive method will attempt to create it.
type: path
archive_compression:
choices:
@@ -149,16 +149,17 @@ options:
- frozen
- clone
description:
- Define the state of a container. If you clone a container using
`clone_name` the newly cloned container created in a stopped state.
The running container will be stopped while the clone operation is
- Define the state of a container.
- If you clone a container using I(clone_name) the newly cloned
container created in a stopped state.
- The running container will be stopped while the clone operation is
happening and upon completion of the clone the original container
state will be restored.
type: str
default: started
container_config:
description:
- list of 'key=value' options to use when configuring a container.
- A list of C(key=value) options to use when configuring a container.
type: list
elements: str
requirements:
@@ -188,7 +189,7 @@ notes:
name lxc-python2.
'''
EXAMPLES = """
EXAMPLES = r"""
- name: Create a started container
community.general.lxc_container:
name: test-container-started
@@ -371,7 +372,7 @@ EXAMPLES = """
- test-container-new-archive-destroyed-clone
"""
RETURN = """
RETURN = r"""
lxc_container:
description: container information
returned: success
@@ -928,8 +929,7 @@ class LxcContainerManagement(object):
if self._container_exists(container_name=self.container_name, lxc_path=self.lxc_path):
return str(self.container.state).lower()
else:
return str('absent')
return str('absent')
def _execute_command(self):
"""Execute a shell command."""

View File

@@ -219,7 +219,7 @@ def init_plugins(bin_path, project_path, backend_config, backend_config_files, i
for f in backend_config_files:
command.extend(['-backend-config', f])
if init_reconfigure:
command.extend('-reconfigure')
command.extend(['-reconfigure'])
rc, out, err = module.run_command(command, cwd=project_path)
if rc != 0:
module.fail_json(msg="Failed to initialize Terraform modules:\r\n{0}".format(err))

View File

@@ -62,6 +62,9 @@ STATE_COMMAND_MAP = {
'restarted': 'restart'
}
MONIT_SERVICES = ['Process', 'File', 'Fifo', 'Filesystem', 'Directory', 'Remote host', 'System', 'Program',
'Network']
@python_2_unicode_compatible
class StatusValue(namedtuple("Status", "value, is_pending")):
@@ -151,7 +154,9 @@ class Monit(object):
return self._parse_status(out, err)
def _parse_status(self, output, err):
if "Process '%s'" % self.process_name not in output:
escaped_monit_services = '|'.join([re.escape(x) for x in MONIT_SERVICES])
pattern = "(%s) '%s'" % (escaped_monit_services, re.escape(self.process_name))
if not re.search(pattern, output, re.IGNORECASE):
return Status.MISSING
status_val = re.findall(r"^\s*status\s*([\w\- ]+)", output, re.MULTILINE)

View File

@@ -19,6 +19,7 @@ module: nagios
short_description: Perform common tasks in Nagios related to downtime and notifications.
description:
- "The C(nagios) module has two basic functions: scheduling downtime and toggling alerts for services or hosts."
- The C(nagios) module is not idempotent.
- All actions require the I(host) parameter to be given explicitly. In playbooks you can use the C({{inventory_hostname}}) variable to refer
to the host the playbook is currently running on.
- You can specify multiple services at once by separating them with commas, .e.g., C(services=httpd,nfs,puppet).
@@ -26,7 +27,6 @@ description:
e.g., C(service=host). This keyword may not be given with other services at the same time.
I(Setting alerts/downtime/acknowledge for a host does not affect alerts/downtime/acknowledge for any of the services running on it.)
To schedule downtime for all services on particular host use keyword "all", e.g., C(service=all).
- When using the C(nagios) module you will need to specify your Nagios server using the C(delegate_to) parameter.
options:
action:
description:

View File

@@ -112,7 +112,7 @@ def main():
except Exception as exception:
module.fail_json(msg="Attribute action failed.", details=to_native(exception))
module.exit_json(changed=True)
module.exit_json(changed=False)
def _extract_entry(dn, attrs):
@@ -144,24 +144,20 @@ class LdapSearch(LdapGeneric):
self.attrsonly = 0
def _load_scope(self):
scope = self.module.params['scope']
if scope == 'base':
self.scope = ldap.SCOPE_BASE
elif scope == 'onelevel':
self.scope = ldap.SCOPE_ONELEVEL
elif scope == 'subordinate':
self.scope = ldap.SCOPE_SUBORDINATE
elif scope == 'children':
self.scope = ldap.SCOPE_SUBTREE
else:
raise AssertionError('Implementation error')
spec = dict(
base=ldap.SCOPE_BASE,
onelevel=ldap.SCOPE_ONELEVEL,
subordinate=ldap.SCOPE_SUBORDINATE,
children=ldap.SCOPE_SUBTREE,
)
self.scope = spec[self.module.params['scope']]
def _load_attrs(self):
self.attrlist = self.module.params['attrs'] or None
def main(self):
results = self.perform_search()
self.module.exit_json(changed=True, results=results)
self.module.exit_json(changed=False, results=results)
def perform_search(self):
try:

View File

@@ -739,7 +739,6 @@ class Nmcli(object):
return self.type in (
'bond',
'bridge',
'bridge-slave',
'ethernet',
'generic',
'team',

View File

@@ -21,51 +21,51 @@ requirements:
options:
host:
description:
- Set to target snmp server (normally C({{ inventory_hostname }})).
- Set to target SNMP server (normally C({{ inventory_hostname }})).
type: str
required: true
version:
description:
- SNMP Version to use, v2/v2c or v3.
- SNMP Version to use, C(v2), C(v2c) or C(v3).
type: str
required: true
choices: [ v2, v2c, v3 ]
community:
description:
- The SNMP community string, required if version is v2/v2c.
- The SNMP community string, required if I(version) is C(v2) or C(v2c).
type: str
level:
description:
- Authentication level.
- Required if version is v3.
- Required if I(version) is C(v3).
type: str
choices: [ authNoPriv, authPriv ]
username:
description:
- Username for SNMPv3.
- Required if version is v3.
- Required if I(version) is C(v3).
type: str
integrity:
description:
- Hashing algorithm.
- Required if version is v3.
- Required if I(version) is C(v3).
type: str
choices: [ md5, sha ]
authkey:
description:
- Authentication key.
- Required if version is v3.
- Required I(version) is C(v3).
type: str
privacy:
description:
- Encryption algorithm.
- Required if level is authPriv.
- Required if I(level) is C(authPriv).
type: str
choices: [ aes, des ]
privkey:
description:
- Encryption key.
- Required if version is authPriv.
- Required if I(level) is C(authPriv).
type: str
'''
@@ -174,10 +174,10 @@ PYSNMP_IMP_ERR = None
try:
from pysnmp.entity.rfc3413.oneliner import cmdgen
from pysnmp.proto.rfc1905 import EndOfMibView
has_pysnmp = True
HAS_PYSNMP = True
except Exception:
PYSNMP_IMP_ERR = traceback.format_exc()
has_pysnmp = False
HAS_PYSNMP = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils._text import to_text
@@ -221,8 +221,7 @@ def decode_hex(hexstring):
return hexstring
if hexstring[:2] == "0x":
return to_text(binascii.unhexlify(hexstring[2:]))
else:
return hexstring
return hexstring
def decode_mac(hexstring):
@@ -231,8 +230,7 @@ def decode_mac(hexstring):
return hexstring
if hexstring[:2] == "0x":
return hexstring[2:]
else:
return hexstring
return hexstring
def lookup_adminstatus(int_adminstatus):
@@ -243,8 +241,7 @@ def lookup_adminstatus(int_adminstatus):
}
if int_adminstatus in adminstatus_options:
return adminstatus_options[int_adminstatus]
else:
return ""
return ""
def lookup_operstatus(int_operstatus):
@@ -259,8 +256,7 @@ def lookup_operstatus(int_operstatus):
}
if int_operstatus in operstatus_options:
return operstatus_options[int_operstatus]
else:
return ""
return ""
def main():
@@ -273,8 +269,8 @@ def main():
level=dict(type='str', choices=['authNoPriv', 'authPriv']),
integrity=dict(type='str', choices=['md5', 'sha']),
privacy=dict(type='str', choices=['aes', 'des']),
authkey=dict(type='str'),
privkey=dict(type='str'),
authkey=dict(type='str', no_log=True),
privkey=dict(type='str', no_log=True),
),
required_together=(
['username', 'level', 'integrity', 'authkey'],
@@ -285,13 +281,13 @@ def main():
m_args = module.params
if not has_pysnmp:
if not HAS_PYSNMP:
module.fail_json(msg=missing_required_lib('pysnmp'), exception=PYSNMP_IMP_ERR)
cmdGen = cmdgen.CommandGenerator()
# Verify that we receive a community when using snmp v2
if m_args['version'] == "v2" or m_args['version'] == "v2c":
if m_args['version'] in ("v2", "v2c"):
if m_args['community'] is None:
module.fail_json(msg='Community not set when using snmp version 2')
@@ -313,7 +309,7 @@ def main():
privacy_proto = cmdgen.usmDESPrivProtocol
# Use SNMP Version 2
if m_args['version'] == "v2" or m_args['version'] == "v2c":
if m_args['version'] in ("v2", "v2c"):
snmp_auth = cmdgen.CommunityData(m_args['community'])
# Use SNMP Version 3 with authNoPriv

View File

@@ -1,14 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2015, Matt Makai <matthew.makai@gmail.com>
# Copyright: (c) 2015, Matt Makai <matthew.makai@gmail.com>
# 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
DOCUMENTATION = '''
DOCUMENTATION = r'''
---
module: sendgrid
short_description: Sends an email with the SendGrid API
@@ -23,73 +23,73 @@ notes:
account."
- "In order to use api_key, cc, bcc, attachments, from_name, html_body, headers
you must pip install sendgrid"
- "since 2.2 username and password are not required if you supply an api_key"
- "since 2.2 I(username) and I(password) are not required if you supply an I(api_key)"
requirements:
- sendgrid python library
- sendgrid Python library 1.6.22 or lower (Sendgrid API V2 supported)
options:
username:
type: str
description:
- username for logging into the SendGrid account.
- Since 2.2 it is only required if api_key is not supplied.
- Username for logging into the SendGrid account.
- Since 2.2 it is only required if I(api_key) is not supplied.
password:
type: str
description:
- password that corresponds to the username
- Since 2.2 it is only required if api_key is not supplied.
- Password that corresponds to the username.
- Since 2.2 it is only required if I(api_key) is not supplied.
from_address:
type: str
description:
- the address in the "from" field for the email
- The address in the "from" field for the email.
required: true
to_addresses:
type: list
description:
- a list with one or more recipient email addresses
- A list with one or more recipient email addresses.
required: true
subject:
type: str
description:
- the desired subject for the email
- The desired subject for the email.
required: true
api_key:
type: str
description:
- sendgrid API key to use instead of username/password
- Sendgrid API key to use instead of username/password.
cc:
type: list
description:
- a list of email addresses to cc
- A list of email addresses to cc.
bcc:
type: list
description:
- a list of email addresses to bcc
- A list of email addresses to bcc.
attachments:
type: list
description:
- a list of relative or explicit paths of files you want to attach (7MB limit as per SendGrid docs)
- A list of relative or explicit paths of files you want to attach (7MB limit as per SendGrid docs).
from_name:
type: str
description:
- the name you want to appear in the from field, i.e 'John Doe'
- The name you want to appear in the from field, i.e 'John Doe'.
html_body:
description:
- whether the body is html content that should be rendered
- Whether the body is html content that should be rendered.
type: bool
default: 'no'
headers:
type: dict
description:
- a dict to pass on as headers
- A dict to pass on as headers.
body:
type: str
description:
- the e-mail body content
- The e-mail body content.
required: yes
author: "Matt Makai (@makaimc)"
'''
EXAMPLES = '''
EXAMPLES = r'''
- name: Send an email to a single recipient that the deployment was successful
community.general.sendgrid:
username: "{{ sendgrid_username }}"
@@ -120,6 +120,8 @@ EXAMPLES = '''
import os
import traceback
from distutils.version import LooseVersion
SENDGRID_IMP_ERR = None
try:
import sendgrid
@@ -155,6 +157,9 @@ def post_sendgrid_api(module, username, password, from_address, to_addresses,
'Accept': 'application/json'}
return fetch_url(module, SENDGRID_URI, data=encoded_data, headers=headers, method='POST')
else:
# Remove this check when adding Sendgrid API v3 support
if LooseVersion(sendgrid.version.__version__) > LooseVersion("1.6.22"):
module.fail_json(msg="Please install sendgrid==1.6.22 or lower since module uses Sendgrid V2 APIs.")
if api_key:
sg = sendgrid.SendGridClient(api_key)

View File

@@ -5,7 +5,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
DOCUMENTATION = r'''
---
module: syslogger
short_description: Log messages in the syslog
@@ -33,7 +33,7 @@ options:
default: "daemon"
log_pid:
description:
- Log the pid in brackets.
- Log the PID in brackets.
type: bool
default: False
ident:
@@ -83,7 +83,7 @@ facility:
type: str
sample: "info"
log_pid:
description: Log pid status
description: Log PID status
returned: always
type: bool
sample: True
@@ -94,11 +94,14 @@ msg:
sample: "Hello from Ansible"
'''
from ansible.module_utils.basic import AnsibleModule
import syslog
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
def get_facility(x):
def get_facility(facility):
return {
'kern': syslog.LOG_KERN,
'user': syslog.LOG_USER,
@@ -118,10 +121,10 @@ def get_facility(x):
'local5': syslog.LOG_LOCAL5,
'local6': syslog.LOG_LOCAL6,
'local7': syslog.LOG_LOCAL7
}.get(x, syslog.LOG_DAEMON)
}.get(facility, syslog.LOG_DAEMON)
def get_priority(x):
def get_priority(priority):
return {
'emerg': syslog.LOG_EMERG,
'alert': syslog.LOG_ALERT,
@@ -131,7 +134,7 @@ def get_priority(x):
'notice': syslog.LOG_NOTICE,
'info': syslog.LOG_INFO,
'debug': syslog.LOG_DEBUG
}.get(x, syslog.LOG_INFO)
}.get(priority, syslog.LOG_INFO)
def main():
@@ -168,20 +171,16 @@ def main():
# do the logging
try:
if module.params['log_pid']:
syslog.openlog(module.params['ident'],
logoption=syslog.LOG_PID,
facility=get_facility(module.params['facility']))
else:
syslog.openlog(module.params['ident'],
facility=get_facility(module.params['facility']))
syslog.openlog(module.params['ident'],
syslog.LOG_PID if module.params['log_pid'] else 0,
get_facility(module.params['facility']))
syslog.syslog(get_priority(module.params['priority']),
module.params['msg'])
syslog.closelog()
result['changed'] = True
except Exception:
module.fail_json(error='Failed to write to syslog', **result)
except Exception as exc:
module.fail_json(error='Failed to write to syslog %s' % to_native(exc), exception=traceback.format_exc(), **result)
module.exit_json(**result)

View File

@@ -7,39 +7,39 @@ from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
DOCUMENTATION = r'''
---
module: npm
short_description: Manage node.js packages with npm
description:
- Manage node.js packages with Node Package Manager (npm)
- Manage node.js packages with Node Package Manager (npm).
author: "Chris Hoffman (@chrishoffman)"
options:
name:
description:
- The name of a node.js library to install
- The name of a node.js library to install.
type: str
required: false
path:
description:
- The base path where to install the node.js libraries
- The base path where to install the node.js libraries.
type: path
required: false
version:
description:
- The version to be installed
- The version to be installed.
type: str
required: false
global:
description:
- Install the node.js library globally
- Install the node.js library globally.
required: false
default: no
type: bool
executable:
description:
- The executable location for npm.
- This is useful if you are using a version manager, such as nvm
- This is useful if you are using a version manager, such as nvm.
type: path
required: false
ignore_scripts:
@@ -55,12 +55,12 @@ options:
default: no
ci:
description:
- Install packages based on package-lock file, same as running npm ci
- Install packages based on package-lock file, same as running C(npm ci).
type: bool
default: no
production:
description:
- Install dependencies in production mode, excluding devDependencies
- Install dependencies in production mode, excluding devDependencies.
required: false
type: bool
default: no
@@ -71,7 +71,7 @@ options:
type: str
state:
description:
- The state of the node.js library
- The state of the node.js library.
required: false
type: str
default: present
@@ -80,7 +80,7 @@ requirements:
- npm installed in bin path (recommended /usr/local/bin)
'''
EXAMPLES = '''
EXAMPLES = r'''
- name: Install "coffee-script" node.js package.
community.general.npm:
name: coffee-script
@@ -124,12 +124,12 @@ EXAMPLES = '''
state: present
'''
import json
import os
import re
from ansible.module_utils.basic import AnsibleModule
import json
from ansible.module_utils._text import to_native
class Npm(object):
@@ -155,7 +155,7 @@ class Npm(object):
else:
self.name_version = self.name
def _exec(self, args, run_in_check_mode=False, check_rc=True):
def _exec(self, args, run_in_check_mode=False, check_rc=True, add_package_name=True):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
cmd = self.executable + args
@@ -167,7 +167,7 @@ class Npm(object):
cmd.append('--ignore-scripts')
if self.unsafe_perm:
cmd.append('--unsafe-perm')
if self.name:
if self.name and add_package_name:
cmd.append(self.name_version)
if self.registry:
cmd.append('--registry')
@@ -191,7 +191,11 @@ class Npm(object):
installed = list()
missing = list()
data = json.loads(self._exec(cmd, True, False))
data = {}
try:
data = json.loads(self._exec(cmd, True, False, False) or '{}')
except (getattr(json, 'JSONDecodeError', ValueError)) as e:
self.module.fail_json(msg="Failed to parse NPM output with error %s" % to_native(e))
if 'dependencies' in data:
for dep in data['dependencies']:
if 'missing' in data['dependencies'][dep] and data['dependencies'][dep]['missing']:

View File

@@ -139,6 +139,7 @@ EXAMPLES = '''
import os
import re
import tempfile
from distutils import version
from ansible.module_utils._text import to_bytes
from ansible.module_utils.basic import AnsibleModule
@@ -356,6 +357,18 @@ class HomebrewCask(object):
else:
self._current_cask = cask
return cask
@property
def brew_version(self):
try:
return self._brew_version
except AttributeError:
return None
@brew_version.setter
def brew_version(self, brew_version):
self._brew_version = brew_version
# /class properties -------------------------------------------- }}}
def __init__(self, module, path=path, casks=None, state=None,
@@ -434,15 +447,12 @@ class HomebrewCask(object):
if not self.valid_cask(self.current_cask):
return False
cask_is_outdated_command = (
[
self.brew_path,
'cask',
'outdated',
]
+ (['--greedy'] if self.greedy else [])
+ [self.current_cask]
)
if self._brew_cask_command_is_deprecated():
base_opts = [self.brew_path, 'outdated', '--cask']
else:
base_opts = [self.brew_path, 'cask', 'outdated']
cask_is_outdated_command = base_opts + (['--greedy'] if self.greedy else []) + [self.current_cask]
rc, out, err = self.module.run_command(cask_is_outdated_command)
@@ -454,18 +464,35 @@ class HomebrewCask(object):
self.message = 'Invalid cask: {0}.'.format(self.current_cask)
raise HomebrewCaskException(self.message)
cmd = [
"{brew_path}".format(brew_path=self.brew_path),
"cask",
"list",
self.current_cask
]
if self._brew_cask_command_is_deprecated():
base_opts = [self.brew_path, "list", "--cask"]
else:
base_opts = [self.brew_path, "cask", "list"]
cmd = base_opts + [self.current_cask]
rc, out, err = self.module.run_command(cmd)
if rc == 0:
return True
else:
return False
def _get_brew_version(self):
if self.brew_version:
return self.brew_version
cmd = [self.brew_path, '--version']
rc, out, err = self.module.run_command(cmd, check_rc=True)
# get version string from first line of "brew --version" output
version = out.split('\n')[0].split(' ')[1]
self.brew_version = version
return self.brew_version
def _brew_cask_command_is_deprecated(self):
# The `brew cask` replacements were fully available in 2.6.0 (https://brew.sh/2020/12/01/homebrew-2.6.0/)
return version.LooseVersion(self._get_brew_version()) >= version.LooseVersion('2.6.0')
# /checks ------------------------------------------------------ }}}
# commands ----------------------------------------------------- {{{
@@ -537,11 +564,10 @@ class HomebrewCask(object):
self.message = 'Casks would be upgraded.'
raise HomebrewCaskException(self.message)
opts = (
[self.brew_path, 'cask', 'upgrade']
)
cmd = [opt for opt in opts if opt]
if self._brew_cask_command_is_deprecated():
cmd = [self.brew_path, 'upgrade', '--cask']
else:
cmd = [self.brew_path, 'cask', 'upgrade']
rc, out, err = '', '', ''
@@ -586,10 +612,12 @@ class HomebrewCask(object):
)
raise HomebrewCaskException(self.message)
opts = (
[self.brew_path, 'cask', 'install', self.current_cask]
+ self.install_options
)
if self._brew_cask_command_is_deprecated():
base_opts = [self.brew_path, 'install', '--cask']
else:
base_opts = [self.brew_path, 'cask', 'install']
opts = base_opts + [self.current_cask] + self.install_options
cmd = [opt for opt in opts if opt]
@@ -650,11 +678,13 @@ class HomebrewCask(object):
)
raise HomebrewCaskException(self.message)
opts = (
[self.brew_path, 'cask', command]
+ self.install_options
+ [self.current_cask]
)
if self._brew_cask_command_is_deprecated():
base_opts = [self.brew_path, command, '--cask']
else:
base_opts = [self.brew_path, 'cask', command]
opts = base_opts + self.install_options + [self.current_cask]
cmd = [opt for opt in opts if opt]
rc, out, err = '', '', ''
@@ -703,10 +733,12 @@ class HomebrewCask(object):
)
raise HomebrewCaskException(self.message)
opts = (
[self.brew_path, 'cask', 'uninstall', self.current_cask]
+ self.install_options
)
if self._brew_cask_command_is_deprecated():
base_opts = [self.brew_path, 'uninstall', '--cask']
else:
base_opts = [self.brew_path, 'cask', 'uninstall']
opts = base_opts + [self.current_cask] + self.install_options
cmd = [opt for opt in opts if opt]

View File

@@ -135,7 +135,7 @@ def main():
try: # Python 2.7.9 and newer
ssl_context = ssl.create_unverified_context()
except AttributeError: # Legacy Python that doesn't verify HTTPS certificates by default
ssl._create_default_context = ssl._create_unverified_context
ssl_context = ssl._create_unverified_context()
else: # Python 2.7.8 and older
ssl._create_default_https_context = ssl._create_unverified_https_context

View File

@@ -85,7 +85,7 @@ EXAMPLES = r'''
RETURN = r''' # '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import AnsibleModule, _load_params
from ansible_collections.community.general.plugins.module_utils.source_control.bitbucket import BitbucketHelper
error_messages = {
@@ -211,6 +211,14 @@ def delete_pipeline_variable(module, bitbucket, variable_uuid):
))
class BitBucketPipelineVariable(AnsibleModule):
def __init__(self, *args, **kwargs):
params = _load_params() or {}
if params.get('secured'):
kwargs['argument_spec']['value'].update({'no_log': True})
super(BitBucketPipelineVariable, self).__init__(*args, **kwargs)
def main():
argument_spec = BitbucketHelper.bitbucket_argument_spec()
argument_spec.update(
@@ -221,7 +229,7 @@ def main():
secured=dict(type='bool', default=False),
state=dict(type='str', choices=['present', 'absent'], required=True),
)
module = AnsibleModule(
module = BitBucketPipelineVariable(
argument_spec=argument_spec,
supports_check_mode=True,
)

View File

@@ -114,6 +114,7 @@ from abc import ABCMeta, abstractmethod
from time import sleep
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
class ServiceState:
@@ -142,6 +143,9 @@ class Plist:
state, pid, dummy, dummy = LaunchCtlList(module, service).run()
# Check if readPlist is available or not
self.old_plistlib = hasattr(plistlib, 'readPlist')
self.__file = self.__find_service_plist(service)
if self.__file is None:
msg = 'Unable to infer the path of %s service plist file' % service
@@ -150,7 +154,8 @@ class Plist:
module.fail_json(msg=msg)
self.__update(module)
def __find_service_plist(self, service_name):
@staticmethod
def __find_service_plist(service_name):
"""Finds the plist file associated with a service"""
launchd_paths = [
@@ -176,9 +181,38 @@ class Plist:
self.__handle_param_enabled(module)
self.__handle_param_force_stop(module)
def __read_plist_file(self, module):
service_plist = {}
if self.old_plistlib:
return plistlib.readPlist(self.__file)
# readPlist is deprecated in Python 3 and onwards
try:
with open(self.__file, 'rb') as plist_fp:
service_plist = plistlib.load(plist_fp)
except Exception as e:
module.fail_json(msg="Failed to read plist file "
"%s due to %s" % (self.__file, to_native(e)))
return service_plist
def __write_plist_file(self, module, service_plist=None):
if not service_plist:
service_plist = {}
if self.old_plistlib:
plistlib.writePlist(service_plist, self.__file)
return
# writePlist is deprecated in Python 3 and onwards
try:
with open(self.__file, 'wb') as plist_fp:
plistlib.dump(service_plist, plist_fp)
except Exception as e:
module.fail_json(msg="Failed to write to plist file "
" %s due to %s" % (self.__file, to_native(e)))
def __handle_param_enabled(self, module):
if module.params['enabled'] is not None:
service_plist = plistlib.readPlist(self.__file)
service_plist = self.__read_plist_file(module)
# Enable/disable service startup at boot if requested
# Launchctl does not expose functionality to set the RunAtLoad
@@ -191,12 +225,12 @@ class Plist:
# Update the plist with one of the changes done.
if not module.check_mode:
plistlib.writePlist(service_plist, self.__file)
self.__write_plist_file(module, service_plist)
self.__changed = True
def __handle_param_force_stop(self, module):
if module.params['force_stop'] is not None:
service_plist = plistlib.readPlist(self.__file)
service_plist = self.__read_plist_file(module)
# Set KeepAlive to false in case force_stop is defined to avoid
# that the service gets restarted when stopping was requested.
@@ -207,7 +241,7 @@ class Plist:
# Update the plist with one of the changes done.
if not module.check_mode:
plistlib.writePlist(service_plist, self.__file)
self.__write_plist_file(module, service_plist)
self.__changed = True
def is_changed(self):
@@ -325,7 +359,7 @@ class LaunchCtlStart(LaunchCtlTask):
def runCommand(self):
state, dummy, dummy, dummy = self.get_state()
if state == ServiceState.STOPPED or state == ServiceState.LOADED:
if state in (ServiceState.STOPPED, ServiceState.LOADED):
self.reload()
self.start()
elif state == ServiceState.STARTED:
@@ -361,7 +395,7 @@ class LaunchCtlStop(LaunchCtlTask):
if self._plist.is_changed():
self.reload()
self.stop()
elif state == ServiceState.STARTED or state == ServiceState.LOADED:
elif state in (ServiceState.STARTED, ServiceState.LOADED):
if self._plist.is_changed():
self.reload()
self.stop()

View File

@@ -136,7 +136,7 @@ def main():
base_command.extend(make_parameters)
# Check if the target is already up to date
rc, out, err = run_command(base_command + ['--question'], module, check_rc=False)
rc, out, err = run_command(base_command + ['-q'], module, check_rc=False)
if module.check_mode:
# If we've been asked to do a dry run, we only need
# to report whether or not the target is up to date

View File

@@ -287,7 +287,7 @@ class PamdLine(object):
@property
def is_valid(self):
if self.line == '':
if self.line.strip() == '':
return True
return False
@@ -304,6 +304,10 @@ class PamdLine(object):
return str(self.line)
class PamdEmptyLine(PamdLine):
pass
class PamdComment(PamdLine):
def __init__(self, line):
@@ -445,8 +449,8 @@ class PamdService(object):
pamd_line = PamdComment(line)
elif line.lstrip().startswith('@include'):
pamd_line = PamdInclude(line)
elif line == '':
pamd_line = PamdLine(line)
elif line.strip() == '':
pamd_line = PamdEmptyLine(line)
else:
pamd_line = PamdRule.rule_from_string(line)
@@ -545,7 +549,7 @@ class PamdService(object):
# Next we may have to loop backwards if the previous line is a comment. If it
# is, we'll get the previous "rule's" previous.
while previous_rule is not None and isinstance(previous_rule, PamdComment):
while previous_rule is not None and isinstance(previous_rule, (PamdComment, PamdEmptyLine)):
previous_rule = previous_rule.prev
# Next we'll see if the previous rule matches what we are trying to insert.
if previous_rule is not None and not previous_rule.matches(new_type, new_control, new_path):
@@ -589,7 +593,7 @@ class PamdService(object):
next_rule = current_rule.next
# Next we may have to loop forwards if the next line is a comment. If it
# is, we'll get the next "rule's" next.
while next_rule is not None and isinstance(next_rule, PamdComment):
while next_rule is not None and isinstance(next_rule, (PamdComment, PamdEmptyLine)):
next_rule = next_rule.next
# First we create a new rule
@@ -780,13 +784,8 @@ def main():
required_if=[
("state", "args_present", ["module_arguments"]),
("state", "args_absent", ["module_arguments"]),
("state", "before", ["new_control"]),
("state", "before", ["new_type"]),
("state", "before", ["new_module_path"]),
("state", "after", ["new_control"]),
("state", "after", ["new_type"]),
("state", "after", ["new_module_path"]),
("state", "before", ["new_control", "new_type", "new_module_path"]),
("state", "after", ["new_control", "new_type", "new_module_path"]),
],
)
content = str()
@@ -798,9 +797,7 @@ def main():
content = service_file_obj.read()
except IOError as e:
# If unable to read the file, fail out
module.fail_json(msg='Unable to open/read PAM module \
file %s with error %s.' %
(fname, str(e)))
module.fail_json(msg='Unable to open/read PAM module file %s with error %s.' % (fname, str(e)))
# Assuming we didn't fail, create the service
service = PamdService(content)

View File

@@ -292,15 +292,16 @@ EXAMPLES = r"""
operation: transition
status: Done
args:
fields:
customfield_14321: [ {'set': {'value': 'Value of Select' }} ]
comment: [ { 'add': { 'body' : 'Test' } }]
fields:
customfield_14321: [ {'set': {'value': 'Value of Select' }} ]
comment: [ { 'add': { 'body' : 'Test' } }]
"""
import base64
import json
import sys
import traceback
from ansible.module_utils.six.moves.urllib.request import pathname2url
@@ -331,7 +332,7 @@ def request(url, user, passwd, timeout, data=None, method=None):
try:
error = json.loads(info['body'])
except Exception:
module.fail_json(msg=to_native(info['body']))
module.fail_json(msg=to_native(info['body']), exception=traceback.format_exc())
if error:
msg = []
for key in ('errorMessages', 'errors'):
@@ -379,27 +380,25 @@ def create(restbase, user, passwd, params):
url = restbase + '/issue/'
return post(url, user, passwd, params['timeout'], data)
return True, post(url, user, passwd, params['timeout'], data)
def comment(restbase, user, passwd, params):
data = {
'body': params['comment']
}
url = restbase + '/issue/' + params['issue'] + '/comment'
return post(url, user, passwd, params['timeout'], data)
return True, post(url, user, passwd, params['timeout'], data)
def edit(restbase, user, passwd, params):
data = {
'fields': params['fields']
}
url = restbase + '/issue/' + params['issue']
return put(url, user, passwd, params['timeout'], data)
return True, put(url, user, passwd, params['timeout'], data)
def update(restbase, user, passwd, params):
@@ -408,13 +407,12 @@ def update(restbase, user, passwd, params):
}
url = restbase + '/issue/' + params['issue']
return put(url, user, passwd, params['timeout'], data)
return True, put(url, user, passwd, params['timeout'], data)
def fetch(restbase, user, passwd, params):
url = restbase + '/issue/' + params['issue']
ret = get(url, user, passwd, params['timeout'])
return ret
return False, get(url, user, passwd, params['timeout'])
def search(restbase, user, passwd, params):
@@ -424,7 +422,7 @@ def search(restbase, user, passwd, params):
url = url + '&fields=' + '&fields='.join([pathname2url(f) for f in fields])
if params['maxresults']:
url = url + '&maxResults=' + str(params['maxresults'])
return get(url, user, passwd, params['timeout'])
return False, get(url, user, passwd, params['timeout'])
def transition(restbase, user, passwd, params):
@@ -447,7 +445,7 @@ def transition(restbase, user, passwd, params):
data = {'transition': {"id": tid},
'update': params['fields']}
return post(url, user, passwd, params['timeout'], data)
return True, post(url, user, passwd, params['timeout'], data)
def link(restbase, user, passwd, params):
@@ -459,18 +457,7 @@ def link(restbase, user, passwd, params):
url = restbase + '/issueLink/'
return post(url, user, passwd, params['timeout'], data)
# Some parameters are required depending on the operation:
OP_REQUIRED = dict(create=['project', 'issuetype', 'summary'],
comment=['issue', 'comment'],
edit=[],
update=[],
fetch=['issue'],
transition=['status'],
link=['linktype', 'inwardissue', 'outwardissue'],
search=['jql'])
return True, post(url, user, passwd, params['timeout'], data)
def main():
@@ -500,19 +487,19 @@ def main():
timeout=dict(type='float', default=10),
validate_certs=dict(default=True, type='bool'),
),
required_if=(
('operation', 'create', ['project', 'issuetype', 'summary']),
('operation', 'comment', ['issue', 'comment']),
('operation', 'fetch', ['issue']),
('operation', 'transition', ['issue', 'status']),
('operation', 'link', ['linktype', 'inwardissue', 'outwardissue']),
('operation', 'search', ['jql']),
),
supports_check_mode=False
)
op = module.params['operation']
# Check we have the necessary per-operation parameters
missing = []
for parm in OP_REQUIRED[op]:
if not module.params[parm]:
missing.append(parm)
if missing:
module.fail_json(msg="Operation %s require the following missing parameters: %s" % (op, ",".join(missing)))
# Handle rest of parameters
uri = module.params['uri']
user = module.params['username']
@@ -532,12 +519,12 @@ def main():
thismod = sys.modules[__name__]
method = getattr(thismod, op)
ret = method(restbase, user, passwd, module.params)
changed, ret = method(restbase, user, passwd, module.params)
except Exception as e:
return module.fail_json(msg=to_native(e))
return module.fail_json(msg=to_native(e), exception=traceback.format_exc())
module.exit_json(changed=True, meta=ret)
module.exit_json(changed=changed, meta=ret)
if __name__ == '__main__':

View File

@@ -0,0 +1,96 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Create temporary playbook files
tempfile:
state: file
suffix: temp
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: temporary_playbook_files
- name: Set temporary playbook file content
copy:
content: "{{ test.playbook }}"
dest: "{{ temporary_playbook_files.results[test_idx].path }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
index_var: test_idx
label: "{{ test.name }}"
- name: Collect outputs
command: "ansible-playbook -i {{ inventory }} {{ playbook }}"
environment: "{{ test.environment }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: outputs
changed_when: false
vars:
inventory: "{{ role_path }}/inventory.yml"
playbook: "
{%- for result in temporary_playbook_files.results -%}
{%- if result.test.name == test.name -%}
{{- result.path -}}
{%- endif -%}
{%- endfor -%}"
- name: Assert test output equals expected output
assert:
that: result.output.differences | length == 0
loop: "{{ results }}"
loop_control:
loop_var: result
label: "{{ result.name }}"
register: assertions
vars:
results: >-
{%- set results = [] -%}
{%- for result in outputs.results -%}
{%- set differences = [] -%}
{%- for i in range([result.test.expected_output | count, result.stdout_lines | count] | max) -%}
{%- set line = "line_%s" | format(i+1) -%}
{%- set test_line = result.stdout_lines[i] | default(none) -%}
{%- set expected_lines = result.test.expected_output[i] | default(none) -%}
{%- if expected_lines is not string and expected_lines is not none -%}
{%- if test_line not in expected_lines -%}
{{- differences.append({
line: {
'expected_one_of': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- else -%}
{%- if expected_lines != test_line -%}
{{- differences.append({
line: {
'expected': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{{- results.append({
'name': result.test.name,
'output': {
'differences': differences,
'expected': result.test.expected_output,
'got': result.stdout_lines }}) -}}
{%- endfor -%}
{{- results -}}
always:
- name: Remove temporary playbooks
file:
path: "{{ temporary_file.path }}"
state: absent
loop: "{{ temporary_playbook_files.results }}"
loop_control:
loop_var: temporary_file
label: "{{ temporary_file.test.name }}: {{ temporary_file.path }}"

View File

@@ -1,2 +1,2 @@
shippable/posix/group3
skip/aix
needs/target/callback

View File

@@ -1,9 +0,0 @@
- name: Remove temporary playbooks
file:
path: "{{ temporary_file.path }}"
state: absent
loop: "{{ temporary_playbook_files.results }}"
loop_control:
loop_var: temporary_file
label: "{{ temporary_file.test.name }}: {{ temporary_file.path }}"

View File

@@ -3,13 +3,16 @@
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Set tests
set_fact:
- name: Run tests
include_role:
name: callback
vars:
tests:
- name: Not using diy callback options
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: |
- hosts: testhost
gather_facts: false
@@ -22,19 +25,20 @@
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set playbook_on_start_msg callback using environment variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
ANSIBLE_CALLBACK_DIY_PLAYBOOK_ON_START_MSG="Sample output Sample playbook message"
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
ANSIBLE_CALLBACK_DIY_PLAYBOOK_ON_START_MSG: "Sample output Sample playbook message"
playbook: |
- hosts: testhost
gather_facts: false
@@ -48,24 +52,25 @@
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set playbook_on_play_start_msg callback using play variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- name: Sample play name
hosts: testhost
gather_facts: false
vars:
ansible_callback_diy_playbook_on_play_start_msg: Sample output \{\{ ansible_callback_diy.play.name \}\}
ansible_callback_diy_playbook_on_play_start_msg: Sample output {{ ansible_callback_diy.play.name }}
tasks:
- name: Sample task name
debug:
@@ -74,23 +79,24 @@
"Sample output Sample play name",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set playbook_on_task_start_msg callback using play variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
vars:
ansible_callback_diy_playbook_on_task_start_msg: Sample output \{\{ ansible_callback_diy.task.name \}\}
ansible_callback_diy_playbook_on_task_start_msg: Sample output {{ ansible_callback_diy.task.name }}
tasks:
- name: Sample task name
debug:
@@ -99,19 +105,20 @@
"",
"PLAY [testhost] ****************************************************************",
"Sample output Sample task name",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set playbook_on_task_start_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
@@ -119,24 +126,25 @@
debug:
msg: sample debug msg
vars:
ansible_callback_diy_playbook_on_task_start_msg: Sample output \{\{ ansible_callback_diy.task.name \}\}
ansible_callback_diy_playbook_on_task_start_msg: Sample output {{ ansible_callback_diy.task.name }}
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"Sample output Sample task name",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set runner_on_ok_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
@@ -144,7 +152,7 @@
debug:
msg: sample debug msg
vars:
ansible_callback_diy_runner_on_ok_msg: Sample output \{\{ ansible_callback_diy.result.output.msg \}\}
ansible_callback_diy_runner_on_ok_msg: Sample output {{ ansible_callback_diy.result.output.msg }}
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
@@ -153,13 +161,14 @@
"Sample output sample debug msg",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set runner_on_failed_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: |
- hosts: testhost
gather_facts: false
@@ -179,14 +188,15 @@
"Sample output Sample failure message",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 \u001b[1;35mignored=1 \u001b[0m"
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 "
]
- name: Set runner_on_skipped_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
@@ -195,7 +205,7 @@
msg: sample debug msg
when: false
vars:
ansible_callback_diy_runner_on_skipped_msg: Sample output Skipped \{\{ ansible_callback_diy.task.name \}\}
ansible_callback_diy_runner_on_skipped_msg: Sample output Skipped {{ ansible_callback_diy.task.name }}
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
@@ -204,26 +214,27 @@
"Sample output Skipped Sample task name",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : ok=0 changed=0 unreachable=0 failed=0 \u001b[0;36mskipped=1 \u001b[0m rescued=0 ignored=0 "
"testhost : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 "
]
- name: Set runner_item_on_ok_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg \{\{ item \}\}
msg: sample debug msg {{ item }}
loop:
- sample item 1
- sample item 2
- sample item 3
vars:
ansible_callback_diy_runner_item_on_ok_msg: Sample output Looping \{\{ ansible_callback_diy.result.output.msg \}\}
ansible_callback_diy_runner_item_on_ok_msg: Sample output Looping {{ ansible_callback_diy.result.output.msg }}
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
@@ -234,20 +245,21 @@
"Sample output Looping sample debug msg sample item 3",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set runner_item_on_failed_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg \{\{ item \}\}
msg: sample debug msg {{ item }}
loop:
- sample item 1
- sample item 2
@@ -261,93 +273,95 @@
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => (item=sample item 1) => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 1\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => (item=sample item 1) => {",
" \"msg\": \"sample debug msg sample item 1\"",
"}",
"Sample output Looping sample failure message",
"\u001b[0;32mok: [testhost] => (item=sample item 3) => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 3\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => (item=sample item 3) => {",
" \"msg\": \"sample debug msg sample item 3\"",
"}",
[
# Apparently a bug was fixed in Ansible, as before it ran through with "All items completed"
"\u001b[0;31mfatal: [testhost]: FAILED! => {\"msg\": \"All items completed\"}\u001b[0m",
"\u001b[0;31mfatal: [testhost]: FAILED! => {\"msg\": \"One or more items failed\"}\u001b[0m",
"fatal: [testhost]: FAILED! => {\"msg\": \"All items completed\"}",
"fatal: [testhost]: FAILED! => {\"msg\": \"One or more items failed\"}",
],
"\u001b[0;36m...ignoring\u001b[0m",
"...ignoring",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 \u001b[1;35mignored=1 \u001b[0m"
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1 "
]
- name: Set runner_item_on_skipped_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg \{\{ item \}\}
msg: sample debug msg {{ item }}
loop:
- sample item 1
- sample item 2
- sample item 3
when: item != 'sample item 2'
vars:
ansible_callback_diy_runner_item_on_skipped_msg: Sample output Looping Skipped \{\{ ansible_callback_diy.result.output.item \}\}
ansible_callback_diy_runner_item_on_skipped_msg: Sample output Looping Skipped {{ ansible_callback_diy.result.output.item }}
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => (item=sample item 1) => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 1\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => (item=sample item 1) => {",
" \"msg\": \"sample debug msg sample item 1\"",
"}",
"Sample output Looping Skipped sample item 2",
"\u001b[0;32mok: [testhost] => (item=sample item 3) => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg sample item 3\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => (item=sample item 3) => {",
" \"msg\": \"sample debug msg sample item 3\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set playbook_on_stats_msg callback using play variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
vars:
ansible_callback_diy_playbook_on_stats_msg: |+2
Sample output stats
===============================
{\% for key in ansible_callback_diy.stats | sort %\}
{\% set color_one = "" %\}
{\% set color_two = "" %\}
{\% if ansible_callback_diy.stats[key] %\}
{\% if key == 'ok' %\}
{\% set prefix = ' ' %\}
{\% set suffix = ' ' %\}
{\% elif key == 'changed' %\}
{\% set prefix = ' ' %\}
{\% set suffix = ' ' %\}
{\% elif key == 'processed' %\}
{\% set prefix = ' ' %\}
{\% set suffix = ' ' %\}
{\% elif key == 'skipped' %\}
{\% set prefix = ' ' %\}
{\% set suffix = ' ' %\}
{\% else %\}
{\% set prefix = "" %\}
{\% set suffix = "" %\}
{\% endif %\}
\{\{ color_one \}\}\{\{ "%s%s%s" | format(prefix,key,suffix) \}\}\{\{ color_two \}\}: \{\{ ansible_callback_diy.stats[key] | to_nice_yaml \}\}
{\% endif %\}
{\% endfor %\}
{% for key in ansible_callback_diy.stats | sort %}
{% set color_one = "" %}
{% set color_two = "" %}
{% if ansible_callback_diy.stats[key] %}
{% if key == 'ok' %}
{% set prefix = ' ' %}
{% set suffix = ' ' %}
{% elif key == 'changed' %}
{% set prefix = ' ' %}
{% set suffix = ' ' %}
{% elif key == 'processed' %}
{% set prefix = ' ' %}
{% set suffix = ' ' %}
{% elif key == 'skipped' %}
{% set prefix = ' ' %}
{% set suffix = ' ' %}
{% else %}
{% set prefix = "" %}
{% set suffix = "" %}
{% endif %}
{{ color_one }}{{ "%s%s%s" | format(prefix,key,suffix) }}{{ color_two }}: {{ ansible_callback_diy.stats[key] | to_nice_yaml }}
{% endif %}
{% endfor %}
tasks:
- name: Sample task name
debug:
@@ -357,9 +371,9 @@
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
" Sample output stats",
"===============================",
" ok : testhost: 1",
@@ -368,9 +382,10 @@
]
- name: Suppress output on playbook_on_task_start_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: |
- hosts: testhost
gather_facts: false
@@ -383,18 +398,19 @@
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"\u001b[0;32mok: [testhost] => {\u001b[0m",
"\u001b[0;32m \"msg\": \"sample debug msg\"\u001b[0m",
"\u001b[0;32m}\u001b[0m",
"ok: [testhost] => {",
" \"msg\": \"sample debug msg\"",
"}",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Suppress output on runner_on_ok_msg callback using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: |
- hosts: testhost
gather_facts: false
@@ -411,14 +427,15 @@
"TASK [Sample task name] ********************************************************",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Set runner_on_ok_msg_color using task variable
environment: >-
ANSIBLE_FORCE_COLOR=True
ANSIBLE_STDOUT_CALLBACK=community.general.diy
playbook: |
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.diy
playbook: !unsafe |
- hosts: testhost
gather_facts: false
tasks:
@@ -426,116 +443,15 @@
debug:
msg: sample debug msg
vars:
ansible_callback_diy_runner_on_ok_msg: Sample output \{\{ ansible_callback_diy.result.output.msg \}\}
ansible_callback_diy_runner_on_ok_msg: Sample output {{ ansible_callback_diy.result.output.msg }}
ansible_callback_diy_runner_on_ok_msg_color: blue
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"\u001b[0;34mSample output sample debug msg\u001b[0m",
"Sample output sample debug msg",
"",
"PLAY RECAP *********************************************************************",
"\u001b[0;32mtesthost\u001b[0m : \u001b[0;32mok=1 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- when: ansible_distribution == 'FreeBSD' and ansible_distribution_version in ['11.1', '12.1']
name: Create temporary playbooks
block:
- name: Create temporary playbook files
tempfile:
state: file
suffix: temp
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: temporary_playbook_files
notify: Remove temporary playbooks
- name: Set temporary playbook file content
copy:
content: "{{ playbook }}"
dest: "{{ playbook_file }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
vars:
playbook_file: "{{ (temporary_playbook_files.results | selectattr('test.name', 'equalto', test.name) | list())[0].path }}"
playbook: "{{
test.playbook
| regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}')
| regex_replace('({\\\\%)(.*?)(%\\\\})', '{%\\2%}')
}}"
- name: Collect outputs
shell: "{{ env }} ansible-playbook -i {{ inventory }} {{ playbook }}"
loop: "{{ tests }}"
loop_control:
loop_var: test
label: "{{ test.name }}"
register: outputs
changed_when: false
vars:
env: "{{ test.environment | regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}') }}"
inventory: "{{ role_path }}/inventory.yml"
playbook: "
{%- if temporary_playbook_files is changed -%}
{%- for result in temporary_playbook_files.results -%}
{%- if result.test.name == test.name -%}
{{- result.path -}}
{%- endif -%}
{%- endfor -%}
{%- else -%}
{{- [
'/dev/fd/0 <<EOF',
(
test.playbook
| regex_replace('(\\\\{){2}(.*?)(\\\\}){2}', '{{\\2}}')
| regex_replace('({\\\\%)(.*?)(%\\\\})', '{%\\2%}')
)
] | join('\n') -}}
{%- endif -%}"
- name: Assert test output equals expected output
assert:
that: result.output.differences | length == 0
loop: "{{ results }}"
loop_control:
loop_var: result
label: "{{ result.name }}"
register: assertions
vars:
results: >-
{%- set results = [] -%}
{%- for result in outputs.results -%}
{%- set differences = [] -%}
{%- for i in range([result.test.expected_output | count, result.stdout_lines | count] | max) -%}
{%- set line = "line_%s" | format(i+1) -%}
{%- set test_line = result.stdout_lines[i] | default(none) -%}
{%- set expected_lines = result.test.expected_output[i] | default(none) -%}
{%- if expected_lines is not string -%}
{%- if test_line not in expected_lines -%}
{{- differences.append({
line: {
'expected_one_of': expected_lines,
'got': test_line }}) -}}
{%- endif -%}
{%- else -%}
{%- if expected_lines != test_line -%}
{{- differences.append({
line: {
'expected': expected_line,
'got': test_line }}) -}}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{{- results.append({
'name': result.test.name,
'output': {
'differences': differences,
'expected': result.test.expected_output,
'got': result.stdout_lines }}) -}}
{%- endfor -%}
{{- results -}}

View File

@@ -0,0 +1,2 @@
shippable/posix/group1
needs/target/callback

View File

@@ -0,0 +1,60 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Run tests
include_role:
name: callback
vars:
tests:
- name: Basic run
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Sample task name
debug:
msg: sample debug msg
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Sample task name] ********************************************************",
"ok: [testhost] => ",
" msg: sample debug msg",
"",
"PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]
- name: Test umlauts in multiline
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
tasks:
- name: Umlaut output
debug:
msg: "äöü\néêè\nßï☺"
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Umlaut output] ***********************************************************",
"ok: [testhost] => ",
" msg: |-",
" äöü",
" éêè",
" ßï☺",
"",
"PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]

View File

@@ -1,3 +1,3 @@
needs/root
shippable/posix/group3
skip/macos # FIXME
skip/macos # Skipped due to limitation of macOS 10.15 SIP, please read https://github.com/ansible-collections/community.general/issues/1017#issuecomment-755088895

View File

@@ -10,7 +10,7 @@
- name: Registering image name
set_fact:
inames: "{{ inames + [iname, test_image_base ~ ':latest', hello_world_image_base ~ ':latest'] }}"
inames: "{{ inames + [iname, test_image_base ~ ':latest', hello_world_image_base ~ ':latest', hello_world_image_base ~ ':newtag', hello_world_image_base ~ ':newtag2'] }}"
####################################################################
## interact with test registry #####################################
@@ -101,6 +101,82 @@
- facts_2.images | length == 0
- facts_3.images | length == 1
- name: Tag different image with new tag
docker_image:
name: "{{ docker_test_image_alpine_different }}"
repository: "{{ hello_world_image_base }}:newtag"
push: no
source: pull
- name: Push different image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag
push: yes
source: local
register: push_1_different
- name: Push different image with new tag (idempotent)
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag
push: yes
source: local
register: push_2_different
- assert:
that:
- push_1_different is changed
- push_2_different is not changed
- name: Tag same image with new tag
docker_image:
name: "{{ docker_test_image_alpine_different }}"
repository: "{{ hello_world_image_base }}:newtag2"
push: no
source: pull
- name: Push same image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag2
push: yes
source: local
register: push_1_same
- name: Push same image with new tag (idempotent)
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag2
push: yes
source: local
register: push_2_same
- assert:
that:
# NOTE: This should be:
# - push_1_same is changed
# Unfortunately docker does *NOT* report whether the tag already existed or not.
# Here are the logs returned by client.push() for both tasks (which are exactly the same):
# push_1_same:
# {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
# {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
# {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
# push_2_same:
# {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
# {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
# {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
- push_1_same is not changed
- push_2_same is not changed
####################################################################
## repository ######################################################
####################################################################

View File

@@ -189,6 +189,11 @@
source: pull
register: archive_image
- name: Create invalid archive
copy:
dest: "{{ output_dir }}/image-invalid.tar"
content: "this is not a valid image"
- name: remove image
docker_image:
name: "{{ docker_test_image_hello_world }}"
@@ -209,11 +214,32 @@
source: load
register: load_image_1
- name: load image (wrong name)
docker_image:
name: foo:bar
load_path: "{{ output_dir }}/image.tar"
source: load
register: load_image_2
ignore_errors: true
- name: load image (invalid image)
docker_image:
name: foo:bar
load_path: "{{ output_dir }}/image-invalid.tar"
source: load
register: load_image_3
ignore_errors: true
- assert:
that:
- load_image is changed
- load_image_1 is not changed
- archive_image['image']['Id'] == load_image['image']['Id']
- load_image_1 is not changed
- load_image_2 is failed
- >-
"The archive did not contain image 'foo:bar'. Instead, found '" ~ docker_test_image_hello_world ~ "'." == load_image_2.msg
- load_image_3 is failed
- '"Detected no loaded images. Archive potentially corrupt?" == load_image_3.msg'
####################################################################
## path ############################################################

View File

@@ -1,4 +1,3 @@
shippable/posix/group2
skip/python3
skip/aix
disabled # tests use bitbucket, which dropped mercurial support on 2020-08-26 (https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket)

View File

@@ -4,22 +4,9 @@
####################################################################
# test code for the hg module
# (c) 2014, James Tanner <tanner.jc@gmail.com>
# This file is part of Ansible
# Copyright: (c) 2014, James Tanner <tanner.jc@gmail.com>
#
# 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/>.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- name: determine if mercurial is already installed
command: which hg

View File

@@ -1,27 +1,16 @@
# test code for the hg module
# (c) 2018, Ansible Project
# This file is part of Ansible
# Copyright: (c) 2018, Ansible Project
#
# 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/>.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- name: set where to extract the repo
set_fact: checkout_dir={{ output_dir }}/epdb
set_fact:
checkout_dir: "{{ output_dir }}/hg_project_test"
- name: set what repo to use
set_fact: repo=https://bitbucket.org/rpathsync/epdb
set_fact:
repo: "http://hg.pf.osdn.net/view/a/ak/akasurde/hg_project_test"
- name: clean out the output_dir
shell: rm -rf {{ output_dir }}/*
@@ -30,7 +19,9 @@
shell: which hg
- name: initial checkout
hg: repo={{ repo }} dest={{ checkout_dir }}
hg:
repo: "{{ repo }}"
dest: "{{ checkout_dir }}"
register: hg_result
- debug: var=hg_result
@@ -46,17 +37,21 @@
- "hg_result.changed"
- name: repeated checkout
hg: repo={{ repo }} dest={{ checkout_dir }}
hg:
repo: "{{ repo }}"
dest: "{{ checkout_dir }}"
register: hg_result2
- debug: var=hg_result2
- name: check for tags
stat: path={{ checkout_dir }}/.hgtags
stat:
path: "{{ checkout_dir }}/.hgtags"
register: tags
- name: check for remotes
stat: path={{ checkout_dir }}/.hg/branch
stat:
path: "{{ checkout_dir }}/.hg/branch"
register: branches
- debug: var=tags
@@ -68,13 +63,16 @@
- "tags.stat.isreg"
- "branches.stat.isreg"
- name: verify on a reclone things are marked unchanged
- name: verify on a re-clone things are marked unchanged
assert:
that:
- "not hg_result2.changed"
- name: Checkout non-existent repo clone
hg: repo=https://bitbucket.org/pyro46/pythonscript_1 clone=no update=no
hg:
repo: "http://hg.pf.osdn.net/view/a/ak/akasurde/hg_project_test_1"
clone: no
update: no
register: hg_result3
ignore_errors: true

View File

@@ -6,3 +6,4 @@ skip/macos
skip/freebsd
skip/aix
skip/python2.6 # python-daemon package used in integration tests requires >=2.7
skip/rhel # FIXME

View File

@@ -4,4 +4,3 @@ destructive
skip/aix
skip/centos6
skip/freebsd
disabled # FIXME

View File

@@ -56,6 +56,15 @@
content: "{{ lookup('file', 'job.hcl') }}"
register: job_deployed_idempotence
- name: get list of nomad jobs
nomad_job_info:
host: localhost
use_ssl: false
register: list_nomad_jobs
- debug:
msg: "{{ list_nomad_jobs }}"
- name: run check delete nomad job
nomad_job:
host: localhost
@@ -80,6 +89,15 @@
name: example
register: get_job_delete
- name: get list of nomad jobs
nomad_job_info:
host: localhost
use_ssl: false
register: list_nomad_jobs
- debug:
msg: "{{ list_nomad_jobs }}"
- name: assert idempotence
assert:
that:

View File

@@ -12,7 +12,7 @@ from ansible_collections.community.general.tests.unit.plugins.modules.utils impo
TEST_OUTPUT = """
Process '%s'
%s '%s'
status %s
monitoring status Not monitored
monitoring mode active
@@ -106,28 +106,45 @@ def test_status_value(status_name):
BASIC_OUTPUT_CASES = [
(TEST_OUTPUT % ('processX', name), getattr(monit.Status, name.upper()))
(TEST_OUTPUT % ('Process', 'processX', name), getattr(monit.Status, name.upper()))
for name in monit.StatusValue.ALL_STATUS
]
@pytest.mark.parametrize('output, expected', BASIC_OUTPUT_CASES + [
('', monit.Status.MISSING),
(TEST_OUTPUT % ('processY', 'OK'), monit.Status.MISSING),
(TEST_OUTPUT % ('processX', 'Not Monitored - start pending'), monit.Status.OK),
(TEST_OUTPUT % ('processX', 'Monitored - stop pending'), monit.Status.NOT_MONITORED),
(TEST_OUTPUT % ('processX', 'Monitored - restart pending'), monit.Status.OK),
(TEST_OUTPUT % ('processX', 'Not Monitored - monitor pending'), monit.Status.OK),
(TEST_OUTPUT % ('processX', 'Does not exist'), monit.Status.DOES_NOT_EXIST),
(TEST_OUTPUT % ('processX', 'Not monitored'), monit.Status.NOT_MONITORED),
(TEST_OUTPUT % ('processX', 'Running'), monit.Status.OK),
(TEST_OUTPUT % ('processX', 'Execution failed | Does not exist'), monit.Status.EXECUTION_FAILED),
(TEST_OUTPUT % ('Process', 'processY', 'OK'), monit.Status.MISSING),
(TEST_OUTPUT % ('Process', 'processX', 'Not Monitored - start pending'), monit.Status.OK),
(TEST_OUTPUT % ('Process', 'processX', 'Monitored - stop pending'), monit.Status.NOT_MONITORED),
(TEST_OUTPUT % ('Process', 'processX', 'Monitored - restart pending'), monit.Status.OK),
(TEST_OUTPUT % ('Process', 'processX', 'Not Monitored - monitor pending'), monit.Status.OK),
(TEST_OUTPUT % ('Process', 'processX', 'Does not exist'), monit.Status.DOES_NOT_EXIST),
(TEST_OUTPUT % ('Process', 'processX', 'Not monitored'), monit.Status.NOT_MONITORED),
(TEST_OUTPUT % ('Process', 'processX', 'Running'), monit.Status.OK),
(TEST_OUTPUT % ('Process', 'processX', 'Execution failed | Does not exist'), monit.Status.EXECUTION_FAILED),
])
def test_parse_status(output, expected):
status = monit.Monit(None, '', 'processX', 0)._parse_status(output, '')
assert status == expected
@pytest.mark.parametrize('output, expected', BASIC_OUTPUT_CASES + [
(TEST_OUTPUT % ('Process', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('File', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Fifo', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Filesystem', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Directory', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Remote host', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('System', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Program', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Network', 'processX', 'OK'), monit.Status.OK),
(TEST_OUTPUT % ('Unsupported', 'processX', 'OK'), monit.Status.MISSING),
])
def test_parse_status_supports_all_services(output, expected):
status = monit.Monit(None, '', 'processX', 0)._parse_status(output, '')
assert status == expected
@pytest.mark.parametrize('output, expected', [
('This is monit version 5.18.1', '5.18.1'),
('This is monit version 12.18', '12.18'),

View File

@@ -0,0 +1,70 @@
#
# Copyright: (c) 2021, Abhijeet Kasurde <akasurde@redhat.com>
# 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
from ansible_collections.community.general.tests.unit.compat.mock import call, patch
from ansible_collections.community.general.plugins.modules.packaging.language import npm
from ansible_collections.community.general.tests.unit.plugins.modules.utils import (
AnsibleExitJson, AnsibleFailJson, ModuleTestCase, set_module_args)
class NPMModuleTestCase(ModuleTestCase):
module = npm
def setUp(self):
super(NPMModuleTestCase, self).setUp()
ansible_module_path = "ansible_collections.community.general.plugins.modules.packaging.language.npm.AnsibleModule"
self.mock_run_command = patch('%s.run_command' % ansible_module_path)
self.module_main_command = self.mock_run_command.start()
self.mock_get_bin_path = patch('%s.get_bin_path' % ansible_module_path)
self.get_bin_path = self.mock_get_bin_path.start()
self.get_bin_path.return_value = '/testbin/npm'
def tearDown(self):
self.mock_run_command.stop()
self.mock_get_bin_path.stop()
super(NPMModuleTestCase, self).tearDown()
def module_main(self, exit_exc):
with self.assertRaises(exit_exc) as exc:
self.module.main()
return exc.exception.args[0]
def test_present(self):
set_module_args({
'name': 'coffee-script',
'global': 'true',
'state': 'present'
})
self.module_main_command.side_effect = [
(0, '{}', ''),
(0, '{}', ''),
]
result = self.module_main(AnsibleExitJson)
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
call(['/testbin/npm', 'list', '--json', '--long', '--global'], check_rc=False, cwd=None),
])
def test_absent(self):
set_module_args({
'name': 'coffee-script',
'global': 'true',
'state': 'absent'
})
self.module_main_command.side_effect = [
(0, '{"dependencies": {"coffee-script": {}}}', ''),
(0, '{}', ''),
]
result = self.module_main(AnsibleExitJson)
self.assertTrue(result['changed'])
self.module_main_command.assert_has_calls([
call(['/testbin/npm', 'uninstall', '--global', 'coffee-script'], check_rc=True, cwd=None),
])