mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-29 01:46:53 +00:00
Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a66140cd3 | ||
|
|
a56cef869d | ||
|
|
53d45efc02 | ||
|
|
c70d79c787 | ||
|
|
b37a0d4397 | ||
|
|
bf8e788964 | ||
|
|
8adc746d90 | ||
|
|
992e14e424 | ||
|
|
3d6cb8fe77 | ||
|
|
c694ceaf95 | ||
|
|
df91c522a4 | ||
|
|
35c0c10e28 | ||
|
|
c97b4e6201 | ||
|
|
1cd0afd3df | ||
|
|
6f14461d0b | ||
|
|
523514713c | ||
|
|
be0694ac21 | ||
|
|
5dde703246 | ||
|
|
c23dbb83d0 | ||
|
|
ae94c11a78 | ||
|
|
a29a365beb | ||
|
|
ba9ec71dba | ||
|
|
ee4e1d997b | ||
|
|
1327d81dd7 | ||
|
|
6ceaee2c9f | ||
|
|
502cc3900e | ||
|
|
2947acb77c | ||
|
|
a4d8929a7e | ||
|
|
e80519dc71 | ||
|
|
53f9958b25 | ||
|
|
a925e020dc | ||
|
|
9512a389f3 | ||
|
|
7c987d7498 | ||
|
|
45d461c0ec | ||
|
|
d1877e1915 | ||
|
|
fa67df12a9 | ||
|
|
65dde57c1a | ||
|
|
6f4167fb01 | ||
|
|
8e37b46912 | ||
|
|
1e83d0a5a8 | ||
|
|
329b01c7af | ||
|
|
96f609d1f2 | ||
|
|
03b128aeff | ||
|
|
ab9a4cb58a | ||
|
|
6b21599def | ||
|
|
ca93145e76 | ||
|
|
a163ec3afa | ||
|
|
868a6303be | ||
|
|
759e82d403 | ||
|
|
ed0c768aaf | ||
|
|
e933ed782f | ||
|
|
69e5a0dbf1 | ||
|
|
c4d166d3bc | ||
|
|
9ae8e544cb | ||
|
|
94aef4526d | ||
|
|
aeece5a107 | ||
|
|
bdc4ee496f | ||
|
|
5f59ec2d01 | ||
|
|
a25e4f679e | ||
|
|
3876df9052 | ||
|
|
12f2ba251b | ||
|
|
e43a9b6974 | ||
|
|
9e2cb4363c | ||
|
|
b61cb29023 | ||
|
|
90d31b9403 | ||
|
|
4d22d0790d | ||
|
|
bffe4c2a3b | ||
|
|
dfdb0a6fe6 | ||
|
|
dd04e11094 | ||
|
|
5b029c66c5 | ||
|
|
760843b9e5 | ||
|
|
19ba15a783 | ||
|
|
70a3dae965 | ||
|
|
26d5409a87 | ||
|
|
2f3a7a981d | ||
|
|
6a74c46e1c | ||
|
|
bec382df87 | ||
|
|
78f69224be | ||
|
|
34682addb8 | ||
|
|
2c106d66a4 | ||
|
|
9c4fd63a4d | ||
|
|
d04c18ffce | ||
|
|
41fe6663d9 | ||
|
|
9f8612f34e |
@@ -24,15 +24,13 @@ schedules:
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-3
|
||||
- stable-4
|
||||
- cron: 0 11 * * 0
|
||||
displayName: Weekly (old stable branches)
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-1
|
||||
- stable-2
|
||||
- stable-3
|
||||
|
||||
variables:
|
||||
- name: checkoutPath
|
||||
@@ -225,12 +223,12 @@ stages:
|
||||
test: macos/12.0
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
- name: RHEL 8.5
|
||||
test: rhel/8.5
|
||||
- name: RHEL 9.0
|
||||
test: rhel/9.0
|
||||
- name: FreeBSD 12.3
|
||||
test: freebsd/12.3
|
||||
- name: FreeBSD 13.0
|
||||
test: freebsd/13.0
|
||||
- name: FreeBSD 13.1
|
||||
test: freebsd/13.1
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -280,8 +278,8 @@ stages:
|
||||
test: rhel/7.9
|
||||
- name: RHEL 8.3
|
||||
test: rhel/8.3
|
||||
- name: FreeBSD 12.2
|
||||
test: freebsd/12.2
|
||||
#- name: FreeBSD 12.2
|
||||
# test: freebsd/12.2
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -312,8 +310,8 @@ stages:
|
||||
test: rhel/8.2
|
||||
- name: RHEL 7.8
|
||||
test: rhel/7.8
|
||||
- name: FreeBSD 12.0
|
||||
test: freebsd/12.0
|
||||
#- name: FreeBSD 12.0
|
||||
# test: freebsd/12.0
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -329,16 +327,16 @@ stages:
|
||||
targets:
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: Fedora 35
|
||||
test: fedora35
|
||||
- name: Fedora 36
|
||||
test: fedora36
|
||||
- name: openSUSE 15
|
||||
test: opensuse15
|
||||
- name: Ubuntu 18.04
|
||||
test: ubuntu1804
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- name: Alpine 3
|
||||
test: alpine3
|
||||
groups:
|
||||
@@ -375,8 +373,8 @@ stages:
|
||||
test: centos6
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 18.04
|
||||
test: ubuntu1804
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
|
||||
40
.github/BOTMETA.yml
vendored
40
.github/BOTMETA.yml
vendored
@@ -126,15 +126,23 @@ files:
|
||||
maintainers: giner
|
||||
$filters/from_csv.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/groupby:
|
||||
$filters/groupby.py:
|
||||
maintainers: felixfontein
|
||||
$filters/hashids:
|
||||
$filters/groupby_as_dict.yml:
|
||||
maintainers: felixfontein
|
||||
$filters/hashids.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/hashids_decode.yml:
|
||||
maintainers: Ajpantuso
|
||||
$filters/hashids_encode.yml:
|
||||
maintainers: Ajpantuso
|
||||
$filters/jc.py:
|
||||
maintainers: kellyjonbrazil
|
||||
$filters/json_query.py: {}
|
||||
$filters/list.py:
|
||||
maintainers: vbotka
|
||||
$filters/lists_mergeby.yml:
|
||||
maintainers: vbotka
|
||||
$filters/path_join_shim.py:
|
||||
maintainers: felixfontein
|
||||
$filters/random_mac.py: {}
|
||||
@@ -142,6 +150,24 @@ files:
|
||||
maintainers: resmo
|
||||
$filters/unicode_normalize.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/to_days.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_hours.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_milliseconds.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_minutes.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_months.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_seconds.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_time_unit.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_weeks.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_years.yml:
|
||||
maintainers: resmo
|
||||
$filters/version_sort.py:
|
||||
maintainers: ericzolf
|
||||
$inventories/:
|
||||
@@ -260,6 +286,8 @@ files:
|
||||
$module_utils/module_helper.py:
|
||||
maintainers: russoz
|
||||
labels: module_helper
|
||||
$module_utils/net_tools/pritunl/:
|
||||
maintainers: Lowess
|
||||
$module_utils/oracle/oci_utils.py:
|
||||
maintainers: $team_oracle
|
||||
labels: cloud
|
||||
@@ -310,6 +338,8 @@ files:
|
||||
ignore: hnakamur
|
||||
$modules/cloud/lxd/lxd_profile.py:
|
||||
maintainers: conloos
|
||||
$modules/cloud/lxd/lxd_project.py:
|
||||
maintainers: we10710aa
|
||||
$modules/cloud/memset/:
|
||||
maintainers: glitchcrab
|
||||
$modules/cloud/misc/cloud_init_data_facts.py:
|
||||
@@ -558,6 +588,8 @@ files:
|
||||
maintainers: phumpal
|
||||
labels: airbrake_deployment
|
||||
ignore: bpennypacker
|
||||
$modules/monitoring/alerta_customer.py:
|
||||
maintainers: cwollinger
|
||||
$modules/monitoring/bigpanda.py:
|
||||
maintainers: hkariti
|
||||
$modules/monitoring/circonus_annotation.py:
|
||||
@@ -589,7 +621,7 @@ files:
|
||||
$modules/monitoring/nagios.py:
|
||||
maintainers: tbielawa tgoetheyn
|
||||
$modules/monitoring/newrelic_deployment.py:
|
||||
maintainers: mcodd
|
||||
ignore: mcodd
|
||||
$modules/monitoring/pagerduty.py:
|
||||
maintainers: suprememoocow thaumos
|
||||
labels: pagerduty
|
||||
@@ -681,7 +713,7 @@ files:
|
||||
$modules/notification/discord.py:
|
||||
maintainers: cwollinger
|
||||
$modules/notification/flowdock.py:
|
||||
maintainers: mcodd
|
||||
ignore: mcodd
|
||||
$modules/notification/grove.py:
|
||||
maintainers: zimbatm
|
||||
$modules/notification/hipchat.py:
|
||||
|
||||
104
.gitignore
vendored
104
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/vim,git,macos,linux,pydev,emacs,dotenv,python,windows,webstorm,pycharm+all,jupyternotebooks
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,git,macos,linux,pydev,emacs,dotenv,python,windows,webstorm,pycharm+all,jupyternotebooks
|
||||
|
||||
### dotenv ###
|
||||
.env
|
||||
@@ -71,7 +71,19 @@ flycheck_*.el
|
||||
*_LOCAL_*.txt
|
||||
*_REMOTE_*.txt
|
||||
|
||||
#!! ERROR: jupyternotebook is undefined. Use list command to see defined gitignore types !!#
|
||||
### JupyterNotebooks ###
|
||||
# gitignore template for Jupyter Notebooks
|
||||
# website: http://jupyter.org/
|
||||
|
||||
.ipynb_checkpoints
|
||||
*/.ipynb_checkpoints/*
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# Remove previous ipynb_checkpoints
|
||||
# git rm -r .ipynb_checkpoints/
|
||||
|
||||
### Linux ###
|
||||
|
||||
@@ -87,6 +99,39 @@ flycheck_*.el
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### PyCharm+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
@@ -151,6 +196,9 @@ atlassian-ide-plugin.xml
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
@@ -164,20 +212,13 @@ fabric.properties
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### PyCharm+all Patch ###
|
||||
# Ignores the whole .idea folder and all .iml files
|
||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||
# Ignore everything but code style settings and run configurations
|
||||
# that are supposed to be shared within teams.
|
||||
|
||||
.idea/
|
||||
.idea/*
|
||||
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
modules.xml
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
!.idea/codeStyles
|
||||
!.idea/runConfigurations
|
||||
|
||||
### pydev ###
|
||||
.pydevproject
|
||||
@@ -260,16 +301,13 @@ docs/_build/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
.python-version
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
@@ -278,7 +316,22 @@ ipython_config.py
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
@@ -320,6 +373,13 @@ dmypy.json
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
### Vim ###
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
@@ -381,6 +441,8 @@ tags
|
||||
|
||||
# Cursive Clojure plugin
|
||||
|
||||
# SonarLint plugin
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
|
||||
# Editor-based Rest Client
|
||||
@@ -443,4 +505,4 @@ $RECYCLE.BIN/
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/git,linux,pydev,python,windows,pycharm+all,jupyternotebook,vim,webstorm,emacs,dotenv
|
||||
# End of https://www.toptal.com/developers/gitignore/api/vim,git,macos,linux,pydev,emacs,dotenv,python,windows,webstorm,pycharm+all,jupyternotebooks
|
||||
125
CHANGELOG.rst
125
CHANGELOG.rst
@@ -6,6 +6,131 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 3.0.0.
|
||||
|
||||
v4.8.2
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular maintenance and bugfix release.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Include ``simplified_bsd.txt`` license file for various module utils, the ``lxca_common`` docs fragment, and the ``utm_utils`` unit tests.
|
||||
- consul - fixed bug introduced in PR 4590 (https://github.com/ansible-collections/community.general/issues/4680).
|
||||
- filesystem - handle ``fatresize --info`` output lines without ``:`` (https://github.com/ansible-collections/community.general/pull/4700).
|
||||
- filesystem - improve error messages when output cannot be parsed by including newlines in escaped form (https://github.com/ansible-collections/community.general/pull/4700).
|
||||
- gitlab_hook - avoid errors during idempotency check when an attribute does not exist (https://github.com/ansible-collections/community.general/pull/4668).
|
||||
- keycloak_realm - fix default groups and roles (https://github.com/ansible-collections/community.general/issues/4241).
|
||||
- redis* modules - fix call to ``module.fail_json`` when failing because of missing Python libraries (https://github.com/ansible-collections/community.general/pull/4733).
|
||||
- xcc_redfish_command - for compatibility due to Redfish spec changes the virtualMedia resource location changed from Manager to System (https://github.com/ansible-collections/community.general/pull/4682).
|
||||
|
||||
v4.8.1
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix release. From now on, only bugfix release will be made of the community.general 4.x.y release stream.
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
|
||||
- consul - fixed bug where class ``ConsulService`` was overwriting the field ``checks``, preventing the addition of checks to a service (https://github.com/ansible-collections/community.general/pull/4590).
|
||||
- gconftool2 - properly escape values when passing them to ``gconftool-2`` (https://github.com/ansible-collections/community.general/pull/4647).
|
||||
- onepassword - search all valid configuration locations and use the first found (https://github.com/ansible-collections/community.general/pull/4640).
|
||||
- opentelemetry callback plugin - fix task message attribute that is reported failed regardless of the task result (https://github.com/ansible-collections/community.general/pull/4624).
|
||||
- opentelemetry callback plugin - fix warning for the include_tasks (https://github.com/ansible-collections/community.general/pull/4623).
|
||||
- terraform - fix list initialization to support both Python 2 and Python 3 (https://github.com/ansible-collections/community.general/issues/4531).
|
||||
|
||||
v4.8.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular feature and bugfix release. Please note that this is the last minor 4.x.0 release. Further releases with major version 4 will be bugfix releases 4.8.y.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- alternatives - add ``state`` parameter, which provides control over whether the alternative should be set as the active selection for its alternatives group (https://github.com/ansible-collections/community.general/issues/4543, https://github.com/ansible-collections/community.general/pull/4557).
|
||||
- atomic_container - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- clc_alert_policy - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_group - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_loadbalancer - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_server - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- cmd_runner module util - reusable command runner with consistent argument formatting and sensible defaults (https://github.com/ansible-collections/community.general/pull/4476).
|
||||
- datadog_monitor - support new datadog event monitor of type `event-v2 alert` (https://github.com/ansible-collections/community.general/pull/4457)
|
||||
- filesystem - add support for resizing btrfs (https://github.com/ansible-collections/community.general/issues/4465).
|
||||
- lxd_container - adds ``project`` option to allow selecting project for LXD instance (https://github.com/ansible-collections/community.general/pull/4479).
|
||||
- lxd_profile - adds ``project`` option to allow selecting project for LXD profile (https://github.com/ansible-collections/community.general/pull/4479).
|
||||
- nmap inventory plugin - add ``sudo`` option in plugin in order to execute ``sudo nmap`` so that ``nmap`` runs with elevated privileges (https://github.com/ansible-collections/community.general/pull/4506).
|
||||
- nomad_job - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- nomad_job_info - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_device - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_sshkey - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_volume - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- profitbricks - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- proxmox - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- proxmox inventory plugin - add token authentication as an alternative to username/password (https://github.com/ansible-collections/community.general/pull/4540).
|
||||
- proxmox inventory plugin - parse LXC configs returned by the proxmox API (https://github.com/ansible-collections/community.general/pull/4472).
|
||||
- proxmox_snap - add restore snapshot option (https://github.com/ansible-collections/community.general/pull/4377).
|
||||
- proxmox_snap - fixed timeout value to correctly reflect time in seconds. The timeout was off by one second (https://github.com/ansible-collections/community.general/pull/4377).
|
||||
- redfish_command - add ``IndicatorLedOn``, ``IndicatorLedOff``, and ``IndicatorLedBlink`` commands to the Systems category for controling system LEDs (https://github.com/ansible-collections/community.general/issues/4084).
|
||||
- seport - minor refactoring (https://github.com/ansible-collections/community.general/pull/4471).
|
||||
- smartos_image_info - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- terraform - adds ``terraform_upgrade`` parameter which allows ``terraform init`` to satisfy new provider constraints in an existing Terraform project (https://github.com/ansible-collections/community.general/issues/4333).
|
||||
- udm_group - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- udm_share - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- vmadm - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- webfaction_app - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- webfaction_db - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- xfconf - added missing value types ``char``, ``uchar``, ``int64`` and ``uint64`` (https://github.com/ansible-collections/community.general/pull/4534).
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
- nmcli - deprecate default hairpin mode for a bridge. This so we can change it to ``false`` in community.general 7.0.0, as this is also the default in ``nmcli`` (https://github.com/ansible-collections/community.general/pull/4334).
|
||||
- proxmox inventory plugin - the current default ``true`` of the ``want_proxmox_nodes_ansible_host`` option has been deprecated. The default will change to ``false`` in community.general 6.0.0. To keep the current behavior, explicitly set ``want_proxmox_nodes_ansible_host`` to ``true`` in your inventory configuration. We suggest to already switch to the new behavior by explicitly setting it to ``false``, and by using ``compose:`` to set ``ansible_host`` to the correct value. See the examples in the plugin documentation for details (https://github.com/ansible-collections/community.general/pull/4466).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- dnsmadeeasy - fix failure on deleting DNS entries when API response does not contain monitor value (https://github.com/ansible-collections/community.general/issues/3620).
|
||||
- git_branch - remove deprecated and unnecessary branch ``unprotect`` method (https://github.com/ansible-collections/community.general/pull/4496).
|
||||
- gitlab_group - improve searching for projects inside group on deletion (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
- gitlab_group_members - handle more than 20 groups when finding a group (https://github.com/ansible-collections/community.general/pull/4491, https://github.com/ansible-collections/community.general/issues/4460, https://github.com/ansible-collections/community.general/issues/3729).
|
||||
- gitlab_hook - handle more than 20 hooks when finding a hook (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
- gitlab_project - handle more than 20 namespaces when finding a namespace (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
- gitlab_project_members - handle more than 20 projects and users when finding a project resp. user (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
- gitlab_user - handle more than 20 users and SSH keys when finding a user resp. SSH key (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
- keycloak - fix parameters types for ``defaultDefaultClientScopes`` and ``defaultOptionalClientScopes`` from list of dictionaries to list of strings (https://github.com/ansible-collections/community.general/pull/4526).
|
||||
- opennebula inventory plugin - complete the implementation of ``constructable`` for opennebula inventory plugin. Now ``keyed_groups``, ``compose``, ``groups`` actually work (https://github.com/ansible-collections/community.general/issues/4497).
|
||||
- pacman - fixed bug where ``absent`` state did not work for locally installed packages (https://github.com/ansible-collections/community.general/pull/4464).
|
||||
- pritunl - fixed bug where pritunl plugin api add unneeded data in ``auth_string`` parameter (https://github.com/ansible-collections/community.general/issues/4527).
|
||||
- proxmox inventory plugin - fix error when parsing container with LXC configs (https://github.com/ansible-collections/community.general/issues/4472, https://github.com/ansible-collections/community.general/pull/4472).
|
||||
- proxmox_kvm - fix a bug when getting a state of VM without name will fail (https://github.com/ansible-collections/community.general/pull/4508).
|
||||
- xbps - fix error message that is reported when installing packages fails (https://github.com/ansible-collections/community.general/pull/4438).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
Cloud
|
||||
~~~~~
|
||||
|
||||
lxd
|
||||
^^^
|
||||
|
||||
- lxd_project - Manage LXD projects
|
||||
|
||||
Monitoring
|
||||
~~~~~~~~~~
|
||||
|
||||
- alerta_customer - Manage customers in Alerta
|
||||
|
||||
v4.7.0
|
||||
======
|
||||
|
||||
|
||||
48
PSF-license.txt
Normal file
48
PSF-license.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
|
||||
All Rights Reserved" are retained in Python alone or in any derivative version
|
||||
prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
@@ -1641,3 +1641,197 @@ releases:
|
||||
- 4422-warn-user-if-incorrect-SDK-version-is-installed.yaml
|
||||
- 4429-keycloak-client-add-always-display-in-console.yml
|
||||
release_date: '2022-04-05'
|
||||
4.8.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- dnsmadeeasy - fix failure on deleting DNS entries when API response does not
|
||||
contain monitor value (https://github.com/ansible-collections/community.general/issues/3620).
|
||||
- git_branch - remove deprecated and unnecessary branch ``unprotect`` method
|
||||
(https://github.com/ansible-collections/community.general/pull/4496).
|
||||
- 'gitlab_group - improve searching for projects inside group on deletion (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
|
||||
'
|
||||
- 'gitlab_group_members - handle more than 20 groups when finding a group (https://github.com/ansible-collections/community.general/pull/4491,
|
||||
https://github.com/ansible-collections/community.general/issues/4460, https://github.com/ansible-collections/community.general/issues/3729).
|
||||
|
||||
'
|
||||
- 'gitlab_hook - handle more than 20 hooks when finding a hook (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
|
||||
'
|
||||
- 'gitlab_project - handle more than 20 namespaces when finding a namespace
|
||||
(https://github.com/ansible-collections/community.general/pull/4491).
|
||||
|
||||
'
|
||||
- 'gitlab_project_members - handle more than 20 projects and users when finding
|
||||
a project resp. user (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
|
||||
'
|
||||
- 'gitlab_user - handle more than 20 users and SSH keys when finding a user
|
||||
resp. SSH key (https://github.com/ansible-collections/community.general/pull/4491).
|
||||
|
||||
'
|
||||
- keycloak - fix parameters types for ``defaultDefaultClientScopes`` and ``defaultOptionalClientScopes``
|
||||
from list of dictionaries to list of strings (https://github.com/ansible-collections/community.general/pull/4526).
|
||||
- opennebula inventory plugin - complete the implementation of ``constructable``
|
||||
for opennebula inventory plugin. Now ``keyed_groups``, ``compose``, ``groups``
|
||||
actually work (https://github.com/ansible-collections/community.general/issues/4497).
|
||||
- pacman - fixed bug where ``absent`` state did not work for locally installed
|
||||
packages (https://github.com/ansible-collections/community.general/pull/4464).
|
||||
- pritunl - fixed bug where pritunl plugin api add unneeded data in ``auth_string``
|
||||
parameter (https://github.com/ansible-collections/community.general/issues/4527).
|
||||
- proxmox inventory plugin - fix error when parsing container with LXC configs
|
||||
(https://github.com/ansible-collections/community.general/issues/4472, https://github.com/ansible-collections/community.general/pull/4472).
|
||||
- proxmox_kvm - fix a bug when getting a state of VM without name will fail
|
||||
(https://github.com/ansible-collections/community.general/pull/4508).
|
||||
- xbps - fix error message that is reported when installing packages fails (https://github.com/ansible-collections/community.general/pull/4438).
|
||||
deprecated_features:
|
||||
- nmcli - deprecate default hairpin mode for a bridge. This so we can change
|
||||
it to ``false`` in community.general 7.0.0, as this is also the default in
|
||||
``nmcli`` (https://github.com/ansible-collections/community.general/pull/4334).
|
||||
- proxmox inventory plugin - the current default ``true`` of the ``want_proxmox_nodes_ansible_host``
|
||||
option has been deprecated. The default will change to ``false`` in community.general
|
||||
6.0.0. To keep the current behavior, explicitly set ``want_proxmox_nodes_ansible_host``
|
||||
to ``true`` in your inventory configuration. We suggest to already switch
|
||||
to the new behavior by explicitly setting it to ``false``, and by using ``compose:``
|
||||
to set ``ansible_host`` to the correct value. See the examples in the plugin
|
||||
documentation for details (https://github.com/ansible-collections/community.general/pull/4466).
|
||||
minor_changes:
|
||||
- alternatives - add ``state`` parameter, which provides control over whether
|
||||
the alternative should be set as the active selection for its alternatives
|
||||
group (https://github.com/ansible-collections/community.general/issues/4543,
|
||||
https://github.com/ansible-collections/community.general/pull/4557).
|
||||
- atomic_container - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- clc_alert_policy - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_group - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_loadbalancer - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- clc_server - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- cmd_runner module util - reusable command runner with consistent argument
|
||||
formatting and sensible defaults (https://github.com/ansible-collections/community.general/pull/4476).
|
||||
- datadog_monitor - support new datadog event monitor of type `event-v2 alert`
|
||||
(https://github.com/ansible-collections/community.general/pull/4457)
|
||||
- filesystem - add support for resizing btrfs (https://github.com/ansible-collections/community.general/issues/4465).
|
||||
- lxd_container - adds ``project`` option to allow selecting project for LXD
|
||||
instance (https://github.com/ansible-collections/community.general/pull/4479).
|
||||
- lxd_profile - adds ``project`` option to allow selecting project for LXD profile
|
||||
(https://github.com/ansible-collections/community.general/pull/4479).
|
||||
- nmap inventory plugin - add ``sudo`` option in plugin in order to execute
|
||||
``sudo nmap`` so that ``nmap`` runs with elevated privileges (https://github.com/ansible-collections/community.general/pull/4506).
|
||||
- nomad_job - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- nomad_job_info - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_device - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_sshkey - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- packet_volume - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- profitbricks - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- proxmox - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- proxmox inventory plugin - add token authentication as an alternative to username/password
|
||||
(https://github.com/ansible-collections/community.general/pull/4540).
|
||||
- proxmox inventory plugin - parse LXC configs returned by the proxmox API (https://github.com/ansible-collections/community.general/pull/4472).
|
||||
- proxmox_snap - add restore snapshot option (https://github.com/ansible-collections/community.general/pull/4377).
|
||||
- proxmox_snap - fixed timeout value to correctly reflect time in seconds. The
|
||||
timeout was off by one second (https://github.com/ansible-collections/community.general/pull/4377).
|
||||
- redfish_command - add ``IndicatorLedOn``, ``IndicatorLedOff``, and ``IndicatorLedBlink``
|
||||
commands to the Systems category for controling system LEDs (https://github.com/ansible-collections/community.general/issues/4084).
|
||||
- seport - minor refactoring (https://github.com/ansible-collections/community.general/pull/4471).
|
||||
- smartos_image_info - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- terraform - adds ``terraform_upgrade`` parameter which allows ``terraform
|
||||
init`` to satisfy new provider constraints in an existing Terraform project
|
||||
(https://github.com/ansible-collections/community.general/issues/4333).
|
||||
- udm_group - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- udm_share - minor refactoring (https://github.com/ansible-collections/community.general/pull/4556).
|
||||
- vmadm - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- webfaction_app - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- webfaction_db - minor refactoring (https://github.com/ansible-collections/community.general/pull/4567).
|
||||
- xfconf - added missing value types ``char``, ``uchar``, ``int64`` and ``uint64``
|
||||
(https://github.com/ansible-collections/community.general/pull/4534).
|
||||
release_summary: Regular feature and bugfix release. Please note that this is
|
||||
the last minor 4.x.0 release. Further releases with major version 4 will be
|
||||
bugfix releases 4.8.y.
|
||||
fragments:
|
||||
- 4.8.0.yml
|
||||
- 4084-add-redfish-system-indicator-led.yml
|
||||
- 4320-nmcli-hairpin.yml
|
||||
- 4377-allow-proxmox-snapshot-restoring.yml
|
||||
- 4438-fix-error-message.yaml
|
||||
- 4455-terraform-provider-upgrade.yml
|
||||
- 4457-support-datadog-monitors-type-event-v2.yaml
|
||||
- 4459-only-get-monitor-if-it-is-not-null-api-response.yaml
|
||||
- 4464-pacman-fix-local-remove.yaml
|
||||
- 4465-btrfs-resize.yml
|
||||
- 4466-proxmox-ansible_host-deprecation.yml
|
||||
- 4471-seport-refactor.yaml
|
||||
- 4476-cmd_runner.yml
|
||||
- 4479-add-project-support-for-lxd_container-and-lxd_profile.yml
|
||||
- 4491-specify_all_in_list_calls.yaml
|
||||
- 4492-proxmox_kvm_fix_vm_without_name.yaml
|
||||
- 4496-remove-deprecated-method-in-gitlab-branch-module.yml
|
||||
- 4506-sudo-in-nmap-inv-plugin.yaml
|
||||
- 4524-update-opennebula-inventory-plugin-to-match-documentation.yaml
|
||||
- 4526-keycloak-realm-types.yaml
|
||||
- 4530-fix-unauthorized-pritunl-request.yaml
|
||||
- 4534-xfconf-added-value-types.yaml
|
||||
- 4540-proxmox-inventory-token-auth.yml
|
||||
- 4555-proxmox-lxc-key.yml
|
||||
- 4556-remove-default-none-1.yml
|
||||
- 4557-alternatives-add-state-parameter.yml
|
||||
- 4567-remove-default-none-2.yml
|
||||
modules:
|
||||
- description: Manage customers in Alerta
|
||||
name: alerta_customer
|
||||
namespace: monitoring
|
||||
- description: Manage LXD projects
|
||||
name: lxd_project
|
||||
namespace: cloud.lxd
|
||||
release_date: '2022-04-26'
|
||||
4.8.1:
|
||||
changes:
|
||||
bugfixes:
|
||||
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
|
||||
- consul - fixed bug where class ``ConsulService`` was overwriting the field
|
||||
``checks``, preventing the addition of checks to a service (https://github.com/ansible-collections/community.general/pull/4590).
|
||||
- gconftool2 - properly escape values when passing them to ``gconftool-2`` (https://github.com/ansible-collections/community.general/pull/4647).
|
||||
- onepassword - search all valid configuration locations and use the first found
|
||||
(https://github.com/ansible-collections/community.general/pull/4640).
|
||||
- opentelemetry callback plugin - fix task message attribute that is reported
|
||||
failed regardless of the task result (https://github.com/ansible-collections/community.general/pull/4624).
|
||||
- opentelemetry callback plugin - fix warning for the include_tasks (https://github.com/ansible-collections/community.general/pull/4623).
|
||||
- terraform - fix list initialization to support both Python 2 and Python 3
|
||||
(https://github.com/ansible-collections/community.general/issues/4531).
|
||||
release_summary: Regular bugfix release. From now on, only bugfix release will
|
||||
be made of the community.general 4.x.y release stream.
|
||||
fragments:
|
||||
- 4.8.1.yml
|
||||
- 4065-onepassword-config.yml
|
||||
- 4590-consul-fix-service-checks.yaml
|
||||
- 4621-terraform-py2-compat.yml
|
||||
- 4623-opentelemetry_bug_fix_include_tasks.yml
|
||||
- 4624-opentelemetry_bug_fix_hardcoded_value.yml
|
||||
- 4647-gconftool2-command-arg.yaml
|
||||
- psf-license.yml
|
||||
release_date: '2022-05-16'
|
||||
4.8.2:
|
||||
changes:
|
||||
bugfixes:
|
||||
- Include ``simplified_bsd.txt`` license file for various module utils, the
|
||||
``lxca_common`` docs fragment, and the ``utm_utils`` unit tests.
|
||||
- consul - fixed bug introduced in PR 4590 (https://github.com/ansible-collections/community.general/issues/4680).
|
||||
- filesystem - handle ``fatresize --info`` output lines without ``:`` (https://github.com/ansible-collections/community.general/pull/4700).
|
||||
- filesystem - improve error messages when output cannot be parsed by including
|
||||
newlines in escaped form (https://github.com/ansible-collections/community.general/pull/4700).
|
||||
- gitlab_hook - avoid errors during idempotency check when an attribute does
|
||||
not exist (https://github.com/ansible-collections/community.general/pull/4668).
|
||||
- keycloak_realm - fix default groups and roles (https://github.com/ansible-collections/community.general/issues/4241).
|
||||
- redis* modules - fix call to ``module.fail_json`` when failing because of
|
||||
missing Python libraries (https://github.com/ansible-collections/community.general/pull/4733).
|
||||
- xcc_redfish_command - for compatibility due to Redfish spec changes the virtualMedia
|
||||
resource location changed from Manager to System (https://github.com/ansible-collections/community.general/pull/4682).
|
||||
release_summary: Regular maintenance and bugfix release.
|
||||
fragments:
|
||||
- 4.8.2.yml
|
||||
- 4668-gitlab_hook-use-None-for-non-existent-attr.yml
|
||||
- 4682-compatibility-virtualmedia-resource-location.yaml
|
||||
- 4700-code-changes.yml
|
||||
- 4712-consul-bugfix.yaml
|
||||
- 4719-fix-keycloak-realm.yaml
|
||||
- 4733-redis-fail.yml
|
||||
- simplified-bsd-license.yml
|
||||
release_date: '2022-06-06'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace: community
|
||||
name: general
|
||||
version: 4.7.0
|
||||
version: 4.8.2
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -45,7 +45,7 @@ DOCUMENTATION = r'''
|
||||
version_added: 1.0.0
|
||||
default: ansible
|
||||
pre_command:
|
||||
description: Executes command before run and result put to ansible_pre_command_output field.
|
||||
description: Executes command before run and its result is added to the C(ansible_pre_command_output) logstash field.
|
||||
version_added: 2.0.0
|
||||
ini:
|
||||
- section: callback_logstash
|
||||
|
||||
@@ -197,7 +197,7 @@ class OpenTelemetrySource(object):
|
||||
|
||||
task = tasks_data[task_uuid]
|
||||
|
||||
if self.ansible_version is None and result._task_fields['args'].get('_ansible_version'):
|
||||
if self.ansible_version is None and hasattr(result, '_task_fields') and result._task_fields['args'].get('_ansible_version'):
|
||||
self.ansible_version = result._task_fields['args'].get('_ansible_version')
|
||||
|
||||
task.add_host(HostData(host_uuid, host_name, status, result))
|
||||
@@ -258,8 +258,9 @@ class OpenTelemetrySource(object):
|
||||
else:
|
||||
res = host_data.result._result
|
||||
rc = res.get('rc', 0)
|
||||
message = self.get_error_message(res)
|
||||
enriched_error_message = self.enrich_error_message(res)
|
||||
if host_data.status == 'failed':
|
||||
message = self.get_error_message(res)
|
||||
enriched_error_message = self.enrich_error_message(res)
|
||||
|
||||
if host_data.status == 'failed':
|
||||
status = Status(status_code=StatusCode.ERROR, description=message)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -5,6 +5,35 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: counter
|
||||
short_description: Counts hashable elements in a sequence
|
||||
version_added: 4.3.0
|
||||
author: Rémy Keil (@keilr)
|
||||
description:
|
||||
- Counts hashable elements in a sequence.
|
||||
options:
|
||||
_input:
|
||||
description: A sequence.
|
||||
type: list
|
||||
elements: any
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Count occurences
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ [1, 'a', 2, 2, 'a', 'b', 'a'] | community.general.counter }}
|
||||
# Produces: {1: 1, 'a': 3, 2: 2, 'b': 1}
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: A dictionary with the elements of the sequence as keys, and their number of occurance in the sequence as values.
|
||||
type: dictionary
|
||||
'''
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common._collections_compat import Sequence
|
||||
from collections import Counter
|
||||
|
||||
@@ -6,6 +6,60 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: dict
|
||||
short_description: Convert a list of tuples into a dictionary
|
||||
version_added: 3.0.0
|
||||
author: Felix Fontein (@felixfontein)
|
||||
description:
|
||||
- Convert a list of tuples into a dictionary. This is a filter version of the C(dict) function.
|
||||
options:
|
||||
_input:
|
||||
description: A list of tuples (with exactly two elements).
|
||||
type: list
|
||||
elements: tuple
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Convert list of tuples into dictionary
|
||||
ansible.builtin.set_fact:
|
||||
dictionary: "{{ [[1, 2], ['a', 'b']] | community.general.dict }}"
|
||||
# Result is {1: 2, 'a': 'b'}
|
||||
|
||||
- name: Create a list of dictionaries with map and the community.general.dict filter
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ values | map('zip', ['k1', 'k2', 'k3'])
|
||||
| map('map', 'reverse')
|
||||
| map('community.general.dict') }}
|
||||
vars:
|
||||
values:
|
||||
- - foo
|
||||
- 23
|
||||
- a
|
||||
- - bar
|
||||
- 42
|
||||
- b
|
||||
# Produces the following list of dictionaries:
|
||||
# {
|
||||
# "k1": "foo",
|
||||
# "k2": 23,
|
||||
# "k3": "a"
|
||||
# },
|
||||
# {
|
||||
# "k1": "bar",
|
||||
# "k2": 42,
|
||||
# "k3": "b"
|
||||
# }
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The dictionary having the provided key-value pairs.
|
||||
type: boolean
|
||||
'''
|
||||
|
||||
|
||||
def dict_filter(sequence):
|
||||
'''Convert a list of tuples to a dictionary.
|
||||
|
||||
@@ -5,6 +5,38 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: dict_kv
|
||||
short_description: Convert a value to a dictionary with a single key-value pair
|
||||
version_added: 1.3.0
|
||||
author: Stanislav German-Evtushenko (@giner)
|
||||
description:
|
||||
- Convert a value to a dictionary with a single key-value pair.
|
||||
positional: key
|
||||
options:
|
||||
_input:
|
||||
description: The value for the single key-value pair.
|
||||
type: any
|
||||
required: true
|
||||
key:
|
||||
description: The key for the single key-value pair.
|
||||
type: any
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a one-element dictionary from a value
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ 'myvalue' | dict_kv('mykey') }}"
|
||||
# Produces the dictionary {'mykey': 'myvalue'}
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: A dictionary with a single key-value pair.
|
||||
type: dictionary
|
||||
'''
|
||||
|
||||
|
||||
def dict_kv(value, key):
|
||||
'''Return a dictionary with a single key-value pair
|
||||
|
||||
@@ -7,6 +7,78 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: from_csv
|
||||
short_description: Converts CSV text input into list of dicts
|
||||
version_added: 2.3.0
|
||||
author: Andrew Pantuso (@Ajpantuso)
|
||||
description:
|
||||
- Converts CSV text input into list of dictionaries.
|
||||
options:
|
||||
_input:
|
||||
description: A string containing a CSV document.
|
||||
type: string
|
||||
required: true
|
||||
dialect:
|
||||
description:
|
||||
- The CSV dialect to use when parsing the CSV file.
|
||||
- Possible values include C(excel), C(excel-tab) or C(unix).
|
||||
type: str
|
||||
default: excel
|
||||
fieldnames:
|
||||
description:
|
||||
- A list of field names for every column.
|
||||
- This is needed if the CSV does not have a header.
|
||||
type: list
|
||||
elements: str
|
||||
delimiter:
|
||||
description:
|
||||
- A one-character string used to separate fields.
|
||||
- When using this parameter, you change the default value used by I(dialect).
|
||||
- The default value depends on the dialect used.
|
||||
type: str
|
||||
skipinitialspace:
|
||||
description:
|
||||
- Whether to ignore any whitespaces immediately following the delimiter.
|
||||
- When using this parameter, you change the default value used by I(dialect).
|
||||
- The default value depends on the dialect used.
|
||||
type: bool
|
||||
strict:
|
||||
description:
|
||||
- Whether to raise an exception on bad CSV input.
|
||||
- When using this parameter, you change the default value used by I(dialect).
|
||||
- The default value depends on the dialect used.
|
||||
type: bool
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Parse a CSV file's contents
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ csv_data | community.genera.from_csv(dialect='unix') }}
|
||||
vars:
|
||||
csv_data: |
|
||||
Column 1,Value
|
||||
foo,23
|
||||
bar,42
|
||||
# Produces the following list of dictionaries:
|
||||
# {
|
||||
# "Column 1": "foo",
|
||||
# "Value": "23",
|
||||
# },
|
||||
# {
|
||||
# "Column 1": "bar",
|
||||
# "Value": "42",
|
||||
# }
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: A list with one dictionary per row.
|
||||
type: list
|
||||
elements: dictionary
|
||||
'''
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
42
plugins/filter/groupby_as_dict.yml
Normal file
42
plugins/filter/groupby_as_dict.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
DOCUMENTATION:
|
||||
name: groupby_as_dict
|
||||
short_description: Transform a sequence of dictionaries to a dictionary where the dictionaries are indexed by an attribute
|
||||
version_added: 3.1.0
|
||||
author: Felix Fontein (@felixfontein)
|
||||
description:
|
||||
- Transform a sequence of dictionaries to a dictionary where the dictionaries are indexed by an attribute.
|
||||
positional: attribute
|
||||
options:
|
||||
_input:
|
||||
description: A list of dictionaries
|
||||
type: list
|
||||
elements: dictionary
|
||||
required: true
|
||||
attribute:
|
||||
description: The attribute to use as the key.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Arrange a list of dictionaries as a dictionary of dictionaries
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ sequence | community.general.groupby_as_dict('key') }}"
|
||||
vars:
|
||||
sequence:
|
||||
- key: value
|
||||
foo: bar
|
||||
- key: other_value
|
||||
baz: bar
|
||||
# Produces the following nested structure:
|
||||
#
|
||||
# value:
|
||||
# key: value
|
||||
# foo: bar
|
||||
# other_value:
|
||||
# key: other_value
|
||||
# baz: bar
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: A dictionary containing the dictionaries from the list as values.
|
||||
type: dictionary
|
||||
38
plugins/filter/hashids_decode.yml
Normal file
38
plugins/filter/hashids_decode.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
DOCUMENTATION:
|
||||
name: hashids_decode
|
||||
short_description: Decodes a sequence of numbers from a YouTube-like hash
|
||||
version_added: 3.0.0
|
||||
author: Andrew Pantuso (@Ajpantuso)
|
||||
description:
|
||||
- Decodes a sequence of numbers from a YouTube-like hash.
|
||||
options:
|
||||
_input:
|
||||
description: A YouTube-like hash.
|
||||
type: string
|
||||
required: true
|
||||
salt:
|
||||
description:
|
||||
- String to use as salt when hashing.
|
||||
type: str
|
||||
default: excel
|
||||
alphabet:
|
||||
description:
|
||||
- String of 16 or more unique characters to produce a hash.
|
||||
type: list
|
||||
elements: str
|
||||
min_length:
|
||||
description:
|
||||
- Minimum length of hash produced.
|
||||
type: integer
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert hash to list of integers
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ 'o2fXhV' | community.general.hashids_decode }}"
|
||||
# Produces: [1, 2, 3]
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: A list of integers.
|
||||
type: list
|
||||
elements: integer
|
||||
38
plugins/filter/hashids_encode.yml
Normal file
38
plugins/filter/hashids_encode.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
DOCUMENTATION:
|
||||
name: hashids_encode
|
||||
short_description: Encodes YouTube-like hashes from a sequence of integers
|
||||
version_added: 3.0.0
|
||||
author: Andrew Pantuso (@Ajpantuso)
|
||||
description:
|
||||
- Encodes YouTube-like hashes from a sequence of integers.
|
||||
options:
|
||||
_input:
|
||||
description: A list of integers.
|
||||
type: list
|
||||
elements: integer
|
||||
required: true
|
||||
salt:
|
||||
description:
|
||||
- String to use as salt when hashing.
|
||||
type: str
|
||||
default: excel
|
||||
alphabet:
|
||||
description:
|
||||
- String of 16 or more unique characters to produce a hash.
|
||||
type: list
|
||||
elements: str
|
||||
min_length:
|
||||
description:
|
||||
- Minimum length of hash produced.
|
||||
type: integer
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert list of integers to hash
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ [1, 2, 3] | community.general.hashids_encode }}"
|
||||
# Produces: 'o2fXhV'
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: A YouTube-like hash.
|
||||
type: string
|
||||
@@ -21,6 +21,67 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: jc
|
||||
short_description: Convert output of many shell commands and file-types to JSON
|
||||
version_added: 1.1.0
|
||||
author: Kelly Brazil (@kellyjonbrazil)
|
||||
description:
|
||||
- Convert output of many shell commands and file-types to JSON.
|
||||
- Uses the L(jc library,https://github.com/kellyjonbrazil/jc).
|
||||
positional: parser
|
||||
options:
|
||||
_input:
|
||||
description: The data to convert.
|
||||
type: string
|
||||
required: true
|
||||
parser:
|
||||
description:
|
||||
- The correct parser for the input data.
|
||||
- For exmaple C(ifconfig).
|
||||
- See U(https://github.com/kellyjonbrazil/jc#parsers) for the latest list of parsers.
|
||||
type: string
|
||||
required: true
|
||||
quiet:
|
||||
description: Set to C(false) to not suppress warnings.
|
||||
type: boolean
|
||||
default: true
|
||||
raw:
|
||||
description: Set to C(true) to return pre-processed JSON.
|
||||
type: boolean
|
||||
default: false
|
||||
requirements:
|
||||
- jc (https://github.com/kellyjonbrazil/jc)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Run command
|
||||
ansible.builtin.command: uname -a
|
||||
register: result
|
||||
|
||||
- name: Convert command's result to JSON
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ result.stdout | community.general.jc('uname') }}"
|
||||
# Possible output:
|
||||
#
|
||||
# "msg": {
|
||||
# "hardware_platform": "x86_64",
|
||||
# "kernel_name": "Linux",
|
||||
# "kernel_release": "4.15.0-112-generic",
|
||||
# "kernel_version": "#113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020",
|
||||
# "machine": "x86_64",
|
||||
# "node_name": "kbrazil-ubuntu",
|
||||
# "operating_system": "GNU/Linux",
|
||||
# "processor": "x86_64"
|
||||
# }
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The processed output.
|
||||
type: any
|
||||
'''
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleFilterError
|
||||
import importlib
|
||||
|
||||
|
||||
@@ -19,6 +19,107 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: json_query
|
||||
short_description: Select a single element or a data subset from a complex data structure
|
||||
description:
|
||||
- This filter lets you query a complex JSON structure and iterate over it using a loop structure.
|
||||
positional: expr
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The JSON data to query.
|
||||
type: any
|
||||
required: true
|
||||
expr:
|
||||
description:
|
||||
- The query expression.
|
||||
- See U(http://jmespath.org/examples.html) for examples.
|
||||
type: string
|
||||
required: true
|
||||
requirements:
|
||||
- jmespath
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Define data to work on in the examples below
|
||||
ansible.builtin.set_fact:
|
||||
domain_definition:
|
||||
domain:
|
||||
cluster:
|
||||
- name: cluster1
|
||||
- name: cluster2
|
||||
server:
|
||||
- name: server11
|
||||
cluster: cluster1
|
||||
port: '8080'
|
||||
- name: server12
|
||||
cluster: cluster1
|
||||
port: '8090'
|
||||
- name: server21
|
||||
cluster: cluster2
|
||||
port: '9080'
|
||||
- name: server22
|
||||
cluster: cluster2
|
||||
port: '9090'
|
||||
library:
|
||||
- name: lib1
|
||||
target: cluster1
|
||||
- name: lib2
|
||||
target: cluster2
|
||||
|
||||
- name: Display all cluster names
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query('domain.cluster[*].name') }}"
|
||||
|
||||
- name: Display all server names
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query('domain.server[*].name') }}"
|
||||
|
||||
- name: Display all ports from cluster1
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
|
||||
vars:
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster1'].port"
|
||||
|
||||
- name: Display all ports from cluster1 as a string
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ domain_definition | community.general.json_query('domain.server[?cluster==`cluster1`].port') | join(', ') }}"
|
||||
|
||||
- name: Display all ports from cluster1
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query('domain.server[?cluster==''cluster1''].port') }}"
|
||||
|
||||
- name: Display all server ports and names from cluster1
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
loop: "{{ domain_definition | community.general.json_query(server_name_cluster1_query) }}"
|
||||
vars:
|
||||
server_name_cluster1_query: "domain.server[?cluster=='cluster2'].{name: name, port: port}"
|
||||
|
||||
- name: Display all ports from cluster1
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
|
||||
vars:
|
||||
server_name_query: "domain.server[?starts_with(name,'server1')].port"
|
||||
|
||||
- name: Display all ports from cluster1
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ domain_definition | to_json | from_json | community.general.json_query(server_name_query) }}"
|
||||
vars:
|
||||
server_name_query: "domain.server[?contains(name,'server1')].port"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The result of the query.
|
||||
type: any
|
||||
'''
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleFilterError
|
||||
|
||||
try:
|
||||
|
||||
88
plugins/filter/lists_mergeby.yml
Normal file
88
plugins/filter/lists_mergeby.yml
Normal file
@@ -0,0 +1,88 @@
|
||||
DOCUMENTATION:
|
||||
name: lists_mergeby
|
||||
short_description: Merge two or more lists of dictionaries by a given attribute
|
||||
version_added: 2.0.0
|
||||
author: Vladimir Botka (@vbotka)
|
||||
description:
|
||||
- Merge two or more lists by attribute I(index). Optional parameters 'recursive' and 'list_merge'
|
||||
control the merging of the lists in values. The function merge_hash from ansible.utils.vars
|
||||
is used. To learn details on how to use the parameters 'recursive' and 'list_merge' see
|
||||
Ansible User's Guide chapter "Using filters to manipulate data" section "Combining
|
||||
hashes/dictionaries".
|
||||
positional: another_list, index
|
||||
options:
|
||||
_input:
|
||||
description: A list of dictionaries.
|
||||
type: list
|
||||
elements: dictionary
|
||||
required: true
|
||||
another_list:
|
||||
description: Another list of dictionaries. This parameter can be specified multiple times.
|
||||
type: list
|
||||
elements: dictionary
|
||||
index:
|
||||
description:
|
||||
- The dictionary key that must be present in every dictionary in every list that is used to
|
||||
merge the lists.
|
||||
type: string
|
||||
required: true
|
||||
recursive:
|
||||
description:
|
||||
- Should the combine recursively merge nested dictionaries (hashes).
|
||||
- "B(Note:) It does not depend on the value of the C(hash_behaviour) setting in C(ansible.cfg)."
|
||||
type: boolean
|
||||
default: false
|
||||
list_merge:
|
||||
description:
|
||||
- Modifies the behaviour when the dictionaries (hashes) to merge contain arrays/lists.
|
||||
type: string
|
||||
default: replace
|
||||
choices:
|
||||
- replace
|
||||
- keep
|
||||
- append
|
||||
- prepend
|
||||
- append_rp
|
||||
- prepend_rp
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Merge two lists
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ list1 | community.general.lists_mergeby(
|
||||
list2,
|
||||
'index',
|
||||
recursive=True,
|
||||
list_merge='append'
|
||||
) }}"
|
||||
vars:
|
||||
list1:
|
||||
- index: a
|
||||
value: 123
|
||||
- index: b
|
||||
value: 42
|
||||
list2:
|
||||
- index: a
|
||||
foo: bar
|
||||
- index: c
|
||||
foo: baz
|
||||
# Produces the following list of dictionaries:
|
||||
# {
|
||||
# "index": "a",
|
||||
# "foo": "bar",
|
||||
# "value": 123
|
||||
# },
|
||||
# {
|
||||
# "index": "b",
|
||||
# "value": 42
|
||||
# },
|
||||
# {
|
||||
# "index": "c",
|
||||
# "foo": "baz"
|
||||
# }
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: The merged list.
|
||||
type: list
|
||||
elements: dictionary
|
||||
@@ -20,6 +20,41 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: random_mac
|
||||
short_description: Generate a random MAC address
|
||||
description:
|
||||
- Generates random networking interfaces MAC addresses for a given prefix.
|
||||
options:
|
||||
_input:
|
||||
description: A string prefix to use as a basis for the random MAC generated.
|
||||
type: string
|
||||
required: true
|
||||
seed:
|
||||
description:
|
||||
- A randomization seed to initialize the process, used to get repeatable results.
|
||||
- If no seed is provided, a system random source such as C(/dev/urandom) is used.
|
||||
required: false
|
||||
type: string
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Random MAC given a prefix
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '52:54:00' | community.general.random_mac }}"
|
||||
# => '52:54:00:ef:1c:03'
|
||||
|
||||
- name: With a seed
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}"
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The generated MAC.
|
||||
type: string
|
||||
'''
|
||||
|
||||
import re
|
||||
from random import Random, SystemRandom
|
||||
|
||||
|
||||
40
plugins/filter/to_days.yml
Normal file
40
plugins/filter/to_days.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_days
|
||||
short_description: Converte a duration string to days
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to days.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into days
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '1y 7m 5d 30h' | community.general.to_days }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of days.
|
||||
type: float
|
||||
40
plugins/filter/to_hours.yml
Normal file
40
plugins/filter/to_hours.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_hours
|
||||
short_description: Converte a duration string to hours
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to hours.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into hours
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '7d 30h 20m 10s 123ms' | community.general.to_hours }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of hours.
|
||||
type: float
|
||||
40
plugins/filter/to_milliseconds.yml
Normal file
40
plugins/filter/to_milliseconds.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_milliseconds
|
||||
short_description: Converte a duration string to milliseconds
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to milliseconds.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into milliseconds
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '30h 20m 10s 123ms' | community.general.to_milliseconds }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of milliseconds.
|
||||
type: float
|
||||
40
plugins/filter/to_minutes.yml
Normal file
40
plugins/filter/to_minutes.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_minutes
|
||||
short_description: Converte a duration string to minutes
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to minutes.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into minutes
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '30h 20m 10s 123ms' | community.general.to_minutes }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of minutes.
|
||||
type: float
|
||||
40
plugins/filter/to_months.yml
Normal file
40
plugins/filter/to_months.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_months
|
||||
short_description: Converte a duration string to months
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to months.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into months
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '1y 7m 5d 30h' | community.general.to_months }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of months.
|
||||
type: float
|
||||
40
plugins/filter/to_seconds.yml
Normal file
40
plugins/filter/to_seconds.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_seconds
|
||||
short_description: Converte a duration string to seconds
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to seconds.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into seconds
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '30h 20m 10s 123ms' | community.general.to_seconds }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of seconds.
|
||||
type: float
|
||||
84
plugins/filter/to_time_unit.yml
Normal file
84
plugins/filter/to_time_unit.yml
Normal file
@@ -0,0 +1,84 @@
|
||||
DOCUMENTATION:
|
||||
name: to_time_unit
|
||||
short_description: Converte a duration string to the given time unit
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to the given time unit.
|
||||
positional: unit
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
unit:
|
||||
description:
|
||||
- Time unit to convert the duration to.
|
||||
default: ms
|
||||
choices:
|
||||
- millisecond
|
||||
- milliseconds
|
||||
- ms
|
||||
- msec
|
||||
- msecs
|
||||
- msecond
|
||||
- mseconds
|
||||
- s
|
||||
- sec
|
||||
- secs
|
||||
- second
|
||||
- seconds
|
||||
- h
|
||||
- hour
|
||||
- hours
|
||||
- hs
|
||||
- m
|
||||
- min
|
||||
- mins
|
||||
- minute
|
||||
- minutes
|
||||
- d
|
||||
- ds
|
||||
- day
|
||||
- days
|
||||
- w
|
||||
- ws
|
||||
- week
|
||||
- weeks
|
||||
- mo
|
||||
- mos
|
||||
- month
|
||||
- months
|
||||
- y
|
||||
- ys
|
||||
- year
|
||||
- years
|
||||
type: string
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into seconds
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '1053d 17h 53m -10s 391ms' | community.general.to_time_unit('s') }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of time units.
|
||||
type: float
|
||||
40
plugins/filter/to_weeks.yml
Normal file
40
plugins/filter/to_weeks.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_weeks
|
||||
short_description: Converte a duration string to weeks
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to weeks.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into weeks
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '1y 7m 5d 30h' | community.general.to_weeks }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of weeks.
|
||||
type: float
|
||||
40
plugins/filter/to_years.yml
Normal file
40
plugins/filter/to_years.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
DOCUMENTATION:
|
||||
name: to_years
|
||||
short_description: Converte a duration string to years
|
||||
version_added: 0.2.0
|
||||
description:
|
||||
- Parse a human readable time duration string and convert to years.
|
||||
options:
|
||||
_input:
|
||||
description:
|
||||
- The time string to convert.
|
||||
- Can use the units C(y) and C(year) for a year, C(mo) and C(month) for a month, C(w) and C(week) for a week,
|
||||
C(d) and C(day) for a day, C(h) and C(hour) for a hour, C(m), C(min) and C(minute) for minutes, C(s), C(sec)
|
||||
and C(second) for seconds, C(ms), C(msec), C(msecond) and C(millisecond) for milliseconds. The suffix C(s)
|
||||
can be added to a unit as well, so C(seconds) is the same as C(second).
|
||||
- Valid strings are space separated combinations of an integer with an optional minus sign and a unit.
|
||||
- Examples are C(1h), C(-5m), and C(3h -5m 6s).
|
||||
type: string
|
||||
required: true
|
||||
year:
|
||||
description:
|
||||
- Number of days per year.
|
||||
default: 365
|
||||
type: float
|
||||
month:
|
||||
description:
|
||||
- Number of days per month.
|
||||
default: 30
|
||||
type: float
|
||||
author:
|
||||
- René Moser (@resmo)
|
||||
|
||||
EXAMPLES: |
|
||||
- name: Convert a duration into years
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ '1053d 30h' | community.general.to_years }}"
|
||||
|
||||
RETURN:
|
||||
_value:
|
||||
description: Number of years.
|
||||
type: float
|
||||
@@ -6,6 +6,46 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: unicode_normalize
|
||||
short_description: Normalizes unicode strings to facilitate comparison of characters with normalized forms
|
||||
version_added: 3.7.0
|
||||
author: Andrew Pantuso (@Ajpantuso)
|
||||
description:
|
||||
- Normalizes unicode strings to facilitate comparison of characters with normalized forms.
|
||||
positional: form
|
||||
options:
|
||||
_input:
|
||||
description: A unicode string.
|
||||
type: string
|
||||
required: true
|
||||
form:
|
||||
description:
|
||||
- The normal form to use.
|
||||
- See U(https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize) for details.
|
||||
type: string
|
||||
default: NFC
|
||||
choices:
|
||||
- NFC
|
||||
- NFD
|
||||
- NFKC
|
||||
- NFKD
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Normalize unicode string
|
||||
ansible.builtin.set_fact:
|
||||
dictionary: "{{ 'ä' | community.general.unicode_normalize('NFKD') }}"
|
||||
# The resulting string has length 2: one letter is 'a', the other
|
||||
# the diacritic combiner.
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The normalized unicode string of the specified normal form.
|
||||
type: string
|
||||
'''
|
||||
|
||||
from unicodedata import normalize
|
||||
|
||||
from ansible.errors import AnsibleFilterError, AnsibleFilterTypeError
|
||||
|
||||
@@ -5,6 +5,35 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: version_sort
|
||||
short_description: Sort a list according to version order instead of pure alphabetical one
|
||||
version_added: 2.2.0
|
||||
author: Eric L. (@ericzolf)
|
||||
description:
|
||||
- Sort a list according to version order instead of pure alphabetical one.
|
||||
options:
|
||||
_input:
|
||||
description: A list of strings to sort.
|
||||
type: list
|
||||
elements: string
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Convert list of tuples into dictionary
|
||||
ansible.builtin.set_fact:
|
||||
dictionary: "{{ ['2.1', '2.10', '2.9'] | community.general.version_sort }}"
|
||||
# Result is ['2.1', '2.9', '2.10']
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: The list of strings sorted by version.
|
||||
type: list
|
||||
elements: string
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@ DOCUMENTATION = '''
|
||||
description: token that ensures this is a source file for the 'nmap' plugin.
|
||||
required: True
|
||||
choices: ['nmap', 'community.general.nmap']
|
||||
sudo:
|
||||
description: Set to C(true) to execute a C(sudo nmap) plugin scan.
|
||||
version_added: 4.8.0
|
||||
default: false
|
||||
type: boolean
|
||||
address:
|
||||
description: Network IP or range of IPs to scan, you can use a simple range (10.2.2.15-25) or CIDR notation.
|
||||
required: True
|
||||
@@ -49,6 +54,13 @@ EXAMPLES = '''
|
||||
plugin: community.general.nmap
|
||||
strict: False
|
||||
address: 192.168.0.0/24
|
||||
|
||||
|
||||
# a sudo nmap scan to fully use nmap scan power.
|
||||
plugin: community.general.nmap
|
||||
sudo: true
|
||||
strict: False
|
||||
address: 192.168.0.0/24
|
||||
'''
|
||||
|
||||
import os
|
||||
@@ -135,6 +147,10 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
if not user_cache_setting or cache_needs_update:
|
||||
# setup command
|
||||
cmd = [self._nmap]
|
||||
|
||||
if self._options['sudo']:
|
||||
cmd.insert(0, 'sudo')
|
||||
|
||||
if not self._options['ports']:
|
||||
cmd.append('-sP')
|
||||
|
||||
|
||||
@@ -206,28 +206,40 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
def _populate(self):
|
||||
hostname_preference = self.get_option('hostname')
|
||||
group_by_labels = self.get_option('group_by_labels')
|
||||
strict = self.get_option('strict')
|
||||
|
||||
# Add a top group 'one'
|
||||
self.inventory.add_group(group='all')
|
||||
|
||||
filter_by_label = self.get_option('filter_by_label')
|
||||
for server in self._retrieve_servers(filter_by_label):
|
||||
servers = self._retrieve_servers(filter_by_label)
|
||||
for server in servers:
|
||||
hostname = server['name']
|
||||
# check for labels
|
||||
if group_by_labels and server['LABELS']:
|
||||
for label in server['LABELS']:
|
||||
self.inventory.add_group(group=label)
|
||||
self.inventory.add_host(host=server['name'], group=label)
|
||||
self.inventory.add_host(host=hostname, group=label)
|
||||
|
||||
self.inventory.add_host(host=server['name'], group='all')
|
||||
self.inventory.add_host(host=hostname, group='all')
|
||||
|
||||
for attribute, value in server.items():
|
||||
self.inventory.set_variable(server['name'], attribute, value)
|
||||
self.inventory.set_variable(hostname, attribute, value)
|
||||
|
||||
if hostname_preference != 'name':
|
||||
self.inventory.set_variable(server['name'], 'ansible_host', server[hostname_preference])
|
||||
self.inventory.set_variable(hostname, 'ansible_host', server[hostname_preference])
|
||||
|
||||
if server.get('SSH_PORT'):
|
||||
self.inventory.set_variable(server['name'], 'ansible_port', server['SSH_PORT'])
|
||||
self.inventory.set_variable(hostname, 'ansible_port', server['SSH_PORT'])
|
||||
|
||||
# handle construcable implementation: get composed variables if any
|
||||
self._set_composite_vars(self.get_option('compose'), server, hostname, strict=strict)
|
||||
|
||||
# groups based on jinja conditionals get added to specific groups
|
||||
self._add_host_to_composed_groups(self.get_option('groups'), server, hostname, strict=strict)
|
||||
|
||||
# groups based on variables associated with them in the inventory
|
||||
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), server, hostname, strict=strict)
|
||||
|
||||
def parse(self, inventory, loader, path, cache=True):
|
||||
if not HAS_PYONE:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Copyright (c) 2018 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
@@ -52,11 +53,32 @@ DOCUMENTATION = '''
|
||||
- Proxmox authentication password.
|
||||
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_PASSWORD) will be used instead.
|
||||
- Since community.general 4.7.0 you can also use templating to specify the value of the I(password).
|
||||
required: yes
|
||||
- If you do not specify a password, you must set I(token_id) and I(token_secret) instead.
|
||||
type: str
|
||||
env:
|
||||
- name: PROXMOX_PASSWORD
|
||||
version_added: 2.0.0
|
||||
token_id:
|
||||
description:
|
||||
- Proxmox authentication token ID.
|
||||
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_TOKEN_ID) will be used instead.
|
||||
- To use token authentication, you must also specify I(token_secret). If you do not specify I(token_id) and I(token_secret),
|
||||
you must set a password instead.
|
||||
- Make sure to grant explicit pve permissions to the token or disable 'privilege separation' to use the users' privileges instead.
|
||||
version_added: 4.8.0
|
||||
type: str
|
||||
env:
|
||||
- name: PROXMOX_TOKEN_ID
|
||||
token_secret:
|
||||
description:
|
||||
- Proxmox authentication token secret.
|
||||
- If the value is not specified in the inventory configuration, the value of environment variable C(PROXMOX_TOKEN_SECRET) will be used instead.
|
||||
- To use token authentication, you must also specify I(token_id). If you do not specify I(token_id) and I(token_secret),
|
||||
you must set a password instead.
|
||||
version_added: 4.8.0
|
||||
type: str
|
||||
env:
|
||||
- name: PROXMOX_TOKEN_SECRET
|
||||
validate_certs:
|
||||
description: Verify SSL certificate if using HTTPS.
|
||||
type: boolean
|
||||
@@ -78,7 +100,9 @@ DOCUMENTATION = '''
|
||||
description:
|
||||
- Whether to set C(ansbile_host) for proxmox nodes.
|
||||
- When set to C(true) (default), will use the first available interface. This can be different from what you expect.
|
||||
default: true
|
||||
- This currently defaults to C(true), but the default is deprecated since community.general 4.8.0.
|
||||
The default will change to C(false) in community.general 6.0.0. To avoid a deprecation warning, please
|
||||
set this parameter explicitly.
|
||||
type: bool
|
||||
filters:
|
||||
version_added: 4.6.0
|
||||
@@ -103,6 +127,25 @@ EXAMPLES = '''
|
||||
plugin: community.general.proxmox
|
||||
user: ansible@pve
|
||||
password: secure
|
||||
# Note that this can easily give you wrong values as ansible_host. See further below for
|
||||
# an example where this is set to `false` and where ansible_host is set with `compose`.
|
||||
want_proxmox_nodes_ansible_host: true
|
||||
|
||||
# Instead of login with password, proxmox supports api token authentication since release 6.2.
|
||||
plugin: community.general.proxmox
|
||||
user: ci@pve
|
||||
token_id: gitlab-1
|
||||
token_secret: fa256e9c-26ab-41ec-82da-707a2c079829
|
||||
|
||||
# The secret can also be a vault string or passed via the environment variable TOKEN_SECRET.
|
||||
token_secret: !vault |
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
62353634333163633336343265623632626339313032653563653165313262343931643431656138
|
||||
6134333736323265656466646539663134306166666237630a653363623262636663333762316136
|
||||
34616361326263383766366663393837626437316462313332663736623066656237386531663731
|
||||
3037646432383064630a663165303564623338666131353366373630656661333437393937343331
|
||||
32643131386134396336623736393634373936356332623632306561356361323737313663633633
|
||||
6231313333666361656537343562333337323030623732323833
|
||||
|
||||
# More complete example demonstrating the use of 'want_facts' and the constructed options
|
||||
# Note that using facts returned by 'want_facts' in constructed options requires 'want_facts=true'
|
||||
@@ -123,6 +166,9 @@ groups:
|
||||
mailservers: "'mail' in (proxmox_tags_parsed|list)"
|
||||
compose:
|
||||
ansible_port: 2222
|
||||
# Note that this can easily give you wrong values as ansible_host. See further below for
|
||||
# an example where this is set to `false` and where ansible_host is set with `compose`.
|
||||
want_proxmox_nodes_ansible_host: true
|
||||
|
||||
# Using the inventory to allow ansible to connect via the first IP address of the VM / Container
|
||||
# (Default is connection by name of QEMU/LXC guests)
|
||||
@@ -134,6 +180,7 @@ user: ansible@pve
|
||||
password: secure
|
||||
validate_certs: false
|
||||
want_facts: true
|
||||
want_proxmox_nodes_ansible_host: false
|
||||
compose:
|
||||
ansible_host: proxmox_ipconfig0.ip | default(proxmox_net0.ip) | ipaddr('address')
|
||||
my_inv_var_1: "'my_var1_value'"
|
||||
@@ -146,6 +193,9 @@ plugin: community.general.proxmox
|
||||
url: "{{ lookup('ansible.builtin.ini', 'url', section='proxmox', file='file.ini') }}"
|
||||
user: "{{ lookup('ansible.builtin.env','PM_USER') | default('ansible@pve') }}"
|
||||
password: "{{ lookup('community.general.random_string', base64=True) }}"
|
||||
# Note that this can easily give you wrong values as ansible_host. See further up for
|
||||
# an example where this is set to `false` and where ansible_host is set with `compose`.
|
||||
want_proxmox_nodes_ansible_host: true
|
||||
|
||||
'''
|
||||
|
||||
@@ -157,6 +207,7 @@ from ansible.module_utils.common._collections_compat import MutableMapping
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.utils.display import Display
|
||||
from ansible.template import Templar
|
||||
@@ -210,15 +261,24 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
def _get_auth(self):
|
||||
credentials = urlencode({'username': self.proxmox_user, 'password': self.proxmox_password, })
|
||||
|
||||
a = self._get_session()
|
||||
ret = a.post('%s/api2/json/access/ticket' % self.proxmox_url, data=credentials)
|
||||
if self.proxmox_password:
|
||||
|
||||
json = ret.json()
|
||||
credentials = urlencode({'username': self.proxmox_user, 'password': self.proxmox_password, })
|
||||
|
||||
self.credentials = {
|
||||
'ticket': json['data']['ticket'],
|
||||
'CSRFPreventionToken': json['data']['CSRFPreventionToken'],
|
||||
}
|
||||
a = self._get_session()
|
||||
ret = a.post('%s/api2/json/access/ticket' % self.proxmox_url, data=credentials)
|
||||
|
||||
json = ret.json()
|
||||
|
||||
self.headers = {
|
||||
# only required for POST/PUT/DELETE methods, which we are not using currently
|
||||
# 'CSRFPreventionToken': json['data']['CSRFPreventionToken'],
|
||||
'Cookie': 'PVEAuthCookie={0}'.format(json['data']['ticket'])
|
||||
}
|
||||
|
||||
else:
|
||||
|
||||
self.headers = {'Authorization': 'PVEAPIToken={0}!{1}={2}'.format(self.proxmox_user, self.proxmox_token_id, self.proxmox_token_secret)}
|
||||
|
||||
def _get_json(self, url, ignore_errors=None):
|
||||
|
||||
@@ -230,8 +290,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
data = []
|
||||
s = self._get_session()
|
||||
while True:
|
||||
headers = {'Cookie': 'PVEAuthCookie={0}'.format(self.credentials['ticket'])}
|
||||
ret = s.get(url, headers=headers)
|
||||
ret = s.get(url, headers=self.headers)
|
||||
if ignore_errors and ret.status_code in ignore_errors:
|
||||
break
|
||||
ret.raise_for_status()
|
||||
@@ -348,7 +407,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
agent_iface_key = self.to_safe('%s%s' % (key, "_interfaces"))
|
||||
properties[agent_iface_key] = agent_iface_value
|
||||
|
||||
if config not in plaintext_configs and not isinstance(value, int) and all("=" in v for v in value.split(",")):
|
||||
if config == 'lxc':
|
||||
out_val = {}
|
||||
for k, v in value:
|
||||
if k.startswith('lxc.'):
|
||||
k = k[len('lxc.'):]
|
||||
out_val[k] = v
|
||||
value = out_val
|
||||
|
||||
if config not in plaintext_configs and isinstance(value, string_types) \
|
||||
and all("=" in v for v in value.split(",")):
|
||||
# split off strings with commas to a dict
|
||||
# skip over any keys that cannot be processed
|
||||
try:
|
||||
@@ -467,6 +535,16 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
nodes_group = self._group('nodes')
|
||||
self.inventory.add_group(nodes_group)
|
||||
|
||||
want_proxmox_nodes_ansible_host = self.get_option("want_proxmox_nodes_ansible_host")
|
||||
if want_proxmox_nodes_ansible_host is None:
|
||||
display.deprecated(
|
||||
'The want_proxmox_nodes_ansible_host option of the community.general.proxmox inventory plugin'
|
||||
' currently defaults to `true`, but this default has been deprecated and will change to `false`'
|
||||
' in community.general 6.0.0. To keep the current behavior and remove this deprecation warning,'
|
||||
' explicitly set `want_proxmox_nodes_ansible_host` to `true` in your inventory configuration',
|
||||
version='6.0.0', collection_name='community.general')
|
||||
want_proxmox_nodes_ansible_host = True
|
||||
|
||||
# gather vm's on nodes
|
||||
self._get_auth()
|
||||
hosts = []
|
||||
@@ -482,7 +560,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
continue
|
||||
|
||||
# get node IP address
|
||||
if self.get_option("want_proxmox_nodes_ansible_host"):
|
||||
if want_proxmox_nodes_ansible_host:
|
||||
ip = self._get_node_ip(node['node'])
|
||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||
|
||||
@@ -530,6 +608,19 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
proxmox_password = t.template(variable=proxmox_password, disable_lookups=False)
|
||||
self.proxmox_password = proxmox_password
|
||||
|
||||
proxmox_token_id = self.get_option('token_id')
|
||||
if t.is_template(proxmox_token_id):
|
||||
proxmox_token_id = t.template(variable=proxmox_token_id, disable_lookups=False)
|
||||
self.proxmox_token_id = proxmox_token_id
|
||||
|
||||
proxmox_token_secret = self.get_option('token_secret')
|
||||
if t.is_template(proxmox_token_secret):
|
||||
proxmox_token_secret = t.template(variable=proxmox_token_secret, disable_lookups=False)
|
||||
self.proxmox_token_secret = proxmox_token_secret
|
||||
|
||||
if proxmox_password is None and (proxmox_token_id is None or proxmox_token_secret is None):
|
||||
raise AnsibleError('You must specify either a password or both token_id and token_secret.')
|
||||
|
||||
self.cache_key = self.get_cache_key(path)
|
||||
self.use_cache = cache and self.get_option('cache')
|
||||
self.host_filters = self.get_option('filters')
|
||||
|
||||
@@ -57,14 +57,19 @@ EXAMPLES = """
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
password:
|
||||
description:
|
||||
- The actual value stored
|
||||
passprops:
|
||||
description: properties assigned to the entry
|
||||
type: dictionary
|
||||
passwordchangeinprocess:
|
||||
description: did the password change?
|
||||
_result:
|
||||
description: A list containing one dictionary.
|
||||
type: list
|
||||
elements: dictionary
|
||||
contains:
|
||||
password:
|
||||
description:
|
||||
- The actual value stored
|
||||
passprops:
|
||||
description: properties assigned to the entry
|
||||
type: dictionary
|
||||
passwordchangeinprocess:
|
||||
description: did the password change?
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
@@ -18,7 +18,7 @@ DOCUMENTATION = '''
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
- name : output secrets to screen (BAD IDEA)
|
||||
- name: output secrets to screen (BAD IDEA)
|
||||
ansible.builtin.debug:
|
||||
msg: "Password: {{item}}"
|
||||
with_community.general.keyring:
|
||||
|
||||
@@ -45,8 +45,8 @@ DOCUMENTATION = '''
|
||||
description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults.
|
||||
notes:
|
||||
- This lookup will use an existing 1Password session if one exists. If not, and you have already
|
||||
performed an initial sign in (meaning C(~/.op/config exists)), then only the C(master_password) is required.
|
||||
You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
performed an initial sign in (meaning C(~/.op/config), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
|
||||
C(master_password) is required. You may optionally specify C(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing C(subdomain), C(username), C(secret_key), and C(master_password).
|
||||
- Due to the B(very) sensitive nature of these credentials, it is B(highly) recommended that you only pass in the minimal credentials
|
||||
needed at any given time. Also, store these credentials in an Ansible Vault using a key that is equal to or greater in strength
|
||||
@@ -105,12 +105,12 @@ from ansible.plugins.lookup import LookupBase
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.onepassword import OnePasswordConfig
|
||||
|
||||
|
||||
class OnePass(object):
|
||||
|
||||
def __init__(self, path='op'):
|
||||
self.cli_path = path
|
||||
self.config_file_path = os.path.expanduser('~/.op/config')
|
||||
self.logged_in = False
|
||||
self.token = None
|
||||
self.subdomain = None
|
||||
@@ -119,9 +119,11 @@ class OnePass(object):
|
||||
self.secret_key = None
|
||||
self.master_password = None
|
||||
|
||||
self._config = OnePasswordConfig()
|
||||
|
||||
def get_token(self):
|
||||
# If the config file exists, assume an initial signin has taken place and try basic sign in
|
||||
if os.path.isfile(self.config_file_path):
|
||||
if os.path.isfile(self._config.config_file_path):
|
||||
|
||||
if not self.master_password:
|
||||
raise AnsibleLookupError('Unable to sign in to 1Password. master_password is required.')
|
||||
@@ -281,4 +283,5 @@ class LookupModule(LookupBase):
|
||||
values = []
|
||||
for term in terms:
|
||||
values.append(op.get_field(term, field, section, vault))
|
||||
|
||||
return values
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Implements multiple version numbering conventions for the
|
||||
# Python Module Distribution Utilities.
|
||||
#
|
||||
# PSF License (see licenses/PSF-license.txt or https://opensource.org/licenses/Python-2.0)
|
||||
# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0)
|
||||
#
|
||||
|
||||
"""Provides classes to represent module version numbers (one class for
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
291
plugins/module_utils/cmd_runner.py
Normal file
291
plugins/module_utils/cmd_runner.py
Normal file
@@ -0,0 +1,291 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2022, Alexei Znamensky <russoz@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
|
||||
|
||||
from functools import wraps
|
||||
|
||||
from ansible.module_utils.common.collections import is_sequence
|
||||
from ansible.module_utils.six import iteritems
|
||||
|
||||
|
||||
def _ensure_list(value):
|
||||
return list(value) if is_sequence(value) else [value]
|
||||
|
||||
|
||||
def _process_as_is(rc, out, err):
|
||||
return rc, out, err
|
||||
|
||||
|
||||
class CmdRunnerException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingArgumentFormat(CmdRunnerException):
|
||||
def __init__(self, arg, args_order, args_formats):
|
||||
self.args_order = args_order
|
||||
self.arg = arg
|
||||
self.args_formats = args_formats
|
||||
|
||||
def __repr__(self):
|
||||
return "MissingArgumentFormat({0!r}, {1!r}, {2!r})".format(
|
||||
self.arg,
|
||||
self.args_order,
|
||||
self.args_formats,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Cannot find format for parameter {0} {1} in: {2}".format(
|
||||
self.arg,
|
||||
self.args_order,
|
||||
self.args_formats,
|
||||
)
|
||||
|
||||
|
||||
class MissingArgumentValue(CmdRunnerException):
|
||||
def __init__(self, args_order, arg):
|
||||
self.args_order = args_order
|
||||
self.arg = arg
|
||||
|
||||
def __repr__(self):
|
||||
return "MissingArgumentValue({0!r}, {1!r})".format(
|
||||
self.args_order,
|
||||
self.arg,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Cannot find value for parameter {0} in {1}".format(
|
||||
self.arg,
|
||||
self.args_order,
|
||||
)
|
||||
|
||||
|
||||
class FormatError(CmdRunnerException):
|
||||
def __init__(self, name, value, args_formats, exc):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.args_formats = args_formats
|
||||
self.exc = exc
|
||||
super(FormatError, self).__init__()
|
||||
|
||||
def __repr__(self):
|
||||
return "FormatError({0!r}, {1!r}, {2!r}, {3!r})".format(
|
||||
self.name,
|
||||
self.value,
|
||||
self.args_formats,
|
||||
self.exc,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Failed to format parameter {0} with value {1}: {2}".format(
|
||||
self.name,
|
||||
self.value,
|
||||
self.exc,
|
||||
)
|
||||
|
||||
|
||||
class _ArgFormat(object):
|
||||
def __init__(self, func, ignore_none=None):
|
||||
self.func = func
|
||||
self.ignore_none = ignore_none
|
||||
|
||||
def __call__(self, value, ctx_ignore_none):
|
||||
ignore_none = self.ignore_none if self.ignore_none is not None else ctx_ignore_none
|
||||
if value is None and ignore_none:
|
||||
return []
|
||||
f = self.func
|
||||
return [str(x) for x in f(value)]
|
||||
|
||||
|
||||
class _Format(object):
|
||||
@staticmethod
|
||||
def as_bool(args):
|
||||
return _ArgFormat(lambda value: _ensure_list(args) if value else [])
|
||||
|
||||
@staticmethod
|
||||
def as_bool_not(args):
|
||||
return _ArgFormat(lambda value: [] if value else _ensure_list(args), ignore_none=False)
|
||||
|
||||
@staticmethod
|
||||
def as_optval(arg, ignore_none=None):
|
||||
return _ArgFormat(lambda value: ["{0}{1}".format(arg, value)], ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_opt_val(arg, ignore_none=None):
|
||||
return _ArgFormat(lambda value: [arg, value], ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_opt_eq_val(arg, ignore_none=None):
|
||||
return _ArgFormat(lambda value: ["{0}={1}".format(arg, value)], ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_list(ignore_none=None):
|
||||
return _ArgFormat(_ensure_list, ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_fixed(args):
|
||||
return _ArgFormat(lambda value: _ensure_list(args), ignore_none=False)
|
||||
|
||||
@staticmethod
|
||||
def as_func(func, ignore_none=None):
|
||||
return _ArgFormat(func, ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_map(_map, default=None, ignore_none=None):
|
||||
return _ArgFormat(lambda value: _ensure_list(_map.get(value, default)), ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def as_default_type(_type, arg="", ignore_none=None):
|
||||
fmt = _Format
|
||||
if _type == "dict":
|
||||
return fmt.as_func(lambda d: ["--{0}={1}".format(*a) for a in iteritems(d)],
|
||||
ignore_none=ignore_none)
|
||||
if _type == "list":
|
||||
return fmt.as_func(lambda value: ["--{0}".format(x) for x in value], ignore_none=ignore_none)
|
||||
if _type == "bool":
|
||||
return fmt.as_bool("--{0}".format(arg))
|
||||
|
||||
return fmt.as_opt_val("--{0}".format(arg), ignore_none=ignore_none)
|
||||
|
||||
@staticmethod
|
||||
def unpack_args(func):
|
||||
@wraps(func)
|
||||
def wrapper(v):
|
||||
return func(*v)
|
||||
return wrapper
|
||||
|
||||
@staticmethod
|
||||
def unpack_kwargs(func):
|
||||
@wraps(func)
|
||||
def wrapper(v):
|
||||
return func(**v)
|
||||
return wrapper
|
||||
|
||||
|
||||
class CmdRunner(object):
|
||||
"""
|
||||
Wrapper for ``AnsibleModule.run_command()``.
|
||||
|
||||
It aims to provide a reusable runner with consistent argument formatting
|
||||
and sensible defaults.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _prepare_args_order(order):
|
||||
return tuple(order) if is_sequence(order) else tuple(order.split())
|
||||
|
||||
def __init__(self, module, command, arg_formats=None, default_args_order=(),
|
||||
check_rc=False, force_lang="C", path_prefix=None, environ_update=None):
|
||||
self.module = module
|
||||
self.command = _ensure_list(command)
|
||||
self.default_args_order = self._prepare_args_order(default_args_order)
|
||||
if arg_formats is None:
|
||||
arg_formats = {}
|
||||
self.arg_formats = dict(arg_formats)
|
||||
self.check_rc = check_rc
|
||||
self.force_lang = force_lang
|
||||
self.path_prefix = path_prefix
|
||||
if environ_update is None:
|
||||
environ_update = {}
|
||||
self.environ_update = environ_update
|
||||
|
||||
self.command[0] = module.get_bin_path(command[0], opt_dirs=path_prefix, required=True)
|
||||
|
||||
for mod_param_name, spec in iteritems(module.argument_spec):
|
||||
if mod_param_name not in self.arg_formats:
|
||||
self.arg_formats[mod_param_name] = _Format.as_default_type(spec['type'], mod_param_name)
|
||||
|
||||
def context(self, args_order=None, output_process=None, ignore_value_none=True, **kwargs):
|
||||
if output_process is None:
|
||||
output_process = _process_as_is
|
||||
if args_order is None:
|
||||
args_order = self.default_args_order
|
||||
args_order = self._prepare_args_order(args_order)
|
||||
for p in args_order:
|
||||
if p not in self.arg_formats:
|
||||
raise MissingArgumentFormat(p, args_order, tuple(self.arg_formats.keys()))
|
||||
return _CmdRunnerContext(runner=self,
|
||||
args_order=args_order,
|
||||
output_process=output_process,
|
||||
ignore_value_none=ignore_value_none, **kwargs)
|
||||
|
||||
def has_arg_format(self, arg):
|
||||
return arg in self.arg_formats
|
||||
|
||||
|
||||
class _CmdRunnerContext(object):
|
||||
def __init__(self, runner, args_order, output_process, ignore_value_none, **kwargs):
|
||||
self.runner = runner
|
||||
self.args_order = tuple(args_order)
|
||||
self.output_process = output_process
|
||||
self.ignore_value_none = ignore_value_none
|
||||
self.run_command_args = dict(kwargs)
|
||||
|
||||
self.environ_update = runner.environ_update
|
||||
self.environ_update.update(self.run_command_args.get('environ_update', {}))
|
||||
if runner.force_lang:
|
||||
self.environ_update.update({
|
||||
'LANGUAGE': runner.force_lang,
|
||||
'LC_ALL': runner.force_lang,
|
||||
})
|
||||
self.run_command_args['environ_update'] = self.environ_update
|
||||
|
||||
if 'check_rc' not in self.run_command_args:
|
||||
self.run_command_args['check_rc'] = runner.check_rc
|
||||
self.check_rc = self.run_command_args['check_rc']
|
||||
|
||||
self.cmd = None
|
||||
self.results_rc = None
|
||||
self.results_out = None
|
||||
self.results_err = None
|
||||
self.results_processed = None
|
||||
|
||||
def run(self, **kwargs):
|
||||
runner = self.runner
|
||||
module = self.runner.module
|
||||
self.cmd = list(runner.command)
|
||||
self.context_run_args = dict(kwargs)
|
||||
|
||||
named_args = dict(module.params)
|
||||
named_args.update(kwargs)
|
||||
for arg_name in self.args_order:
|
||||
value = None
|
||||
try:
|
||||
value = named_args[arg_name]
|
||||
self.cmd.extend(runner.arg_formats[arg_name](value, ctx_ignore_none=self.ignore_value_none))
|
||||
except KeyError:
|
||||
raise MissingArgumentValue(self.args_order, arg_name)
|
||||
except Exception as e:
|
||||
raise FormatError(arg_name, value, runner.arg_formats[arg_name], e)
|
||||
|
||||
results = module.run_command(self.cmd, **self.run_command_args)
|
||||
self.results_rc, self.results_out, self.results_err = results
|
||||
self.results_processed = self.output_process(*results)
|
||||
return self.results_processed
|
||||
|
||||
@property
|
||||
def run_info(self):
|
||||
return dict(
|
||||
ignore_value_none=self.ignore_value_none,
|
||||
check_rc=self.check_rc,
|
||||
environ_update=self.environ_update,
|
||||
args_order=self.args_order,
|
||||
cmd=self.cmd,
|
||||
run_command_args=self.run_command_args,
|
||||
context_run_args=self.context_run_args,
|
||||
results_rc=self.results_rc,
|
||||
results_out=self.results_out,
|
||||
results_err=self.results_err,
|
||||
results_processed=self.results_processed,
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
return False
|
||||
|
||||
|
||||
fmt = _Format()
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2019 Gregory Thiemonge <gregory.thiemonge@gmail.com>
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c), Google Inc, 2017
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or
|
||||
# Simplified BSD License (see simplified_bsd.txt or
|
||||
# https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (C) 2018 IBM CORPORATION
|
||||
# Author(s): Tzur Eliyahu <tzure@il.ibm.com>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2017, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c) 2016 Thomas Krahn (@Nosmoht)
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c), Michael DeHaan <michael.dehaan@gmail.com>, 2012-2013
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c), Luke Murphy @decentral1se
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c) 2018, Simon Weald <ansible@simonweald.com>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -337,7 +337,6 @@ def pritunl_auth_request(
|
||||
|
||||
auth_string = "&".join(
|
||||
[api_token, auth_timestamp, auth_nonce, method.upper(), path]
|
||||
+ ([data] if data else [])
|
||||
)
|
||||
|
||||
auth_signature = base64.b64encode(
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
29
plugins/module_utils/onepassword.py
Normal file
29
plugins/module_utils/onepassword.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class OnePasswordConfig(object):
|
||||
_config_file_paths = (
|
||||
"~/.op/config",
|
||||
"~/.config/op/config",
|
||||
"~/.config/.op/config",
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self._config_file_path = ""
|
||||
|
||||
@property
|
||||
def config_file_path(self):
|
||||
if self._config_file_path:
|
||||
return self._config_file_path
|
||||
|
||||
for path in self._config_file_paths:
|
||||
realpath = os.path.expanduser(path)
|
||||
if os.path.exists(realpath):
|
||||
self._config_file_path = realpath
|
||||
return self._config_file_path
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (2016-2017) Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Copyright 2018 www.privaz.io Valletech AB
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# to the complete work.
|
||||
#
|
||||
# Copyright (c), Simon Dodsley <simon@purestorage.com>,2017
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c), Michael DeHaan <michael.dehaan@gmail.com>, 2012-2013
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -732,14 +732,22 @@ class RedfishUtils(object):
|
||||
def get_multi_volume_inventory(self):
|
||||
return self.aggregate_systems(self.get_volume_inventory)
|
||||
|
||||
def manage_indicator_led(self, command):
|
||||
def manage_system_indicator_led(self, command):
|
||||
return self.manage_indicator_led(command, self.systems_uri)
|
||||
|
||||
def manage_chassis_indicator_led(self, command):
|
||||
return self.manage_indicator_led(command, self.chassis_uri)
|
||||
|
||||
def manage_indicator_led(self, command, resource_uri=None):
|
||||
result = {}
|
||||
key = 'IndicatorLED'
|
||||
if resource_uri is None:
|
||||
resource_uri = self.chassis_uri
|
||||
|
||||
payloads = {'IndicatorLedOn': 'Lit', 'IndicatorLedOff': 'Off', "IndicatorLedBlink": 'Blinking'}
|
||||
|
||||
result = {}
|
||||
response = self.get_request(self.root_uri + self.chassis_uri)
|
||||
response = self.get_request(self.root_uri + resource_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
result['ret'] = True
|
||||
@@ -749,7 +757,7 @@ class RedfishUtils(object):
|
||||
|
||||
if command in payloads.keys():
|
||||
payload = {'IndicatorLED': payloads[command]}
|
||||
response = self.patch_request(self.root_uri + self.chassis_uri, payload)
|
||||
response = self.patch_request(self.root_uri + resource_uri, payload)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
else:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright (c), James Laska
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -37,7 +37,7 @@ def fail_imports(module, needs_certifi=True):
|
||||
errors.append(missing_required_lib('certifi'))
|
||||
traceback.append(CERTIFI_IMPORT_ERROR)
|
||||
if errors:
|
||||
module.fail_json(errors=errors, traceback='\n'.join(traceback))
|
||||
module.fail_json(msg='\n'.join(errors), traceback='\n'.join(traceback))
|
||||
|
||||
|
||||
def redis_auth_argument_spec(tls_default=True):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# own license to the complete work.
|
||||
#
|
||||
# Copyright (C) 2017 Lenovo, Inc.
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
#
|
||||
# Contains LXCA common class
|
||||
# Lenovo xClarity Administrator (LXCA)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# (c) 2018 Luca 'remix_tj' Lorenzetto
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2018, Hewlett Packard Enterprise Development LP
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# Copyright (c) 2016, Adfinis SyGroup AG
|
||||
# Tobias Rueetschi <tobias.ruetschi@adfinis-sygroup.ch>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
# Copyright: (c) 2018, Johannes Brunswicker <johannes.brunswicker@gmail.com>
|
||||
#
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright: (c) 2019, Sandeep Kasargod <sandeep@vexata.com>
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
1
plugins/modules/alerta_customer.py
Symbolic link
1
plugins/modules/alerta_customer.py
Symbolic link
@@ -0,0 +1 @@
|
||||
./monitoring/alerta_customer.py
|
||||
@@ -182,10 +182,10 @@ def core(module):
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
mode=dict(default=None, choices=['user', 'system']),
|
||||
mode=dict(choices=['user', 'system']),
|
||||
name=dict(required=True),
|
||||
image=dict(required=True),
|
||||
rootfs=dict(default=None),
|
||||
rootfs=dict(),
|
||||
state=dict(default='latest', choices=['present', 'absent', 'latest', 'rollback']),
|
||||
backend=dict(required=True, choices=['docker', 'ostree']),
|
||||
values=dict(type='list', default=[], elements='str'),
|
||||
|
||||
@@ -228,8 +228,7 @@ class ClcAlertPolicy:
|
||||
choices=[
|
||||
'cpu',
|
||||
'memory',
|
||||
'disk'],
|
||||
default=None),
|
||||
'disk']),
|
||||
duration=dict(type='str'),
|
||||
threshold=dict(type='int'),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
|
||||
@@ -297,9 +297,9 @@ class ClcGroup(object):
|
||||
"""
|
||||
argument_spec = dict(
|
||||
name=dict(required=True),
|
||||
description=dict(default=None),
|
||||
parent=dict(default=None),
|
||||
location=dict(default=None),
|
||||
description=dict(),
|
||||
parent=dict(),
|
||||
location=dict(),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
wait=dict(type='bool', default=True))
|
||||
|
||||
|
||||
@@ -865,7 +865,7 @@ class ClcLoadBalancer:
|
||||
"""
|
||||
argument_spec = dict(
|
||||
name=dict(required=True),
|
||||
description=dict(default=None),
|
||||
description=dict(),
|
||||
location=dict(required=True),
|
||||
alias=dict(required=True),
|
||||
port=dict(choices=[80, 443]),
|
||||
|
||||
@@ -567,31 +567,31 @@ class ClcServer:
|
||||
template=dict(),
|
||||
group=dict(default='Default Group'),
|
||||
network_id=dict(),
|
||||
location=dict(default=None),
|
||||
location=dict(),
|
||||
cpu=dict(default=1, type='int'),
|
||||
memory=dict(default=1, type='int'),
|
||||
alias=dict(default=None),
|
||||
password=dict(default=None, no_log=True),
|
||||
ip_address=dict(default=None),
|
||||
alias=dict(),
|
||||
password=dict(no_log=True),
|
||||
ip_address=dict(),
|
||||
storage_type=dict(
|
||||
default='standard',
|
||||
choices=[
|
||||
'standard',
|
||||
'hyperscale']),
|
||||
type=dict(default='standard', choices=['standard', 'hyperscale', 'bareMetal']),
|
||||
primary_dns=dict(default=None),
|
||||
secondary_dns=dict(default=None),
|
||||
primary_dns=dict(),
|
||||
secondary_dns=dict(),
|
||||
additional_disks=dict(type='list', default=[], elements='dict'),
|
||||
custom_fields=dict(type='list', default=[], elements='dict'),
|
||||
ttl=dict(default=None),
|
||||
ttl=dict(),
|
||||
managed_os=dict(type='bool', default=False),
|
||||
description=dict(default=None),
|
||||
source_server_password=dict(default=None, no_log=True),
|
||||
cpu_autoscale_policy_id=dict(default=None),
|
||||
anti_affinity_policy_id=dict(default=None),
|
||||
anti_affinity_policy_name=dict(default=None),
|
||||
alert_policy_id=dict(default=None),
|
||||
alert_policy_name=dict(default=None),
|
||||
description=dict(),
|
||||
source_server_password=dict(no_log=True),
|
||||
cpu_autoscale_policy_id=dict(),
|
||||
anti_affinity_policy_id=dict(),
|
||||
anti_affinity_policy_name=dict(),
|
||||
alert_policy_id=dict(),
|
||||
alert_policy_name=dict(),
|
||||
packages=dict(type='list', default=[], elements='dict'),
|
||||
state=dict(
|
||||
default='present',
|
||||
@@ -601,7 +601,7 @@ class ClcServer:
|
||||
'started',
|
||||
'stopped']),
|
||||
count=dict(type='int', default=1),
|
||||
exact_count=dict(type='int', default=None),
|
||||
exact_count=dict(type='int', ),
|
||||
count_group=dict(),
|
||||
server_ids=dict(type='list', default=[], elements='str'),
|
||||
add_public_ip=dict(type='bool', default=False),
|
||||
@@ -612,14 +612,13 @@ class ClcServer:
|
||||
'UDP',
|
||||
'ICMP']),
|
||||
public_ip_ports=dict(type='list', default=[], elements='dict'),
|
||||
configuration_id=dict(default=None),
|
||||
os_type=dict(default=None,
|
||||
choices=[
|
||||
'redHat6_64Bit',
|
||||
'centOS6_64Bit',
|
||||
'windows2012R2Standard_64Bit',
|
||||
'ubuntu14_64Bit'
|
||||
]),
|
||||
configuration_id=dict(),
|
||||
os_type=dict(choices=[
|
||||
'redHat6_64Bit',
|
||||
'centOS6_64Bit',
|
||||
'windows2012R2Standard_64Bit',
|
||||
'ubuntu14_64Bit'
|
||||
]),
|
||||
wait=dict(type='bool', default=True))
|
||||
|
||||
mutually_exclusive = [
|
||||
|
||||
@@ -21,6 +21,13 @@ options:
|
||||
- Name of an instance.
|
||||
type: str
|
||||
required: true
|
||||
project:
|
||||
description:
|
||||
- 'Project of an instance.
|
||||
See U(https://github.com/lxc/lxd/blob/master/doc/projects.md).'
|
||||
required: false
|
||||
type: str
|
||||
version_added: 4.8.0
|
||||
architecture:
|
||||
description:
|
||||
- 'The architecture for the instance (for example C(x86_64) or C(i686)).
|
||||
@@ -248,6 +255,26 @@ EXAMPLES = '''
|
||||
wait_for_ipv4_addresses: true
|
||||
timeout: 600
|
||||
|
||||
# An example for creating container in project other than default
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Create a started container in project mytestproject
|
||||
community.general.lxd_container:
|
||||
name: mycontainer
|
||||
project: mytestproject
|
||||
ignore_volatile_options: true
|
||||
state: started
|
||||
source:
|
||||
protocol: simplestreams
|
||||
type: image
|
||||
mode: pull
|
||||
server: https://images.linuxcontainers.org
|
||||
alias: ubuntu/20.04/cloud
|
||||
profiles: ["default"]
|
||||
wait_for_ipv4_addresses: true
|
||||
timeout: 600
|
||||
|
||||
# An example for deleting a container
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
@@ -412,6 +439,7 @@ class LXDContainerManagement(object):
|
||||
"""
|
||||
self.module = module
|
||||
self.name = self.module.params['name']
|
||||
self.project = self.module.params['project']
|
||||
self._build_config()
|
||||
|
||||
self.state = self.module.params['state']
|
||||
@@ -468,16 +496,16 @@ class LXDContainerManagement(object):
|
||||
self.config[attr] = param_val
|
||||
|
||||
def _get_instance_json(self):
|
||||
return self.client.do(
|
||||
'GET', '{0}/{1}'.format(self.api_endpoint, self.name),
|
||||
ok_error_codes=[404]
|
||||
)
|
||||
url = '{0}/{1}'.format(self.api_endpoint, self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
return self.client.do('GET', url, ok_error_codes=[404])
|
||||
|
||||
def _get_instance_state_json(self):
|
||||
return self.client.do(
|
||||
'GET', '{0}/{1}/state'.format(self.api_endpoint, self.name),
|
||||
ok_error_codes=[404]
|
||||
)
|
||||
url = '{0}/{1}/state'.format(self.api_endpoint, self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
return self.client.do('GET', url, ok_error_codes=[404])
|
||||
|
||||
@staticmethod
|
||||
def _instance_json_to_module_state(resp_json):
|
||||
@@ -486,18 +514,26 @@ class LXDContainerManagement(object):
|
||||
return ANSIBLE_LXD_STATES[resp_json['metadata']['status']]
|
||||
|
||||
def _change_state(self, action, force_stop=False):
|
||||
url = '{0}/{1}/state'.format(self.api_endpoint, self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
body_json = {'action': action, 'timeout': self.timeout}
|
||||
if force_stop:
|
||||
body_json['force'] = True
|
||||
return self.client.do('PUT', '{0}/{1}/state'.format(self.api_endpoint, self.name), body_json=body_json)
|
||||
return self.client.do('PUT', url, body_json=body_json)
|
||||
|
||||
def _create_instance(self):
|
||||
url = self.api_endpoint
|
||||
url_params = dict()
|
||||
if self.target:
|
||||
url_params['target'] = self.target
|
||||
if self.project:
|
||||
url_params['project'] = self.project
|
||||
if url_params:
|
||||
url = '{0}?{1}'.format(url, urlencode(url_params))
|
||||
config = self.config.copy()
|
||||
config['name'] = self.name
|
||||
if self.target:
|
||||
self.client.do('POST', '{0}?{1}'.format(self.api_endpoint, urlencode(dict(target=self.target))), config, wait_for_container=self.wait_for_container)
|
||||
else:
|
||||
self.client.do('POST', self.api_endpoint, config, wait_for_container=self.wait_for_container)
|
||||
self.client.do('POST', url, config, wait_for_container=self.wait_for_container)
|
||||
self.actions.append('create')
|
||||
|
||||
def _start_instance(self):
|
||||
@@ -513,7 +549,10 @@ class LXDContainerManagement(object):
|
||||
self.actions.append('restart')
|
||||
|
||||
def _delete_instance(self):
|
||||
self.client.do('DELETE', '{0}/{1}'.format(self.api_endpoint, self.name))
|
||||
url = '{0}/{1}'.format(self.api_endpoint, self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
self.client.do('DELETE', url)
|
||||
self.actions.append('delete')
|
||||
|
||||
def _freeze_instance(self):
|
||||
@@ -666,7 +705,10 @@ class LXDContainerManagement(object):
|
||||
if self._needs_to_change_instance_config('profiles'):
|
||||
body_json['profiles'] = self.config['profiles']
|
||||
|
||||
self.client.do('PUT', '{0}/{1}'.format(self.api_endpoint, self.name), body_json=body_json)
|
||||
url = '{0}/{1}'.format(self.api_endpoint, self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
self.client.do('PUT', url, body_json=body_json)
|
||||
self.actions.append('apply_instance_configs')
|
||||
|
||||
def run(self):
|
||||
@@ -715,6 +757,9 @@ def main():
|
||||
type='str',
|
||||
required=True
|
||||
),
|
||||
project=dict(
|
||||
type='str',
|
||||
),
|
||||
architecture=dict(
|
||||
type='str',
|
||||
),
|
||||
|
||||
@@ -21,6 +21,13 @@ options:
|
||||
- Name of a profile.
|
||||
required: true
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- 'Project of a profile.
|
||||
See U(https://github.com/lxc/lxd/blob/master/doc/projects.md).'
|
||||
type: str
|
||||
required: false
|
||||
version_added: 4.8.0
|
||||
description:
|
||||
description:
|
||||
- Description of the profile.
|
||||
@@ -129,6 +136,19 @@ EXAMPLES = '''
|
||||
parent: br0
|
||||
type: nic
|
||||
|
||||
# An example for creating a profile in project mytestproject
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Create a profile
|
||||
community.general.lxd_profile:
|
||||
name: testprofile
|
||||
project: mytestproject
|
||||
state: present
|
||||
config: {}
|
||||
description: test profile in project mytestproject
|
||||
devices: {}
|
||||
|
||||
# An example for creating a profile via http connection
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
@@ -208,6 +228,7 @@ actions:
|
||||
import os
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
|
||||
# ANSIBLE_LXD_DEFAULT_URL is a default value of the lxd endpoint
|
||||
ANSIBLE_LXD_DEFAULT_URL = 'unix:/var/lib/lxd/unix.socket'
|
||||
@@ -232,6 +253,7 @@ class LXDProfileManagement(object):
|
||||
"""
|
||||
self.module = module
|
||||
self.name = self.module.params['name']
|
||||
self.project = self.module.params['project']
|
||||
self._build_config()
|
||||
self.state = self.module.params['state']
|
||||
self.new_name = self.module.params.get('new_name', None)
|
||||
@@ -272,10 +294,10 @@ class LXDProfileManagement(object):
|
||||
self.config[attr] = param_val
|
||||
|
||||
def _get_profile_json(self):
|
||||
return self.client.do(
|
||||
'GET', '/1.0/profiles/{0}'.format(self.name),
|
||||
ok_error_codes=[404]
|
||||
)
|
||||
url = '/1.0/profiles/{0}'.format(self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
return self.client.do('GET', url, ok_error_codes=[404])
|
||||
|
||||
@staticmethod
|
||||
def _profile_json_to_module_state(resp_json):
|
||||
@@ -307,14 +329,20 @@ class LXDProfileManagement(object):
|
||||
changed=False)
|
||||
|
||||
def _create_profile(self):
|
||||
url = '/1.0/profiles'
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
config = self.config.copy()
|
||||
config['name'] = self.name
|
||||
self.client.do('POST', '/1.0/profiles', config)
|
||||
self.client.do('POST', url, config)
|
||||
self.actions.append('create')
|
||||
|
||||
def _rename_profile(self):
|
||||
url = '/1.0/profiles/{0}'.format(self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
config = {'name': self.new_name}
|
||||
self.client.do('POST', '/1.0/profiles/{0}'.format(self.name), config)
|
||||
self.client.do('POST', url, config)
|
||||
self.actions.append('rename')
|
||||
self.name = self.new_name
|
||||
|
||||
@@ -421,11 +449,17 @@ class LXDProfileManagement(object):
|
||||
config = self._generate_new_config(config)
|
||||
|
||||
# upload config to lxd
|
||||
self.client.do('PUT', '/1.0/profiles/{0}'.format(self.name), config)
|
||||
url = '/1.0/profiles/{0}'.format(self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
self.client.do('PUT', url, config)
|
||||
self.actions.append('apply_profile_configs')
|
||||
|
||||
def _delete_profile(self):
|
||||
self.client.do('DELETE', '/1.0/profiles/{0}'.format(self.name))
|
||||
url = '/1.0/profiles/{0}'.format(self.name)
|
||||
if self.project:
|
||||
url = '{0}?{1}'.format(url, urlencode(dict(project=self.project)))
|
||||
self.client.do('DELETE', url)
|
||||
self.actions.append('delete')
|
||||
|
||||
def run(self):
|
||||
@@ -469,6 +503,9 @@ def main():
|
||||
type='str',
|
||||
required=True
|
||||
),
|
||||
project=dict(
|
||||
type='str',
|
||||
),
|
||||
new_name=dict(
|
||||
type='str',
|
||||
),
|
||||
|
||||
451
plugins/modules/cloud/lxd/lxd_project.py
Normal file
451
plugins/modules/cloud/lxd/lxd_project.py
Normal file
@@ -0,0 +1,451 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 = '''
|
||||
---
|
||||
module: lxd_project
|
||||
short_description: Manage LXD projects
|
||||
version_added: 4.8.0
|
||||
description:
|
||||
- Management of LXD projects.
|
||||
author: "Raymond Chang (@we10710aa)"
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the project.
|
||||
required: true
|
||||
type: str
|
||||
description:
|
||||
description:
|
||||
- Description of the project.
|
||||
type: str
|
||||
config:
|
||||
description:
|
||||
- 'The config for the project (for example C({"features.profiles": "true"})).
|
||||
See U(https://linuxcontainers.org/lxd/docs/master/projects/).'
|
||||
- If the project already exists and its "config" value in metadata
|
||||
obtained from
|
||||
C(GET /1.0/projects/<name>)
|
||||
U(https://linuxcontainers.org/lxd/docs/master/api/#/projects/project_get)
|
||||
are different, then this module tries to apply the configurations.
|
||||
type: dict
|
||||
new_name:
|
||||
description:
|
||||
- A new name of a project.
|
||||
- If this parameter is specified a project will be renamed to this name.
|
||||
See U(https://linuxcontainers.org/lxd/docs/master/api/#/projects/project_post).
|
||||
required: false
|
||||
type: str
|
||||
merge_project:
|
||||
description:
|
||||
- Merge the configuration of the present project with the new desired configuration,
|
||||
instead of replacing it. If configuration is the same after merged, no change will be made.
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
state:
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
description:
|
||||
- Define the state of a project.
|
||||
required: false
|
||||
default: present
|
||||
type: str
|
||||
url:
|
||||
description:
|
||||
- The Unix domain socket path or the https URL for the LXD server.
|
||||
required: false
|
||||
default: unix:/var/lib/lxd/unix.socket
|
||||
type: str
|
||||
snap_url:
|
||||
description:
|
||||
- The Unix domain socket path when LXD is installed by snap package manager.
|
||||
required: false
|
||||
default: unix:/var/snap/lxd/common/lxd/unix.socket
|
||||
type: str
|
||||
client_key:
|
||||
description:
|
||||
- The client certificate key file path.
|
||||
- If not specified, it defaults to C($HOME/.config/lxc/client.key).
|
||||
required: false
|
||||
aliases: [ key_file ]
|
||||
type: path
|
||||
client_cert:
|
||||
description:
|
||||
- The client certificate file path.
|
||||
- If not specified, it defaults to C($HOME/.config/lxc/client.crt).
|
||||
required: false
|
||||
aliases: [ cert_file ]
|
||||
type: path
|
||||
trust_password:
|
||||
description:
|
||||
- The client trusted password.
|
||||
- 'You need to set this password on the LXD server before
|
||||
running this module using the following command:
|
||||
C(lxc config set core.trust_password <some random password>)
|
||||
See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/).'
|
||||
- If I(trust_password) is set, this module send a request for
|
||||
authentication before sending any requests.
|
||||
required: false
|
||||
type: str
|
||||
notes:
|
||||
- Projects must have a unique name. If you attempt to create a project
|
||||
with a name that already existed in the users namespace the module will
|
||||
simply return as "unchanged".
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# An example for creating a project
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Create a project
|
||||
community.general.lxd_project:
|
||||
name: ansible-test-project
|
||||
state: present
|
||||
config: {}
|
||||
description: my new project
|
||||
|
||||
# An example for renaming a project
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Rename ansible-test-project to ansible-test-project-new-name
|
||||
community.general.lxd_project:
|
||||
name: ansible-test-project
|
||||
new_name: ansible-test-project-new-name
|
||||
state: present
|
||||
config: {}
|
||||
description: my new project
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
old_state:
|
||||
description: The old state of the project.
|
||||
returned: success
|
||||
type: str
|
||||
sample: "absent"
|
||||
logs:
|
||||
description: The logs of requests and responses.
|
||||
returned: when ansible-playbook is invoked with -vvvv.
|
||||
type: list
|
||||
elements: dict
|
||||
contains:
|
||||
type:
|
||||
description: Type of actions performed, currently only C(sent request).
|
||||
type: str
|
||||
sample: "sent request"
|
||||
request:
|
||||
description: HTTP request sent to LXD server.
|
||||
type: dict
|
||||
contains:
|
||||
method:
|
||||
description: Method of HTTP request.
|
||||
type: str
|
||||
sample: "GET"
|
||||
url:
|
||||
description: URL path of HTTP request.
|
||||
type: str
|
||||
sample: "/1.0/projects/test-project"
|
||||
json:
|
||||
description: JSON body of HTTP request.
|
||||
type: str
|
||||
sample: "(too long to be placed here)"
|
||||
timeout:
|
||||
description: Timeout of HTTP request, C(null) if unset.
|
||||
type: int
|
||||
sample: null
|
||||
response:
|
||||
description: HTTP response received from LXD server.
|
||||
type: dict
|
||||
contains:
|
||||
json:
|
||||
description: JSON of HTTP response.
|
||||
type: str
|
||||
sample: "(too long to be placed here)"
|
||||
actions:
|
||||
description: List of actions performed for the project.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
sample: ["create"]
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os
|
||||
|
||||
# ANSIBLE_LXD_DEFAULT_URL is a default value of the lxd endpoint
|
||||
ANSIBLE_LXD_DEFAULT_URL = 'unix:/var/lib/lxd/unix.socket'
|
||||
|
||||
# PROJECTS_STATES is a list for states supported
|
||||
PROJECTS_STATES = [
|
||||
'present', 'absent'
|
||||
]
|
||||
|
||||
# CONFIG_PARAMS is a list of config attribute names.
|
||||
CONFIG_PARAMS = [
|
||||
'config', 'description'
|
||||
]
|
||||
|
||||
|
||||
class LXDProjectManagement(object):
|
||||
def __init__(self, module):
|
||||
"""Management of LXC projects via Ansible.
|
||||
|
||||
:param module: Processed Ansible Module.
|
||||
:type module: ``object``
|
||||
"""
|
||||
self.module = module
|
||||
self.name = self.module.params['name']
|
||||
self._build_config()
|
||||
self.state = self.module.params['state']
|
||||
self.new_name = self.module.params.get('new_name', None)
|
||||
|
||||
self.key_file = self.module.params.get('client_key')
|
||||
if self.key_file is None:
|
||||
self.key_file = os.path.expanduser('~/.config/lxc/client.key')
|
||||
self.cert_file = self.module.params.get('client_cert')
|
||||
if self.cert_file is None:
|
||||
self.cert_file = os.path.expanduser('~/.config/lxc/client.crt')
|
||||
self.debug = self.module._verbosity >= 4
|
||||
|
||||
try:
|
||||
if self.module.params['url'] != ANSIBLE_LXD_DEFAULT_URL:
|
||||
self.url = self.module.params['url']
|
||||
elif os.path.exists(self.module.params['snap_url'].replace('unix:', '')):
|
||||
self.url = self.module.params['snap_url']
|
||||
else:
|
||||
self.url = self.module.params['url']
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=e.msg)
|
||||
|
||||
try:
|
||||
self.client = LXDClient(
|
||||
self.url, key_file=self.key_file, cert_file=self.cert_file,
|
||||
debug=self.debug
|
||||
)
|
||||
except LXDClientException as e:
|
||||
self.module.fail_json(msg=e.msg)
|
||||
self.trust_password = self.module.params.get('trust_password', None)
|
||||
self.actions = []
|
||||
|
||||
def _build_config(self):
|
||||
self.config = {}
|
||||
for attr in CONFIG_PARAMS:
|
||||
param_val = self.module.params.get(attr, None)
|
||||
if param_val is not None:
|
||||
self.config[attr] = param_val
|
||||
|
||||
def _get_project_json(self):
|
||||
return self.client.do(
|
||||
'GET', '/1.0/projects/{0}'.format(self.name),
|
||||
ok_error_codes=[404]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _project_json_to_module_state(resp_json):
|
||||
if resp_json['type'] == 'error':
|
||||
return 'absent'
|
||||
return 'present'
|
||||
|
||||
def _update_project(self):
|
||||
if self.state == 'present':
|
||||
if self.old_state == 'absent':
|
||||
if self.new_name is None:
|
||||
self._create_project()
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg='new_name must not be set when the project does not exist and the state is present',
|
||||
changed=False)
|
||||
else:
|
||||
if self.new_name is not None and self.new_name != self.name:
|
||||
self._rename_project()
|
||||
if self._needs_to_apply_project_configs():
|
||||
self._apply_project_configs()
|
||||
elif self.state == 'absent':
|
||||
if self.old_state == 'present':
|
||||
if self.new_name is None:
|
||||
self._delete_project()
|
||||
else:
|
||||
self.module.fail_json(
|
||||
msg='new_name must not be set when the project exists and the specified state is absent',
|
||||
changed=False)
|
||||
|
||||
def _create_project(self):
|
||||
config = self.config.copy()
|
||||
config['name'] = self.name
|
||||
self.client.do('POST', '/1.0/projects', config)
|
||||
self.actions.append('create')
|
||||
|
||||
def _rename_project(self):
|
||||
config = {'name': self.new_name}
|
||||
self.client.do('POST', '/1.0/projects/{0}'.format(self.name), config)
|
||||
self.actions.append('rename')
|
||||
self.name = self.new_name
|
||||
|
||||
def _needs_to_change_project_config(self, key):
|
||||
if key not in self.config:
|
||||
return False
|
||||
old_configs = self.old_project_json['metadata'].get(key, None)
|
||||
return self.config[key] != old_configs
|
||||
|
||||
def _needs_to_apply_project_configs(self):
|
||||
return (
|
||||
self._needs_to_change_project_config('config') or
|
||||
self._needs_to_change_project_config('description')
|
||||
)
|
||||
|
||||
def _merge_dicts(self, source, destination):
|
||||
""" Return a new dict taht merge two dict,
|
||||
with values in source dict overwrite destination dict
|
||||
|
||||
Args:
|
||||
dict(source): source dict
|
||||
dict(destination): destination dict
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
dict(destination): merged dict"""
|
||||
result = destination.copy()
|
||||
for key, value in source.items():
|
||||
if isinstance(value, dict):
|
||||
# get node or create one
|
||||
node = result.setdefault(key, {})
|
||||
self._merge_dicts(value, node)
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
def _apply_project_configs(self):
|
||||
""" Selection of the procedure: rebuild or merge
|
||||
|
||||
The standard behavior is that all information not contained
|
||||
in the play is discarded.
|
||||
|
||||
If "merge_project" is provides in the play and "True", then existing
|
||||
configurations from the project and new ones defined are merged.
|
||||
|
||||
Args:
|
||||
None
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
None"""
|
||||
old_config = dict()
|
||||
old_metadata = self.old_project_json['metadata'].copy()
|
||||
for attr in CONFIG_PARAMS:
|
||||
old_config[attr] = old_metadata[attr]
|
||||
|
||||
if self.module.params['merge_project']:
|
||||
config = self._merge_dicts(self.config, old_config)
|
||||
if config == old_config:
|
||||
# no need to call api if merged config is the same
|
||||
# as old config
|
||||
return
|
||||
else:
|
||||
config = self.config.copy()
|
||||
# upload config to lxd
|
||||
self.client.do('PUT', '/1.0/projects/{0}'.format(self.name), config)
|
||||
self.actions.append('apply_projects_configs')
|
||||
|
||||
def _delete_project(self):
|
||||
self.client.do('DELETE', '/1.0/projects/{0}'.format(self.name))
|
||||
self.actions.append('delete')
|
||||
|
||||
def run(self):
|
||||
"""Run the main method."""
|
||||
|
||||
try:
|
||||
if self.trust_password is not None:
|
||||
self.client.authenticate(self.trust_password)
|
||||
|
||||
self.old_project_json = self._get_project_json()
|
||||
self.old_state = self._project_json_to_module_state(
|
||||
self.old_project_json)
|
||||
self._update_project()
|
||||
|
||||
state_changed = len(self.actions) > 0
|
||||
result_json = {
|
||||
'changed': state_changed,
|
||||
'old_state': self.old_state,
|
||||
'actions': self.actions
|
||||
}
|
||||
if self.client.debug:
|
||||
result_json['logs'] = self.client.logs
|
||||
self.module.exit_json(**result_json)
|
||||
except LXDClientException as e:
|
||||
state_changed = len(self.actions) > 0
|
||||
fail_params = {
|
||||
'msg': e.msg,
|
||||
'changed': state_changed,
|
||||
'actions': self.actions
|
||||
}
|
||||
if self.client.debug:
|
||||
fail_params['logs'] = e.kwargs['logs']
|
||||
self.module.fail_json(**fail_params)
|
||||
|
||||
|
||||
def main():
|
||||
"""Ansible Main module."""
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(
|
||||
type='str',
|
||||
required=True
|
||||
),
|
||||
new_name=dict(
|
||||
type='str',
|
||||
),
|
||||
config=dict(
|
||||
type='dict',
|
||||
),
|
||||
description=dict(
|
||||
type='str',
|
||||
),
|
||||
merge_project=dict(
|
||||
type='bool',
|
||||
default=False
|
||||
),
|
||||
state=dict(
|
||||
choices=PROJECTS_STATES,
|
||||
default='present'
|
||||
),
|
||||
url=dict(
|
||||
type='str',
|
||||
default=ANSIBLE_LXD_DEFAULT_URL
|
||||
),
|
||||
snap_url=dict(
|
||||
type='str',
|
||||
default='unix:/var/snap/lxd/common/lxd/unix.socket'
|
||||
),
|
||||
client_key=dict(
|
||||
type='path',
|
||||
aliases=['key_file']
|
||||
),
|
||||
client_cert=dict(
|
||||
type='path',
|
||||
aliases=['cert_file']
|
||||
),
|
||||
trust_password=dict(type='str', no_log=True)
|
||||
),
|
||||
supports_check_mode=False,
|
||||
)
|
||||
|
||||
lxd_manage = LXDProjectManagement(module=module)
|
||||
lxd_manage.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -564,7 +564,7 @@ def main():
|
||||
force=dict(type='bool', default=False),
|
||||
purge=dict(type='bool', default=False),
|
||||
state=dict(default='present', choices=['present', 'absent', 'stopped', 'started', 'restarted']),
|
||||
pubkey=dict(type='str', default=None),
|
||||
pubkey=dict(type='str'),
|
||||
unprivileged=dict(type='bool', default=False),
|
||||
description=dict(type='str'),
|
||||
hookscript=dict(type='str'),
|
||||
|
||||
@@ -1397,7 +1397,7 @@ def main():
|
||||
module.fail_json(msg='VM with name = %s does not exist in cluster' % name)
|
||||
vm = proxmox.get_vm(vmid)
|
||||
if not name:
|
||||
name = vm['name']
|
||||
name = vm.get('name', '(unnamed)')
|
||||
current = proxmox.proxmox_api.nodes(vm['node']).qemu(vmid).status.current.get()['status']
|
||||
status['status'] = current
|
||||
if status:
|
||||
|
||||
@@ -13,7 +13,7 @@ module: proxmox_snap
|
||||
short_description: Snapshot management of instances in Proxmox VE cluster
|
||||
version_added: 2.0.0
|
||||
description:
|
||||
- Allows you to create/delete snapshots from instances in Proxmox VE cluster.
|
||||
- Allows you to create/delete/restore snapshots from instances in Proxmox VE cluster.
|
||||
- Supports both KVM and LXC, OpenVZ has not been tested, as it is no longer supported on Proxmox VE.
|
||||
options:
|
||||
hostname:
|
||||
@@ -28,7 +28,8 @@ options:
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the instance snapshot.
|
||||
choices: ['present', 'absent']
|
||||
- The C(rollback) value was added in community.general 4.8.0.
|
||||
choices: ['present', 'absent', 'rollback']
|
||||
default: present
|
||||
type: str
|
||||
force:
|
||||
@@ -53,7 +54,7 @@ options:
|
||||
type: int
|
||||
snapname:
|
||||
description:
|
||||
- Name of the snapshot that has to be created.
|
||||
- Name of the snapshot that has to be created/deleted/restored.
|
||||
default: 'ansible_snap'
|
||||
type: str
|
||||
|
||||
@@ -84,6 +85,15 @@ EXAMPLES = r'''
|
||||
vmid: 100
|
||||
state: absent
|
||||
snapname: pre-updates
|
||||
|
||||
- name: Rollback container snapshot
|
||||
community.general.proxmox_snap:
|
||||
api_user: root@pam
|
||||
api_password: 1q2w3e
|
||||
api_host: node1
|
||||
vmid: 100
|
||||
state: rollback
|
||||
snapname: pre-updates
|
||||
'''
|
||||
|
||||
RETURN = r'''#'''
|
||||
@@ -109,15 +119,15 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
|
||||
else:
|
||||
taskid = self.snapshot(vm, vmid).post(snapname=snapname, description=description, vmstate=int(vmstate))
|
||||
while timeout:
|
||||
if (self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['status'] == 'stopped' and
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['exitstatus'] == 'OK'):
|
||||
status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
|
||||
if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
|
||||
return True
|
||||
timeout -= 1
|
||||
if timeout == 0:
|
||||
self.module.fail_json(msg='Reached timeout while waiting for creating VM snapshot. Last line in task before timeout: %s' %
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
|
||||
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
return False
|
||||
|
||||
def snapshot_remove(self, vm, vmid, timeout, snapname, force):
|
||||
@@ -126,15 +136,32 @@ class ProxmoxSnapAnsible(ProxmoxAnsible):
|
||||
|
||||
taskid = self.snapshot(vm, vmid).delete(snapname, force=int(force))
|
||||
while timeout:
|
||||
if (self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['status'] == 'stopped' and
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()['exitstatus'] == 'OK'):
|
||||
status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
|
||||
if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
|
||||
return True
|
||||
timeout -= 1
|
||||
if timeout == 0:
|
||||
self.module.fail_json(msg='Reached timeout while waiting for removing VM snapshot. Last line in task before timeout: %s' %
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
|
||||
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
return False
|
||||
|
||||
def snapshot_rollback(self, vm, vmid, timeout, snapname):
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
||||
taskid = self.snapshot(vm, vmid)(snapname).post("rollback")
|
||||
while timeout:
|
||||
status_data = self.proxmox_api.nodes(vm['node']).tasks(taskid).status.get()
|
||||
if status_data['status'] == 'stopped' and status_data['exitstatus'] == 'OK':
|
||||
return True
|
||||
if timeout == 0:
|
||||
self.module.fail_json(msg='Reached timeout while waiting for rolling back VM snapshot. Last line in task before timeout: %s' %
|
||||
self.proxmox_api.nodes(vm['node']).tasks(taskid).log.get()[:1])
|
||||
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
return False
|
||||
|
||||
|
||||
@@ -144,7 +171,7 @@ def main():
|
||||
vmid=dict(required=False),
|
||||
hostname=dict(),
|
||||
timeout=dict(type='int', default=30),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
state=dict(default='present', choices=['present', 'absent', 'rollback']),
|
||||
description=dict(type='str'),
|
||||
snapname=dict(type='str', default='ansible_snap'),
|
||||
force=dict(type='bool', default='no'),
|
||||
@@ -211,6 +238,25 @@ def main():
|
||||
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Removing snapshot %s of VM %s failed with exception: %s" % (snapname, vmid, to_native(e)))
|
||||
elif state == 'rollback':
|
||||
try:
|
||||
snap_exist = False
|
||||
|
||||
for i in proxmox.snapshot(vm, vmid).get():
|
||||
if i['name'] == snapname:
|
||||
snap_exist = True
|
||||
continue
|
||||
|
||||
if not snap_exist:
|
||||
module.exit_json(changed=False, msg="Snapshot %s does not exist" % snapname)
|
||||
if proxmox.snapshot_rollback(vm, vmid, timeout, snapname):
|
||||
if module.check_mode:
|
||||
module.exit_json(changed=True, msg="Snapshot %s would be rolled back" % snapname)
|
||||
else:
|
||||
module.exit_json(changed=True, msg="Snapshot %s rolled back" % snapname)
|
||||
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Rollback of snapshot %s of VM %s failed with exception: %s" % (snapname, vmid, to_native(e)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -124,6 +124,12 @@ options:
|
||||
type: list
|
||||
elements: path
|
||||
version_added: '0.2.0'
|
||||
provider_upgrade:
|
||||
description:
|
||||
- Allows Terraform init to upgrade providers to versions specified in the project's version constraints.
|
||||
default: false
|
||||
type: bool
|
||||
version_added: 4.8.0
|
||||
init_reconfigure:
|
||||
description:
|
||||
- Forces backend reconfiguration during init.
|
||||
@@ -266,7 +272,7 @@ def _state_args(state_file):
|
||||
return []
|
||||
|
||||
|
||||
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths):
|
||||
def init_plugins(bin_path, project_path, backend_config, backend_config_files, init_reconfigure, provider_upgrade, plugin_paths):
|
||||
command = [bin_path, 'init', '-input=false']
|
||||
if backend_config:
|
||||
for key, val in backend_config.items():
|
||||
@@ -279,6 +285,8 @@ def init_plugins(bin_path, project_path, backend_config, backend_config_files, i
|
||||
command.extend(['-backend-config', f])
|
||||
if init_reconfigure:
|
||||
command.extend(['-reconfigure'])
|
||||
if provider_upgrade:
|
||||
command.extend(['-upgrade'])
|
||||
if plugin_paths:
|
||||
for plugin_path in plugin_paths:
|
||||
command.extend(['-plugin-dir', plugin_path])
|
||||
@@ -324,7 +332,7 @@ def build_plan(command, project_path, variables_args, state_file, targets, state
|
||||
if plan_path is None:
|
||||
f, plan_path = tempfile.mkstemp(suffix='.tfplan')
|
||||
|
||||
local_command = command.copy()
|
||||
local_command = command[:]
|
||||
|
||||
plan_command = [command[0], 'plan']
|
||||
|
||||
@@ -384,6 +392,7 @@ def main():
|
||||
overwrite_init=dict(type='bool', default=True),
|
||||
check_destroy=dict(type='bool', default=False),
|
||||
parallelism=dict(type='int'),
|
||||
provider_upgrade=dict(type='bool', default=False),
|
||||
),
|
||||
required_if=[('state', 'planned', ['plan_file'])],
|
||||
supports_check_mode=True,
|
||||
@@ -405,6 +414,7 @@ def main():
|
||||
init_reconfigure = module.params.get('init_reconfigure')
|
||||
overwrite_init = module.params.get('overwrite_init')
|
||||
check_destroy = module.params.get('check_destroy')
|
||||
provider_upgrade = module.params.get('provider_upgrade')
|
||||
|
||||
if bin_path is not None:
|
||||
command = [bin_path]
|
||||
@@ -422,7 +432,7 @@ def main():
|
||||
|
||||
if force_init:
|
||||
if overwrite_init or not os.path.isfile(os.path.join(project_path, ".terraform", "terraform.tfstate")):
|
||||
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure, plugin_paths)
|
||||
init_plugins(command[0], project_path, backend_config, backend_config_files, init_reconfigure, provider_upgrade, plugin_paths)
|
||||
|
||||
workspace_ctx = get_workspace_context(command[0], project_path)
|
||||
if workspace_ctx["current"] != workspace:
|
||||
|
||||
@@ -630,7 +630,7 @@ def main():
|
||||
plan=dict(),
|
||||
project_id=dict(required=True),
|
||||
state=dict(choices=ALLOWED_STATES, default='present'),
|
||||
user_data=dict(default=None),
|
||||
user_data=dict(),
|
||||
wait_for_public_IPv=dict(type='int', choices=[4, 6]),
|
||||
wait_timeout=dict(type='int', default=900),
|
||||
ipxe_script_url=dict(default=''),
|
||||
|
||||
@@ -226,11 +226,11 @@ def main():
|
||||
state=dict(choices=['present', 'absent'], default='present'),
|
||||
auth_token=dict(default=os.environ.get(PACKET_API_TOKEN_ENV_VAR),
|
||||
no_log=True),
|
||||
label=dict(type='str', aliases=['name'], default=None),
|
||||
id=dict(type='str', default=None),
|
||||
fingerprint=dict(type='str', default=None),
|
||||
key=dict(type='str', default=None, no_log=True),
|
||||
key_file=dict(type='path', default=None),
|
||||
label=dict(type='str', aliases=['name']),
|
||||
id=dict(type='str'),
|
||||
fingerprint=dict(type='str'),
|
||||
key=dict(type='str', no_log=True),
|
||||
key_file=dict(type='path'),
|
||||
),
|
||||
mutually_exclusive=[
|
||||
('label', 'id'),
|
||||
|
||||
@@ -263,9 +263,9 @@ def act_on_volume(target_state, module, packet_conn):
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
id=dict(type='str', default=None),
|
||||
description=dict(type="str", default=None),
|
||||
name=dict(type='str', default=None),
|
||||
id=dict(type='str'),
|
||||
description=dict(type="str"),
|
||||
name=dict(type='str'),
|
||||
state=dict(choices=VOLUME_STATES, default="present"),
|
||||
auth_token=dict(
|
||||
type='str',
|
||||
@@ -277,7 +277,7 @@ def main():
|
||||
facility=dict(type="str"),
|
||||
size=dict(type="int"),
|
||||
locked=dict(type="bool", default=False),
|
||||
snapshot_policy=dict(type='dict', default=None),
|
||||
snapshot_policy=dict(type='dict'),
|
||||
billing_cycle=dict(type='str', choices=BILLING, default="hourly"),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
|
||||
@@ -583,7 +583,7 @@ def main():
|
||||
default='AMD_OPTERON'),
|
||||
volume_size=dict(type='int', default=10),
|
||||
disk_type=dict(choices=['HDD', 'SSD'], default='HDD'),
|
||||
image_password=dict(default=None, no_log=True),
|
||||
image_password=dict(no_log=True),
|
||||
ssh_keys=dict(type='list', elements='str', default=[], no_log=False),
|
||||
bus=dict(choices=['VIRTIO', 'IDE'], default='VIRTIO'),
|
||||
lan=dict(type='int', default=1),
|
||||
|
||||
@@ -95,7 +95,7 @@ class ImageFacts(object):
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
filters=dict(default=None),
|
||||
filters=dict(),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user