mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-29 09:56:53 +00:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
980a9817f3 | ||
|
|
778662921f | ||
|
|
a045d088d5 | ||
|
|
395fc1e77a | ||
|
|
42c65f32eb | ||
|
|
4776e7bed3 | ||
|
|
d423b27288 | ||
|
|
89c56631c8 | ||
|
|
2e34cba62c | ||
|
|
ce5417bb73 | ||
|
|
bf089294b4 | ||
|
|
87a079e93c | ||
|
|
2de375eaf8 | ||
|
|
3a946bf115 | ||
|
|
1e3ad7f189 | ||
|
|
8c386516eb | ||
|
|
058c918cad | ||
|
|
a7dac117e5 | ||
|
|
9fc447dedb | ||
|
|
fc70818ee3 | ||
|
|
a7bbf99448 | ||
|
|
718f88d2c7 | ||
|
|
c596558846 | ||
|
|
21a7159472 | ||
|
|
5dc20d9028 | ||
|
|
2f47748154 | ||
|
|
ddf6b13f18 | ||
|
|
293aee5648 | ||
|
|
f6603d552e | ||
|
|
26dfe96ad6 | ||
|
|
d7b89cde46 | ||
|
|
6808f77f1a | ||
|
|
ec9fd625fc | ||
|
|
b80d408a25 | ||
|
|
7db93a7dd3 | ||
|
|
c79073c687 | ||
|
|
09047058ce | ||
|
|
7de503a2a3 | ||
|
|
b746024c96 | ||
|
|
908a9836c0 | ||
|
|
adea41d773 | ||
|
|
2dd964cab3 | ||
|
|
410101a116 | ||
|
|
ec5dd70f8b | ||
|
|
3473cb504e | ||
|
|
c329192e82 | ||
|
|
7fe5e5f02c | ||
|
|
4482b04463 | ||
|
|
05608ea658 | ||
|
|
a43132ba93 | ||
|
|
33c5e17762 | ||
|
|
42efe21600 | ||
|
|
fc02a7c74e | ||
|
|
ef16e7ea4e | ||
|
|
dce0a65ffe | ||
|
|
ab2c0992e4 | ||
|
|
2c6b2e344b | ||
|
|
d87b91e279 | ||
|
|
505cde7e6b | ||
|
|
0fcf81dd18 | ||
|
|
e62a256724 | ||
|
|
ee7ba1a691 | ||
|
|
ee428ccd64 | ||
|
|
580f8b30a8 | ||
|
|
7204798479 | ||
|
|
59b1329337 | ||
|
|
e3eaeda81a | ||
|
|
b7e68f5b2d | ||
|
|
dcb38bece0 | ||
|
|
c82c375aef | ||
|
|
d5f6889f51 | ||
|
|
ff8e67840f | ||
|
|
c1d142f543 | ||
|
|
cb9be1349a | ||
|
|
59086813c1 | ||
|
|
12319f4a82 | ||
|
|
04b29342d2 | ||
|
|
0d23fa7a49 | ||
|
|
dbec1ebf7a | ||
|
|
feefec42df | ||
|
|
a60cba237f | ||
|
|
76d011ed4b | ||
|
|
3ba00d5a07 | ||
|
|
8eb3003894 | ||
|
|
89158ce325 | ||
|
|
7f8d77b9f3 | ||
|
|
3cf90b3e36 | ||
|
|
189b737c50 | ||
|
|
c4bd7c2b7b | ||
|
|
ea427d3c82 | ||
|
|
bc011c60e6 | ||
|
|
a76537b24f | ||
|
|
327777a1da | ||
|
|
d8ee97c7e9 | ||
|
|
52ffc4eb7c | ||
|
|
be8c05bf65 | ||
|
|
bf284a01cb | ||
|
|
c1f9aeaac8 | ||
|
|
1a5ad80589 | ||
|
|
f2e2157bcc | ||
|
|
20d2488f0f | ||
|
|
7d75bb3d7e | ||
|
|
c5f8719fe9 | ||
|
|
79cfc48dd5 | ||
|
|
e0489d738a | ||
|
|
3e1cbbb617 |
@@ -173,8 +173,8 @@ stages:
|
||||
targets:
|
||||
- name: Alpine 3.18
|
||||
test: alpine/3.18
|
||||
# - name: Fedora 38
|
||||
# test: fedora/38
|
||||
# - name: Fedora 39
|
||||
# test: fedora/39
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu/22.04
|
||||
groups:
|
||||
@@ -189,8 +189,8 @@ stages:
|
||||
targets:
|
||||
- name: macOS 13.2
|
||||
test: macos/13.2
|
||||
- name: RHEL 9.2
|
||||
test: rhel/9.2
|
||||
- name: RHEL 9.3
|
||||
test: rhel/9.3
|
||||
- name: FreeBSD 13.2
|
||||
test: freebsd/13.2
|
||||
groups:
|
||||
@@ -207,6 +207,8 @@ stages:
|
||||
targets:
|
||||
#- name: macOS 13.2
|
||||
# test: macos/13.2
|
||||
- name: RHEL 9.2
|
||||
test: rhel/9.2
|
||||
- name: RHEL 8.8
|
||||
test: rhel/8.8
|
||||
#- name: FreeBSD 13.2
|
||||
@@ -229,10 +231,10 @@ stages:
|
||||
test: rhel/8.7
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
- name: FreeBSD 13.1
|
||||
test: freebsd/13.1
|
||||
- name: FreeBSD 12.4
|
||||
test: freebsd/12.4
|
||||
# - name: FreeBSD 13.1
|
||||
# test: freebsd/13.1
|
||||
# - name: FreeBSD 12.4
|
||||
# test: freebsd/12.4
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
@@ -265,8 +267,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 38
|
||||
test: fedora38
|
||||
- name: Fedora 39
|
||||
test: fedora39
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
@@ -285,6 +287,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.16/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 38
|
||||
test: fedora38
|
||||
- name: openSUSE 15
|
||||
test: opensuse15
|
||||
groups:
|
||||
@@ -315,8 +319,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.14/linux/{0}
|
||||
targets:
|
||||
- name: Fedora 36
|
||||
test: fedora36
|
||||
- name: Alpine 3
|
||||
test: alpine3
|
||||
groups:
|
||||
- 1
|
||||
- 2
|
||||
|
||||
67
.github/BOTMETA.yml
vendored
67
.github/BOTMETA.yml
vendored
@@ -97,6 +97,9 @@ files:
|
||||
$connections/funcd.py:
|
||||
maintainers: mscherer
|
||||
$connections/iocage.py: {}
|
||||
$connections/incus.py:
|
||||
labels: incus
|
||||
maintainers: stgraber
|
||||
$connections/jail.py:
|
||||
maintainers: $team_ansible_core
|
||||
$connections/lxc.py: {}
|
||||
@@ -119,7 +122,7 @@ files:
|
||||
labels: hwc
|
||||
maintainers: $team_huawei
|
||||
$doc_fragments/nomad.py:
|
||||
maintainers: chris93111
|
||||
maintainers: chris93111 apecnascimento
|
||||
$doc_fragments/xenserver.py:
|
||||
labels: xenserver
|
||||
maintainers: bvitnik
|
||||
@@ -133,6 +136,8 @@ files:
|
||||
maintainers: giner
|
||||
$filters/from_csv.py:
|
||||
maintainers: Ajpantuso
|
||||
$filters/from_ini.py:
|
||||
maintainers: sscheib
|
||||
$filters/groupby_as_dict.py:
|
||||
maintainers: felixfontein
|
||||
$filters/hashids.py:
|
||||
@@ -153,6 +158,8 @@ files:
|
||||
maintainers: resmo
|
||||
$filters/to_hours.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_ini.py:
|
||||
maintainers: sscheib
|
||||
$filters/to_milliseconds.yml:
|
||||
maintainers: resmo
|
||||
$filters/to_minutes.yml:
|
||||
@@ -234,6 +241,8 @@ files:
|
||||
$lookups/filetree.py:
|
||||
maintainers: dagwieers
|
||||
$lookups/flattened.py: {}
|
||||
$lookups/github_app_access_token.py:
|
||||
maintainers: weisheng-p
|
||||
$lookups/hiera.py:
|
||||
maintainers: jparrill
|
||||
$lookups/keyring.py: {}
|
||||
@@ -475,6 +484,8 @@ files:
|
||||
maintainers: russoz
|
||||
$modules/dnf_versionlock.py:
|
||||
maintainers: moreda
|
||||
$modules/dnf_config_manager.py:
|
||||
maintainers: ahyattdev
|
||||
$modules/dnsimple.py:
|
||||
maintainers: drcapulet
|
||||
$modules/dnsimple_info.py:
|
||||
@@ -526,6 +537,8 @@ files:
|
||||
maintainers: russoz
|
||||
$modules/git_config.py:
|
||||
maintainers: djmattyg007 mgedmin
|
||||
$modules/git_config_info.py:
|
||||
maintainers: guenhter
|
||||
$modules/github_:
|
||||
maintainers: stpierre
|
||||
$modules/github_deploy_key.py:
|
||||
@@ -547,6 +560,8 @@ files:
|
||||
ignore: dj-wasabi
|
||||
$modules/gitlab_branch.py:
|
||||
maintainers: paytroff
|
||||
$modules/gitlab_issue.py:
|
||||
maintainers: zvaraondrej
|
||||
$modules/gitlab_merge_request.py:
|
||||
maintainers: zvaraondrej
|
||||
$modules/gitlab_project_variable.py:
|
||||
@@ -645,6 +660,9 @@ files:
|
||||
maintainers: bregman-arie
|
||||
$modules/ipa_:
|
||||
maintainers: $team_ipa
|
||||
ignore: fxfitz
|
||||
$modules/ipa_dnsrecord.py:
|
||||
maintainers: $team_ipa jwbernin
|
||||
$modules/ipbase_info.py:
|
||||
maintainers: dominikkukacka
|
||||
$modules/ipa_pwpolicy.py:
|
||||
@@ -740,8 +758,12 @@ files:
|
||||
maintainers: elfelip
|
||||
$modules/keycloak_user_federation.py:
|
||||
maintainers: laurpaum
|
||||
$modules/keycloak_component_info.py:
|
||||
maintainers: desand01
|
||||
$modules/keycloak_user_rolemapping.py:
|
||||
maintainers: bratwurzt
|
||||
$modules/keycloak_realm_rolemapping.py:
|
||||
maintainers: agross mhuysamen Gaetan2907
|
||||
$modules/keyring.py:
|
||||
maintainers: ahussey-redhat
|
||||
$modules/keyring_info.py:
|
||||
@@ -870,7 +892,7 @@ files:
|
||||
$modules/nmcli.py:
|
||||
maintainers: alcamie101
|
||||
$modules/nomad_:
|
||||
maintainers: chris93111
|
||||
maintainers: chris93111 apecnascimento
|
||||
$modules/nosh.py:
|
||||
maintainers: tacatac
|
||||
$modules/npm.py:
|
||||
@@ -1029,6 +1051,10 @@ files:
|
||||
maintainers: helldorado
|
||||
$modules/proxmox_nic.py:
|
||||
maintainers: Kogelvis
|
||||
$modules/proxmox_node_info.py:
|
||||
maintainers: jwbernin
|
||||
$modules/proxmox_storage_contents_info.py:
|
||||
maintainers: l00ptr
|
||||
$modules/proxmox_tasks_info:
|
||||
maintainers: paginabianca
|
||||
$modules/proxmox_template.py:
|
||||
@@ -1399,6 +1425,41 @@ files:
|
||||
maintainers: $team_suse
|
||||
$tests/a_module.py:
|
||||
maintainers: felixfontein
|
||||
$tests/fqdn_valid.py:
|
||||
maintainers: vbotka
|
||||
#########################
|
||||
docs/docsite/rst/filter_guide.rst: {}
|
||||
docs/docsite/rst/filter_guide_abstract_informations.rst: {}
|
||||
docs/docsite/rst/filter_guide_abstract_informations_counting_elements_in_sequence.rst:
|
||||
maintainers: keilr
|
||||
docs/docsite/rst/filter_guide_abstract_informations_dictionaries.rst:
|
||||
maintainers: felixfontein giner
|
||||
docs/docsite/rst/filter_guide_abstract_informations_grouping.rst:
|
||||
maintainers: felixfontein
|
||||
docs/docsite/rst/filter_guide_abstract_informations_merging_lists_of_dictionaries.rst:
|
||||
maintainers: vbotka
|
||||
docs/docsite/rst/filter_guide_conversions.rst:
|
||||
maintainers: Ajpantuso kellyjonbrazil
|
||||
docs/docsite/rst/filter_guide_creating_identifiers.rst:
|
||||
maintainers: Ajpantuso
|
||||
docs/docsite/rst/filter_guide_paths.rst: {}
|
||||
docs/docsite/rst/filter_guide_selecting_json_data.rst: {}
|
||||
docs/docsite/rst/filter_guide_working_with_times.rst:
|
||||
maintainers: resmo
|
||||
docs/docsite/rst/filter_guide_working_with_unicode.rst:
|
||||
maintainers: Ajpantuso
|
||||
docs/docsite/rst/filter_guide_working_with_versions.rst:
|
||||
maintainers: ericzolf
|
||||
docs/docsite/rst/guide_alicloud.rst:
|
||||
maintainers: xiaozhu36
|
||||
docs/docsite/rst/guide_online.rst:
|
||||
maintainers: remyleone
|
||||
docs/docsite/rst/guide_packet.rst:
|
||||
maintainers: baldwinSPC nurfet-becirevic t0mk teebes
|
||||
docs/docsite/rst/guide_scaleway.rst:
|
||||
maintainers: $team_scaleway
|
||||
docs/docsite/rst/test_guide.rst:
|
||||
maintainers: felixfontein
|
||||
#########################
|
||||
tests/:
|
||||
labels: tests
|
||||
@@ -1436,7 +1497,7 @@ macros:
|
||||
team_gitlab: Lunik Shaps marwatk waheedi zanssa scodeman metanovii sh0shin nejch lgatellier suukit
|
||||
team_hpux: bcoca davx8342
|
||||
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
||||
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
||||
team_ipa: Akasurde Nosmoht justchris1
|
||||
team_jboss: Wolfant jairojunior wbrefvem
|
||||
team_keycloak: eikef ndclt mattock
|
||||
team_linode: InTheCloudDan decentral1se displague rmcintosh Charliekenney23 LBGarber
|
||||
|
||||
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -28,9 +28,9 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: python
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
144
CHANGELOG.rst
144
CHANGELOG.rst
@@ -6,6 +6,150 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 7.0.0.
|
||||
|
||||
v8.2.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- ipa_dnsrecord - adds ability to manage NS record types (https://github.com/ansible-collections/community.general/pull/7737).
|
||||
- ipa_pwpolicy - refactor module and exchange a sequence ``if`` statements with a ``for`` loop (https://github.com/ansible-collections/community.general/pull/7723).
|
||||
- ipa_pwpolicy - update module to support ``maxrepeat``, ``maxsequence``, ``dictcheck``, ``usercheck``, ``gracelimit`` parameters in FreeIPA password policies (https://github.com/ansible-collections/community.general/pull/7723).
|
||||
- keycloak_realm_key - the ``config.algorithm`` option now supports 8 additional key algorithms (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_realm_key - the ``config.certificate`` option value is no longer defined with ``no_log=True`` (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_realm_key - the ``provider_id`` option now supports RSA encryption key usage (value ``rsa-enc``) (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_user_federation - allow custom user storage providers to be set through ``provider_id`` (https://github.com/ansible-collections/community.general/pull/7789).
|
||||
- mail - add ``Message-ID`` header; which is required by some mail servers (https://github.com/ansible-collections/community.general/pull/7740).
|
||||
- mail module, mail callback plugin - allow to configure the domain name of the Message-ID header with a new ``message_id_domain`` option (https://github.com/ansible-collections/community.general/pull/7765).
|
||||
- ssh_config - new feature to set ``AddKeysToAgent`` option to ``yes`` or ``no`` (https://github.com/ansible-collections/community.general/pull/7703).
|
||||
- ssh_config - new feature to set ``IdentitiesOnly`` option to ``yes`` or ``no`` (https://github.com/ansible-collections/community.general/pull/7704).
|
||||
- xcc_redfish_command - added support for raw POSTs (``command=PostResource`` in ``category=Raw``) without a specific action info (https://github.com/ansible-collections/community.general/pull/7746).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- keycloak_identity_provider - ``mappers`` processing was not idempotent if the mappers configuration list had not been sorted by name (in ascending order). Fix resolves the issue by sorting mappers in the desired state using the same key which is used for obtaining existing state (https://github.com/ansible-collections/community.general/pull/7418).
|
||||
- keycloak_identity_provider - it was not possible to reconfigure (add, remove) ``mappers`` once they were created initially. Removal was ignored, adding new ones resulted in dropping the pre-existing unmodified mappers. Fix resolves the issue by supplying correct input to the internal update call (https://github.com/ansible-collections/community.general/pull/7418).
|
||||
- keycloak_user - when ``force`` is set, but user does not exist, do not try to delete it (https://github.com/ansible-collections/community.general/pull/7696).
|
||||
- proxmox_kvm - running ``state=template`` will first check whether VM is already a template (https://github.com/ansible-collections/community.general/pull/7792).
|
||||
- statusio_maintenance - fix error caused by incorrectly formed API data payload. Was raising "Failed to create maintenance HTTP Error 400 Bad Request" caused by bad data type for date/time and deprecated dict keys (https://github.com/ansible-collections/community.general/pull/7754).
|
||||
|
||||
New Plugins
|
||||
-----------
|
||||
|
||||
Connection
|
||||
~~~~~~~~~~
|
||||
|
||||
- incus - Run tasks in Incus instances via the Incus CLI.
|
||||
|
||||
Filter
|
||||
~~~~~~
|
||||
|
||||
- from_ini - Converts INI text input into a dictionary
|
||||
- to_ini - Converts a dictionary to the INI file format
|
||||
|
||||
Lookup
|
||||
~~~~~~
|
||||
|
||||
- github_app_access_token - Obtain short-lived Github App Access tokens
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- dnf_config_manager - Enable or disable dnf repositories using config-manager
|
||||
- keycloak_component_info - Retrive component info in Keycloak
|
||||
- keycloak_realm_rolemapping - Allows administration of Keycloak realm role mappings into groups with the Keycloak API
|
||||
- proxmox_node_info - Retrieve information about one or more Proxmox VE nodes
|
||||
- proxmox_storage_contents_info - List content from a Proxmox VE storage
|
||||
|
||||
v8.1.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- bitwarden lookup plugin - when looking for items using an item ID, the item is now accessed directly with ``bw get item`` instead of searching through all items. This doubles the lookup speed (https://github.com/ansible-collections/community.general/pull/7468).
|
||||
- elastic callback plugin - close elastic client to not leak resources (https://github.com/ansible-collections/community.general/pull/7517).
|
||||
- git_config - allow multiple git configs for the same name with the new ``add_mode`` option (https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- git_config - the ``after`` and ``before`` fields in the ``diff`` of the return value can be a list instead of a string in case more configs with the same key are affected (https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- git_config - when a value is unset, all configs with the same key are unset (https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- gitlab modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/7472).
|
||||
- gitlab modules - remove duplicate ``gitlab`` package check (https://github.com/ansible-collections/community.general/pull/7486).
|
||||
- gitlab_runner - add support for new runner creation workflow (https://github.com/ansible-collections/community.general/pull/7199).
|
||||
- ipa_config - adds ``passkey`` choice to ``ipauserauthtype`` parameter's choices (https://github.com/ansible-collections/community.general/pull/7588).
|
||||
- ipa_sudorule - adds options to include denied commands or command groups (https://github.com/ansible-collections/community.general/pull/7415).
|
||||
- ipa_user - adds ``idp`` and ``passkey`` choice to ``ipauserauthtype`` parameter's choices (https://github.com/ansible-collections/community.general/pull/7589).
|
||||
- irc - add ``validate_certs`` option, and rename ``use_ssl`` to ``use_tls``, while keeping ``use_ssl`` as an alias. The default value for ``validate_certs`` is ``false`` for backwards compatibility. We recommend to every user of this module to explicitly set ``use_tls=true`` and `validate_certs=true`` whenever possible, especially when communicating to IRC servers over the internet (https://github.com/ansible-collections/community.general/pull/7550).
|
||||
- keycloak module utils - expose error message from Keycloak server for HTTP errors in some specific situations (https://github.com/ansible-collections/community.general/pull/7645).
|
||||
- keycloak_user_federation - add option for ``krbPrincipalAttribute`` (https://github.com/ansible-collections/community.general/pull/7538).
|
||||
- lvol - change ``pvs`` argument type to list of strings (https://github.com/ansible-collections/community.general/pull/7676, https://github.com/ansible-collections/community.general/issues/7504).
|
||||
- lxd connection plugin - tighten the detection logic for lxd ``Instance not found`` errors, to avoid false detection on unrelated errors such as ``/usr/bin/python3: not found`` (https://github.com/ansible-collections/community.general/pull/7521).
|
||||
- netcup_dns - adds support for record types ``OPENPGPKEY``, ``SMIMEA``, and ``SSHFP`` (https://github.com/ansible-collections/community.general/pull/7489).
|
||||
- nmcli - add support for new connection type ``loopback`` (https://github.com/ansible-collections/community.general/issues/6572).
|
||||
- nmcli - allow for ``infiniband`` slaves of ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7569).
|
||||
- nmcli - allow for the setting of ``MTU`` for ``infiniband`` and ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7499).
|
||||
- onepassword lookup plugin - support 1Password Connect with the opv2 client by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116).
|
||||
- onepassword_raw lookup plugin - support 1Password Connect with the opv2 client by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116)
|
||||
- passwordstore - adds ``timestamp`` and ``preserve`` parameters to modify the stored password format (https://github.com/ansible-collections/community.general/pull/7426).
|
||||
- proxmox - adds ``template`` value to the ``state`` parameter, allowing conversion of container to a template (https://github.com/ansible-collections/community.general/pull/7143).
|
||||
- proxmox - adds ``update`` parameter, allowing update of an already existing containers configuration (https://github.com/ansible-collections/community.general/pull/7540).
|
||||
- proxmox inventory plugin - adds an option to exclude nodes from the dynamic inventory generation. The new setting is optional, not using this option will behave as usual (https://github.com/ansible-collections/community.general/issues/6714, https://github.com/ansible-collections/community.general/pull/7461).
|
||||
- proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).
|
||||
- proxmox_kvm - adds ``template`` value to the ``state`` parameter, allowing conversion of a VM to a template (https://github.com/ansible-collections/community.general/pull/7143).
|
||||
- proxmox_kvm - support the ``hookscript`` parameter (https://github.com/ansible-collections/community.general/issues/7600).
|
||||
- proxmox_ostype - it is now possible to specify the ``ostype`` when creating an LXC container (https://github.com/ansible-collections/community.general/pull/7462).
|
||||
- proxmox_vm_info - add ability to retrieve configuration info (https://github.com/ansible-collections/community.general/pull/7485).
|
||||
- redfish_info - adding the ``BootProgress`` property when getting ``Systems`` info (https://github.com/ansible-collections/community.general/pull/7626).
|
||||
- ssh_config - adds ``controlmaster``, ``controlpath`` and ``controlpersist`` parameters (https://github.com/ansible-collections/community.general/pull/7456).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- apt-rpm - the module did not upgrade packages if a newer version exists. Now the package will be reinstalled if the candidate is newer than the installed version (https://github.com/ansible-collections/community.general/issues/7414).
|
||||
- cloudflare_dns - fix Cloudflare lookup of SHFP records (https://github.com/ansible-collections/community.general/issues/7652).
|
||||
- interface_files - also consider ``address_family`` when changing ``option=method`` (https://github.com/ansible-collections/community.general/issues/7610, https://github.com/ansible-collections/community.general/pull/7612).
|
||||
- irc - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
|
||||
- keycloak_* - fix Keycloak API client to quote ``/`` properly (https://github.com/ansible-collections/community.general/pull/7641).
|
||||
- keycloak_authz_permission - resource payload variable for scope-based permission was constructed as a string, when it needs to be a list, even for a single item (https://github.com/ansible-collections/community.general/issues/7151).
|
||||
- log_entries callback plugin - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
|
||||
- lvol - test for output messages in both ``stdout`` and ``stderr`` (https://github.com/ansible-collections/community.general/pull/7601, https://github.com/ansible-collections/community.general/issues/7182).
|
||||
- onepassword lookup plugin - field and section titles are now case insensitive when using op CLI version two or later. This matches the behavior of version one (https://github.com/ansible-collections/community.general/pull/7564).
|
||||
- redhat_subscription - use the D-Bus registration on RHEL 7 only on 7.4 and
|
||||
greater; older versions of RHEL 7 do not have it
|
||||
(https://github.com/ansible-collections/community.general/issues/7622,
|
||||
https://github.com/ansible-collections/community.general/pull/7624).
|
||||
- terraform - fix multiline string handling in complex variables (https://github.com/ansible-collections/community.general/pull/7535).
|
||||
|
||||
New Plugins
|
||||
-----------
|
||||
|
||||
Lookup
|
||||
~~~~~~
|
||||
|
||||
- onepassword_doc - Fetch documents stored in 1Password
|
||||
|
||||
Test
|
||||
~~~~
|
||||
|
||||
- fqdn_valid - Validates fully-qualified domain names against RFC 1123
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
- git_config_info - Read git configuration
|
||||
- gitlab_issue - Create, update, or delete GitLab issues
|
||||
- nomad_token - Manage Nomad ACL tokens
|
||||
|
||||
v8.0.2
|
||||
======
|
||||
|
||||
|
||||
@@ -823,3 +823,252 @@ releases:
|
||||
- 7506-pipx-pipargs.yml
|
||||
- 8.0.2.yml
|
||||
release_date: '2023-11-13'
|
||||
8.1.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- apt-rpm - the module did not upgrade packages if a newer version exists. Now
|
||||
the package will be reinstalled if the candidate is newer than the installed
|
||||
version (https://github.com/ansible-collections/community.general/issues/7414).
|
||||
- cloudflare_dns - fix Cloudflare lookup of SHFP records (https://github.com/ansible-collections/community.general/issues/7652).
|
||||
- interface_files - also consider ``address_family`` when changing ``option=method``
|
||||
(https://github.com/ansible-collections/community.general/issues/7610, https://github.com/ansible-collections/community.general/pull/7612).
|
||||
- irc - replace ``ssl.wrap_socket`` that was removed from Python 3.12 with code
|
||||
for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
|
||||
- keycloak_* - fix Keycloak API client to quote ``/`` properly (https://github.com/ansible-collections/community.general/pull/7641).
|
||||
- keycloak_authz_permission - resource payload variable for scope-based permission
|
||||
was constructed as a string, when it needs to be a list, even for a single
|
||||
item (https://github.com/ansible-collections/community.general/issues/7151).
|
||||
- log_entries callback plugin - replace ``ssl.wrap_socket`` that was removed
|
||||
from Python 3.12 with code for creating a proper SSL context (https://github.com/ansible-collections/community.general/pull/7542).
|
||||
- lvol - test for output messages in both ``stdout`` and ``stderr`` (https://github.com/ansible-collections/community.general/pull/7601,
|
||||
https://github.com/ansible-collections/community.general/issues/7182).
|
||||
- onepassword lookup plugin - field and section titles are now case insensitive
|
||||
when using op CLI version two or later. This matches the behavior of version
|
||||
one (https://github.com/ansible-collections/community.general/pull/7564).
|
||||
- 'redhat_subscription - use the D-Bus registration on RHEL 7 only on 7.4 and
|
||||
|
||||
greater; older versions of RHEL 7 do not have it
|
||||
|
||||
(https://github.com/ansible-collections/community.general/issues/7622,
|
||||
|
||||
https://github.com/ansible-collections/community.general/pull/7624).
|
||||
|
||||
'
|
||||
- terraform - fix multiline string handling in complex variables (https://github.com/ansible-collections/community.general/pull/7535).
|
||||
minor_changes:
|
||||
- bitwarden lookup plugin - when looking for items using an item ID, the item
|
||||
is now accessed directly with ``bw get item`` instead of searching through
|
||||
all items. This doubles the lookup speed (https://github.com/ansible-collections/community.general/pull/7468).
|
||||
- elastic callback plugin - close elastic client to not leak resources (https://github.com/ansible-collections/community.general/pull/7517).
|
||||
- git_config - allow multiple git configs for the same name with the new ``add_mode``
|
||||
option (https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- git_config - the ``after`` and ``before`` fields in the ``diff`` of the return
|
||||
value can be a list instead of a string in case more configs with the same
|
||||
key are affected (https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- git_config - when a value is unset, all configs with the same key are unset
|
||||
(https://github.com/ansible-collections/community.general/pull/7260).
|
||||
- gitlab modules - add ``ca_path`` option (https://github.com/ansible-collections/community.general/pull/7472).
|
||||
- gitlab modules - remove duplicate ``gitlab`` package check (https://github.com/ansible-collections/community.general/pull/7486).
|
||||
- gitlab_runner - add support for new runner creation workflow (https://github.com/ansible-collections/community.general/pull/7199).
|
||||
- ipa_config - adds ``passkey`` choice to ``ipauserauthtype`` parameter's choices
|
||||
(https://github.com/ansible-collections/community.general/pull/7588).
|
||||
- ipa_sudorule - adds options to include denied commands or command groups (https://github.com/ansible-collections/community.general/pull/7415).
|
||||
- ipa_user - adds ``idp`` and ``passkey`` choice to ``ipauserauthtype`` parameter's
|
||||
choices (https://github.com/ansible-collections/community.general/pull/7589).
|
||||
- irc - add ``validate_certs`` option, and rename ``use_ssl`` to ``use_tls``,
|
||||
while keeping ``use_ssl`` as an alias. The default value for ``validate_certs``
|
||||
is ``false`` for backwards compatibility. We recommend to every user of this
|
||||
module to explicitly set ``use_tls=true`` and `validate_certs=true`` whenever
|
||||
possible, especially when communicating to IRC servers over the internet (https://github.com/ansible-collections/community.general/pull/7550).
|
||||
- keycloak module utils - expose error message from Keycloak server for HTTP
|
||||
errors in some specific situations (https://github.com/ansible-collections/community.general/pull/7645).
|
||||
- keycloak_user_federation - add option for ``krbPrincipalAttribute`` (https://github.com/ansible-collections/community.general/pull/7538).
|
||||
- lvol - change ``pvs`` argument type to list of strings (https://github.com/ansible-collections/community.general/pull/7676,
|
||||
https://github.com/ansible-collections/community.general/issues/7504).
|
||||
- 'lxd connection plugin - tighten the detection logic for lxd ``Instance not
|
||||
found`` errors, to avoid false detection on unrelated errors such as ``/usr/bin/python3:
|
||||
not found`` (https://github.com/ansible-collections/community.general/pull/7521).'
|
||||
- netcup_dns - adds support for record types ``OPENPGPKEY``, ``SMIMEA``, and
|
||||
``SSHFP`` (https://github.com/ansible-collections/community.general/pull/7489).
|
||||
- nmcli - add support for new connection type ``loopback`` (https://github.com/ansible-collections/community.general/issues/6572).
|
||||
- nmcli - allow for ``infiniband`` slaves of ``bond`` interface types (https://github.com/ansible-collections/community.general/pull/7569).
|
||||
- nmcli - allow for the setting of ``MTU`` for ``infiniband`` and ``bond`` interface
|
||||
types (https://github.com/ansible-collections/community.general/pull/7499).
|
||||
- onepassword lookup plugin - support 1Password Connect with the opv2 client
|
||||
by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116).
|
||||
- onepassword_raw lookup plugin - support 1Password Connect with the opv2 client
|
||||
by setting the connect_host and connect_token parameters (https://github.com/ansible-collections/community.general/pull/7116)
|
||||
- passwordstore - adds ``timestamp`` and ``preserve`` parameters to modify the
|
||||
stored password format (https://github.com/ansible-collections/community.general/pull/7426).
|
||||
- proxmox - adds ``template`` value to the ``state`` parameter, allowing conversion
|
||||
of container to a template (https://github.com/ansible-collections/community.general/pull/7143).
|
||||
- proxmox - adds ``update`` parameter, allowing update of an already existing
|
||||
containers configuration (https://github.com/ansible-collections/community.general/pull/7540).
|
||||
- proxmox inventory plugin - adds an option to exclude nodes from the dynamic
|
||||
inventory generation. The new setting is optional, not using this option will
|
||||
behave as usual (https://github.com/ansible-collections/community.general/issues/6714,
|
||||
https://github.com/ansible-collections/community.general/pull/7461).
|
||||
- proxmox_disk - add ability to manipulate CD-ROM drive (https://github.com/ansible-collections/community.general/pull/7495).
|
||||
- proxmox_kvm - adds ``template`` value to the ``state`` parameter, allowing
|
||||
conversion of a VM to a template (https://github.com/ansible-collections/community.general/pull/7143).
|
||||
- proxmox_kvm - support the ``hookscript`` parameter (https://github.com/ansible-collections/community.general/issues/7600).
|
||||
- proxmox_ostype - it is now possible to specify the ``ostype`` when creating
|
||||
an LXC container (https://github.com/ansible-collections/community.general/pull/7462).
|
||||
- proxmox_vm_info - add ability to retrieve configuration info (https://github.com/ansible-collections/community.general/pull/7485).
|
||||
- redfish_info - adding the ``BootProgress`` property when getting ``Systems``
|
||||
info (https://github.com/ansible-collections/community.general/pull/7626).
|
||||
- ssh_config - adds ``controlmaster``, ``controlpath`` and ``controlpersist``
|
||||
parameters (https://github.com/ansible-collections/community.general/pull/7456).
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 000-redhat_subscription-dbus-on-7.4-plus.yaml
|
||||
- 5588-support-1password-connect.yml
|
||||
- 6572-nmcli-add-support-loopback-type.yml
|
||||
- 7143-proxmox-template.yml
|
||||
- 7151-fix-keycloak_authz_permission-incorrect-resource-payload.yml
|
||||
- 7199-gitlab-runner-new-creation-workflow.yml
|
||||
- 7242-multi-values-for-same-name-in-git-config.yml
|
||||
- 7426-add-timestamp-and-preserve-options-for-passwordstore.yaml
|
||||
- 7456-add-ssh-control-master.yml
|
||||
- 7461-proxmox-inventory-add-exclude-nodes.yaml
|
||||
- 7462-Add-ostype-parameter-in-LXC-container-clone-of-ProxmoxVE.yaml
|
||||
- 7472-gitlab-add-ca-path-option.yml
|
||||
- 7485-proxmox_vm_info-config.yml
|
||||
- 7486-gitlab-refactor-package-check.yml
|
||||
- 7489-netcup-dns-record-types.yml
|
||||
- 7495-proxmox_disk-manipulate-cdrom.yml
|
||||
- 7499-allow-mtu-setting-on-bond-and-infiniband-interfaces.yml
|
||||
- 7517-elastic-close-client.yaml
|
||||
- 7535-terraform-fix-multiline-string-handling-in-complex-variables.yml
|
||||
- 7538-add-krbprincipalattribute-option.yml
|
||||
- 7540-proxmox-update config.yml
|
||||
- 7542-irc-logentries-ssl.yml
|
||||
- 7550-irc-use_tls-validate_certs.yml
|
||||
- 7564-onepassword-lookup-case-insensitive.yaml
|
||||
- 7569-infiniband-slave-support.yml
|
||||
- 7577-fix-apt_rpm-module.yml
|
||||
- 7588-ipa-config-new-choice-passkey-to-ipauserauthtype.yml
|
||||
- 7589-ipa-config-new-choices-idp-and-passkey-to-ipauserauthtype.yml
|
||||
- 7600-proxmox_kvm-hookscript.yml
|
||||
- 7601-lvol-fix.yml
|
||||
- 7612-interface_file-method.yml
|
||||
- 7626-redfish-info-add-boot-progress-property.yml
|
||||
- 7641-fix-keycloak-api-client-to-quote-properly.yml
|
||||
- 7645-Keycloak-print-error-msg-from-server.yml
|
||||
- 7653-fix-cloudflare-lookup.yml
|
||||
- 7676-lvol-pvs-as-list.yml
|
||||
- 8.1.0.yml
|
||||
- add-ipa-sudorule-deny-cmd.yml
|
||||
- bitwarden-lookup-performance.yaml
|
||||
- lxd-instance-not-found-avoid-false-positives.yml
|
||||
modules:
|
||||
- description: Read git configuration
|
||||
name: git_config_info
|
||||
namespace: ''
|
||||
- description: Create, update, or delete GitLab issues
|
||||
name: gitlab_issue
|
||||
namespace: ''
|
||||
- description: Manage Nomad ACL tokens
|
||||
name: nomad_token
|
||||
namespace: ''
|
||||
plugins:
|
||||
lookup:
|
||||
- description: Fetch documents stored in 1Password
|
||||
name: onepassword_doc
|
||||
namespace: null
|
||||
test:
|
||||
- description: Validates fully-qualified domain names against RFC 1123
|
||||
name: fqdn_valid
|
||||
namespace: null
|
||||
release_date: '2023-12-04'
|
||||
8.2.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- keycloak_identity_provider - ``mappers`` processing was not idempotent if
|
||||
the mappers configuration list had not been sorted by name (in ascending order).
|
||||
Fix resolves the issue by sorting mappers in the desired state using the same
|
||||
key which is used for obtaining existing state (https://github.com/ansible-collections/community.general/pull/7418).
|
||||
- keycloak_identity_provider - it was not possible to reconfigure (add, remove)
|
||||
``mappers`` once they were created initially. Removal was ignored, adding
|
||||
new ones resulted in dropping the pre-existing unmodified mappers. Fix resolves
|
||||
the issue by supplying correct input to the internal update call (https://github.com/ansible-collections/community.general/pull/7418).
|
||||
- keycloak_user - when ``force`` is set, but user does not exist, do not try
|
||||
to delete it (https://github.com/ansible-collections/community.general/pull/7696).
|
||||
- proxmox_kvm - running ``state=template`` will first check whether VM is already
|
||||
a template (https://github.com/ansible-collections/community.general/pull/7792).
|
||||
- statusio_maintenance - fix error caused by incorrectly formed API data payload.
|
||||
Was raising "Failed to create maintenance HTTP Error 400 Bad Request" caused
|
||||
by bad data type for date/time and deprecated dict keys (https://github.com/ansible-collections/community.general/pull/7754).
|
||||
minor_changes:
|
||||
- ipa_dnsrecord - adds ability to manage NS record types (https://github.com/ansible-collections/community.general/pull/7737).
|
||||
- ipa_pwpolicy - refactor module and exchange a sequence ``if`` statements with
|
||||
a ``for`` loop (https://github.com/ansible-collections/community.general/pull/7723).
|
||||
- ipa_pwpolicy - update module to support ``maxrepeat``, ``maxsequence``, ``dictcheck``,
|
||||
``usercheck``, ``gracelimit`` parameters in FreeIPA password policies (https://github.com/ansible-collections/community.general/pull/7723).
|
||||
- keycloak_realm_key - the ``config.algorithm`` option now supports 8 additional
|
||||
key algorithms (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_realm_key - the ``config.certificate`` option value is no longer
|
||||
defined with ``no_log=True`` (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_realm_key - the ``provider_id`` option now supports RSA encryption
|
||||
key usage (value ``rsa-enc``) (https://github.com/ansible-collections/community.general/pull/7698).
|
||||
- keycloak_user_federation - allow custom user storage providers to be set through
|
||||
``provider_id`` (https://github.com/ansible-collections/community.general/pull/7789).
|
||||
- mail - add ``Message-ID`` header; which is required by some mail servers (https://github.com/ansible-collections/community.general/pull/7740).
|
||||
- mail module, mail callback plugin - allow to configure the domain name of
|
||||
the Message-ID header with a new ``message_id_domain`` option (https://github.com/ansible-collections/community.general/pull/7765).
|
||||
- ssh_config - new feature to set ``AddKeysToAgent`` option to ``yes`` or ``no``
|
||||
(https://github.com/ansible-collections/community.general/pull/7703).
|
||||
- ssh_config - new feature to set ``IdentitiesOnly`` option to ``yes`` or ``no``
|
||||
(https://github.com/ansible-collections/community.general/pull/7704).
|
||||
- xcc_redfish_command - added support for raw POSTs (``command=PostResource``
|
||||
in ``category=Raw``) without a specific action info (https://github.com/ansible-collections/community.general/pull/7746).
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 7418-kc_identity_provider-mapper-reconfiguration-fixes.yml
|
||||
- 7696-avoid-attempt-to-delete-non-existing-user.yml
|
||||
- 7698-improvements-to-keycloak_realm_key.yml
|
||||
- 7703-ssh_config_add_keys_to_agent_option.yml
|
||||
- 7704-ssh_config_identities_only_option.yml
|
||||
- 7723-ipa-pwpolicy-update-pwpolicy-module.yml
|
||||
- 7737-add-ipa-dnsrecord-ns-type.yml
|
||||
- 7740-add-message-id-header-to-mail-module.yml
|
||||
- 7746-raw_post-without-actions.yml
|
||||
- 7754-fixed-payload-format.yml
|
||||
- 7765-mail-message-id.yml
|
||||
- 7789-keycloak-user-federation-custom-provider-type.yml
|
||||
- 7791-proxmox_kvm-state-template-will-check-status-first.yaml
|
||||
- 8.2.0.yml
|
||||
modules:
|
||||
- description: Enable or disable dnf repositories using config-manager
|
||||
name: dnf_config_manager
|
||||
namespace: ''
|
||||
- description: Retrive component info in Keycloak
|
||||
name: keycloak_component_info
|
||||
namespace: ''
|
||||
- description: Allows administration of Keycloak realm role mappings into groups
|
||||
with the Keycloak API
|
||||
name: keycloak_realm_rolemapping
|
||||
namespace: ''
|
||||
- description: Retrieve information about one or more Proxmox VE nodes
|
||||
name: proxmox_node_info
|
||||
namespace: ''
|
||||
- description: List content from a Proxmox VE storage
|
||||
name: proxmox_storage_contents_info
|
||||
namespace: ''
|
||||
plugins:
|
||||
connection:
|
||||
- description: Run tasks in Incus instances via the Incus CLI.
|
||||
name: incus
|
||||
namespace: null
|
||||
filter:
|
||||
- description: Converts INI text input into a dictionary
|
||||
name: from_ini
|
||||
namespace: null
|
||||
- description: Converts a dictionary to the INI file format
|
||||
name: to_ini
|
||||
namespace: null
|
||||
lookup:
|
||||
- description: Obtain short-lived Github App Access tokens
|
||||
name: github_app_access_token
|
||||
namespace: null
|
||||
release_date: '2024-01-01'
|
||||
|
||||
@@ -8,3 +8,9 @@ sections:
|
||||
toctree:
|
||||
- filter_guide
|
||||
- test_guide
|
||||
- title: Cloud Guides
|
||||
toctree:
|
||||
- guide_alicloud
|
||||
- guide_online
|
||||
- guide_packet
|
||||
- guide_scaleway
|
||||
|
||||
96
docs/docsite/rst/guide_alicloud.rst
Normal file
96
docs/docsite/rst/guide_alicloud.rst
Normal file
@@ -0,0 +1,96 @@
|
||||
..
|
||||
Copyright (c) Ansible Project
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_alicloud:
|
||||
|
||||
Alibaba Cloud Compute Services Guide
|
||||
====================================
|
||||
|
||||
Introduction
|
||||
````````````
|
||||
|
||||
The community.general collection contains several modules for controlling and managing Alibaba Cloud Compute Services (Alicloud). This guide
|
||||
explains how to use the Alicloud Ansible modules together.
|
||||
|
||||
All Alicloud modules require ``footmark`` - install it on your control machine with ``pip install footmark``.
|
||||
|
||||
Cloud modules, including Alicloud modules, are usually executed on your local machine (the control machine) with ``connection: local``, rather than on remote machines defined in your hosts.
|
||||
|
||||
Normally, you'll use the following pattern for plays that provision Alicloud resources:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
vars:
|
||||
- ...
|
||||
tasks:
|
||||
- ...
|
||||
|
||||
Authentication
|
||||
``````````````
|
||||
|
||||
You can specify your Alicloud authentication credentials (access key and secret key) by passing them as
|
||||
environment variables or by storing them in a vars file.
|
||||
|
||||
To pass authentication credentials as environment variables:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
export ALICLOUD_ACCESS_KEY='Alicloud123'
|
||||
export ALICLOUD_SECRET_KEY='AlicloudSecret123'
|
||||
|
||||
To store authentication credentials in a vars file, encrypt them with :ref:`Ansible Vault <vault>` to keep them secure, then list them:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
alicloud_access_key: "--REMOVED--"
|
||||
alicloud_secret_key: "--REMOVED--"
|
||||
|
||||
Note that if you store your credentials in a vars file, you need to refer to them in each Alicloud module. For example:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- community.general.ali_instance:
|
||||
alicloud_access_key: "{{ alicloud_access_key }}"
|
||||
alicloud_secret_key: "{{ alicloud_secret_key }}"
|
||||
image_id: "..."
|
||||
|
||||
Provisioning
|
||||
````````````
|
||||
|
||||
Alicloud modules create Alicloud ECS instances (:ansplugin:`community.general.ali_instance#module`) and retrieve information on these (:ansplugin:`community.general.ali_instance_info#module`).
|
||||
|
||||
You can use the ``count`` parameter to control the number of resources you create or terminate. For example, if you want exactly 5 instances tagged ``NewECS``, set the ``count`` of instances to 5 and the ``count_tag`` to ``NewECS``, as shown in the last task of the example playbook below. If there are no instances with the tag ``NewECS``, the task creates 5 new instances. If there are 2 instances with that tag, the task creates 3 more. If there are 8 instances with that tag, the task terminates 3 of those instances.
|
||||
|
||||
If you do not specify a ``count_tag``, the task creates the number of instances you specify in ``count`` with the ``instance_name`` you provide.
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
# alicloud_setup.yml
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
|
||||
tasks:
|
||||
- name: Create a set of instances
|
||||
community.general.ali_instance:
|
||||
instance_type: ecs.n4.small
|
||||
image_id: "{{ ami_id }}"
|
||||
instance_name: "My-new-instance"
|
||||
instance_tags:
|
||||
Name: NewECS
|
||||
Version: 0.0.1
|
||||
count: 5
|
||||
count_tag:
|
||||
Name: NewECS
|
||||
allocate_public_ip: true
|
||||
max_bandwidth_out: 50
|
||||
register: create_instance
|
||||
|
||||
In the example playbook above, data about the instances created by this playbook is saved in the variable defined by the ``register`` keyword in the task.
|
||||
|
||||
Each Alicloud module offers a variety of parameter options. Not all options are demonstrated in the above example. See each individual module for further details and examples.
|
||||
49
docs/docsite/rst/guide_online.rst
Normal file
49
docs/docsite/rst/guide_online.rst
Normal file
@@ -0,0 +1,49 @@
|
||||
..
|
||||
Copyright (c) Ansible Project
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_online:
|
||||
|
||||
****************
|
||||
Online.net Guide
|
||||
****************
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Online is a French hosting company mainly known for providing bare-metal servers named Dedibox.
|
||||
Check it out: `https://www.online.net/en <https://www.online.net/en>`_
|
||||
|
||||
Dynamic inventory for Online resources
|
||||
--------------------------------------
|
||||
|
||||
Ansible has a dynamic inventory plugin that can list your resources.
|
||||
|
||||
1. Create a YAML configuration such as ``online_inventory.yml`` with this content:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
plugin: community.general.online
|
||||
|
||||
2. Set your ``ONLINE_TOKEN`` environment variable with your token.
|
||||
|
||||
You need to open an account and log into it before you can get a token.
|
||||
You can find your token at the following page: `https://console.online.net/en/api/access <https://console.online.net/en/api/access>`_
|
||||
|
||||
3. You can test that your inventory is working by running:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ansible-inventory -v -i online_inventory.yml --list
|
||||
|
||||
|
||||
4. Now you can run your playbook or any other module with this inventory:
|
||||
|
||||
.. code-block:: ansible-output
|
||||
|
||||
$ ansible all -i online_inventory.yml -m ping
|
||||
sd-96735 | SUCCESS => {
|
||||
"changed": false,
|
||||
"ping": "pong"
|
||||
}
|
||||
214
docs/docsite/rst/guide_packet.rst
Normal file
214
docs/docsite/rst/guide_packet.rst
Normal file
@@ -0,0 +1,214 @@
|
||||
..
|
||||
Copyright (c) Ansible Project
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_packet:
|
||||
|
||||
**********************************
|
||||
Packet.net Guide
|
||||
**********************************
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
`Packet.net <https://packet.net>`_ is a bare metal infrastructure host that is supported by the community.general collection through six cloud modules. The six modules are:
|
||||
|
||||
- :ansplugin:`community.general.packet_device#module`: manages servers on Packet. You can use this module to create, restart and delete devices.
|
||||
- :ansplugin:`community.general.packet_ip_subnet#module`: assign IP subnet to a bare metal server
|
||||
- :ansplugin:`community.general.packet_project#module`: create/delete a project in Packet host
|
||||
- :ansplugin:`community.general.packet_sshkey#module`: adds a public SSH key from file or value to the Packet infrastructure. Every subsequently-created device will have this public key installed in .ssh/authorized_keys.
|
||||
- :ansplugin:`community.general.packet_volume#module`: create/delete a volume in Packet host
|
||||
- :ansplugin:`community.general.packet_volume_attachment#module`: attach/detach a volume to a device in the Packet host
|
||||
|
||||
Note, this guide assumes you are familiar with Ansible and how it works. If you are not, have a look at their :ref:`docs <ansible_documentation>` before getting started.
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
The Packet modules connect to the Packet API using the `packet-python package <https://pypi.org/project/packet-python/>`_. You can install it with pip:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install packet-python
|
||||
|
||||
In order to check the state of devices created by Ansible on Packet, it is a good idea to install one of the `Packet CLI clients <https://www.packet.net/developers/integrations/>`_. Otherwise you can check them through the `Packet portal <https://app.packet.net/portal>`_.
|
||||
|
||||
To use the modules you will need a Packet API token. You can generate an API token through the Packet portal `here <https://app.packet.net/portal#/api-keys>`__. The simplest way to authenticate yourself is to set the Packet API token in an environment variable:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export PACKET_API_TOKEN=Bfse9F24SFtfs423Gsd3ifGsd43sSdfs
|
||||
|
||||
If you are not comfortable exporting your API token, you can pass it as a parameter to the modules.
|
||||
|
||||
On Packet, devices and reserved IP addresses belong to `projects <https://www.packet.com/developers/api/#projects>`_. In order to use the packet_device module, you need to specify the UUID of the project in which you want to create or manage devices. You can find a project's UUID in the Packet portal `here <https://app.packet.net/portal#/projects/list/table/>`_ (it is just under the project table) or through one of the available `CLIs <https://www.packet.net/developers/integrations/>`_.
|
||||
|
||||
|
||||
If you want to use a new SSH key pair in this tutorial, you can generate it to ``./id_rsa`` and ``./id_rsa.pub`` as:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ssh-keygen -t rsa -f ./id_rsa
|
||||
|
||||
If you want to use an existing key pair, just copy the private and public key over to the playbook directory.
|
||||
|
||||
|
||||
Device Creation
|
||||
===============
|
||||
|
||||
The following code block is a simple playbook that creates one `Type 0 <https://www.packet.com/cloud/servers/t1-small/>`_ server (the ``plan`` parameter). You have to supply ``plan`` and ``operating_system``. ``location`` defaults to ``ewr1`` (Parsippany, NJ). You can find all the possible values for the parameters through a `CLI client <https://www.packet.net/developers/integrations/>`_.
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
# playbook_create.yml
|
||||
|
||||
- name: Create Ubuntu device
|
||||
hosts: localhost
|
||||
tasks:
|
||||
|
||||
- community.general.packet_sshkey:
|
||||
key_file: ./id_rsa.pub
|
||||
label: tutorial key
|
||||
|
||||
- community.general.packet_device:
|
||||
project_id: <your_project_id>
|
||||
hostnames: myserver
|
||||
operating_system: ubuntu_16_04
|
||||
plan: baremetal_0
|
||||
facility: sjc1
|
||||
|
||||
After running ``ansible-playbook playbook_create.yml``, you should have a server provisioned on Packet. You can verify through a CLI or in the `Packet portal <https://app.packet.net/portal#/projects/list/table>`__.
|
||||
|
||||
If you get an error with the message "failed to set machine state present, error: Error 404: Not Found", please verify your project UUID.
|
||||
|
||||
|
||||
Updating Devices
|
||||
================
|
||||
|
||||
The two parameters used to uniquely identify Packet devices are: "device_ids" and "hostnames". Both parameters accept either a single string (later converted to a one-element list), or a list of strings.
|
||||
|
||||
The ``device_ids`` and ``hostnames`` parameters are mutually exclusive. The following values are all acceptable:
|
||||
|
||||
- device_ids: ``a27b7a83-fc93-435b-a128-47a5b04f2dcf``
|
||||
|
||||
- hostnames: ``mydev1``
|
||||
|
||||
- device_ids: ``[a27b7a83-fc93-435b-a128-47a5b04f2dcf, 4887130f-0ccd-49a0-99b0-323c1ceb527b]``
|
||||
|
||||
- hostnames: ``[mydev1, mydev2]``
|
||||
|
||||
In addition, hostnames can contain a special ``%d`` formatter along with a ``count`` parameter that lets you easily expand hostnames that follow a simple name and number pattern; in other words, ``hostnames: "mydev%d", count: 2`` will expand to [mydev1, mydev2].
|
||||
|
||||
If your playbook acts on existing Packet devices, you can only pass the ``hostname`` and ``device_ids`` parameters. The following playbook shows how you can reboot a specific Packet device by setting the ``hostname`` parameter:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
# playbook_reboot.yml
|
||||
|
||||
- name: reboot myserver
|
||||
hosts: localhost
|
||||
tasks:
|
||||
|
||||
- community.general.packet_device:
|
||||
project_id: <your_project_id>
|
||||
hostnames: myserver
|
||||
state: rebooted
|
||||
|
||||
You can also identify specific Packet devices with the ``device_ids`` parameter. The device's UUID can be found in the `Packet Portal <https://app.packet.net/portal>`_ or by using a `CLI <https://www.packet.net/developers/integrations/>`_. The following playbook removes a Packet device using the ``device_ids`` field:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
# playbook_remove.yml
|
||||
|
||||
- name: remove a device
|
||||
hosts: localhost
|
||||
tasks:
|
||||
|
||||
- community.general.packet_device:
|
||||
project_id: <your_project_id>
|
||||
device_ids: <myserver_device_id>
|
||||
state: absent
|
||||
|
||||
|
||||
More Complex Playbooks
|
||||
======================
|
||||
|
||||
In this example, we will create a CoreOS cluster with `user data <https://packet.com/developers/docs/servers/key-features/user-data/>`_.
|
||||
|
||||
|
||||
The CoreOS cluster will use `etcd <https://etcd.io/>`_ for discovery of other servers in the cluster. Before provisioning your servers, you will need to generate a discovery token for your cluster:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ curl -w "\n" 'https://discovery.etcd.io/new?size=3'
|
||||
|
||||
The following playbook will create an SSH key, 3 Packet servers, and then wait until SSH is ready (or until 5 minutes passed). Make sure to substitute the discovery token URL in ``user_data``, and the ``project_id`` before running ``ansible-playbook``. Also, feel free to change ``plan`` and ``facility``.
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
# playbook_coreos.yml
|
||||
|
||||
- name: Start 3 CoreOS nodes in Packet and wait until SSH is ready
|
||||
hosts: localhost
|
||||
tasks:
|
||||
|
||||
- community.general.packet_sshkey:
|
||||
key_file: ./id_rsa.pub
|
||||
label: new
|
||||
|
||||
- community.general.packet_device:
|
||||
hostnames: [coreos-one, coreos-two, coreos-three]
|
||||
operating_system: coreos_beta
|
||||
plan: baremetal_0
|
||||
facility: ewr1
|
||||
project_id: <your_project_id>
|
||||
wait_for_public_IPv: 4
|
||||
user_data: |
|
||||
#cloud-config
|
||||
coreos:
|
||||
etcd2:
|
||||
discovery: https://discovery.etcd.io/<token>
|
||||
advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001
|
||||
initial-advertise-peer-urls: http://$private_ipv4:2380
|
||||
listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
|
||||
listen-peer-urls: http://$private_ipv4:2380
|
||||
fleet:
|
||||
public-ip: $private_ipv4
|
||||
units:
|
||||
- name: etcd2.service
|
||||
command: start
|
||||
- name: fleet.service
|
||||
command: start
|
||||
register: newhosts
|
||||
|
||||
- name: wait for ssh
|
||||
ansible.builtin.wait_for:
|
||||
delay: 1
|
||||
host: "{{ item.public_ipv4 }}"
|
||||
port: 22
|
||||
state: started
|
||||
timeout: 500
|
||||
loop: "{{ newhosts.results[0].devices }}"
|
||||
|
||||
|
||||
As with most Ansible modules, the default states of the Packet modules are idempotent, meaning the resources in your project will remain the same after re-runs of a playbook. Thus, we can keep the ``packet_sshkey`` module call in our playbook. If the public key is already in your Packet account, the call will have no effect.
|
||||
|
||||
The second module call provisions 3 Packet Type 0 (specified using the ``plan`` parameter) servers in the project identified by the ``project_id`` parameter. The servers are all provisioned with CoreOS beta (the ``operating_system`` parameter) and are customized with cloud-config user data passed to the ``user_data`` parameter.
|
||||
|
||||
The ``packet_device`` module has a ``wait_for_public_IPv`` that is used to specify the version of the IP address to wait for (valid values are ``4`` or ``6`` for IPv4 or IPv6). If specified, Ansible will wait until the GET API call for a device contains an Internet-routeable IP address of the specified version. When referring to an IP address of a created device in subsequent module calls, it is wise to use the ``wait_for_public_IPv`` parameter, or ``state: active`` in the packet_device module call.
|
||||
|
||||
Run the playbook:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ansible-playbook playbook_coreos.yml
|
||||
|
||||
Once the playbook quits, your new devices should be reachable through SSH. Try to connect to one and check if etcd has started properly:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
tomk@work $ ssh -i id_rsa core@$one_of_the_servers_ip
|
||||
core@coreos-one ~ $ etcdctl cluster-health
|
||||
|
||||
If you have any questions or comments let us know! help@packet.net
|
||||
320
docs/docsite/rst/guide_scaleway.rst
Normal file
320
docs/docsite/rst/guide_scaleway.rst
Normal file
@@ -0,0 +1,320 @@
|
||||
..
|
||||
Copyright (c) Ansible Project
|
||||
GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
.. _ansible_collections.community.general.docsite.guide_scaleway:
|
||||
|
||||
**************
|
||||
Scaleway Guide
|
||||
**************
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
`Scaleway <https://scaleway.com>`_ is a cloud provider supported by the community.general collection through a set of plugins and modules.
|
||||
Those modules are:
|
||||
|
||||
- :ansplugin:`community.general.scaleway_compute#module`: manages servers on Scaleway. You can use this module to create, restart and delete servers.
|
||||
- :ansplugin:`community.general.scaleway_compute_private_network#module`
|
||||
- :ansplugin:`community.general.scaleway_container#module`
|
||||
- :ansplugin:`community.general.scaleway_container_info#module`
|
||||
- :ansplugin:`community.general.scaleway_container_namespace_info#module`
|
||||
- :ansplugin:`community.general.scaleway_container_namespace#module`
|
||||
- :ansplugin:`community.general.scaleway_container_registry_info#module`
|
||||
- :ansplugin:`community.general.scaleway_container_registry#module`
|
||||
- :ansplugin:`community.general.scaleway_database_backup#module`
|
||||
- :ansplugin:`community.general.scaleway_function#module`
|
||||
- :ansplugin:`community.general.scaleway_function_info#module`
|
||||
- :ansplugin:`community.general.scaleway_function_namespace_info#module`
|
||||
- :ansplugin:`community.general.scaleway_function_namespace#module`
|
||||
- :ansplugin:`community.general.scaleway_image_info#module`
|
||||
- :ansplugin:`community.general.scaleway_ip#module`
|
||||
- :ansplugin:`community.general.scaleway_ip_info#module`
|
||||
- :ansplugin:`community.general.scaleway_lb#module`
|
||||
- :ansplugin:`community.general.scaleway_organization_info#module`
|
||||
- :ansplugin:`community.general.scaleway_private_network#module`
|
||||
- :ansplugin:`community.general.scaleway_security_group#module`
|
||||
- :ansplugin:`community.general.scaleway_security_group_info#module`
|
||||
- :ansplugin:`community.general.scaleway_security_group_rule#module`
|
||||
- :ansplugin:`community.general.scaleway_server_info#module`
|
||||
- :ansplugin:`community.general.scaleway_snapshot_info#module`
|
||||
- :ansplugin:`community.general.scaleway_sshkey#module`: adds a public SSH key from a file or value to the Packet infrastructure. Every subsequently-created device will have this public key installed in .ssh/authorized_keys.
|
||||
- :ansplugin:`community.general.scaleway_user_data#module`
|
||||
- :ansplugin:`community.general.scaleway_volume#module`: manages volumes on Scaleway.
|
||||
- :ansplugin:`community.general.scaleway_volume_info#module`
|
||||
|
||||
The plugins are:
|
||||
|
||||
- :ansplugin:`community.general.scaleway#inventory`: inventory plugin
|
||||
|
||||
|
||||
.. note::
|
||||
This guide assumes you are familiar with Ansible and how it works.
|
||||
If you are not, have a look at :ref:`ansible_documentation` before getting started.
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
The Scaleway modules and inventory script connect to the Scaleway API using `Scaleway REST API <https://developer.scaleway.com>`_.
|
||||
To use the modules and inventory script you will need a Scaleway API token.
|
||||
You can generate an API token through the `Scaleway console's credential page <https://cloud.scaleway.com/#/credentials>`__.
|
||||
The simplest way to authenticate yourself is to set the Scaleway API token in an environment variable:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ export SCW_TOKEN=00000000-1111-2222-3333-444444444444
|
||||
|
||||
If you are not comfortable exporting your API token, you can pass it as a parameter to the modules using the ``api_token`` argument.
|
||||
|
||||
If you want to use a new SSH key pair in this tutorial, you can generate it to ``./id_rsa`` and ``./id_rsa.pub`` as:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ssh-keygen -t rsa -f ./id_rsa
|
||||
|
||||
If you want to use an existing key pair, just copy the private and public key over to the playbook directory.
|
||||
|
||||
How to add an SSH key?
|
||||
======================
|
||||
|
||||
Connection to Scaleway Compute nodes use Secure Shell.
|
||||
SSH keys are stored at the account level, which means that you can reuse the same SSH key in multiple nodes.
|
||||
The first step to configure Scaleway compute resources is to have at least one SSH key configured.
|
||||
|
||||
:ansplugin:`community.general.scaleway_sshkey#module` is a module that manages SSH keys on your Scaleway account.
|
||||
You can add an SSH key to your account by including the following task in a playbook:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- name: "Add SSH key"
|
||||
community.general.scaleway_sshkey:
|
||||
ssh_pub_key: "ssh-rsa AAAA..."
|
||||
state: "present"
|
||||
|
||||
The ``ssh_pub_key`` parameter contains your ssh public key as a string. Here is an example inside a playbook:
|
||||
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- name: Test SSH key lifecycle on a Scaleway account
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
environment:
|
||||
SCW_API_KEY: ""
|
||||
|
||||
tasks:
|
||||
|
||||
- community.general.scaleway_sshkey:
|
||||
ssh_pub_key: "ssh-rsa AAAAB...424242 developer@example.com"
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- ansible.builtin.assert:
|
||||
that:
|
||||
- result is success and result is changed
|
||||
|
||||
How to create a compute instance?
|
||||
=================================
|
||||
|
||||
Now that we have an SSH key configured, the next step is to spin up a server!
|
||||
:ansplugin:`community.general.scaleway_compute#module` is a module that can create, update and delete Scaleway compute instances:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- name: Create a server
|
||||
community.general.scaleway_compute:
|
||||
name: foobar
|
||||
state: present
|
||||
image: 00000000-1111-2222-3333-444444444444
|
||||
organization: 00000000-1111-2222-3333-444444444444
|
||||
region: ams1
|
||||
commercial_type: START1-S
|
||||
|
||||
Here are the parameter details for the example shown above:
|
||||
|
||||
- ``name`` is the name of the instance (the one that will show up in your web console).
|
||||
- ``image`` is the UUID of the system image you would like to use.
|
||||
A list of all images is available for each availability zone.
|
||||
- ``organization`` represents the organization that your account is attached to.
|
||||
- ``region`` represents the Availability Zone which your instance is in (for this example, ``par1`` and ``ams1``).
|
||||
- ``commercial_type`` represents the name of the commercial offers.
|
||||
You can check out the Scaleway pricing page to find which instance is right for you.
|
||||
|
||||
Take a look at this short playbook to see a working example using ``scaleway_compute``:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- name: Test compute instance lifecycle on a Scaleway account
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
environment:
|
||||
SCW_API_KEY: ""
|
||||
|
||||
tasks:
|
||||
|
||||
- name: Create a server
|
||||
register: server_creation_task
|
||||
community.general.scaleway_compute:
|
||||
name: foobar
|
||||
state: present
|
||||
image: 00000000-1111-2222-3333-444444444444
|
||||
organization: 00000000-1111-2222-3333-444444444444
|
||||
region: ams1
|
||||
commercial_type: START1-S
|
||||
wait: true
|
||||
|
||||
- ansible.builtin.debug:
|
||||
var: server_creation_task
|
||||
|
||||
- ansible.builtin.assert:
|
||||
that:
|
||||
- server_creation_task is success
|
||||
- server_creation_task is changed
|
||||
|
||||
- name: Run it
|
||||
community.general.scaleway_compute:
|
||||
name: foobar
|
||||
state: running
|
||||
image: 00000000-1111-2222-3333-444444444444
|
||||
organization: 00000000-1111-2222-3333-444444444444
|
||||
region: ams1
|
||||
commercial_type: START1-S
|
||||
wait: true
|
||||
tags:
|
||||
- web_server
|
||||
register: server_run_task
|
||||
|
||||
- ansible.builtin.debug:
|
||||
var: server_run_task
|
||||
|
||||
- ansible.builtin.assert:
|
||||
that:
|
||||
- server_run_task is success
|
||||
- server_run_task is changed
|
||||
|
||||
Dynamic Inventory Plugin
|
||||
========================
|
||||
|
||||
Ansible ships with :ansplugin:`community.general.scaleway#inventory`.
|
||||
You can now get a complete inventory of your Scaleway resources through this plugin and filter it on
|
||||
different parameters (``regions`` and ``tags`` are currently supported).
|
||||
|
||||
Let us create an example!
|
||||
Suppose that we want to get all hosts that got the tag web_server.
|
||||
Create a file named ``scaleway_inventory.yml`` with the following content:
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
plugin: community.general.scaleway
|
||||
regions:
|
||||
- ams1
|
||||
- par1
|
||||
tags:
|
||||
- web_server
|
||||
|
||||
This inventory means that we want all hosts that got the tag ``web_server`` on the zones ``ams1`` and ``par1``.
|
||||
Once you have configured this file, you can get the information using the following command:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ansible-inventory --list -i scaleway_inventory.yml
|
||||
|
||||
The output will be:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_meta": {
|
||||
"hostvars": {
|
||||
"dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d": {
|
||||
"ansible_verbosity": 6,
|
||||
"arch": "x86_64",
|
||||
"commercial_type": "START1-S",
|
||||
"hostname": "foobar",
|
||||
"ipv4": "192.0.2.1",
|
||||
"organization": "00000000-1111-2222-3333-444444444444",
|
||||
"state": "running",
|
||||
"tags": [
|
||||
"web_server"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"all": {
|
||||
"children": [
|
||||
"ams1",
|
||||
"par1",
|
||||
"ungrouped",
|
||||
"web_server"
|
||||
]
|
||||
},
|
||||
"ams1": {},
|
||||
"par1": {
|
||||
"hosts": [
|
||||
"dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d"
|
||||
]
|
||||
},
|
||||
"ungrouped": {},
|
||||
"web_server": {
|
||||
"hosts": [
|
||||
"dd8e3ae9-0c7c-459e-bc7b-aba8bfa1bb8d"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
As you can see, we get different groups of hosts.
|
||||
``par1`` and ``ams1`` are groups based on location.
|
||||
``web_server`` is a group based on a tag.
|
||||
|
||||
In case a filter parameter is not defined, the plugin supposes all values possible are wanted.
|
||||
This means that for each tag that exists on your Scaleway compute nodes, a group based on each tag will be created.
|
||||
|
||||
Scaleway S3 object storage
|
||||
==========================
|
||||
|
||||
`Object Storage <https://www.scaleway.com/object-storage>`_ allows you to store any kind of objects (documents, images, videos, and so on).
|
||||
As the Scaleway API is S3 compatible, Ansible supports it natively through the amazon.aws modules: :ansplugin:`amazon.aws.s3_bucket#module`, :ansplugin:`amazon.aws.s3_object#module`.
|
||||
|
||||
You can find many examples in the `scaleway_s3 integration tests <https://github.com/ansible/ansible-legacy-tests/tree/devel/test/legacy/roles/scaleway_s3>`_.
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- hosts: myserver
|
||||
vars:
|
||||
scaleway_region: nl-ams
|
||||
s3_url: https://s3.nl-ams.scw.cloud
|
||||
environment:
|
||||
# AWS_ACCESS_KEY matches your scaleway organization id available at https://cloud.scaleway.com/#/account
|
||||
AWS_ACCESS_KEY: 00000000-1111-2222-3333-444444444444
|
||||
# AWS_SECRET_KEY matches a secret token that you can retrieve at https://cloud.scaleway.com/#/credentials
|
||||
AWS_SECRET_KEY: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
|
||||
module_defaults:
|
||||
group/amazon.aws.aws:
|
||||
s3_url: '{{ s3_url }}'
|
||||
region: '{{ scaleway_region }}'
|
||||
tasks:
|
||||
# use a fact instead of a variable, otherwise template is evaluate each time variable is used
|
||||
- ansible.builtin.set_fact:
|
||||
bucket_name: "{{ 99999999 | random | to_uuid }}"
|
||||
|
||||
# "requester_pays:" is mandatory because Scaleway does not implement related API
|
||||
# another way is to use amazon.aws.s3_object and "mode: create" !
|
||||
- amazon.aws.s3_bucket:
|
||||
name: '{{ bucket_name }}'
|
||||
requester_pays:
|
||||
|
||||
- name: Another way to create the bucket
|
||||
amazon.aws.s3_object:
|
||||
bucket: '{{ bucket_name }}'
|
||||
mode: create
|
||||
encrypt: false
|
||||
register: bucket_creation_check
|
||||
|
||||
- name: add something in the bucket
|
||||
amazon.aws.s3_object:
|
||||
mode: put
|
||||
bucket: '{{ bucket_name }}'
|
||||
src: /tmp/test.txt # needs to be created before
|
||||
object: test.txt
|
||||
encrypt: false # server side encryption must be disabled
|
||||
12
galaxy.yml
12
galaxy.yml
@@ -5,17 +5,17 @@
|
||||
|
||||
namespace: community
|
||||
name: general
|
||||
version: 8.0.2
|
||||
version: 8.2.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
description: null
|
||||
description: >-
|
||||
The community.general collection is a part of the Ansible package and includes many modules and
|
||||
plugins supported by Ansible community which are not part of more specialized community collections.
|
||||
license_file: COPYING
|
||||
tags: [community]
|
||||
# NOTE: No dependencies are expected to be added here
|
||||
# dependencies:
|
||||
tags:
|
||||
- community
|
||||
repository: https://github.com/ansible-collections/community.general
|
||||
documentation: https://docs.ansible.com/ansible/latest/collections/community/general/
|
||||
homepage: https://github.com/ansible-collections/community.general
|
||||
issues: https://github.com/ansible-collections/community.general/issues
|
||||
#type: flatmap
|
||||
|
||||
@@ -84,6 +84,7 @@ import time
|
||||
import uuid
|
||||
|
||||
from collections import OrderedDict
|
||||
from contextlib import closing
|
||||
from os.path import basename
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleRuntimeError
|
||||
@@ -201,24 +202,25 @@ class ElasticSource(object):
|
||||
|
||||
apm_cli = self.init_apm_client(apm_server_url, apm_service_name, apm_verify_server_cert, apm_secret_token, apm_api_key)
|
||||
if apm_cli:
|
||||
instrument() # Only call this once, as early as possible.
|
||||
if traceparent:
|
||||
parent = trace_parent_from_string(traceparent)
|
||||
apm_cli.begin_transaction("Session", trace_parent=parent, start=parent_start_time)
|
||||
else:
|
||||
apm_cli.begin_transaction("Session", start=parent_start_time)
|
||||
# Populate trace metadata attributes
|
||||
if self.ansible_version is not None:
|
||||
label(ansible_version=self.ansible_version)
|
||||
label(ansible_session=self.session, ansible_host_name=self.host, ansible_host_user=self.user)
|
||||
if self.ip_address is not None:
|
||||
label(ansible_host_ip=self.ip_address)
|
||||
with closing(apm_cli):
|
||||
instrument() # Only call this once, as early as possible.
|
||||
if traceparent:
|
||||
parent = trace_parent_from_string(traceparent)
|
||||
apm_cli.begin_transaction("Session", trace_parent=parent, start=parent_start_time)
|
||||
else:
|
||||
apm_cli.begin_transaction("Session", start=parent_start_time)
|
||||
# Populate trace metadata attributes
|
||||
if self.ansible_version is not None:
|
||||
label(ansible_version=self.ansible_version)
|
||||
label(ansible_session=self.session, ansible_host_name=self.host, ansible_host_user=self.user)
|
||||
if self.ip_address is not None:
|
||||
label(ansible_host_ip=self.ip_address)
|
||||
|
||||
for task_data in tasks:
|
||||
for host_uuid, host_data in task_data.host_data.items():
|
||||
self.create_span_data(apm_cli, task_data, host_data)
|
||||
for task_data in tasks:
|
||||
for host_uuid, host_data in task_data.host_data.items():
|
||||
self.create_span_data(apm_cli, task_data, host_data)
|
||||
|
||||
apm_cli.end_transaction(name=__name__, result=status, duration=end_time - parent_start_time)
|
||||
apm_cli.end_transaction(name=__name__, result=status, duration=end_time - parent_start_time)
|
||||
|
||||
def create_span_data(self, apm_cli, task_data, host_data):
|
||||
""" create the span with the given TaskData and HostData """
|
||||
|
||||
@@ -18,7 +18,7 @@ DOCUMENTATION = '''
|
||||
requirements:
|
||||
- whitelisting in configuration
|
||||
- certifi (Python library)
|
||||
- flatdict (Python library), if you want to use the 'flatten' option
|
||||
- flatdict (Python library), if you want to use the O(flatten) option
|
||||
options:
|
||||
api:
|
||||
description: URI to the Logentries API.
|
||||
@@ -90,9 +90,9 @@ examples: >
|
||||
api = data.logentries.com
|
||||
port = 10000
|
||||
tls_port = 20000
|
||||
use_tls = no
|
||||
use_tls = true
|
||||
token = dd21fc88-f00a-43ff-b977-e3a4233c53af
|
||||
flatten = False
|
||||
flatten = false
|
||||
'''
|
||||
|
||||
import os
|
||||
@@ -196,15 +196,11 @@ else:
|
||||
class TLSSocketAppender(PlainTextSocketAppender):
|
||||
def open_connection(self):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock = ssl.wrap_socket(
|
||||
context = ssl.create_default_context(
|
||||
purpose=ssl.Purpose.SERVER_AUTH,
|
||||
cafile=certifi.where(), )
|
||||
sock = context.wrap_socket(
|
||||
sock=sock,
|
||||
keyfile=None,
|
||||
certfile=None,
|
||||
server_side=False,
|
||||
cert_reqs=ssl.CERT_REQUIRED,
|
||||
ssl_version=getattr(
|
||||
ssl, 'PROTOCOL_TLSv1_2', ssl.PROTOCOL_TLSv1),
|
||||
ca_certs=certifi.where(),
|
||||
do_handshake_on_connect=True,
|
||||
suppress_ragged_eofs=True, )
|
||||
sock.connect((self.LE_API, self.LE_TLS_PORT))
|
||||
|
||||
@@ -71,6 +71,16 @@ options:
|
||||
ini:
|
||||
- section: callback_mail
|
||||
key: bcc
|
||||
message_id_domain:
|
||||
description:
|
||||
- The domain name to use for the L(Message-ID header, https://en.wikipedia.org/wiki/Message-ID).
|
||||
- The default is the hostname of the control node.
|
||||
type: str
|
||||
ini:
|
||||
- section: callback_mail
|
||||
key: message_id_domain
|
||||
version_added: 8.2.0
|
||||
|
||||
'''
|
||||
|
||||
import json
|
||||
@@ -131,7 +141,7 @@ class CallbackModule(CallbackBase):
|
||||
content += 'To: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in to_addresses])
|
||||
if self.cc:
|
||||
content += 'Cc: %s\n' % ', '.join([email.utils.formataddr(pair) for pair in cc_addresses])
|
||||
content += 'Message-ID: %s\n' % email.utils.make_msgid()
|
||||
content += 'Message-ID: %s\n' % email.utils.make_msgid(domain=self.get_option('message_id_domain'))
|
||||
content += 'Subject: %s\n\n' % subject.strip()
|
||||
content += body
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ DOCUMENTATION = '''
|
||||
short_description: notify using software speech synthesizer
|
||||
description:
|
||||
- This plugin will use the C(say) or C(espeak) program to "speak" about play events.
|
||||
notes:
|
||||
- In Ansible 2.8, this callback has been renamed from C(osx_say) into M(community.general.say).
|
||||
'''
|
||||
|
||||
import platform
|
||||
|
||||
@@ -18,7 +18,6 @@ DOCUMENTATION = '''
|
||||
short_description: Sends play events to a Slack channel
|
||||
description:
|
||||
- This is an ansible callback plugin that sends status updates to a Slack channel during playbook execution.
|
||||
- Before Ansible 2.4 only environment variables were available for configuring this plugin.
|
||||
options:
|
||||
webhook_url:
|
||||
required: true
|
||||
|
||||
@@ -16,7 +16,6 @@ DOCUMENTATION = '''
|
||||
short_description: sends JSON events to syslog
|
||||
description:
|
||||
- This plugin logs ansible-playbook and ansible runs to a syslog server in JSON format.
|
||||
- Before Ansible 2.9 only environment variables were available for configuration.
|
||||
options:
|
||||
server:
|
||||
description: Syslog server that will receive the event.
|
||||
|
||||
168
plugins/connection/incus.py
Normal file
168
plugins/connection/incus.py
Normal file
@@ -0,0 +1,168 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Based on lxd.py (c) 2016, Matt Clay <matt@mystile.com>
|
||||
# (c) 2023, Stephane Graber <stgraber@stgraber.org>
|
||||
# Copyright (c) 2023 Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
author: Stéphane Graber (@stgraber)
|
||||
name: incus
|
||||
short_description: Run tasks in Incus instances via the Incus CLI.
|
||||
description:
|
||||
- Run commands or put/fetch files to an existing Incus instance using Incus CLI.
|
||||
version_added: "8.2.0"
|
||||
options:
|
||||
remote_addr:
|
||||
description:
|
||||
- The instance identifier.
|
||||
default: inventory_hostname
|
||||
vars:
|
||||
- name: ansible_host
|
||||
- name: ansible_incus_host
|
||||
executable:
|
||||
description:
|
||||
- The shell to use for execution inside the instance.
|
||||
default: /bin/sh
|
||||
vars:
|
||||
- name: ansible_executable
|
||||
- name: ansible_incus_executable
|
||||
remote:
|
||||
description:
|
||||
- The name of the Incus remote to use (per C(incus remote list)).
|
||||
- Remotes are used to access multiple servers from a single client.
|
||||
default: local
|
||||
vars:
|
||||
- name: ansible_incus_remote
|
||||
project:
|
||||
description:
|
||||
- The name of the Incus project to use (per C(incus project list)).
|
||||
- Projects are used to divide the instances running on a server.
|
||||
default: default
|
||||
vars:
|
||||
- name: ansible_incus_project
|
||||
"""
|
||||
|
||||
import os
|
||||
from subprocess import call, Popen, PIPE
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleFileNotFound
|
||||
from ansible.module_utils.common.process import get_bin_path
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
from ansible.plugins.connection import ConnectionBase
|
||||
|
||||
|
||||
class Connection(ConnectionBase):
|
||||
""" Incus based connections """
|
||||
|
||||
transport = "incus"
|
||||
has_pipelining = True
|
||||
default_user = 'root'
|
||||
|
||||
def __init__(self, play_context, new_stdin, *args, **kwargs):
|
||||
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
|
||||
|
||||
self._incus_cmd = get_bin_path("incus")
|
||||
|
||||
if not self._incus_cmd:
|
||||
raise AnsibleError("incus command not found in PATH")
|
||||
|
||||
def _connect(self):
|
||||
"""connect to Incus (nothing to do here) """
|
||||
super(Connection, self)._connect()
|
||||
|
||||
if not self._connected:
|
||||
self._display.vvv(u"ESTABLISH Incus CONNECTION FOR USER: root",
|
||||
host=self._instance())
|
||||
self._connected = True
|
||||
|
||||
def _instance(self):
|
||||
# Return only the leading part of the FQDN as the instance name
|
||||
# as Incus instance names cannot be a FQDN.
|
||||
return self.get_option('remote_addr').split(".")[0]
|
||||
|
||||
def exec_command(self, cmd, in_data=None, sudoable=True):
|
||||
""" execute a command on the Incus host """
|
||||
super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
self._display.vvv(u"EXEC {0}".format(cmd),
|
||||
host=self._instance())
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"exec",
|
||||
"%s:%s" % (self.get_option("remote"), self._instance()),
|
||||
"--",
|
||||
self._play_context.executable, "-c", cmd]
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
|
||||
|
||||
process = Popen(local_cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
stdout, stderr = process.communicate(in_data)
|
||||
|
||||
stdout = to_text(stdout)
|
||||
stderr = to_text(stderr)
|
||||
|
||||
if stderr == "Error: Instance is not running.\n":
|
||||
raise AnsibleConnectionFailure("instance not running: %s" %
|
||||
self._instance())
|
||||
|
||||
if stderr == "Error: Instance not found\n":
|
||||
raise AnsibleConnectionFailure("instance not found: %s" %
|
||||
self._instance())
|
||||
|
||||
return process.returncode, stdout, stderr
|
||||
|
||||
def put_file(self, in_path, out_path):
|
||||
""" put a file from local to Incus """
|
||||
super(Connection, self).put_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"PUT {0} TO {1}".format(in_path, out_path),
|
||||
host=self._instance())
|
||||
|
||||
if not os.path.isfile(to_bytes(in_path, errors='surrogate_or_strict')):
|
||||
raise AnsibleFileNotFound("input path is not a file: %s" % in_path)
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"file", "push", "--quiet",
|
||||
in_path,
|
||||
"%s:%s/%s" % (self.get_option("remote"),
|
||||
self._instance(),
|
||||
out_path)]
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
|
||||
call(local_cmd)
|
||||
|
||||
def fetch_file(self, in_path, out_path):
|
||||
""" fetch a file from Incus to local """
|
||||
super(Connection, self).fetch_file(in_path, out_path)
|
||||
|
||||
self._display.vvv(u"FETCH {0} TO {1}".format(in_path, out_path),
|
||||
host=self._instance())
|
||||
|
||||
local_cmd = [
|
||||
self._incus_cmd,
|
||||
"--project", self.get_option("project"),
|
||||
"file", "pull", "--quiet",
|
||||
"%s:%s/%s" % (self.get_option("remote"),
|
||||
self._instance(),
|
||||
in_path),
|
||||
out_path]
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
|
||||
call(local_cmd)
|
||||
|
||||
def close(self):
|
||||
""" close the connection (nothing to do here) """
|
||||
super(Connection, self).close()
|
||||
|
||||
self._connected = False
|
||||
@@ -101,6 +101,8 @@ class Connection(ConnectionBase):
|
||||
self.get_option("executable"), "-c", cmd
|
||||
])
|
||||
|
||||
self._display.vvvvv(u"EXEC {0}".format(local_cmd), host=self._host())
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
in_data = to_bytes(in_data, errors='surrogate_or_strict', nonstring='passthru')
|
||||
|
||||
@@ -110,10 +112,12 @@ class Connection(ConnectionBase):
|
||||
stdout = to_text(stdout)
|
||||
stderr = to_text(stderr)
|
||||
|
||||
self._display.vvvvv(u"EXEC lxc output: {0} {1}".format(stdout, stderr), host=self._host())
|
||||
|
||||
if "is not running" in stderr:
|
||||
raise AnsibleConnectionFailure("instance not running: %s" % self._host())
|
||||
|
||||
if "not found" in stderr:
|
||||
if stderr.strip() == "Error: Instance not found" or stderr.strip() == "error: not found":
|
||||
raise AnsibleConnectionFailure("instance not found: %s" % self._host())
|
||||
|
||||
return process.returncode, stdout, stderr
|
||||
|
||||
@@ -47,7 +47,7 @@ options:
|
||||
aliases: ['assume_role']
|
||||
alicloud_assume_role_arn:
|
||||
description:
|
||||
- The Alibaba Cloud role_arn. The ARN of the role to assume. If ARN is set to an empty string,
|
||||
- The Alibaba Cloud C(role_arn). The ARN of the role to assume. If ARN is set to an empty string,
|
||||
it does not perform role switching. It supports environment variable E(ALICLOUD_ASSUME_ROLE_ARN).
|
||||
ansible will execute with provided credentials.
|
||||
aliases: ['assume_role_arn']
|
||||
@@ -61,7 +61,7 @@ options:
|
||||
type: str
|
||||
alicloud_assume_role_session_expiration:
|
||||
description:
|
||||
- The Alibaba Cloud session_expiration. The time after which the established session for assuming
|
||||
- The Alibaba Cloud C(session_expiration). The time after which the established session for assuming
|
||||
role expires. Valid value range 900-3600 seconds. Default to 3600 (in this case Alicloud use own default
|
||||
value). It supports environment variable E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
aliases: ['assume_role_session_expiration']
|
||||
@@ -85,12 +85,12 @@ options:
|
||||
description:
|
||||
- This is the path to the shared credentials file. It can also be sourced from the E(ALICLOUD_SHARED_CREDENTIALS_FILE)
|
||||
environment variable.
|
||||
- If this is not set and a profile is specified, ~/.aliyun/config.json will be used.
|
||||
- If this is not set and a profile is specified, C(~/.aliyun/config.json) will be used.
|
||||
type: str
|
||||
author:
|
||||
- "He Guimin (@xiaozhu36)"
|
||||
requirements:
|
||||
- "python >= 3.6"
|
||||
- "Python >= 3.6"
|
||||
notes:
|
||||
- If parameters are not set within the module, the following
|
||||
environment variables can be used in decreasing order of precedence
|
||||
@@ -103,7 +103,7 @@ notes:
|
||||
E(ALICLOUD_PROFILE),
|
||||
E(ALICLOUD_ASSUME_ROLE_ARN),
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_NAME),
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION),
|
||||
E(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION).
|
||||
- E(ALICLOUD_REGION) or E(ALICLOUD_REGION_ID) can be typically be used to specify the
|
||||
ALICLOUD region, when required, but this can also be configured in the footmark config file
|
||||
Alicloud region, when required, but this can also be configured in the footmark config file
|
||||
'''
|
||||
|
||||
@@ -14,19 +14,19 @@ class ModuleDocFragment(object):
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
- The resolvable endpoint for the API
|
||||
- The resolvable endpoint for the API.
|
||||
type: str
|
||||
api_username:
|
||||
description:
|
||||
- The username to use for authentication against the API
|
||||
- The username to use for authentication against the API.
|
||||
type: str
|
||||
api_password:
|
||||
description:
|
||||
- The password to use for authentication against the API
|
||||
- The password to use for authentication against the API.
|
||||
type: str
|
||||
validate_certs:
|
||||
description:
|
||||
- Whether or not to validate SSL certs when supplying a https endpoint.
|
||||
- Whether or not to validate SSL certs when supplying a HTTPS endpoint.
|
||||
type: bool
|
||||
default: true
|
||||
'''
|
||||
|
||||
@@ -20,10 +20,10 @@ options:
|
||||
region:
|
||||
description:
|
||||
- The target region.
|
||||
- Regions are defined in Apache libcloud project [libcloud/common/dimensiondata.py]
|
||||
- They are also listed in U(https://libcloud.readthedocs.io/en/latest/compute/drivers/dimensiondata.html)
|
||||
- Note that the default value "na" stands for "North America".
|
||||
- The module prepends 'dd-' to the region choice.
|
||||
- Regions are defined in Apache libcloud project [libcloud/common/dimensiondata.py].
|
||||
- They are also listed in U(https://libcloud.readthedocs.io/en/latest/compute/drivers/dimensiondata.html).
|
||||
- Note that the default value C(na) stands for "North America".
|
||||
- The module prepends C(dd-) to the region choice.
|
||||
type: str
|
||||
default: na
|
||||
mcp_user:
|
||||
|
||||
@@ -34,4 +34,4 @@ options:
|
||||
- Only applicable if O(wait=true).
|
||||
type: int
|
||||
default: 2
|
||||
'''
|
||||
'''
|
||||
|
||||
@@ -39,8 +39,7 @@ options:
|
||||
default: sysadmin
|
||||
requirements:
|
||||
- An EMC VNX Storage device.
|
||||
- Ansible 2.7.
|
||||
- storops (0.5.10 or greater). Install using 'pip install storops'.
|
||||
- storops (0.5.10 or greater). Install using C(pip install storops).
|
||||
notes:
|
||||
- The modules prefixed with emc_vnx are built to support the EMC VNX storage platform.
|
||||
- The modules prefixed with C(emc_vnx) are built to support the EMC VNX storage platform.
|
||||
'''
|
||||
|
||||
@@ -29,4 +29,9 @@ options:
|
||||
- GitLab CI job token for logging in.
|
||||
type: str
|
||||
version_added: 4.2.0
|
||||
ca_path:
|
||||
description:
|
||||
- The CA certificates bundle to use to verify GitLab server certificate.
|
||||
type: str
|
||||
version_added: 8.1.0
|
||||
'''
|
||||
|
||||
@@ -19,8 +19,8 @@ options:
|
||||
required: true
|
||||
user:
|
||||
description:
|
||||
- The user name to login with (currently only user names are
|
||||
supported, and not user IDs).
|
||||
- The user name to login with.
|
||||
- Currently only user names are supported, and not user IDs.
|
||||
type: str
|
||||
required: true
|
||||
password:
|
||||
@@ -31,14 +31,13 @@ options:
|
||||
domain:
|
||||
description:
|
||||
- The name of the Domain to scope to (Identity v3).
|
||||
(currently only domain names are supported, and not domain IDs).
|
||||
- Currently only domain names are supported, and not domain IDs.
|
||||
type: str
|
||||
required: true
|
||||
project:
|
||||
description:
|
||||
- The name of the Tenant (Identity v2) or Project (Identity v3).
|
||||
(currently only project names are supported, and not
|
||||
project IDs).
|
||||
- Currently only project names are supported, and not project IDs.
|
||||
type: str
|
||||
required: true
|
||||
region:
|
||||
@@ -47,20 +46,20 @@ options:
|
||||
type: str
|
||||
id:
|
||||
description:
|
||||
- The id of resource to be managed.
|
||||
- The ID of resource to be managed.
|
||||
type: str
|
||||
notes:
|
||||
- For authentication, you can set identity_endpoint using the
|
||||
E(ANSIBLE_HWC_IDENTITY_ENDPOINT) env variable.
|
||||
E(ANSIBLE_HWC_IDENTITY_ENDPOINT) environment variable.
|
||||
- For authentication, you can set user using the
|
||||
E(ANSIBLE_HWC_USER) env variable.
|
||||
- For authentication, you can set password using the E(ANSIBLE_HWC_PASSWORD) env
|
||||
E(ANSIBLE_HWC_USER) environment variable.
|
||||
- For authentication, you can set password using the E(ANSIBLE_HWC_PASSWORD) environment
|
||||
variable.
|
||||
- For authentication, you can set domain using the E(ANSIBLE_HWC_DOMAIN) env
|
||||
- For authentication, you can set domain using the E(ANSIBLE_HWC_DOMAIN) environment
|
||||
variable.
|
||||
- For authentication, you can set project using the E(ANSIBLE_HWC_PROJECT) env
|
||||
- For authentication, you can set project using the E(ANSIBLE_HWC_PROJECT) environment
|
||||
variable.
|
||||
- For authentication, you can set region using the E(ANSIBLE_HWC_REGION) env variable.
|
||||
- For authentication, you can set region using the E(ANSIBLE_HWC_REGION) environment variable.
|
||||
- Environment variables values will only be used if the playbook values are
|
||||
not set.
|
||||
'''
|
||||
|
||||
@@ -31,8 +31,7 @@ options:
|
||||
required: true
|
||||
notes:
|
||||
- This module requires pyxcli python library.
|
||||
Use 'pip install pyxcli' in order to get pyxcli.
|
||||
Use C(pip install pyxcli) in order to get pyxcli.
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- pyxcli
|
||||
'''
|
||||
|
||||
@@ -16,32 +16,29 @@ options:
|
||||
hostname:
|
||||
description:
|
||||
- The hostname or IP address on which InfluxDB server is listening.
|
||||
- Since Ansible 2.5, defaulted to localhost.
|
||||
type: str
|
||||
default: localhost
|
||||
username:
|
||||
description:
|
||||
- Username that will be used to authenticate against InfluxDB server.
|
||||
- Alias O(login_username) added in Ansible 2.5.
|
||||
type: str
|
||||
default: root
|
||||
aliases: [ login_username ]
|
||||
password:
|
||||
description:
|
||||
- Password that will be used to authenticate against InfluxDB server.
|
||||
- Alias O(login_password) added in Ansible 2.5.
|
||||
type: str
|
||||
default: root
|
||||
aliases: [ login_password ]
|
||||
port:
|
||||
description:
|
||||
- The port on which InfluxDB server is listening
|
||||
- The port on which InfluxDB server is listening.
|
||||
type: int
|
||||
default: 8086
|
||||
path:
|
||||
description:
|
||||
- The path on which InfluxDB server is accessible
|
||||
- Only available when using python-influxdb >= 5.1.0
|
||||
- The path on which InfluxDB server is accessible.
|
||||
- Only available when using python-influxdb >= 5.1.0.
|
||||
type: str
|
||||
default: ''
|
||||
version_added: '0.2.0'
|
||||
@@ -64,7 +61,7 @@ options:
|
||||
description:
|
||||
- Number of retries client will try before aborting.
|
||||
- V(0) indicates try until success.
|
||||
- Only available when using python-influxdb >= 4.1.0
|
||||
- Only available when using python-influxdb >= 4.1.0.
|
||||
type: int
|
||||
default: 3
|
||||
use_udp:
|
||||
|
||||
@@ -18,7 +18,6 @@ options:
|
||||
- Port of FreeIPA / IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PORT) will be used instead.
|
||||
- If both the environment variable E(IPA_PORT) and the value are not specified in the task, then default value is set.
|
||||
- Environment variable fallback mechanism is added in Ansible 2.5.
|
||||
type: int
|
||||
default: 443
|
||||
ipa_host:
|
||||
@@ -26,9 +25,8 @@ options:
|
||||
- IP or hostname of IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_HOST) will be used instead.
|
||||
- If both the environment variable E(IPA_HOST) and the value are not specified in the task, then DNS will be used to try to discover the FreeIPA server.
|
||||
- The relevant entry needed in FreeIPA is the 'ipa-ca' entry.
|
||||
- The relevant entry needed in FreeIPA is the C(ipa-ca) entry.
|
||||
- If neither the DNS entry, nor the environment E(IPA_HOST), nor the value are available in the task, then the default value will be used.
|
||||
- Environment variable fallback mechanism is added in Ansible 2.5.
|
||||
type: str
|
||||
default: ipa.example.com
|
||||
ipa_user:
|
||||
@@ -36,7 +34,6 @@ options:
|
||||
- Administrative account used on IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_USER) will be used instead.
|
||||
- If both the environment variable E(IPA_USER) and the value are not specified in the task, then default value is set.
|
||||
- Environment variable fallback mechanism is added in Ansible 2.5.
|
||||
type: str
|
||||
default: admin
|
||||
ipa_pass:
|
||||
@@ -47,14 +44,12 @@ options:
|
||||
- If the environment variable E(KRB5CCNAME) is available, the module will use this kerberos credentials cache to authenticate to the FreeIPA server.
|
||||
- If the environment variable E(KRB5_CLIENT_KTNAME) is available, and E(KRB5CCNAME) is not; the module will use this kerberos keytab to authenticate.
|
||||
- If GSSAPI is not available, the usage of O(ipa_pass) is required.
|
||||
- Environment variable fallback mechanism is added in Ansible 2.5.
|
||||
type: str
|
||||
ipa_prot:
|
||||
description:
|
||||
- Protocol used by IPA server.
|
||||
- If the value is not specified in the task, the value of environment variable E(IPA_PROT) will be used instead.
|
||||
- If both the environment variable E(IPA_PROT) and the value are not specified in the task, then default value is set.
|
||||
- Environment variable fallback mechanism is added in Ansible 2.5.
|
||||
type: str
|
||||
choices: [ http, https ]
|
||||
default: https
|
||||
|
||||
@@ -69,6 +69,7 @@ options:
|
||||
type: int
|
||||
default: 10
|
||||
version_added: 4.5.0
|
||||
|
||||
http_agent:
|
||||
description:
|
||||
- Configures the HTTP User-Agent header.
|
||||
|
||||
@@ -30,7 +30,7 @@ options:
|
||||
|
||||
auth_url:
|
||||
description:
|
||||
- lxca https full web address
|
||||
- lxca HTTPS full web address.
|
||||
type: str
|
||||
required: true
|
||||
|
||||
@@ -38,7 +38,6 @@ requirements:
|
||||
- pylxca
|
||||
|
||||
notes:
|
||||
- Additional detail about pylxca can be found at U(https://github.com/lenovo/pylxca)
|
||||
- Playbooks using these modules can be found at U(https://github.com/lenovo/ansible.lenovo-lxca)
|
||||
- Check mode is not supported.
|
||||
- Additional detail about pylxca can be found at U(https://github.com/lenovo/pylxca).
|
||||
- Playbooks using these modules can be found at U(https://github.com/lenovo/ansible.lenovo-lxca).
|
||||
'''
|
||||
|
||||
79
plugins/doc_fragments/onepassword.py
Normal file
79
plugins/doc_fragments/onepassword.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
DOCUMENTATION = r'''
|
||||
requirements:
|
||||
- See U(https://support.1password.com/command-line/)
|
||||
options:
|
||||
master_password:
|
||||
description: The password used to unlock the specified vault.
|
||||
aliases: ['vault_password']
|
||||
type: str
|
||||
section:
|
||||
description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
|
||||
domain:
|
||||
description: Domain of 1Password.
|
||||
default: '1password.com'
|
||||
type: str
|
||||
subdomain:
|
||||
description: The 1Password subdomain to authenticate against.
|
||||
type: str
|
||||
account_id:
|
||||
description: The account ID to target.
|
||||
type: str
|
||||
username:
|
||||
description: The username used to sign in.
|
||||
type: str
|
||||
secret_key:
|
||||
description: The secret key used when performing an initial sign in.
|
||||
type: str
|
||||
service_account_token:
|
||||
description:
|
||||
- The access key for a service account.
|
||||
- Only works with 1Password CLI version 2 or later.
|
||||
type: str
|
||||
vault:
|
||||
description: Vault containing the item to retrieve (case-insensitive). If absent will search all vaults.
|
||||
type: str
|
||||
connect_host:
|
||||
description: The host for 1Password Connect. Must be used in combination with O(connect_token).
|
||||
type: str
|
||||
env:
|
||||
- name: OP_CONNECT_HOST
|
||||
version_added: 8.1.0
|
||||
connect_token:
|
||||
description: The token for 1Password Connect. Must be used in combination with O(connect_host).
|
||||
type: str
|
||||
env:
|
||||
- name: OP_CONNECT_TOKEN
|
||||
version_added: 8.1.0
|
||||
'''
|
||||
|
||||
LOOKUP = r'''
|
||||
options:
|
||||
service_account_token:
|
||||
env:
|
||||
- name: OP_SERVICE_ACCOUNT_TOKEN
|
||||
version_added: 8.2.0
|
||||
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), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
|
||||
O(master_password) is required. You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
|
||||
- Can target a specific account by providing the O(account_id).
|
||||
- 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
|
||||
to the 1Password master password.
|
||||
- This lookup stores potentially sensitive data from 1Password as Ansible facts.
|
||||
Facts are subject to caching if enabled, which means this data could be stored in clear text
|
||||
on disk or in a database.
|
||||
- Tested with C(op) version 2.7.2.
|
||||
'''
|
||||
@@ -15,7 +15,7 @@ class ModuleDocFragment(object):
|
||||
options:
|
||||
config:
|
||||
description:
|
||||
- Path to a .json configuration file containing the OneView client configuration.
|
||||
- Path to a JSON configuration file containing the OneView client configuration.
|
||||
The configuration file is optional and when used should be present in the host running the ansible commands.
|
||||
If the file path is not provided, the configuration will be loaded from environment variables.
|
||||
For links to example configuration files or how to use the environment variables verify the notes section.
|
||||
@@ -42,7 +42,7 @@ options:
|
||||
type: str
|
||||
|
||||
requirements:
|
||||
- python >= 2.7.9
|
||||
- Python >= 2.7.9
|
||||
|
||||
notes:
|
||||
- "A sample configuration file for the config parameter can be found at:
|
||||
@@ -70,11 +70,11 @@ options:
|
||||
options:
|
||||
params:
|
||||
description:
|
||||
- List of params to delimit, filter and sort the list of resources.
|
||||
- "params allowed:
|
||||
- C(start): The first item to return, using 0-based indexing.
|
||||
- C(count): The number of resources to return.
|
||||
- C(filter): A general filter/query string to narrow the list of items returned.
|
||||
- C(sort): The sort order of the returned data set."
|
||||
- List of parameters to delimit, filter and sort the list of resources.
|
||||
- "Parameter keys allowed are:"
|
||||
- "C(start): The first item to return, using 0-based indexing."
|
||||
- "C(count): The number of resources to return."
|
||||
- "C(filter): A general filter/query string to narrow the list of items returned."
|
||||
- "C(sort): The sort order of the returned data set."
|
||||
type: dict
|
||||
'''
|
||||
|
||||
@@ -20,7 +20,7 @@ options:
|
||||
aliases: [ oauth_token ]
|
||||
api_url:
|
||||
description:
|
||||
- Online API URL
|
||||
- Online API URL.
|
||||
type: str
|
||||
default: 'https://api.online.net'
|
||||
aliases: [ base_url ]
|
||||
@@ -36,7 +36,7 @@ options:
|
||||
type: bool
|
||||
default: true
|
||||
notes:
|
||||
- Also see the API documentation on U(https://console.online.net/en/api/)
|
||||
- Also see the API documentation on U(https://console.online.net/en/api/).
|
||||
- If O(api_token) is not set within the module, the following
|
||||
environment variables can be used in decreasing order of precedence
|
||||
E(ONLINE_TOKEN), E(ONLINE_API_KEY), E(ONLINE_OAUTH_TOKEN), E(ONLINE_API_TOKEN).
|
||||
|
||||
@@ -64,7 +64,7 @@ options:
|
||||
description:
|
||||
- Configures the transport connection to use when connecting to the
|
||||
remote device. The transport argument supports connectivity to the
|
||||
device over ssh, cli or REST.
|
||||
device over SSH (V(ssh)), CLI (V(cli)), or REST (V(rest)).
|
||||
required: true
|
||||
type: str
|
||||
choices: [ cli, rest, ssh ]
|
||||
|
||||
@@ -10,22 +10,21 @@ __metaclass__ = type
|
||||
class ModuleDocFragment(object):
|
||||
DOCUMENTATION = """
|
||||
requirements:
|
||||
- "python >= 2.7"
|
||||
- Python SDK for Oracle Cloud Infrastructure U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io)
|
||||
- Python SDK for Oracle Cloud Infrastructure U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io)
|
||||
notes:
|
||||
- For OCI python sdk configuration, please refer to
|
||||
U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/configuration.html)
|
||||
- For OCI Python SDK configuration, please refer to
|
||||
U(https://oracle-cloud-infrastructure-python-sdk.readthedocs.io/en/latest/configuration.html).
|
||||
options:
|
||||
config_file_location:
|
||||
description:
|
||||
- Path to configuration file. If not set then the value of the E(OCI_CONFIG_FILE) environment variable,
|
||||
if any, is used. Otherwise, defaults to ~/.oci/config.
|
||||
if any, is used. Otherwise, defaults to C(~/.oci/config).
|
||||
type: str
|
||||
config_profile_name:
|
||||
description:
|
||||
- The profile to load from the config file referenced by O(config_file_location). If not set, then the
|
||||
value of the E(OCI_CONFIG_PROFILE) environment variable, if any, is used. Otherwise, defaults to the
|
||||
"DEFAULT" profile in O(config_file_location).
|
||||
C(DEFAULT) profile in O(config_file_location).
|
||||
default: "DEFAULT"
|
||||
type: str
|
||||
api_user:
|
||||
@@ -70,8 +69,8 @@ class ModuleDocFragment(object):
|
||||
description:
|
||||
- OCID of your tenancy. If not set, then the value of the OCI_TENANCY variable, if any, is
|
||||
used. This option is required if the tenancy OCID is not specified through a configuration file
|
||||
(See O(config_file_location)). To get the tenancy OCID, please refer
|
||||
U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm)
|
||||
(See O(config_file_location)). To get the tenancy OCID, please refer to
|
||||
U(https://docs.us-phoenix-1.oraclecloud.com/Content/API/Concepts/apisigningkey.htm).
|
||||
type: str
|
||||
region:
|
||||
description:
|
||||
|
||||
@@ -21,7 +21,7 @@ class ModuleDocFragment(object):
|
||||
wait_until:
|
||||
description: The lifecycle state to wait for the resource to transition into when O(wait=true). By default,
|
||||
when O(wait=true), we wait for the resource to get into ACTIVE/ATTACHED/AVAILABLE/PROVISIONED/
|
||||
RUNNING applicable lifecycle state during create operation & to get into DELETED/DETACHED/
|
||||
RUNNING applicable lifecycle state during create operation and to get into DELETED/DETACHED/
|
||||
TERMINATED lifecycle state during delete operation.
|
||||
type: str
|
||||
"""
|
||||
|
||||
@@ -32,11 +32,10 @@ options:
|
||||
- FlashBlade API token for admin privileged user.
|
||||
type: str
|
||||
notes:
|
||||
- This module requires the C(purity_fb) Python library
|
||||
- This module requires the C(purity_fb) Python library.
|
||||
- You must set E(PUREFB_URL) and E(PUREFB_API) environment variables
|
||||
if O(fb_url) and O(api_token) arguments are not passed to the module directly
|
||||
if O(fb_url) and O(api_token) arguments are not passed to the module directly.
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- purity_fb >= 1.1
|
||||
'''
|
||||
|
||||
@@ -54,10 +53,9 @@ options:
|
||||
type: str
|
||||
required: true
|
||||
notes:
|
||||
- This module requires the C(purestorage) Python library
|
||||
- This module requires the C(purestorage) Python library.
|
||||
- You must set E(PUREFA_URL) and E(PUREFA_API) environment variables
|
||||
if O(fa_url) and O(api_token) arguments are not passed to the module directly
|
||||
if O(fa_url) and O(api_token) arguments are not passed to the module directly.
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- purestorage
|
||||
'''
|
||||
|
||||
@@ -43,15 +43,14 @@ options:
|
||||
type: bool
|
||||
aliases: [ verify_ssl ]
|
||||
requirements:
|
||||
- python >= 2.6
|
||||
- pyrax
|
||||
notes:
|
||||
- The following environment variables can be used, E(RAX_USERNAME),
|
||||
E(RAX_API_KEY), E(RAX_CREDS_FILE), E(RAX_CREDENTIALS), E(RAX_REGION).
|
||||
- E(RAX_CREDENTIALS) and E(RAX_CREDS_FILE) point to a credentials file
|
||||
appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating)
|
||||
- E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file
|
||||
- E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...)
|
||||
appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating).
|
||||
- E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file.
|
||||
- E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...).
|
||||
'''
|
||||
|
||||
# Documentation fragment including attributes to enable communication
|
||||
@@ -67,7 +66,7 @@ options:
|
||||
type: str
|
||||
description:
|
||||
- The URI of the authentication service.
|
||||
- If not specified will be set to U(https://identity.api.rackspacecloud.com/v2.0/)
|
||||
- If not specified will be set to U(https://identity.api.rackspacecloud.com/v2.0/).
|
||||
credentials:
|
||||
type: path
|
||||
description:
|
||||
@@ -110,13 +109,12 @@ deprecated:
|
||||
why: This module relies on the deprecated package pyrax.
|
||||
alternative: Use the Openstack modules instead.
|
||||
requirements:
|
||||
- python >= 2.6
|
||||
- pyrax
|
||||
notes:
|
||||
- The following environment variables can be used, E(RAX_USERNAME),
|
||||
E(RAX_API_KEY), E(RAX_CREDS_FILE), E(RAX_CREDENTIALS), E(RAX_REGION).
|
||||
- E(RAX_CREDENTIALS) and E(RAX_CREDS_FILE) points to a credentials file
|
||||
appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating)
|
||||
- E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file
|
||||
- E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...)
|
||||
appropriate for pyrax. See U(https://github.com/rackspace/pyrax/blob/master/docs/getting_started.md#authenticating).
|
||||
- E(RAX_USERNAME) and E(RAX_API_KEY) obviate the use of a credentials file.
|
||||
- E(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...).
|
||||
'''
|
||||
|
||||
@@ -42,7 +42,7 @@ options:
|
||||
type: bool
|
||||
default: true
|
||||
notes:
|
||||
- Also see the API documentation on U(https://developer.scaleway.com/)
|
||||
- Also see the API documentation on U(https://developer.scaleway.com/).
|
||||
- If O(api_token) is not set within the module, the following
|
||||
environment variables can be used in decreasing order of precedence
|
||||
E(SCW_TOKEN), E(SCW_API_KEY), E(SCW_OAUTH_TOKEN) or E(SCW_API_TOKEN).
|
||||
|
||||
@@ -14,7 +14,7 @@ options:
|
||||
headers:
|
||||
description:
|
||||
- A dictionary of additional headers to be sent to POST and PUT requests.
|
||||
- Is needed for some modules
|
||||
- Is needed for some modules.
|
||||
type: dict
|
||||
required: false
|
||||
default: {}
|
||||
@@ -30,8 +30,9 @@ options:
|
||||
default: 4444
|
||||
utm_token:
|
||||
description:
|
||||
- "The token used to identify at the REST-API. See U(https://www.sophos.com/en-us/medialibrary/\
|
||||
PDFs/documentation/UTMonAWS/Sophos-UTM-RESTful-API.pdf?la=en), Chapter 2.4.2."
|
||||
- "The token used to identify at the REST-API. See
|
||||
U(https://www.sophos.com/en-us/medialibrary/PDFs/documentation/UTMonAWS/Sophos-UTM-RESTful-API.pdf?la=en),
|
||||
Chapter 2.4.2."
|
||||
type: str
|
||||
required: true
|
||||
utm_protocol:
|
||||
@@ -48,8 +49,8 @@ options:
|
||||
state:
|
||||
description:
|
||||
- The desired state of the object.
|
||||
- V(present) will create or update an object
|
||||
- V(absent) will delete an object if it was present
|
||||
- V(present) will create or update an object.
|
||||
- V(absent) will delete an object if it was present.
|
||||
type: str
|
||||
choices: [ absent, present ]
|
||||
default: present
|
||||
|
||||
@@ -30,11 +30,13 @@ options:
|
||||
user:
|
||||
description:
|
||||
- Vexata API user with administrative privileges.
|
||||
- Uses the E(VEXATA_USER) environment variable as a fallback.
|
||||
required: false
|
||||
type: str
|
||||
password:
|
||||
description:
|
||||
- Vexata API user password.
|
||||
- Uses the E(VEXATA_PASSWORD) environment variable as a fallback.
|
||||
required: false
|
||||
type: str
|
||||
validate_certs:
|
||||
@@ -48,7 +50,6 @@ options:
|
||||
requirements:
|
||||
- Vexata VX100 storage array with VXOS >= v3.5.0 on storage array
|
||||
- vexatapi >= 0.0.1
|
||||
- python >= 2.7
|
||||
- VEXATA_USER and VEXATA_PASSWORD environment variables must be set if
|
||||
- E(VEXATA_USER) and E(VEXATA_PASSWORD) environment variables must be set if
|
||||
user and password arguments are not passed to the module directly.
|
||||
'''
|
||||
|
||||
99
plugins/filter/from_ini.py
Normal file
99
plugins/filter/from_ini.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
name: from_ini
|
||||
short_description: Converts INI text input into a dictionary
|
||||
version_added: 8.2.0
|
||||
author: Steffen Scheib (@sscheib)
|
||||
description:
|
||||
- Converts INI text input into a dictionary.
|
||||
options:
|
||||
_input:
|
||||
description: A string containing an INI document.
|
||||
type: string
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Slurp an INI file
|
||||
ansible.builtin.slurp:
|
||||
src: /etc/rhsm/rhsm.conf
|
||||
register: rhsm_conf
|
||||
|
||||
- name: Display the INI file as dictionary
|
||||
ansible.builtin.debug:
|
||||
var: rhsm_conf.content | b64decode | community.general.from_ini
|
||||
|
||||
- name: Set a new dictionary fact with the contents of the INI file
|
||||
ansible.builtin.set_fact:
|
||||
rhsm_dict: >-
|
||||
{{
|
||||
rhsm_conf.content | b64decode | community.general.from_ini
|
||||
}}
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_value:
|
||||
description: A dictionary representing the INI file.
|
||||
type: dictionary
|
||||
'''
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils.six.moves import StringIO
|
||||
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
''' Implements a configparser which is able to return a dict '''
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.optionxform = str
|
||||
|
||||
def as_dict(self):
|
||||
d = dict(self._sections)
|
||||
for k in d:
|
||||
d[k] = dict(self._defaults, **d[k])
|
||||
d[k].pop('__name__', None)
|
||||
|
||||
if self._defaults:
|
||||
d['DEFAULT'] = dict(self._defaults)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def from_ini(obj):
|
||||
''' Read the given string as INI file and return a dict '''
|
||||
|
||||
if not isinstance(obj, string_types):
|
||||
raise AnsibleFilterError(f'from_ini requires a str, got {type(obj)}')
|
||||
|
||||
parser = IniParser()
|
||||
|
||||
try:
|
||||
parser.read_file(StringIO(obj))
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError(f'from_ini failed to parse given string: '
|
||||
f'{to_native(ex)}', orig_exc=ex)
|
||||
|
||||
return parser.as_dict()
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
''' Query filter '''
|
||||
|
||||
def filters(self):
|
||||
|
||||
return {
|
||||
'from_ini': from_ini
|
||||
}
|
||||
105
plugins/filter/to_ini.py
Normal file
105
plugins/filter/to_ini.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Steffen Scheib <steffen@scheib.me>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
name: to_ini
|
||||
short_description: Converts a dictionary to the INI file format
|
||||
version_added: 8.2.0
|
||||
author: Steffen Scheib (@sscheib)
|
||||
description:
|
||||
- Converts a dictionary to the INI file format.
|
||||
options:
|
||||
_input:
|
||||
description: The dictionary that should be converted to the INI format.
|
||||
type: dictionary
|
||||
required: true
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Define a dictionary
|
||||
ansible.builtin.set_fact:
|
||||
my_dict:
|
||||
section_name:
|
||||
key_name: 'key value'
|
||||
|
||||
another_section:
|
||||
connection: 'ssh'
|
||||
|
||||
- name: Write dictionary to INI file
|
||||
ansible.builtin.copy:
|
||||
dest: /tmp/test.ini
|
||||
content: '{{ my_dict | community.general.to_ini }}'
|
||||
|
||||
# /tmp/test.ini will look like this:
|
||||
# [section_name]
|
||||
# key_name = key value
|
||||
#
|
||||
# [another_section]
|
||||
# connection = ssh
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
_value:
|
||||
description: A string formatted as INI file.
|
||||
type: string
|
||||
'''
|
||||
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.errors import AnsibleFilterError
|
||||
from ansible.module_utils.common._collections_compat import Mapping
|
||||
from ansible.module_utils.six.moves import StringIO
|
||||
from ansible.module_utils.six.moves.configparser import ConfigParser
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
|
||||
class IniParser(ConfigParser):
|
||||
''' Implements a configparser which sets the correct optionxform '''
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.optionxform = str
|
||||
|
||||
|
||||
def to_ini(obj):
|
||||
''' Read the given dict and return an INI formatted string '''
|
||||
|
||||
if not isinstance(obj, Mapping):
|
||||
raise AnsibleFilterError(f'to_ini requires a dict, got {type(obj)}')
|
||||
|
||||
ini_parser = IniParser()
|
||||
|
||||
try:
|
||||
ini_parser.read_dict(obj)
|
||||
except Exception as ex:
|
||||
raise AnsibleFilterError('to_ini failed to parse given dict:'
|
||||
f'{to_native(ex)}', orig_exc=ex)
|
||||
|
||||
# catching empty dicts
|
||||
if obj == dict():
|
||||
raise AnsibleFilterError('to_ini received an empty dict. '
|
||||
'An empty dict cannot be converted.')
|
||||
|
||||
config = StringIO()
|
||||
ini_parser.write(config)
|
||||
|
||||
# config.getvalue() returns two \n at the end
|
||||
# with the below insanity, we remove the very last character of
|
||||
# the resulting string
|
||||
return ''.join(config.getvalue().rsplit(config.getvalue()[-1], 1))
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
''' Query filter '''
|
||||
|
||||
def filters(self):
|
||||
|
||||
return {
|
||||
'to_ini': to_ini
|
||||
}
|
||||
@@ -14,7 +14,6 @@ DOCUMENTATION = '''
|
||||
- Stefan Heitmüller (@morph027) <stefan.heitmueller@gmx.com>
|
||||
short_description: Ansible dynamic inventory plugin for GitLab runners.
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab > 1.8.0
|
||||
extends_documentation_fragment:
|
||||
- constructed
|
||||
|
||||
@@ -72,7 +72,7 @@ url: http://localhost:5665
|
||||
user: ansible
|
||||
password: secure
|
||||
host_filter: \"linux-servers\" in host.groups
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when connecting to localhost!
|
||||
inventory_attr: name
|
||||
groups:
|
||||
# simple name matching
|
||||
|
||||
@@ -12,7 +12,6 @@ DOCUMENTATION = r'''
|
||||
- Luke Murphy (@decentral1se)
|
||||
short_description: Ansible dynamic inventory plugin for Linode.
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- linode_api4 >= 2.0.0
|
||||
description:
|
||||
- Reads inventories from the Linode API v4.
|
||||
|
||||
@@ -116,6 +116,11 @@ DOCUMENTATION = '''
|
||||
- The default of this option changed from V(true) to V(false) in community.general 6.0.0.
|
||||
type: bool
|
||||
default: false
|
||||
exclude_nodes:
|
||||
description: Exclude proxmox nodes and the nodes-group from the inventory output.
|
||||
type: bool
|
||||
default: false
|
||||
version_added: 8.1.0
|
||||
filters:
|
||||
version_added: 4.6.0
|
||||
description: A list of Jinja templates that allow filtering hosts.
|
||||
@@ -166,7 +171,6 @@ plugin: community.general.proxmox
|
||||
url: http://pve.domain.com:8006
|
||||
user: ansible@pve
|
||||
password: secure
|
||||
validate_certs: false
|
||||
want_facts: true
|
||||
keyed_groups:
|
||||
# proxmox_tags_parsed is an example of a fact only returned when 'want_facts=true'
|
||||
@@ -187,10 +191,10 @@ want_proxmox_nodes_ansible_host: true
|
||||
# Note: my_inv_var demonstrates how to add a string variable to every host used by the inventory.
|
||||
# my.proxmox.yml
|
||||
plugin: community.general.proxmox
|
||||
url: http://pve.domain.com:8006
|
||||
url: http://192.168.1.2:8006
|
||||
user: ansible@pve
|
||||
password: secure
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
want_facts: true
|
||||
want_proxmox_nodes_ansible_host: false
|
||||
compose:
|
||||
@@ -565,9 +569,9 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
for group in default_groups:
|
||||
self.inventory.add_group(self._group('all_%s' % (group)))
|
||||
|
||||
nodes_group = self._group('nodes')
|
||||
self.inventory.add_group(nodes_group)
|
||||
if not self.exclude_nodes:
|
||||
self.inventory.add_group(nodes_group)
|
||||
|
||||
want_proxmox_nodes_ansible_host = self.get_option("want_proxmox_nodes_ansible_host")
|
||||
|
||||
@@ -577,22 +581,23 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
for node in self._get_nodes():
|
||||
if not node.get('node'):
|
||||
continue
|
||||
|
||||
self.inventory.add_host(node['node'])
|
||||
if node['type'] == 'node':
|
||||
if not self.exclude_nodes:
|
||||
self.inventory.add_host(node['node'])
|
||||
if node['type'] == 'node' and not self.exclude_nodes:
|
||||
self.inventory.add_child(nodes_group, node['node'])
|
||||
|
||||
if node['status'] == 'offline':
|
||||
continue
|
||||
|
||||
# get node IP address
|
||||
if want_proxmox_nodes_ansible_host:
|
||||
if want_proxmox_nodes_ansible_host and not self.exclude_nodes:
|
||||
ip = self._get_node_ip(node['node'])
|
||||
self.inventory.set_variable(node['node'], 'ansible_host', ip)
|
||||
|
||||
# Setting composite variables
|
||||
variables = self.inventory.get_host(node['node']).get_vars()
|
||||
self._set_composite_vars(self.get_option('compose'), variables, node['node'], strict=self.strict)
|
||||
if not self.exclude_nodes:
|
||||
variables = self.inventory.get_host(node['node']).get_vars()
|
||||
self._set_composite_vars(self.get_option('compose'), variables, node['node'], strict=self.strict)
|
||||
|
||||
# add LXC/Qemu groups for the node
|
||||
for ittype in ('lxc', 'qemu'):
|
||||
@@ -635,8 +640,8 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
|
||||
|
||||
if self.get_option('qemu_extended_statuses') and not self.get_option('want_facts'):
|
||||
raise AnsibleError('You must set want_facts to True if you want to use qemu_extended_statuses.')
|
||||
|
||||
# read rest of options
|
||||
self.exclude_nodes = self.get_option('exclude_nodes')
|
||||
self.cache_key = self.get_cache_key(path)
|
||||
self.use_cache = cache and self.get_option('cache')
|
||||
self.host_filters = self.get_option('filters')
|
||||
|
||||
@@ -25,7 +25,10 @@ DOCUMENTATION = """
|
||||
type: list
|
||||
elements: str
|
||||
search:
|
||||
description: Field to retrieve, for example V(name) or V(id).
|
||||
description:
|
||||
- Field to retrieve, for example V(name) or V(id).
|
||||
- If set to V(id), only zero or one element can be returned.
|
||||
Use the Jinja C(first) filter to get the only list element.
|
||||
type: str
|
||||
default: name
|
||||
version_added: 5.7.0
|
||||
@@ -39,27 +42,27 @@ DOCUMENTATION = """
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: "Get 'password' from Bitwarden record named 'a_test'"
|
||||
- name: "Get 'password' from all Bitwarden records named 'a_test'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test', field='password') }}
|
||||
|
||||
- name: "Get 'password' from Bitwarden record with id 'bafba515-af11-47e6-abe3-af1200cd18b2'"
|
||||
- name: "Get 'password' from Bitwarden record with ID 'bafba515-af11-47e6-abe3-af1200cd18b2'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') }}
|
||||
{{ lookup('community.general.bitwarden', 'bafba515-af11-47e6-abe3-af1200cd18b2', search='id', field='password') | first }}
|
||||
|
||||
- name: "Get 'password' from Bitwarden record named 'a_test' from collection"
|
||||
- name: "Get 'password' from all Bitwarden records named 'a_test' from collection"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test', field='password', collection_id='bafba515-af11-47e6-abe3-af1200cd18b2') }}
|
||||
|
||||
- name: "Get full Bitwarden record named 'a_test'"
|
||||
- name: "Get list of all full Bitwarden records named 'a_test'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test') }}
|
||||
|
||||
- name: "Get custom field 'api_key' from Bitwarden record named 'a_test'"
|
||||
- name: "Get custom field 'api_key' from all Bitwarden records named 'a_test'"
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
{{ lookup('community.general.bitwarden', 'a_test', field='api_key') }}
|
||||
@@ -67,9 +70,12 @@ EXAMPLES = """
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: List of requested field or JSON object of list of matches.
|
||||
description:
|
||||
- A one-element list that contains a list of requested fields or JSON objects of matches.
|
||||
- If you use C(query), you get a list of lists. If you use C(lookup) without C(wantlist=true),
|
||||
this always gets reduced to a list of field values or JSON objects.
|
||||
type: list
|
||||
elements: raw
|
||||
elements: list
|
||||
"""
|
||||
|
||||
from subprocess import Popen, PIPE
|
||||
@@ -104,6 +110,8 @@ class Bitwarden(object):
|
||||
out, err = p.communicate(to_bytes(stdin))
|
||||
rc = p.wait()
|
||||
if rc != expected_rc:
|
||||
if len(args) > 2 and args[0] == 'get' and args[1] == 'item' and b'Not found.' in err:
|
||||
return 'null', ''
|
||||
raise BitwardenException(err)
|
||||
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')
|
||||
|
||||
@@ -112,7 +120,10 @@ class Bitwarden(object):
|
||||
"""
|
||||
|
||||
# Prepare set of params for Bitwarden CLI
|
||||
params = ['list', 'items', '--search', search_value]
|
||||
if search_field == 'id':
|
||||
params = ['get', 'item', search_value]
|
||||
else:
|
||||
params = ['list', 'items', '--search', search_value]
|
||||
|
||||
if collection_id:
|
||||
params.extend(['--collectionid', collection_id])
|
||||
@@ -121,7 +132,11 @@ class Bitwarden(object):
|
||||
|
||||
# This includes things that matched in different fields.
|
||||
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]
|
||||
|
||||
if search_field == 'id':
|
||||
if initial_matches is None:
|
||||
initial_matches = []
|
||||
else:
|
||||
initial_matches = [initial_matches]
|
||||
# Filter to only include results from the right field.
|
||||
return [item for item in initial_matches if item[search_field] == search_value]
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ EXAMPLES = '''
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ lookup('community.general.etcd', 'foo', 'bar', 'baz') }}"
|
||||
|
||||
- name: "since Ansible 2.5 you can set server options inline"
|
||||
- name: "you can set server options inline"
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ lookup('community.general.etcd', 'foo', version='v2', url='http://192.168.0.27:4001') }}"
|
||||
'''
|
||||
@@ -62,7 +62,7 @@ EXAMPLES = '''
|
||||
RETURN = '''
|
||||
_raw:
|
||||
description:
|
||||
- list of values associated with input keys
|
||||
- List of values associated with input keys.
|
||||
type: list
|
||||
elements: string
|
||||
'''
|
||||
|
||||
156
plugins/lookup/github_app_access_token.py
Normal file
156
plugins/lookup/github_app_access_token.py
Normal file
@@ -0,0 +1,156 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2023, Poh Wei Sheng <weisheng-p@hotmail.sg>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: github_app_access_token
|
||||
author:
|
||||
- Poh Wei Sheng (@weisheng-p)
|
||||
short_description: Obtain short-lived Github App Access tokens
|
||||
version_added: '8.2.0'
|
||||
requirements:
|
||||
- jwt (https://github.com/GehirnInc/python-jwt)
|
||||
description:
|
||||
- This generates a Github access token that can be used with a C(git) command, if you use a Github App.
|
||||
options:
|
||||
key_path:
|
||||
description:
|
||||
- Path to your private key.
|
||||
required: true
|
||||
type: path
|
||||
app_id:
|
||||
description:
|
||||
- Your GitHub App ID, you can find this in the Settings page.
|
||||
required: true
|
||||
type: str
|
||||
installation_id:
|
||||
description:
|
||||
- The installation ID that contains the git repository you would like access to.
|
||||
- As of 2023-12-24, this can be found via Settings page > Integrations > Application. The last part of the URL in the
|
||||
configure button is the installation ID.
|
||||
- Alternatively, you can use PyGithub (U(https://github.com/PyGithub/PyGithub)) to get your installation ID.
|
||||
required: true
|
||||
type: str
|
||||
token_expiry:
|
||||
description:
|
||||
- How long the token should last for in seconds.
|
||||
default: 600
|
||||
type: int
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Get access token to be used for git checkout with app_id=123456, installation_id=64209
|
||||
ansible.builtin.git:
|
||||
repo: >-
|
||||
https://x-access-token:{{ github_token }}@github.com/hidden_user/super-secret-repo.git
|
||||
dest: /srv/checkout
|
||||
vars:
|
||||
github_token: >-
|
||||
lookup('github_app_token', key_path='/home/to_your/key',
|
||||
app_id='123456', installation_id='64209')
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
_raw:
|
||||
description: A one-element list containing your GitHub access token.
|
||||
type: list
|
||||
elements: str
|
||||
'''
|
||||
|
||||
|
||||
try:
|
||||
from jwt import JWT, jwk_from_pem
|
||||
HAS_JWT = True
|
||||
except ImportError:
|
||||
HAS_JWT = False
|
||||
|
||||
import time
|
||||
import json
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.utils.display import Display
|
||||
|
||||
if HAS_JWT:
|
||||
jwt_instance = JWT()
|
||||
else:
|
||||
jwk_from_pem = None
|
||||
jwt_instance = None
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
def read_key(path):
|
||||
try:
|
||||
with open(path, 'rb') as pem_file:
|
||||
return jwk_from_pem(pem_file.read())
|
||||
except Exception as e:
|
||||
raise AnsibleError("Error while parsing key file: {0}".format(e))
|
||||
|
||||
|
||||
def encode_jwt(app_id, jwk, exp=600):
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
'iat': now,
|
||||
'exp': now + exp,
|
||||
'iss': app_id,
|
||||
}
|
||||
try:
|
||||
return jwt_instance.encode(payload, jwk, alg='RS256')
|
||||
except Exception as e:
|
||||
raise AnsibleError("Error while encoding jwt: {0}".format(e))
|
||||
|
||||
|
||||
def post_request(generated_jwt, installation_id):
|
||||
github_api_url = f'https://api.github.com/app/installations/{installation_id}/access_tokens'
|
||||
headers = {
|
||||
"Authorization": f'Bearer {generated_jwt}',
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
}
|
||||
try:
|
||||
response = open_url(github_api_url, headers=headers, method='POST')
|
||||
except HTTPError as e:
|
||||
try:
|
||||
error_body = json.loads(e.read().decode())
|
||||
display.vvv("Error returned: {0}".format(error_body))
|
||||
except Exception:
|
||||
error_body = {}
|
||||
if e.code == 404:
|
||||
raise AnsibleError("Github return error. Please confirm your installationd_id value is valid")
|
||||
elif e.code == 401:
|
||||
raise AnsibleError("Github return error. Please confirm your private key is valid")
|
||||
raise AnsibleError("Unexpected data returned: {0} -- {1}".format(e, error_body))
|
||||
response_body = response.read()
|
||||
try:
|
||||
json_data = json.loads(response_body.decode('utf-8'))
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
raise AnsibleError("Error while dencoding JSON respone from github: {0}".format(e))
|
||||
return json_data.get('token')
|
||||
|
||||
|
||||
def get_token(key_path, app_id, installation_id, expiry=600):
|
||||
jwk = read_key(key_path)
|
||||
generated_jwt = encode_jwt(app_id, jwk, exp=expiry)
|
||||
return post_request(generated_jwt, installation_id)
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
if not HAS_JWT:
|
||||
raise AnsibleError('Python jwt library is required. '
|
||||
'Please install using "pip install jwt"')
|
||||
|
||||
self.set_options(var_options=variables, direct=kwargs)
|
||||
|
||||
t = get_token(
|
||||
self.get_option('key_path'),
|
||||
self.get_option('app_id'),
|
||||
self.get_option('installation_id'),
|
||||
self.get_option('token_expiry'),
|
||||
)
|
||||
|
||||
return [t]
|
||||
@@ -14,59 +14,28 @@ DOCUMENTATION = '''
|
||||
- Scott Buchanan (@scottsb)
|
||||
- Andrew Zenk (@azenk)
|
||||
- Sam Doran (@samdoran)
|
||||
requirements:
|
||||
- C(op) 1Password command line utility. See U(https://support.1password.com/command-line/)
|
||||
short_description: fetch field values from 1Password
|
||||
short_description: Fetch field values from 1Password
|
||||
description:
|
||||
- P(community.general.onepassword#lookup) wraps the C(op) command line utility to fetch specific field values from 1Password.
|
||||
requirements:
|
||||
- C(op) 1Password command line utility
|
||||
options:
|
||||
_terms:
|
||||
description: identifier(s) (UUID, name, or subdomain; case-insensitive) of item(s) to retrieve.
|
||||
description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
|
||||
required: true
|
||||
field:
|
||||
description: field to return from each matching item (case-insensitive).
|
||||
default: 'password'
|
||||
master_password:
|
||||
description: The password used to unlock the specified vault.
|
||||
aliases: ['vault_password']
|
||||
section:
|
||||
description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
|
||||
domain:
|
||||
description: Domain of 1Password.
|
||||
version_added: 3.2.0
|
||||
default: '1password.com'
|
||||
type: str
|
||||
subdomain:
|
||||
description: The 1Password subdomain to authenticate against.
|
||||
account_id:
|
||||
description: The account ID to target.
|
||||
type: str
|
||||
version_added: 7.5.0
|
||||
username:
|
||||
description: The username used to sign in.
|
||||
secret_key:
|
||||
description: The secret key used when performing an initial sign in.
|
||||
service_account_token:
|
||||
description:
|
||||
- The access key for a service account.
|
||||
- Only works with 1Password CLI version 2 or later.
|
||||
domain:
|
||||
version_added: 3.2.0
|
||||
field:
|
||||
description: Field to return from each matching item (case-insensitive).
|
||||
default: 'password'
|
||||
type: str
|
||||
service_account_token:
|
||||
version_added: 7.1.0
|
||||
vault:
|
||||
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), C(~/.config/op/config) or C(~/.config/.op/config) exists), then only the
|
||||
C(master_password) is required. You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
|
||||
- Can target a specific account by providing the O(account_id).
|
||||
- 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
|
||||
to the 1Password master password.
|
||||
- This lookup stores potentially sensitive data from 1Password as Ansible facts.
|
||||
Facts are subject to caching if enabled, which means this data could be stored in clear text
|
||||
on disk or in a database.
|
||||
- Tested with C(op) version 2.7.2
|
||||
extends_documentation_fragment:
|
||||
- community.general.onepassword
|
||||
- community.general.onepassword.lookup
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -108,7 +77,7 @@ EXAMPLES = """
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: field data requested
|
||||
description: Field data requested.
|
||||
type: list
|
||||
elements: str
|
||||
"""
|
||||
@@ -119,7 +88,7 @@ import json
|
||||
import subprocess
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.errors import AnsibleLookupError, AnsibleOptionsError
|
||||
from ansible.module_utils.common.process import get_bin_path
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
||||
from ansible.module_utils.six import with_metaclass
|
||||
@@ -127,6 +96,14 @@ from ansible.module_utils.six import with_metaclass
|
||||
from ansible_collections.community.general.plugins.module_utils.onepassword import OnePasswordConfig
|
||||
|
||||
|
||||
def _lower_if_possible(value):
|
||||
"""Return the lower case version value, otherwise return the value"""
|
||||
try:
|
||||
return value.lower()
|
||||
except AttributeError:
|
||||
return value
|
||||
|
||||
|
||||
class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
||||
bin = "op"
|
||||
|
||||
@@ -139,6 +116,8 @@ class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
||||
master_password=None,
|
||||
service_account_token=None,
|
||||
account_id=None,
|
||||
connect_host=None,
|
||||
connect_token=None,
|
||||
):
|
||||
self.subdomain = subdomain
|
||||
self.domain = domain
|
||||
@@ -147,6 +126,8 @@ class OnePassCLIBase(with_metaclass(abc.ABCMeta, object)):
|
||||
self.secret_key = secret_key
|
||||
self.service_account_token = service_account_token
|
||||
self.account_id = account_id
|
||||
self.connect_host = connect_host
|
||||
self.connect_token = connect_token
|
||||
|
||||
self._path = None
|
||||
self._version = None
|
||||
@@ -325,6 +306,10 @@ class OnePassCLIv1(OnePassCLIBase):
|
||||
return not bool(rc)
|
||||
|
||||
def full_signin(self):
|
||||
if self.connect_host or self.connect_token:
|
||||
raise AnsibleLookupError(
|
||||
"1Password Connect is not available with 1Password CLI version 1. Please use version 2 or later.")
|
||||
|
||||
if self.service_account_token:
|
||||
raise AnsibleLookupError(
|
||||
"1Password CLI version 1 does not support Service Accounts. Please use version 2 or later.")
|
||||
@@ -480,6 +465,7 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
}
|
||||
"""
|
||||
data = json.loads(data_json)
|
||||
field_name = _lower_if_possible(field_name)
|
||||
for field in data.get("fields", []):
|
||||
if section_title is None:
|
||||
# If the field name exists in the section, return that value
|
||||
@@ -488,17 +474,19 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
|
||||
# If the field name doesn't exist in the section, match on the value of "label"
|
||||
# then "id" and return "value"
|
||||
if field.get("label") == field_name:
|
||||
if field.get("label", "").lower() == field_name:
|
||||
return field.get("value", "")
|
||||
|
||||
if field.get("id") == field_name:
|
||||
if field.get("id", "").lower() == field_name:
|
||||
return field.get("value", "")
|
||||
|
||||
# Look at the section data and get an identifier. The value of 'id' is either a unique ID
|
||||
# or a human-readable string. If a 'label' field exists, prefer that since
|
||||
# it is the value visible in the 1Password UI when both 'id' and 'label' exist.
|
||||
section = field.get("section", {})
|
||||
current_section_title = section.get("label", section.get("id"))
|
||||
section_title = _lower_if_possible(section_title)
|
||||
|
||||
current_section_title = section.get("label", section.get("id", "")).lower()
|
||||
if section_title == current_section_title:
|
||||
# In the correct section. Check "label" then "id" for the desired field_name
|
||||
if field.get("label") == field_name:
|
||||
@@ -510,6 +498,9 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
return ""
|
||||
|
||||
def assert_logged_in(self):
|
||||
if self.connect_host and self.connect_token:
|
||||
return True
|
||||
|
||||
if self.service_account_token:
|
||||
args = ["whoami"]
|
||||
environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
|
||||
@@ -569,6 +560,15 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
if vault is not None:
|
||||
args += ["--vault={0}".format(vault)]
|
||||
|
||||
if self.connect_host and self.connect_token:
|
||||
if vault is None:
|
||||
raise AnsibleLookupError("'vault' is required with 1Password Connect")
|
||||
environment_update = {
|
||||
"OP_CONNECT_HOST": self.connect_host,
|
||||
"OP_CONNECT_TOKEN": self.connect_token,
|
||||
}
|
||||
return self._run(args, environment_update=environment_update)
|
||||
|
||||
if self.service_account_token:
|
||||
if vault is None:
|
||||
raise AnsibleLookupError("'vault' is required with 'service_account_token'")
|
||||
@@ -592,7 +592,7 @@ class OnePassCLIv2(OnePassCLIBase):
|
||||
|
||||
class OnePass(object):
|
||||
def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None,
|
||||
service_account_token=None, account_id=None):
|
||||
service_account_token=None, account_id=None, connect_host=None, connect_token=None, cli_class=None):
|
||||
self.subdomain = subdomain
|
||||
self.domain = domain
|
||||
self.username = username
|
||||
@@ -600,19 +600,28 @@ class OnePass(object):
|
||||
self.master_password = master_password
|
||||
self.service_account_token = service_account_token
|
||||
self.account_id = account_id
|
||||
self.connect_host = connect_host
|
||||
self.connect_token = connect_token
|
||||
|
||||
self.logged_in = False
|
||||
self.token = None
|
||||
|
||||
self._config = OnePasswordConfig()
|
||||
self._cli = self._get_cli_class()
|
||||
self._cli = self._get_cli_class(cli_class)
|
||||
|
||||
if (self.connect_host or self.connect_token) and None in (self.connect_host, self.connect_token):
|
||||
raise AnsibleOptionsError("connect_host and connect_token are required together")
|
||||
|
||||
def _get_cli_class(self, cli_class=None):
|
||||
if cli_class is not None:
|
||||
return cli_class(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token)
|
||||
|
||||
def _get_cli_class(self):
|
||||
version = OnePassCLIBase.get_current_version()
|
||||
for cls in OnePassCLIBase.__subclasses__():
|
||||
if cls.supports_version == version.split(".")[0]:
|
||||
try:
|
||||
return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token, self.account_id)
|
||||
return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token,
|
||||
self.account_id, self.connect_host, self.connect_token)
|
||||
except TypeError as e:
|
||||
raise AnsibleLookupError(e)
|
||||
|
||||
@@ -677,8 +686,20 @@ class LookupModule(LookupBase):
|
||||
master_password = self.get_option("master_password")
|
||||
service_account_token = self.get_option("service_account_token")
|
||||
account_id = self.get_option("account_id")
|
||||
connect_host = self.get_option("connect_host")
|
||||
connect_token = self.get_option("connect_token")
|
||||
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token, account_id)
|
||||
op = OnePass(
|
||||
subdomain=subdomain,
|
||||
domain=domain,
|
||||
username=username,
|
||||
secret_key=secret_key,
|
||||
master_password=master_password,
|
||||
service_account_token=service_account_token,
|
||||
account_id=account_id,
|
||||
connect_host=connect_host,
|
||||
connect_token=connect_token,
|
||||
)
|
||||
op.assert_logged_in()
|
||||
|
||||
values = []
|
||||
|
||||
104
plugins/lookup/onepassword_doc.py
Normal file
104
plugins/lookup/onepassword_doc.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2023, Ansible Project
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
name: onepassword_doc
|
||||
author:
|
||||
- Sam Doran (@samdoran)
|
||||
requirements:
|
||||
- C(op) 1Password command line utility version 2 or later.
|
||||
short_description: Fetch documents stored in 1Password
|
||||
version_added: "8.1.0"
|
||||
description:
|
||||
- P(community.general.onepassword_doc#lookup) wraps C(op) command line utility to fetch one or more documents from 1Password.
|
||||
notes:
|
||||
- The document contents are a string exactly as stored in 1Password.
|
||||
- This plugin requires C(op) version 2 or later.
|
||||
|
||||
options:
|
||||
_terms:
|
||||
description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
|
||||
required: true
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.onepassword
|
||||
- community.general.onepassword.lookup
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Retrieve a private key from 1Password
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.onepassword_doc', 'Private key')
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: Requested document
|
||||
type: list
|
||||
elements: string
|
||||
"""
|
||||
|
||||
from ansible_collections.community.general.plugins.lookup.onepassword import OnePass, OnePassCLIv2
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.module_utils.common.text.converters import to_bytes
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
|
||||
class OnePassCLIv2Doc(OnePassCLIv2):
|
||||
def get_raw(self, item_id, vault=None, token=None):
|
||||
args = ["document", "get", item_id]
|
||||
if vault is not None:
|
||||
args = [*args, "--vault={0}".format(vault)]
|
||||
|
||||
if self.service_account_token:
|
||||
if vault is None:
|
||||
raise AnsibleLookupError("'vault' is required with 'service_account_token'")
|
||||
|
||||
environment_update = {"OP_SERVICE_ACCOUNT_TOKEN": self.service_account_token}
|
||||
return self._run(args, environment_update=environment_update)
|
||||
|
||||
if token is not None:
|
||||
args = [*args, to_bytes("--session=") + token]
|
||||
|
||||
return self._run(args)
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
self.set_options(var_options=variables, direct=kwargs)
|
||||
|
||||
vault = self.get_option("vault")
|
||||
subdomain = self.get_option("subdomain")
|
||||
domain = self.get_option("domain", "1password.com")
|
||||
username = self.get_option("username")
|
||||
secret_key = self.get_option("secret_key")
|
||||
master_password = self.get_option("master_password")
|
||||
service_account_token = self.get_option("service_account_token")
|
||||
account_id = self.get_option("account_id")
|
||||
connect_host = self.get_option("connect_host")
|
||||
connect_token = self.get_option("connect_token")
|
||||
|
||||
op = OnePass(
|
||||
subdomain=subdomain,
|
||||
domain=domain,
|
||||
username=username,
|
||||
secret_key=secret_key,
|
||||
master_password=master_password,
|
||||
service_account_token=service_account_token,
|
||||
account_id=account_id,
|
||||
connect_host=connect_host,
|
||||
connect_token=connect_token,
|
||||
cli_class=OnePassCLIv2Doc,
|
||||
)
|
||||
op.assert_logged_in()
|
||||
|
||||
values = []
|
||||
for term in terms:
|
||||
values.append(op.get_raw(term, vault))
|
||||
|
||||
return values
|
||||
@@ -15,55 +15,23 @@ DOCUMENTATION = '''
|
||||
- Andrew Zenk (@azenk)
|
||||
- Sam Doran (@samdoran)
|
||||
requirements:
|
||||
- C(op) 1Password command line utility. See U(https://support.1password.com/command-line/)
|
||||
short_description: fetch an entire item from 1Password
|
||||
- C(op) 1Password command line utility
|
||||
short_description: Fetch an entire item from 1Password
|
||||
description:
|
||||
- P(community.general.onepassword_raw#lookup) wraps C(op) command line utility to fetch an entire item from 1Password.
|
||||
options:
|
||||
_terms:
|
||||
description: identifier(s) (UUID, name, or domain; case-insensitive) of item(s) to retrieve.
|
||||
description: Identifier(s) (case-insensitive UUID or name) of item(s) to retrieve.
|
||||
required: true
|
||||
master_password:
|
||||
description: The password used to unlock the specified vault.
|
||||
aliases: ['vault_password']
|
||||
section:
|
||||
description: Item section containing the field to retrieve (case-insensitive). If absent will return first match from any section.
|
||||
subdomain:
|
||||
description: The 1Password subdomain to authenticate against.
|
||||
domain:
|
||||
description: Domain of 1Password.
|
||||
version_added: 6.0.0
|
||||
default: '1password.com'
|
||||
type: str
|
||||
account_id:
|
||||
description: The account ID to target.
|
||||
type: str
|
||||
version_added: 7.5.0
|
||||
username:
|
||||
description: The username used to sign in.
|
||||
secret_key:
|
||||
description: The secret key used when performing an initial sign in.
|
||||
domain:
|
||||
version_added: 6.0.0
|
||||
service_account_token:
|
||||
description:
|
||||
- The access key for a service account.
|
||||
- Only works with 1Password CLI version 2 or later.
|
||||
type: string
|
||||
version_added: 7.1.0
|
||||
vault:
|
||||
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 O(master_password) is required.
|
||||
You may optionally specify O(subdomain) in this scenario, otherwise the last used subdomain will be used by C(op).
|
||||
- This lookup can perform an initial login by providing O(subdomain), O(username), O(secret_key), and O(master_password).
|
||||
- Can target a specific account by providing the O(account_id).
|
||||
- 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
|
||||
to the 1Password master password.
|
||||
- This lookup stores potentially sensitive data from 1Password as Ansible facts.
|
||||
Facts are subject to caching if enabled, which means this data could be stored in clear text
|
||||
on disk or in a database.
|
||||
- Tested with C(op) version 2.7.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.onepassword
|
||||
- community.general.onepassword.lookup
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -78,7 +46,7 @@ EXAMPLES = """
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: field data requested
|
||||
description: Entire item requested.
|
||||
type: list
|
||||
elements: dict
|
||||
"""
|
||||
@@ -102,8 +70,20 @@ class LookupModule(LookupBase):
|
||||
master_password = self.get_option("master_password")
|
||||
service_account_token = self.get_option("service_account_token")
|
||||
account_id = self.get_option("account_id")
|
||||
connect_host = self.get_option("connect_host")
|
||||
connect_token = self.get_option("connect_token")
|
||||
|
||||
op = OnePass(subdomain, domain, username, secret_key, master_password, service_account_token, account_id)
|
||||
op = OnePass(
|
||||
subdomain=subdomain,
|
||||
domain=domain,
|
||||
username=username,
|
||||
secret_key=secret_key,
|
||||
master_password=master_password,
|
||||
service_account_token=service_account_token,
|
||||
account_id=account_id,
|
||||
connect_host=connect_host,
|
||||
connect_token=connect_token,
|
||||
)
|
||||
op.assert_logged_in()
|
||||
|
||||
values = []
|
||||
|
||||
@@ -129,6 +129,16 @@ DOCUMENTATION = '''
|
||||
- pass
|
||||
- gopass
|
||||
version_added: 5.2.0
|
||||
timestamp:
|
||||
description: Add the password generation information to the end of the file.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 8.1.0
|
||||
preserve:
|
||||
description: Include the old (edited) password inside the pass file.
|
||||
type: bool
|
||||
default: true
|
||||
version_added: 8.1.0
|
||||
notes:
|
||||
- The lookup supports passing all options as lookup parameters since community.general 6.0.0.
|
||||
'''
|
||||
@@ -386,11 +396,13 @@ class LookupModule(LookupBase):
|
||||
# generate new password, insert old lines from current result and return new password
|
||||
newpass = self.get_newpass()
|
||||
datetime = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||
msg = newpass + '\n'
|
||||
if self.passoutput[1:]:
|
||||
msg += '\n'.join(self.passoutput[1:]) + '\n'
|
||||
if self.paramvals['backup']:
|
||||
msg += "lookup_pass: old password was {0} (Updated on {1})\n".format(self.password, datetime)
|
||||
msg = newpass
|
||||
if self.paramvals['preserve'] or self.paramvals['timestamp']:
|
||||
msg += '\n'
|
||||
if self.paramvals['preserve'] and self.passoutput[1:]:
|
||||
msg += '\n'.join(self.passoutput[1:]) + '\n'
|
||||
if self.paramvals['timestamp'] and self.paramvals['backup']:
|
||||
msg += "lookup_pass: old password was {0} (Updated on {1})\n".format(self.password, datetime)
|
||||
try:
|
||||
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
|
||||
except (subprocess.CalledProcessError) as e:
|
||||
@@ -402,7 +414,9 @@ class LookupModule(LookupBase):
|
||||
# use pwgen to generate the password and insert values with pass -m
|
||||
newpass = self.get_newpass()
|
||||
datetime = time.strftime("%d/%m/%Y %H:%M:%S")
|
||||
msg = newpass + '\n' + "lookup_pass: First generated by ansible on {0}\n".format(datetime)
|
||||
msg = newpass
|
||||
if self.paramvals['timestamp']:
|
||||
msg += '\n' + "lookup_pass: First generated by ansible on {0}\n".format(datetime)
|
||||
try:
|
||||
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
|
||||
except (subprocess.CalledProcessError) as e:
|
||||
@@ -465,6 +479,8 @@ class LookupModule(LookupBase):
|
||||
'backup': self.get_option('backup'),
|
||||
'missing': self.get_option('missing'),
|
||||
'umask': self.get_option('umask'),
|
||||
'timestamp': self.get_option('timestamp'),
|
||||
'preserve': self.get_option('preserve'),
|
||||
}
|
||||
|
||||
def run(self, terms, variables, **kwargs):
|
||||
|
||||
@@ -34,6 +34,7 @@ except Exception:
|
||||
|
||||
def auth_argument_spec(spec=None):
|
||||
arg_spec = (dict(
|
||||
ca_path=dict(type='str'),
|
||||
api_token=dict(type='str', no_log=True),
|
||||
api_oauth_token=dict(type='str', no_log=True),
|
||||
api_job_token=dict(type='str', no_log=True),
|
||||
@@ -74,33 +75,36 @@ def ensure_gitlab_package(module):
|
||||
|
||||
|
||||
def gitlab_authentication(module):
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
gitlab_url = module.params['api_url']
|
||||
validate_certs = module.params['validate_certs']
|
||||
ca_path = module.params['ca_path']
|
||||
gitlab_user = module.params['api_username']
|
||||
gitlab_password = module.params['api_password']
|
||||
gitlab_token = module.params['api_token']
|
||||
gitlab_oauth_token = module.params['api_oauth_token']
|
||||
gitlab_job_token = module.params['api_job_token']
|
||||
|
||||
ensure_gitlab_package(module)
|
||||
verify = ca_path if validate_certs and ca_path else validate_certs
|
||||
|
||||
try:
|
||||
# python-gitlab library remove support for username/password authentication since 1.13.0
|
||||
# Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0
|
||||
# This condition allow to still support older version of the python-gitlab library
|
||||
if LooseVersion(gitlab.__version__) < LooseVersion("1.13.0"):
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, email=gitlab_user, password=gitlab_password,
|
||||
private_token=gitlab_token, api_version=4)
|
||||
else:
|
||||
# We can create an oauth_token using a username and password
|
||||
# https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
|
||||
if gitlab_user:
|
||||
data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}
|
||||
resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=validate_certs)
|
||||
resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=verify)
|
||||
resp_data = resp.json()
|
||||
gitlab_oauth_token = resp_data["access_token"]
|
||||
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, private_token=gitlab_token,
|
||||
oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
|
||||
|
||||
gitlab_instance.auth()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -180,3 +180,17 @@ class ProxmoxAnsible(object):
|
||||
return self.proxmox_api.storage.get(type=type)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="Unable to retrieve storages information with type %s: %s" % (type, e))
|
||||
|
||||
def get_storage_content(self, node, storage, content=None, vmid=None):
|
||||
try:
|
||||
return (
|
||||
self.proxmox_api.nodes(node)
|
||||
.storage(storage)
|
||||
.content()
|
||||
.get(content=content, vmid=vmid)
|
||||
)
|
||||
except Exception as e:
|
||||
self.module.fail_json(
|
||||
msg="Unable to list content on %s, %s for %s and %s: %s"
|
||||
% (node, storage, content, vmid, e)
|
||||
)
|
||||
|
||||
@@ -2955,7 +2955,7 @@ class RedfishUtils(object):
|
||||
result = {}
|
||||
inventory = {}
|
||||
# Get these entries, but does not fail if not found
|
||||
properties = ['Status', 'HostName', 'PowerState', 'Model', 'Manufacturer',
|
||||
properties = ['Status', 'HostName', 'PowerState', 'BootProgress', 'Model', 'Manufacturer',
|
||||
'PartNumber', 'SystemType', 'AssetTag', 'ServiceTag',
|
||||
'SerialNumber', 'SKU', 'BiosVersion', 'MemorySummary',
|
||||
'ProcessorSummary', 'TrustedModules', 'Name', 'Id']
|
||||
|
||||
@@ -253,7 +253,7 @@ options:
|
||||
author:
|
||||
- "He Guimin (@xiaozhu36)"
|
||||
requirements:
|
||||
- "python >= 3.6"
|
||||
- "Python >= 3.6"
|
||||
- "footmark >= 1.19.0"
|
||||
extends_documentation_fragment:
|
||||
- community.general.alicloud
|
||||
|
||||
@@ -31,7 +31,6 @@ short_description: Gather information on instances of Alibaba Cloud ECS
|
||||
description:
|
||||
- This module fetches data from the Open API in Alicloud.
|
||||
The module must be called from within the ECS instance itself.
|
||||
- This module was called C(ali_instance_facts) before Ansible 2.9. The usage did not change.
|
||||
|
||||
attributes:
|
||||
check_mode:
|
||||
@@ -61,7 +60,7 @@ options:
|
||||
author:
|
||||
- "He Guimin (@xiaozhu36)"
|
||||
requirements:
|
||||
- "python >= 3.6"
|
||||
- "Python >= 3.6"
|
||||
- "footmark >= 1.13.0"
|
||||
extends_documentation_fragment:
|
||||
- community.general.alicloud
|
||||
|
||||
@@ -37,7 +37,6 @@ options:
|
||||
- The type of installation performed by C(ansible-galaxy).
|
||||
- If O(type=both), then O(requirements_file) must be passed and it may contain both roles and collections.
|
||||
- "Note however that the opposite is not true: if using a O(requirements_file), then O(type) can be any of the three choices."
|
||||
- "B(Ansible 2.9): The option V(both) will have the same effect as V(role)."
|
||||
type: str
|
||||
choices: [collection, role, both]
|
||||
required: true
|
||||
@@ -54,7 +53,6 @@ options:
|
||||
- Path to a file containing a list of requirements to be installed.
|
||||
- It works for O(type) equals to V(collection) and V(role).
|
||||
- O(name) and O(requirements_file) are mutually exclusive.
|
||||
- "B(Ansible 2.9): It can only be used to install either O(type=role) or O(type=collection), but not both at the same run."
|
||||
type: path
|
||||
dest:
|
||||
description:
|
||||
|
||||
@@ -115,6 +115,7 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils.basic import (
|
||||
@@ -132,6 +133,7 @@ else:
|
||||
HAS_RPM_PYTHON = True
|
||||
RPM_PYTHON_IMPORT_ERROR = None
|
||||
|
||||
APT_CACHE = "/usr/bin/apt-cache"
|
||||
APT_PATH = "/usr/bin/apt-get"
|
||||
RPM_PATH = "/usr/bin/rpm"
|
||||
APT_GET_ZERO = "\n0 upgraded, 0 newly installed"
|
||||
@@ -165,6 +167,19 @@ def query_package(module, name):
|
||||
return False
|
||||
|
||||
|
||||
def check_package_version(module, name):
|
||||
# compare installed and candidate version
|
||||
# if newest version already installed return True
|
||||
# otherwise return False
|
||||
|
||||
rc, out, err = module.run_command([APT_CACHE, "policy", name], environ_update={"LANG": "C"})
|
||||
installed = re.split("\n |: ", out)[2]
|
||||
candidate = re.split("\n |: ", out)[4]
|
||||
if installed >= candidate:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def query_package_provides(module, name):
|
||||
# rpm -q returns 0 if the package is installed,
|
||||
# 1 if it is not installed
|
||||
@@ -179,7 +194,11 @@ def query_package_provides(module, name):
|
||||
name = local_rpm_package_name(name)
|
||||
|
||||
rc, out, err = module.run_command("%s -q --provides %s" % (RPM_PATH, name))
|
||||
return rc == 0
|
||||
if rc == 0:
|
||||
if check_package_version(module, name):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def update_package_db(module):
|
||||
|
||||
@@ -36,7 +36,6 @@ options:
|
||||
format:
|
||||
description:
|
||||
- The type of compression to use.
|
||||
- Support for xz was added in Ansible 2.5.
|
||||
type: str
|
||||
choices: [ bz2, gz, tar, xz, zip ]
|
||||
default: gz
|
||||
|
||||
@@ -21,7 +21,6 @@ notes:
|
||||
- Host should support C(atomic) command
|
||||
requirements:
|
||||
- atomic
|
||||
- "python >= 2.6"
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -21,7 +21,6 @@ notes:
|
||||
- Host should be an atomic platform (verified by existence of '/run/ostree-booted' file).
|
||||
requirements:
|
||||
- atomic
|
||||
- python >= 2.6
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -21,7 +21,6 @@ notes:
|
||||
- Host should support C(atomic) command.
|
||||
requirements:
|
||||
- atomic
|
||||
- python >= 2.6
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
|
||||
@@ -45,8 +45,7 @@ options:
|
||||
force:
|
||||
description:
|
||||
- If V(true), any modified files in the working
|
||||
tree will be discarded. Before Ansible 1.9 the default
|
||||
value was V(true).
|
||||
tree will be discarded.
|
||||
type: bool
|
||||
default: false
|
||||
executable:
|
||||
|
||||
@@ -13,8 +13,6 @@ DOCUMENTATION = r'''
|
||||
module: cloudflare_dns
|
||||
author:
|
||||
- Michael Gruener (@mgruener)
|
||||
requirements:
|
||||
- python >= 2.6
|
||||
short_description: Manage Cloudflare DNS records
|
||||
description:
|
||||
- "Manages dns records via the Cloudflare API, see the docs: U(https://api.cloudflare.com/)."
|
||||
@@ -99,7 +97,6 @@ options:
|
||||
description:
|
||||
- Service protocol. Required for O(type=SRV) and O(type=TLSA).
|
||||
- Common values are TCP and UDP.
|
||||
- Before Ansible 2.6 only TCP and UDP were available.
|
||||
type: str
|
||||
proxied:
|
||||
description:
|
||||
@@ -151,7 +148,7 @@ options:
|
||||
type:
|
||||
description:
|
||||
- The type of DNS record to create. Required if O(state=present).
|
||||
- O(type=DS), O(type=SSHFP), and O(type=TLSA) were added in Ansible 2.7.
|
||||
- Note that V(SPF) is no longer supported by CloudFlare. Support for it will be removed from community.general 9.0.0.
|
||||
type: str
|
||||
choices: [ A, AAAA, CNAME, DS, MX, NS, SPF, SRV, SSHFP, TLSA, CAA, TXT ]
|
||||
value:
|
||||
@@ -638,7 +635,7 @@ class CloudflareAPI(object):
|
||||
content = str(params['key_tag']) + '\t' + str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
|
||||
elif params['type'] == 'SSHFP':
|
||||
if not (params['value'] is None or params['value'] == ''):
|
||||
content = str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
|
||||
content = str(params['algorithm']) + ' ' + str(params['hash_type']) + ' ' + params['value'].upper()
|
||||
elif params['type'] == 'TLSA':
|
||||
if not (params['value'] is None or params['value'] == ''):
|
||||
content = str(params['cert_usage']) + '\t' + str(params['selector']) + '\t' + str(params['hash_type']) + '\t' + params['value']
|
||||
@@ -751,7 +748,7 @@ class CloudflareAPI(object):
|
||||
if (attr is None) or (attr == ''):
|
||||
self.module.fail_json(msg="You must provide algorithm, hash_type and a value to create this record type")
|
||||
sshfp_data = {
|
||||
"fingerprint": params['value'],
|
||||
"fingerprint": params['value'].upper(),
|
||||
"type": params['hash_type'],
|
||||
"algorithm": params['algorithm'],
|
||||
}
|
||||
@@ -761,7 +758,7 @@ class CloudflareAPI(object):
|
||||
'data': sshfp_data,
|
||||
"ttl": params['ttl'],
|
||||
}
|
||||
search_value = str(params['algorithm']) + '\t' + str(params['hash_type']) + '\t' + params['value']
|
||||
search_value = str(params['algorithm']) + ' ' + str(params['hash_type']) + ' ' + params['value']
|
||||
|
||||
if params['type'] == 'TLSA':
|
||||
for attr in [params['port'], params['proto'], params['cert_usage'], params['selector'], params['hash_type'], params['value']]:
|
||||
|
||||
@@ -122,6 +122,16 @@ options:
|
||||
description:
|
||||
- Name for the service check. Required if standalone, ignored if
|
||||
part of service definition.
|
||||
check_node:
|
||||
description:
|
||||
- Node name.
|
||||
# TODO: properly document!
|
||||
type: str
|
||||
check_host:
|
||||
description:
|
||||
- Host name.
|
||||
# TODO: properly document!
|
||||
type: str
|
||||
ttl:
|
||||
type: str
|
||||
description:
|
||||
|
||||
225
plugins/modules/dnf_config_manager.py
Normal file
225
plugins/modules/dnf_config_manager.py
Normal file
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Andrew Hyatt <andy@hyatt.xyz>
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: dnf_config_manager
|
||||
short_description: Enable or disable dnf repositories using config-manager
|
||||
version_added: 8.2.0
|
||||
description:
|
||||
- This module enables or disables repositories using the C(dnf config-manager) sub-command.
|
||||
author: Andrew Hyatt (@ahyattdev) <andy@hyatt.xyz>
|
||||
requirements:
|
||||
- dnf
|
||||
- dnf-plugins-core
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
attributes:
|
||||
check_mode:
|
||||
support: full
|
||||
diff_mode:
|
||||
support: none
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Repository ID, for example V(crb).
|
||||
default: []
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
state:
|
||||
description:
|
||||
- Whether the repositories should be V(enabled) or V(disabled).
|
||||
default: enabled
|
||||
required: false
|
||||
type: str
|
||||
choices: [enabled, disabled]
|
||||
seealso:
|
||||
- module: ansible.builtin.dnf
|
||||
- module: ansible.builtin.yum_repository
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Ensure the crb repository is enabled
|
||||
community.general.dnf_config_manager:
|
||||
name: crb
|
||||
state: enabled
|
||||
|
||||
- name: Ensure the appstream and zfs repositories are disabled
|
||||
community.general.dnf_config_manager:
|
||||
name:
|
||||
- appstream
|
||||
- zfs
|
||||
state: disabled
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
repo_states_pre:
|
||||
description: Repo IDs before action taken.
|
||||
returned: success
|
||||
type: dict
|
||||
contains:
|
||||
enabled:
|
||||
description: Enabled repository IDs.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
disabled:
|
||||
description: Disabled repository IDs.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
sample:
|
||||
enabled:
|
||||
- appstream
|
||||
- baseos
|
||||
- crb
|
||||
disabled:
|
||||
- appstream-debuginfo
|
||||
- appstream-source
|
||||
- baseos-debuginfo
|
||||
- baseos-source
|
||||
- crb-debug
|
||||
- crb-source
|
||||
repo_states_post:
|
||||
description: Repository states after action taken.
|
||||
returned: success
|
||||
type: dict
|
||||
contains:
|
||||
enabled:
|
||||
description: Enabled repository IDs.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
disabled:
|
||||
description: Disabled repository IDs.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
sample:
|
||||
enabled:
|
||||
- appstream
|
||||
- baseos
|
||||
- crb
|
||||
disabled:
|
||||
- appstream-debuginfo
|
||||
- appstream-source
|
||||
- baseos-debuginfo
|
||||
- baseos-source
|
||||
- crb-debug
|
||||
- crb-source
|
||||
changed_repos:
|
||||
description: Repositories changed.
|
||||
returned: success
|
||||
type: list
|
||||
elements: str
|
||||
sample: [ 'crb' ]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
import os
|
||||
import re
|
||||
|
||||
DNF_BIN = "/usr/bin/dnf"
|
||||
REPO_ID_RE = re.compile(r'^Repo-id\s*:\s*(\S+)$')
|
||||
REPO_STATUS_RE = re.compile(r'^Repo-status\s*:\s*(disabled|enabled)$')
|
||||
|
||||
|
||||
def get_repo_states(module):
|
||||
rc, out, err = module.run_command([DNF_BIN, 'repolist', '--all', '--verbose'], check_rc=True)
|
||||
|
||||
repos = dict()
|
||||
last_repo = ''
|
||||
for i, line in enumerate(out.split('\n')):
|
||||
m = REPO_ID_RE.match(line)
|
||||
if m:
|
||||
if len(last_repo) > 0:
|
||||
module.fail_json(msg='dnf repolist parse failure: parsed another repo id before next status')
|
||||
last_repo = m.group(1)
|
||||
continue
|
||||
m = REPO_STATUS_RE.match(line)
|
||||
if m:
|
||||
if len(last_repo) == 0:
|
||||
module.fail_json(msg='dnf repolist parse failure: parsed status before repo id')
|
||||
repos[last_repo] = m.group(1)
|
||||
last_repo = ''
|
||||
return repos
|
||||
|
||||
|
||||
def set_repo_states(module, repo_ids, state):
|
||||
module.run_command([DNF_BIN, 'config-manager', '--set-{0}'.format(state)] + repo_ids, check_rc=True)
|
||||
|
||||
|
||||
def pack_repo_states_for_return(states):
|
||||
enabled = []
|
||||
disabled = []
|
||||
for repo_id in states:
|
||||
if states[repo_id] == 'enabled':
|
||||
enabled.append(repo_id)
|
||||
else:
|
||||
disabled.append(repo_id)
|
||||
|
||||
# Sort for consistent results
|
||||
enabled.sort()
|
||||
disabled.sort()
|
||||
|
||||
return {'enabled': enabled, 'disabled': disabled}
|
||||
|
||||
|
||||
def main():
|
||||
module_args = dict(
|
||||
name=dict(type='list', elements='str', required=False, default=[]),
|
||||
state=dict(type='str', required=False, choices=['enabled', 'disabled'], default='enabled')
|
||||
)
|
||||
|
||||
result = dict(
|
||||
changed=False
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
if not os.path.exists(DNF_BIN):
|
||||
module.fail_json(msg="%s was not found" % DNF_BIN)
|
||||
|
||||
repo_states = get_repo_states(module)
|
||||
result['repo_states_pre'] = pack_repo_states_for_return(repo_states)
|
||||
|
||||
desired_repo_state = module.params['state']
|
||||
names = module.params['name']
|
||||
|
||||
to_change = []
|
||||
for repo_id in names:
|
||||
if repo_id not in repo_states:
|
||||
module.fail_json(msg="did not find repo with ID '{0}' in dnf repolist --all --verbose".format(repo_id))
|
||||
if repo_states[repo_id] != desired_repo_state:
|
||||
to_change.append(repo_id)
|
||||
result['changed'] = len(to_change) > 0
|
||||
result['changed_repos'] = to_change
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
if len(to_change) > 0:
|
||||
set_repo_states(module, to_change, desired_repo_state)
|
||||
|
||||
repo_states_post = get_repo_states(module)
|
||||
result['repo_states_post'] = pack_repo_states_for_return(repo_states_post)
|
||||
|
||||
for repo_id in to_change:
|
||||
if repo_states_post[repo_id] != desired_repo_state:
|
||||
module.fail_json(msg="dnf config-manager failed to make '{0}' {1}".format(repo_id, desired_repo_state))
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -69,7 +69,6 @@ options:
|
||||
plugin_bin:
|
||||
description:
|
||||
- Location of the plugin binary. If this file is not found, the default plugin binaries will be used.
|
||||
- The default changed in Ansible 2.4 to None.
|
||||
type: path
|
||||
plugin_dir:
|
||||
description:
|
||||
|
||||
@@ -20,7 +20,7 @@ author:
|
||||
requirements: ['git']
|
||||
short_description: Read and write git configuration
|
||||
description:
|
||||
- The M(community.general.git_config) module changes git configuration by invoking 'git config'.
|
||||
- The M(community.general.git_config) module changes git configuration by invoking C(git config).
|
||||
This is needed if you do not want to use M(ansible.builtin.template) for the entire git
|
||||
config file (for example because you need to change just C(user.email) in
|
||||
/etc/.git/config). Solutions involving M(ansible.builtin.command) are cumbersome or
|
||||
@@ -75,6 +75,16 @@ options:
|
||||
- When specifying the name of a single setting, supply a value to
|
||||
set that setting to the given value.
|
||||
type: str
|
||||
add_mode:
|
||||
description:
|
||||
- Specify if a value should replace the existing value(s) or if the new
|
||||
value should be added alongside other values with the same name.
|
||||
- This option is only relevant when adding/replacing values. If O(state=absent) or
|
||||
values are just read out, this option is not considered.
|
||||
choices: [ "add", "replace-all" ]
|
||||
type: str
|
||||
default: "replace-all"
|
||||
version_added: 8.1.0
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -118,6 +128,15 @@ EXAMPLES = '''
|
||||
name: color.ui
|
||||
value: auto
|
||||
|
||||
- name: Add several options for the same name
|
||||
community.general.git_config:
|
||||
name: push.pushoption
|
||||
value: "{{ item }}"
|
||||
add_mode: add
|
||||
loop:
|
||||
- merge_request.create
|
||||
- merge_request.draft
|
||||
|
||||
- name: Make etckeeper not complaining when it is invoked by cron
|
||||
community.general.git_config:
|
||||
name: user.email
|
||||
@@ -178,6 +197,7 @@ def main():
|
||||
name=dict(type='str'),
|
||||
repo=dict(type='path'),
|
||||
file=dict(type='path'),
|
||||
add_mode=dict(required=False, type='str', default='replace-all', choices=['add', 'replace-all']),
|
||||
scope=dict(required=False, type='str', choices=['file', 'local', 'global', 'system']),
|
||||
state=dict(required=False, type='str', default='present', choices=['present', 'absent']),
|
||||
value=dict(required=False),
|
||||
@@ -197,94 +217,118 @@ def main():
|
||||
# Set the locale to C to ensure consistent messages.
|
||||
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
|
||||
|
||||
if params['name']:
|
||||
name = params['name']
|
||||
else:
|
||||
name = None
|
||||
name = params['name'] or ''
|
||||
unset = params['state'] == 'absent'
|
||||
new_value = params['value'] or ''
|
||||
add_mode = params['add_mode']
|
||||
|
||||
if params['scope']:
|
||||
scope = params['scope']
|
||||
elif params['list_all']:
|
||||
scope = None
|
||||
else:
|
||||
scope = 'system'
|
||||
scope = determine_scope(params)
|
||||
cwd = determine_cwd(scope, params)
|
||||
|
||||
if params['state'] == 'absent':
|
||||
unset = 'unset'
|
||||
params['value'] = None
|
||||
else:
|
||||
unset = None
|
||||
base_args = [git_path, "config", "--includes"]
|
||||
|
||||
if params['value']:
|
||||
new_value = params['value']
|
||||
else:
|
||||
new_value = None
|
||||
|
||||
args = [git_path, "config", "--includes"]
|
||||
if params['list_all']:
|
||||
args.append('-l')
|
||||
if scope == 'file':
|
||||
args.append('-f')
|
||||
args.append(params['file'])
|
||||
base_args.append('-f')
|
||||
base_args.append(params['file'])
|
||||
elif scope:
|
||||
args.append("--" + scope)
|
||||
base_args.append("--" + scope)
|
||||
|
||||
list_args = list(base_args)
|
||||
|
||||
if params['list_all']:
|
||||
list_args.append('-l')
|
||||
|
||||
if name:
|
||||
args.append(name)
|
||||
list_args.append("--get-all")
|
||||
list_args.append(name)
|
||||
|
||||
if scope == 'local':
|
||||
dir = params['repo']
|
||||
elif params['list_all'] and params['repo']:
|
||||
# Include local settings from a specific repo when listing all available settings
|
||||
dir = params['repo']
|
||||
else:
|
||||
# Run from root directory to avoid accidentally picking up any local config settings
|
||||
dir = "/"
|
||||
(rc, out, err) = module.run_command(list_args, cwd=cwd, expand_user_and_vars=False)
|
||||
|
||||
(rc, out, err) = module.run_command(args, cwd=dir, expand_user_and_vars=False)
|
||||
if params['list_all'] and scope and rc == 128 and 'unable to read config file' in err:
|
||||
# This just means nothing has been set at the given scope
|
||||
module.exit_json(changed=False, msg='', config_values={})
|
||||
elif rc >= 2:
|
||||
# If the return code is 1, it just means the option hasn't been set yet, which is fine.
|
||||
module.fail_json(rc=rc, msg=err, cmd=' '.join(args))
|
||||
module.fail_json(rc=rc, msg=err, cmd=' '.join(list_args))
|
||||
|
||||
old_values = out.rstrip().splitlines()
|
||||
|
||||
if params['list_all']:
|
||||
values = out.rstrip().splitlines()
|
||||
config_values = {}
|
||||
for value in values:
|
||||
for value in old_values:
|
||||
k, v = value.split('=', 1)
|
||||
config_values[k] = v
|
||||
module.exit_json(changed=False, msg='', config_values=config_values)
|
||||
elif not new_value and not unset:
|
||||
module.exit_json(changed=False, msg='', config_value=out.rstrip())
|
||||
module.exit_json(changed=False, msg='', config_value=old_values[0] if old_values else '')
|
||||
elif unset and not out:
|
||||
module.exit_json(changed=False, msg='no setting to unset')
|
||||
elif new_value in old_values and (len(old_values) == 1 or add_mode == "add"):
|
||||
module.exit_json(changed=False, msg="")
|
||||
|
||||
# Until this point, the git config was just read and in case no change is needed, the module has already exited.
|
||||
|
||||
set_args = list(base_args)
|
||||
if unset:
|
||||
set_args.append("--unset-all")
|
||||
set_args.append(name)
|
||||
else:
|
||||
old_value = out.rstrip()
|
||||
if old_value == new_value:
|
||||
module.exit_json(changed=False, msg="")
|
||||
set_args.append("--" + add_mode)
|
||||
set_args.append(name)
|
||||
set_args.append(new_value)
|
||||
|
||||
if not module.check_mode:
|
||||
if unset:
|
||||
args.insert(len(args) - 1, "--" + unset)
|
||||
cmd = args
|
||||
else:
|
||||
cmd = args + [new_value]
|
||||
(rc, out, err) = module.run_command(cmd, cwd=dir, ignore_invalid_cwd=False, expand_user_and_vars=False)
|
||||
(rc, out, err) = module.run_command(set_args, cwd=cwd, ignore_invalid_cwd=False, expand_user_and_vars=False)
|
||||
if err:
|
||||
module.fail_json(rc=rc, msg=err, cmd=cmd)
|
||||
module.fail_json(rc=rc, msg=err, cmd=set_args)
|
||||
|
||||
if unset:
|
||||
after_values = []
|
||||
elif add_mode == "add":
|
||||
after_values = old_values + [new_value]
|
||||
else:
|
||||
after_values = [new_value]
|
||||
|
||||
module.exit_json(
|
||||
msg='setting changed',
|
||||
diff=dict(
|
||||
before_header=' '.join(args),
|
||||
before=old_value + "\n",
|
||||
after_header=' '.join(args),
|
||||
after=(new_value or '') + "\n"
|
||||
before_header=' '.join(set_args),
|
||||
before=build_diff_value(old_values),
|
||||
after_header=' '.join(set_args),
|
||||
after=build_diff_value(after_values),
|
||||
),
|
||||
changed=True
|
||||
)
|
||||
|
||||
|
||||
def determine_scope(params):
|
||||
if params['scope']:
|
||||
return params['scope']
|
||||
elif params['list_all']:
|
||||
return ""
|
||||
else:
|
||||
return 'system'
|
||||
|
||||
|
||||
def build_diff_value(value):
|
||||
if not value:
|
||||
return "\n"
|
||||
elif len(value) == 1:
|
||||
return value[0] + "\n"
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def determine_cwd(scope, params):
|
||||
if scope == 'local':
|
||||
return params['repo']
|
||||
elif params['list_all'] and params['repo']:
|
||||
# Include local settings from a specific repo when listing all available settings
|
||||
return params['repo']
|
||||
else:
|
||||
# Run from root directory to avoid accidentally picking up any local config settings
|
||||
return "/"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
187
plugins/modules/git_config_info.py
Normal file
187
plugins/modules/git_config_info.py
Normal file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Guenther Grill <grill.guenther@gmail.com>
|
||||
#
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: git_config_info
|
||||
author:
|
||||
- Guenther Grill (@guenhter)
|
||||
version_added: 8.1.0
|
||||
requirements: ['git']
|
||||
short_description: Read git configuration
|
||||
description:
|
||||
- The M(community.general.git_config_info) module reads the git configuration
|
||||
by invoking C(git config).
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the setting to read.
|
||||
- If not provided, all settings will be returned as RV(config_values).
|
||||
type: str
|
||||
path:
|
||||
description:
|
||||
- Path to a git repository or file for reading values from a specific repo.
|
||||
- If O(scope) is V(local), this must point to a repository to read from.
|
||||
- If O(scope) is V(file), this must point to specific git config file to read from.
|
||||
- Otherwise O(path) is ignored if set.
|
||||
type: path
|
||||
scope:
|
||||
description:
|
||||
- Specify which scope to read values from.
|
||||
- If set to V(global), the global git config is used. O(path) is ignored.
|
||||
- If set to V(system), the system git config is used. O(path) is ignored.
|
||||
- If set to V(local), O(path) must be set to the repo to read from.
|
||||
- If set to V(file), O(path) must be set to the config file to read from.
|
||||
choices: [ "global", "system", "local", "file" ]
|
||||
default: "system"
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Read a system wide config
|
||||
community.general.git_config_info:
|
||||
name: core.editor
|
||||
register: result
|
||||
|
||||
- name: Show value of core.editor
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ result.config_value | default('(not set)', true) }}"
|
||||
|
||||
- name: Read a global config from ~/.gitconfig
|
||||
community.general.git_config_info:
|
||||
name: alias.remotev
|
||||
scope: global
|
||||
|
||||
- name: Read a project specific config
|
||||
community.general.git_config_info:
|
||||
name: color.ui
|
||||
scope: local
|
||||
path: /etc
|
||||
|
||||
- name: Read all global values
|
||||
community.general.git_config_info:
|
||||
scope: global
|
||||
|
||||
- name: Read all system wide values
|
||||
community.general.git_config_info:
|
||||
|
||||
- name: Read all values of a specific file
|
||||
community.general.git_config_info:
|
||||
scope: file
|
||||
path: /etc/gitconfig
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
---
|
||||
config_value:
|
||||
description: >
|
||||
When O(name) is set, a string containing the value of the setting in name. If O(name) is not set, empty.
|
||||
If a config key such as V(push.pushoption) has more then one entry, just the first one is returned here.
|
||||
returned: success if O(name) is set
|
||||
type: str
|
||||
sample: "vim"
|
||||
|
||||
config_values:
|
||||
description:
|
||||
- This is a dictionary mapping a git configuration setting to a list of its values.
|
||||
- When O(name) is not set, all configuration settings are returned here.
|
||||
- When O(name) is set, only the setting specified in O(name) is returned here.
|
||||
If that setting is not set, the key will still be present, and its value will be an empty list.
|
||||
returned: success
|
||||
type: dict
|
||||
sample:
|
||||
core.editor: ["vim"]
|
||||
color.ui: ["auto"]
|
||||
push.pushoption: ["merge_request.create", "merge_request.draft"]
|
||||
alias.remotev: ["remote -v"]
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(type="str"),
|
||||
path=dict(type="path"),
|
||||
scope=dict(required=False, type="str", default="system", choices=["global", "system", "local", "file"]),
|
||||
),
|
||||
required_if=[
|
||||
("scope", "local", ["path"]),
|
||||
("scope", "file", ["path"]),
|
||||
],
|
||||
required_one_of=[],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
|
||||
# Set the locale to C to ensure consistent messages.
|
||||
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
|
||||
|
||||
name = module.params["name"]
|
||||
path = module.params["path"]
|
||||
scope = module.params["scope"]
|
||||
|
||||
run_cwd = path if scope == "local" else "/"
|
||||
args = build_args(module, name, path, scope)
|
||||
|
||||
(rc, out, err) = module.run_command(args, cwd=run_cwd, expand_user_and_vars=False)
|
||||
|
||||
if rc == 128 and "unable to read config file" in err:
|
||||
# This just means nothing has been set at the given scope
|
||||
pass
|
||||
elif rc >= 2:
|
||||
# If the return code is 1, it just means the option hasn't been set yet, which is fine.
|
||||
module.fail_json(rc=rc, msg=err, cmd=" ".join(args))
|
||||
|
||||
output_lines = out.strip("\0").split("\0") if out else []
|
||||
|
||||
if name:
|
||||
first_value = output_lines[0] if output_lines else ""
|
||||
config_values = {name: output_lines}
|
||||
module.exit_json(changed=False, msg="", config_value=first_value, config_values=config_values)
|
||||
else:
|
||||
config_values = text_to_dict(output_lines)
|
||||
module.exit_json(changed=False, msg="", config_value="", config_values=config_values)
|
||||
|
||||
|
||||
def build_args(module, name, path, scope):
|
||||
git_path = module.get_bin_path("git", True)
|
||||
args = [git_path, "config", "--includes", "--null", "--" + scope]
|
||||
|
||||
if scope == "file":
|
||||
args.append(path)
|
||||
|
||||
if name:
|
||||
args.extend(["--get-all", name])
|
||||
else:
|
||||
args.append("--list")
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def text_to_dict(text_lines):
|
||||
config_values = {}
|
||||
for value in text_lines:
|
||||
k, v = value.split("\n", 1)
|
||||
if k in config_values:
|
||||
config_values[k].append(v)
|
||||
else:
|
||||
config_values[k] = [v]
|
||||
return config_values
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -94,7 +94,7 @@ EXAMPLES = '''
|
||||
repo: testrepo
|
||||
action: latest_release
|
||||
|
||||
- name: Get latest release of test repo using username and password. Ansible 2.4.
|
||||
- name: Get latest release of test repo using username and password
|
||||
community.general.github_release:
|
||||
user: testuser
|
||||
password: secret123
|
||||
|
||||
@@ -14,7 +14,6 @@ module: github_webhook_info
|
||||
short_description: Query information about GitHub webhooks
|
||||
description:
|
||||
- "Query information about GitHub webhooks"
|
||||
- This module was called C(github_webhook_facts) before Ansible 2.9. The usage did not change.
|
||||
requirements:
|
||||
- "PyGithub >= 1.3.5"
|
||||
extends_documentation_fragment:
|
||||
|
||||
@@ -16,7 +16,6 @@ description:
|
||||
author:
|
||||
- paytroff (@paytroff)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -84,7 +83,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -144,7 +143,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=False
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
project = module.params['project']
|
||||
branch = module.params['branch']
|
||||
@@ -156,7 +157,6 @@ def main():
|
||||
module.fail_json(msg="community.general.gitlab_proteched_branch requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
|
||||
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
this_gitlab = GitlabBranch(module=module, project=project, gitlab_instance=gitlab_instance)
|
||||
|
||||
this_branch = this_gitlab.get_branch(branch)
|
||||
|
||||
@@ -20,7 +20,6 @@ author:
|
||||
- Marcus Watkins (@marwatk)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -121,7 +120,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_project, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, find_project, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -261,7 +260,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
state = module.params['state']
|
||||
project_identifier = module.params['project']
|
||||
@@ -269,8 +270,6 @@ def main():
|
||||
key_keyfile = module.params['key']
|
||||
key_can_push = module.params['can_push']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
gitlab_deploy_key = GitLabDeployKey(module, gitlab_instance)
|
||||
|
||||
project = find_project(gitlab_instance, project_identifier)
|
||||
|
||||
@@ -20,7 +20,6 @@ author:
|
||||
- Werner Dijkerman (@dj-wasabi)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -108,7 +107,6 @@ EXAMPLES = '''
|
||||
community.general.gitlab_group:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_token: "{{ access_token }}"
|
||||
validate_certs: false
|
||||
name: my_first_group
|
||||
state: absent
|
||||
|
||||
@@ -178,7 +176,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_group, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, find_group, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -355,7 +353,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
group_name = module.params['name']
|
||||
group_path = module.params['path']
|
||||
@@ -370,8 +370,6 @@ def main():
|
||||
avatar_path = module.params['avatar_path']
|
||||
force_delete = module.params['force_delete']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
# Define default group_path based on group_name
|
||||
if group_path is None:
|
||||
group_path = group_name.replace(" ", "_")
|
||||
|
||||
@@ -160,7 +160,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -273,7 +273,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
access_level_int = {
|
||||
'guest': gitlab.const.GUEST_ACCESS,
|
||||
@@ -291,9 +293,6 @@ def main():
|
||||
if purge_users:
|
||||
purge_users = [access_level_int[level] for level in purge_users]
|
||||
|
||||
# connect to gitlab server
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
group = GitLabGroup(module, gl)
|
||||
|
||||
gitlab_group_id = group.get_group_id(gitlab_group)
|
||||
|
||||
@@ -21,7 +21,6 @@ description:
|
||||
author:
|
||||
- Florent Madiot (@scodeman)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -207,7 +206,7 @@ group_variable:
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables, vars_to_variables
|
||||
auth_argument_spec, gitlab_authentication, filter_returned_variables, vars_to_variables
|
||||
)
|
||||
|
||||
|
||||
@@ -413,7 +412,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
purge = module.params['purge']
|
||||
var_list = module.params['vars']
|
||||
@@ -428,8 +429,6 @@ def main():
|
||||
if any(x['value'] is None for x in variables):
|
||||
module.fail_json(msg='value parameter is required in state present')
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
this_gitlab = GitlabGroupVariables(module=module, gitlab_instance=gitlab_instance)
|
||||
|
||||
changed, raw_return_value, before, after = native_python_main(this_gitlab, purge, variables, state, module)
|
||||
|
||||
@@ -21,7 +21,6 @@ author:
|
||||
- Marcus Watkins (@marwatk)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -123,7 +122,6 @@ EXAMPLES = '''
|
||||
state: present
|
||||
push_events: true
|
||||
tag_push_events: true
|
||||
hook_validate_certs: false
|
||||
token: "my-super-secret-token-that-my-ci-server-will-check"
|
||||
|
||||
- name: "Delete the previous hook"
|
||||
@@ -171,7 +169,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_project, gitlab_authentication, ensure_gitlab_package
|
||||
auth_argument_spec, find_project, gitlab_authentication
|
||||
)
|
||||
|
||||
|
||||
@@ -325,7 +323,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
state = module.params['state']
|
||||
project_identifier = module.params['project']
|
||||
@@ -342,8 +342,6 @@ def main():
|
||||
enable_ssl_verification = module.params['hook_validate_certs']
|
||||
hook_token = module.params['token']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
gitlab_hook = GitLabHook(module, gitlab_instance)
|
||||
|
||||
project = find_project(gitlab_instance, project_identifier)
|
||||
|
||||
@@ -23,7 +23,6 @@ description:
|
||||
author:
|
||||
- Benedikt Braunger (@benibr)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -139,7 +138,7 @@ instance_variable:
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables
|
||||
auth_argument_spec, gitlab_authentication, filter_returned_variables
|
||||
)
|
||||
|
||||
|
||||
@@ -326,7 +325,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
purge = module.params['purge']
|
||||
state = module.params['state']
|
||||
@@ -337,8 +338,6 @@ def main():
|
||||
if any(x['value'] is None for x in variables):
|
||||
module.fail_json(msg='value parameter is required in state present')
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
this_gitlab = GitlabInstanceVariables(module=module, gitlab_instance=gitlab_instance)
|
||||
|
||||
changed, raw_return_value, before, after = native_python_main(this_gitlab, purge, variables, state, module)
|
||||
|
||||
408
plugins/modules/gitlab_issue.py
Normal file
408
plugins/modules/gitlab_issue.py
Normal file
@@ -0,0 +1,408 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023, Ondrej Zvara (ozvara1@gmail.com)
|
||||
# Based on code:
|
||||
# Copyright (c) 2021, Lennert Mertens (lennert@nubera.be)
|
||||
# Copyright (c) 2021, Werner Dijkerman (ikben@werner-dijkerman.nl)
|
||||
# Copyright (c) 2015, Werner Dijkerman (ikben@werner-dijkerman.nl)
|
||||
# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
|
||||
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: gitlab_issue
|
||||
short_description: Create, update, or delete GitLab issues
|
||||
version_added: '8.1.0'
|
||||
description:
|
||||
- Creates an issue if it does not exist.
|
||||
- When an issue does exist, it will be updated if the provided parameters are different.
|
||||
- When an issue does exist and O(state=absent), the issue will be deleted.
|
||||
- When multiple issues are detected, the task fails.
|
||||
- Existing issues are matched based on O(title) and O(state_filter) filters.
|
||||
author:
|
||||
- zvaraondrej (@zvaraondrej)
|
||||
requirements:
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
- community.general.attributes
|
||||
|
||||
attributes:
|
||||
check_mode:
|
||||
support: full
|
||||
diff_mode:
|
||||
support: none
|
||||
|
||||
options:
|
||||
assignee_ids:
|
||||
description:
|
||||
- A list of assignee usernames omitting V(@) character.
|
||||
- Set to an empty array to unassign all assignees.
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
description:
|
||||
- A description of the issue.
|
||||
- Gets overridden by a content of file specified at O(description_path), if found.
|
||||
type: str
|
||||
description_path:
|
||||
description:
|
||||
- A path of file containing issue's description.
|
||||
- Accepts MarkDown formatted files.
|
||||
type: path
|
||||
issue_type:
|
||||
description:
|
||||
- Type of the issue.
|
||||
default: issue
|
||||
type: str
|
||||
choices: ["issue", "incident", "test_case"]
|
||||
labels:
|
||||
description:
|
||||
- A list of label names.
|
||||
- Set to an empty array to remove all labels.
|
||||
type: list
|
||||
elements: str
|
||||
milestone_search:
|
||||
description:
|
||||
- The name of the milestone.
|
||||
- Set to empty string to unassign milestone.
|
||||
type: str
|
||||
milestone_group_id:
|
||||
description:
|
||||
- The path or numeric ID of the group hosting desired milestone.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- The path or name of the project.
|
||||
required: true
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Create or delete issue.
|
||||
default: present
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
state_filter:
|
||||
description:
|
||||
- Filter specifying state of issues while searching.
|
||||
type: str
|
||||
choices: ["opened", "closed"]
|
||||
default: opened
|
||||
title:
|
||||
description:
|
||||
- A title for the issue. The title is used as a unique identifier to ensure idempotency.
|
||||
type: str
|
||||
required: true
|
||||
'''
|
||||
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create Issue
|
||||
community.general.gitlab_issue:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "group1/project1"
|
||||
title: "Ansible demo Issue"
|
||||
description: "Demo Issue description"
|
||||
labels:
|
||||
- Ansible
|
||||
- Demo
|
||||
assignee_ids:
|
||||
- testassignee
|
||||
state_filter: "opened"
|
||||
state: present
|
||||
|
||||
- name: Delete Issue
|
||||
community.general.gitlab_issue:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "group1/project1"
|
||||
title: "Ansible demo Issue"
|
||||
state_filter: "opened"
|
||||
state: absent
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
msg:
|
||||
description: Success or failure message.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Success"
|
||||
|
||||
issue:
|
||||
description: API object.
|
||||
returned: success
|
||||
type: dict
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, find_project, find_group
|
||||
)
|
||||
|
||||
|
||||
class GitlabIssue(object):
|
||||
|
||||
def __init__(self, module, project, gitlab_instance):
|
||||
self._gitlab = gitlab_instance
|
||||
self._module = module
|
||||
self.project = project
|
||||
|
||||
'''
|
||||
@param milestone_id Title of the milestone
|
||||
'''
|
||||
def get_milestone(self, milestone_id, group):
|
||||
milestones = []
|
||||
try:
|
||||
milestones = group.milestones.list(search=milestone_id)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
self._module.fail_json(msg="Failed to list the Milestones: %s" % to_native(e))
|
||||
|
||||
if len(milestones) > 1:
|
||||
self._module.fail_json(msg="Multiple Milestones matched search criteria.")
|
||||
if len(milestones) < 1:
|
||||
self._module.fail_json(msg="No Milestones matched search criteria.")
|
||||
if len(milestones) == 1:
|
||||
try:
|
||||
return group.milestones.get(id=milestones[0].id)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
self._module.fail_json(msg="Failed to get the Milestones: %s" % to_native(e))
|
||||
|
||||
'''
|
||||
@param title Title of the Issue
|
||||
@param state_filter Issue's state to filter on
|
||||
'''
|
||||
def get_issue(self, title, state_filter):
|
||||
issues = []
|
||||
try:
|
||||
issues = self.project.issues.list(title=title, state=state_filter)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
self._module.fail_json(msg="Failed to list the Issues: %s" % to_native(e))
|
||||
|
||||
if len(issues) > 1:
|
||||
self._module.fail_json(msg="Multiple Issues matched search criteria.")
|
||||
if len(issues) == 1:
|
||||
try:
|
||||
return self.project.issues.get(id=issues[0].iid)
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
self._module.fail_json(msg="Failed to get the Issue: %s" % to_native(e))
|
||||
|
||||
'''
|
||||
@param username Name of the user
|
||||
'''
|
||||
def get_user(self, username):
|
||||
users = []
|
||||
try:
|
||||
users = [user for user in self.project.users.list(username=username, all=True) if user.username == username]
|
||||
except gitlab.exceptions.GitlabGetError as e:
|
||||
self._module.fail_json(msg="Failed to list the users: %s" % to_native(e))
|
||||
|
||||
if len(users) > 1:
|
||||
self._module.fail_json(msg="Multiple Users matched search criteria.")
|
||||
elif len(users) < 1:
|
||||
self._module.fail_json(msg="No User matched search criteria.")
|
||||
else:
|
||||
return users[0]
|
||||
|
||||
'''
|
||||
@param users List of usernames
|
||||
'''
|
||||
def get_user_ids(self, users):
|
||||
return [self.get_user(user).id for user in users]
|
||||
|
||||
'''
|
||||
@param options Options of the Issue
|
||||
'''
|
||||
def create_issue(self, options):
|
||||
if self._module.check_mode:
|
||||
self._module.exit_json(changed=True, msg="Successfully created Issue '%s'." % options["title"])
|
||||
|
||||
try:
|
||||
return self.project.issues.create(options)
|
||||
except gitlab.exceptions.GitlabCreateError as e:
|
||||
self._module.fail_json(msg="Failed to create Issue: %s " % to_native(e))
|
||||
|
||||
'''
|
||||
@param issue Issue object to delete
|
||||
'''
|
||||
def delete_issue(self, issue):
|
||||
if self._module.check_mode:
|
||||
self._module.exit_json(changed=True, msg="Successfully deleted Issue '%s'." % issue["title"])
|
||||
|
||||
try:
|
||||
return issue.delete()
|
||||
except gitlab.exceptions.GitlabDeleteError as e:
|
||||
self._module.fail_json(msg="Failed to delete Issue: '%s'." % to_native(e))
|
||||
|
||||
'''
|
||||
@param issue Issue object to update
|
||||
@param options Options of the Issue
|
||||
'''
|
||||
def update_issue(self, issue, options):
|
||||
if self._module.check_mode:
|
||||
self._module.exit_json(changed=True, msg="Successfully updated Issue '%s'." % issue["title"])
|
||||
|
||||
try:
|
||||
return self.project.issues.update(issue.iid, options)
|
||||
except gitlab.exceptions.GitlabUpdateError as e:
|
||||
self._module.fail_json(msg="Failed to update Issue %s." % to_native(e))
|
||||
|
||||
'''
|
||||
@param issue Issue object to evaluate
|
||||
@param options New options to update Issue with
|
||||
'''
|
||||
def issue_has_changed(self, issue, options):
|
||||
for key, value in options.items():
|
||||
if value is not None:
|
||||
|
||||
if key == 'milestone_id':
|
||||
old_milestone = getattr(issue, 'milestone')['id'] if getattr(issue, 'milestone') else ""
|
||||
if options[key] != old_milestone:
|
||||
return True
|
||||
elif key == 'assignee_ids':
|
||||
if options[key] != sorted([user["id"] for user in getattr(issue, 'assignees')]):
|
||||
return True
|
||||
|
||||
elif key == 'labels':
|
||||
if options[key] != sorted(getattr(issue, key)):
|
||||
return True
|
||||
|
||||
elif getattr(issue, key) != value:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(
|
||||
assignee_ids=dict(type='list', elements='str', required=False),
|
||||
description=dict(type='str', required=False),
|
||||
description_path=dict(type='path', required=False),
|
||||
issue_type=dict(type='str', default='issue', choices=["issue", "incident", "test_case"], required=False),
|
||||
labels=dict(type='list', elements='str', required=False),
|
||||
milestone_search=dict(type='str', required=False),
|
||||
milestone_group_id=dict(type='str', required=False),
|
||||
project=dict(type='str', required=True),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
state_filter=dict(type='str', default="opened", choices=["opened", "closed"]),
|
||||
title=dict(type='str', required=True),
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
['description', 'description_path'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
['milestone_search', 'milestone_group_id'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
assignee_ids = module.params['assignee_ids']
|
||||
description = module.params['description']
|
||||
description_path = module.params['description_path']
|
||||
issue_type = module.params['issue_type']
|
||||
labels = module.params['labels']
|
||||
milestone_id = module.params['milestone_search']
|
||||
milestone_group_id = module.params['milestone_group_id']
|
||||
project = module.params['project']
|
||||
state = module.params['state']
|
||||
state_filter = module.params['state_filter']
|
||||
title = module.params['title']
|
||||
|
||||
gitlab_version = gitlab.__version__
|
||||
if LooseVersion(gitlab_version) < LooseVersion('2.3.0'):
|
||||
module.fail_json(msg="community.general.gitlab_issue requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
|
||||
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
this_project = find_project(gitlab_instance, project)
|
||||
if this_project is None:
|
||||
module.fail_json(msg="Failed to get the project: %s" % project)
|
||||
|
||||
this_gitlab = GitlabIssue(module=module, project=this_project, gitlab_instance=gitlab_instance)
|
||||
|
||||
if milestone_id and milestone_group_id:
|
||||
this_group = find_group(gitlab_instance, milestone_group_id)
|
||||
if this_group is None:
|
||||
module.fail_json(msg="Failed to get the group: %s" % milestone_group_id)
|
||||
|
||||
milestone_id = this_gitlab.get_milestone(milestone_id, this_group).id
|
||||
|
||||
this_issue = this_gitlab.get_issue(title, state_filter)
|
||||
|
||||
if state == "present":
|
||||
if description_path:
|
||||
try:
|
||||
with open(description_path, 'rb') as f:
|
||||
description = to_text(f.read(), errors='surrogate_or_strict')
|
||||
except IOError as e:
|
||||
module.fail_json(msg='Cannot open {0}: {1}'.format(description_path, e))
|
||||
|
||||
# sorting necessary in order to properly detect changes, as we don't want to get false positive
|
||||
# results due to differences in ids ordering;
|
||||
assignee_ids = sorted(this_gitlab.get_user_ids(assignee_ids)) if assignee_ids else assignee_ids
|
||||
labels = sorted(labels) if labels else labels
|
||||
|
||||
options = {
|
||||
"title": title,
|
||||
"description": description,
|
||||
"labels": labels,
|
||||
"issue_type": issue_type,
|
||||
"milestone_id": milestone_id,
|
||||
"assignee_ids": assignee_ids,
|
||||
}
|
||||
|
||||
if not this_issue:
|
||||
issue = this_gitlab.create_issue(options)
|
||||
module.exit_json(
|
||||
changed=True, msg="Created Issue '{t}'.".format(t=title),
|
||||
issue=issue.asdict()
|
||||
)
|
||||
else:
|
||||
if this_gitlab.issue_has_changed(this_issue, options):
|
||||
issue = this_gitlab.update_issue(this_issue, options)
|
||||
module.exit_json(
|
||||
changed=True, msg="Updated Issue '{t}'.".format(t=title),
|
||||
issue=issue
|
||||
)
|
||||
else:
|
||||
module.exit_json(
|
||||
changed=False, msg="Issue '{t}' already exists".format(t=title),
|
||||
issue=this_issue.asdict()
|
||||
)
|
||||
elif state == "absent":
|
||||
if not this_issue:
|
||||
module.exit_json(changed=False, msg="Issue '{t}' does not exist or has already been deleted.".format(t=title))
|
||||
else:
|
||||
issue = this_gitlab.delete_issue(this_issue)
|
||||
module.exit_json(
|
||||
changed=True, msg="Issue '{t}' deleted.".format(t=title),
|
||||
issue=issue
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -26,7 +26,6 @@ description:
|
||||
author:
|
||||
- zvaraondrej (@zvaraondrej)
|
||||
requirements:
|
||||
- Python >= 2.7
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -152,7 +151,7 @@ from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package, find_project
|
||||
auth_argument_spec, gitlab_authentication, gitlab, find_project
|
||||
)
|
||||
|
||||
|
||||
@@ -321,7 +320,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
project = module.params['project']
|
||||
source_branch = module.params['source_branch']
|
||||
@@ -341,8 +342,6 @@ def main():
|
||||
module.fail_json(msg="community.general.gitlab_merge_request requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
|
||||
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
this_project = find_project(gitlab_instance, project)
|
||||
if this_project is None:
|
||||
module.fail_json(msg="Failed to get the project: %s" % project)
|
||||
|
||||
@@ -21,7 +21,6 @@ author:
|
||||
- Werner Dijkerman (@dj-wasabi)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -274,7 +273,6 @@ EXAMPLES = r'''
|
||||
community.general.gitlab_project:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_token: "{{ access_token }}"
|
||||
validate_certs: false
|
||||
name: my_first_project
|
||||
state: absent
|
||||
delegate_to: localhost
|
||||
@@ -340,7 +338,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_group, find_project, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, find_group, find_project, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
@@ -558,7 +556,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
group_identifier = module.params['group']
|
||||
project_name = module.params['name']
|
||||
@@ -596,8 +596,6 @@ def main():
|
||||
security_and_compliance_access_level = module.params['security_and_compliance_access_level']
|
||||
topics = module.params['topics']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
# Set project_path to project_name if it is empty.
|
||||
if project_path is None:
|
||||
project_path = project_name.replace(" ", "_")
|
||||
|
||||
@@ -97,7 +97,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, find_project, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, find_project
|
||||
)
|
||||
|
||||
|
||||
@@ -159,13 +159,12 @@ state_strategy = {
|
||||
|
||||
|
||||
def core(module):
|
||||
ensure_gitlab_package(module)
|
||||
# check prerequisites and connect to gitlab server
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
gitlab_project = module.params['project']
|
||||
state = module.params['state']
|
||||
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
project = find_project(gl, gitlab_project)
|
||||
# project doesn't exist
|
||||
if not project:
|
||||
|
||||
@@ -106,7 +106,6 @@ EXAMPLES = r'''
|
||||
community.general.gitlab_project_members:
|
||||
api_url: 'https://gitlab.example.com'
|
||||
api_token: 'Your-Private-Token'
|
||||
validate_certs: false
|
||||
project: projectname
|
||||
gitlab_user: username
|
||||
state: absent
|
||||
@@ -163,7 +162,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -279,7 +278,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
access_level_int = {
|
||||
'guest': gitlab.const.GUEST_ACCESS,
|
||||
@@ -296,9 +297,6 @@ def main():
|
||||
if purge_users:
|
||||
purge_users = [access_level_int[level] for level in purge_users]
|
||||
|
||||
# connect to gitlab server
|
||||
gl = gitlab_authentication(module)
|
||||
|
||||
project = GitLabProjectMembers(module, gl)
|
||||
|
||||
gitlab_project_id = project.get_project(gitlab_project)
|
||||
|
||||
@@ -18,7 +18,6 @@ description:
|
||||
author:
|
||||
- "Markus Bergholz (@markuman)"
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -221,13 +220,12 @@ project_variable:
|
||||
sample: ['ACCESS_KEY_ID', 'SECRET_ACCESS_KEY']
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, ensure_gitlab_package, filter_returned_variables, vars_to_variables,
|
||||
HAS_GITLAB_PACKAGE, GITLAB_IMP_ERR
|
||||
auth_argument_spec, gitlab_authentication, filter_returned_variables, vars_to_variables
|
||||
)
|
||||
|
||||
|
||||
@@ -436,10 +434,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
if not HAS_GITLAB_PACKAGE:
|
||||
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
purge = module.params['purge']
|
||||
var_list = module.params['vars']
|
||||
@@ -454,8 +451,6 @@ def main():
|
||||
if any(x['value'] is None for x in variables):
|
||||
module.fail_json(msg='value parameter is required for all variables in state present')
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
this_gitlab = GitlabProjectVariables(module=module, gitlab_instance=gitlab_instance)
|
||||
|
||||
change, raw_return_value, before, after = native_python_main(this_gitlab, purge, variables, state, module)
|
||||
|
||||
@@ -16,7 +16,6 @@ description:
|
||||
author:
|
||||
- "Werner Dijkerman (@dj-wasabi)"
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -83,7 +82,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -164,7 +163,9 @@ def main():
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
project = module.params['project']
|
||||
name = module.params['name']
|
||||
@@ -177,7 +178,6 @@ def main():
|
||||
module.fail_json(msg="community.general.gitlab_proteched_branch requires python-gitlab Python module >= 2.3.0 (installed version: [%s])."
|
||||
" Please upgrade python-gitlab to version 2.3.0 or above." % gitlab_version)
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
this_gitlab = GitlabProtectedBranch(module=module, project=project, gitlab_instance=gitlab_instance)
|
||||
|
||||
p_branch = this_gitlab.protected_branch_exist(name=name)
|
||||
|
||||
@@ -30,7 +30,6 @@ author:
|
||||
- Samy Coenen (@SamyCoenen)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 1.5.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
@@ -48,6 +47,7 @@ options:
|
||||
description:
|
||||
- ID or full path of the group in the form group/subgroup.
|
||||
- Mutually exclusive with O(owned) and O(project).
|
||||
- Must be group's numeric ID if O(registration_token) is not set and O(state=present).
|
||||
type: str
|
||||
version_added: '6.5.0'
|
||||
project:
|
||||
@@ -55,6 +55,7 @@ options:
|
||||
- ID or full path of the project in the form of group/name.
|
||||
- Mutually exclusive with O(owned) since community.general 4.5.0.
|
||||
- Mutually exclusive with O(group).
|
||||
- Must be project's numeric ID if O(registration_token) is not set and O(state=present).
|
||||
type: str
|
||||
version_added: '3.7.0'
|
||||
description:
|
||||
@@ -73,8 +74,11 @@ options:
|
||||
type: str
|
||||
registration_token:
|
||||
description:
|
||||
- The registration token is used to register new runners.
|
||||
- Required if O(state=present).
|
||||
- The registration token is used to register new runners before GitLab 16.0.
|
||||
- Required if O(state=present) for GitLab < 16.0.
|
||||
- If set, the runner will be created using the old runner creation workflow.
|
||||
- If not set, the runner will be created using the new runner creation workflow, introduced in GitLab 16.0.
|
||||
- If not set, requires python-gitlab >= 4.0.0.
|
||||
type: str
|
||||
owned:
|
||||
description:
|
||||
@@ -87,9 +91,18 @@ options:
|
||||
active:
|
||||
description:
|
||||
- Define if the runners is immediately active after creation.
|
||||
- Mutually exclusive with O(paused).
|
||||
required: false
|
||||
default: true
|
||||
type: bool
|
||||
paused:
|
||||
description:
|
||||
- Define if the runners is active or paused after creation.
|
||||
- Mutually exclusive with O(active).
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
version_added: 8.1.0
|
||||
locked:
|
||||
description:
|
||||
- Determines if the runner is locked or not.
|
||||
@@ -206,10 +219,13 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
|
||||
|
||||
|
||||
class GitLabRunner(object):
|
||||
def __init__(self, module, gitlab_instance, group=None, project=None):
|
||||
self._module = module
|
||||
@@ -232,18 +248,32 @@ class GitLabRunner(object):
|
||||
changed = False
|
||||
|
||||
arguments = {
|
||||
'active': options['active'],
|
||||
'locked': options['locked'],
|
||||
'run_untagged': options['run_untagged'],
|
||||
'maximum_timeout': options['maximum_timeout'],
|
||||
'tag_list': options['tag_list'],
|
||||
}
|
||||
|
||||
if options.get('paused') is not None:
|
||||
arguments['paused'] = options['paused']
|
||||
else:
|
||||
arguments['active'] = options['active']
|
||||
|
||||
if options.get('access_level') is not None:
|
||||
arguments['access_level'] = options['access_level']
|
||||
# Because we have already call userExists in main()
|
||||
if self.runner_object is None:
|
||||
arguments['description'] = description
|
||||
arguments['token'] = options['registration_token']
|
||||
if options.get('registration_token') is not None:
|
||||
arguments['token'] = options['registration_token']
|
||||
elif options.get('group') is not None:
|
||||
arguments['runner_type'] = 'group_type'
|
||||
arguments['group_id'] = options['group']
|
||||
elif options.get('project') is not None:
|
||||
arguments['runner_type'] = 'project_type'
|
||||
arguments['project_id'] = options['project']
|
||||
else:
|
||||
arguments['runner_type'] = 'instance_type'
|
||||
|
||||
access_level_on_creation = self._module.params['access_level_on_creation']
|
||||
if not access_level_on_creation:
|
||||
@@ -253,19 +283,17 @@ class GitLabRunner(object):
|
||||
changed = True
|
||||
else:
|
||||
changed, runner = self.update_runner(self.runner_object, arguments)
|
||||
if changed:
|
||||
if self._module.check_mode:
|
||||
self._module.exit_json(changed=True, msg="Successfully updated the runner %s" % description)
|
||||
|
||||
try:
|
||||
runner.save()
|
||||
except Exception as e:
|
||||
self._module.fail_json(msg="Failed to update runner: %s " % to_native(e))
|
||||
|
||||
self.runner_object = runner
|
||||
if changed:
|
||||
if self._module.check_mode:
|
||||
self._module.exit_json(changed=True, msg="Successfully created or updated the runner %s" % description)
|
||||
|
||||
try:
|
||||
runner.save()
|
||||
except Exception as e:
|
||||
self._module.fail_json(msg="Failed to update runner: %s " % to_native(e))
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return changed
|
||||
|
||||
'''
|
||||
@param arguments Attributes of the runner
|
||||
@@ -275,7 +303,12 @@ class GitLabRunner(object):
|
||||
return True
|
||||
|
||||
try:
|
||||
runner = self._gitlab.runners.create(arguments)
|
||||
if arguments.get('token') is not None:
|
||||
runner = self._gitlab.runners.create(arguments)
|
||||
elif LooseVersion(gitlab.__version__) < LooseVersion('4.0.0'):
|
||||
self._module.fail_json(msg="New runner creation workflow requires python-gitlab 4.0.0 or higher")
|
||||
else:
|
||||
runner = self._gitlab.user.runners.create(arguments)
|
||||
except (gitlab.exceptions.GitlabCreateError) as e:
|
||||
self._module.fail_json(msg="Failed to create runner: %s " % to_native(e))
|
||||
|
||||
@@ -348,6 +381,7 @@ def main():
|
||||
argument_spec.update(dict(
|
||||
description=dict(type='str', required=True, aliases=["name"]),
|
||||
active=dict(type='bool', default=True),
|
||||
paused=dict(type='bool', default=False),
|
||||
owned=dict(type='bool', default=False),
|
||||
tag_list=dict(type='list', elements='str', default=[]),
|
||||
run_untagged=dict(type='bool', default=True),
|
||||
@@ -372,6 +406,7 @@ def main():
|
||||
['project', 'owned'],
|
||||
['group', 'owned'],
|
||||
['project', 'group'],
|
||||
['active', 'paused'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
@@ -379,12 +414,11 @@ def main():
|
||||
required_one_of=[
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
|
||||
],
|
||||
required_if=[
|
||||
('state', 'present', ['registration_token']),
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
state = module.params['state']
|
||||
runner_description = module.params['description']
|
||||
@@ -398,7 +432,6 @@ def main():
|
||||
project = module.params['project']
|
||||
group = module.params['group']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
gitlab_project = None
|
||||
gitlab_group = None
|
||||
|
||||
@@ -432,6 +465,8 @@ def main():
|
||||
"access_level": access_level,
|
||||
"maximum_timeout": maximum_timeout,
|
||||
"registration_token": registration_token,
|
||||
"group": group,
|
||||
"project": project,
|
||||
}):
|
||||
module.exit_json(changed=True, runner=gitlab_runner.runner_object._attrs,
|
||||
msg="Successfully created or updated the runner %s" % runner_description)
|
||||
|
||||
@@ -27,7 +27,6 @@ author:
|
||||
- Lennert Mertens (@LennertMertens)
|
||||
- Stef Graces (@stgrace)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
- administrator rights on the GitLab server
|
||||
extends_documentation_fragment:
|
||||
@@ -151,7 +150,6 @@ EXAMPLES = '''
|
||||
community.general.gitlab_user:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_token: "{{ access_token }}"
|
||||
validate_certs: false
|
||||
username: myusername
|
||||
state: absent
|
||||
|
||||
@@ -191,7 +189,6 @@ EXAMPLES = '''
|
||||
community.general.gitlab_user:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_token: "{{ access_token }}"
|
||||
validate_certs: false
|
||||
username: myusername
|
||||
state: blocked
|
||||
|
||||
@@ -199,7 +196,6 @@ EXAMPLES = '''
|
||||
community.general.gitlab_user:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_token: "{{ access_token }}"
|
||||
validate_certs: false
|
||||
username: myusername
|
||||
state: unblocked
|
||||
'''
|
||||
@@ -234,7 +230,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import (
|
||||
auth_argument_spec, find_group, gitlab_authentication, gitlab, ensure_gitlab_package
|
||||
auth_argument_spec, find_group, gitlab_authentication, gitlab
|
||||
)
|
||||
|
||||
|
||||
@@ -616,7 +612,9 @@ def main():
|
||||
('state', 'present', ['name', 'email']),
|
||||
)
|
||||
)
|
||||
ensure_gitlab_package(module)
|
||||
|
||||
# check prerequisites and connect to gitlab server
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
user_name = module.params['name']
|
||||
state = module.params['state']
|
||||
@@ -635,8 +633,6 @@ def main():
|
||||
user_identities = module.params['identities']
|
||||
overwrite_identities = module.params['overwrite_identities']
|
||||
|
||||
gitlab_instance = gitlab_authentication(module)
|
||||
|
||||
gitlab_user = GitLabUser(module, gitlab_instance)
|
||||
user_exists = gitlab_user.exists_user(user_username)
|
||||
if user_exists:
|
||||
|
||||
@@ -43,8 +43,7 @@ options:
|
||||
type: str
|
||||
force:
|
||||
description:
|
||||
- Discards uncommitted changes. Runs C(hg update -C). Prior to
|
||||
Ansible 1.9, the default was V(true).
|
||||
- Discards uncommitted changes. Runs C(hg update -C).
|
||||
type: bool
|
||||
default: false
|
||||
purge:
|
||||
|
||||
@@ -19,8 +19,6 @@ description:
|
||||
These information includes hardware and network related information useful
|
||||
for provisioning (e.g. macaddress, uuid).
|
||||
- This module requires the C(hpilo) python module.
|
||||
- This module was called C(hpilo_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||
Note that the M(community.general.hpilo_info) module no longer returns C(ansible_facts)!
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
|
||||
@@ -16,8 +16,6 @@ description:
|
||||
- Builds Redfish URIs locally and sends them to remote iDRAC controllers to
|
||||
get information back.
|
||||
- For use with Dell EMC iDRAC operations that require Redfish OEM extensions.
|
||||
- This module was called C(idrac_redfish_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||
Note that the M(community.general.idrac_redfish_info) module no longer returns C(ansible_facts)!
|
||||
extends_documentation_fragment:
|
||||
- community.general.attributes
|
||||
- community.general.attributes.info_module
|
||||
|
||||
@@ -100,7 +100,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_hostname }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
content: |
|
||||
<configConfMo><inConfig>
|
||||
<computeRackUnit dn="sys/rack-unit-1" adminPower="down"/>
|
||||
@@ -112,7 +112,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_hostname }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
timeout: 120
|
||||
content: |
|
||||
<!-- Configure Serial-on-LAN -->
|
||||
@@ -137,7 +137,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_hostname }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
content: |
|
||||
<!-- Configure PXE boot -->
|
||||
<configConfMo><inConfig>
|
||||
@@ -155,7 +155,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_host }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
content: |
|
||||
<configConfMo><inConfig>
|
||||
<lsbootStorage dn="sys/rack-unit-1/boot-policy/storage-read-write" access="read-write" order="1" type="storage"/>
|
||||
@@ -167,7 +167,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_host }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
content: |
|
||||
<configConfMo><inConfig>
|
||||
<computeRackUnit dn="sys/rack-unit-1" usrLbl="Customer Lab - POD{{ pod_id }} - {{ inventory_hostname_short }}"/>
|
||||
@@ -179,7 +179,7 @@ EXAMPLES = r'''
|
||||
hostname: '{{ imc_host }}'
|
||||
username: '{{ imc_username }}'
|
||||
password: '{{ imc_password }}'
|
||||
validate_certs: false
|
||||
validate_certs: false # only do this when you trust the network!
|
||||
timeout: 120
|
||||
content: |
|
||||
<configConfMo><inConfig>
|
||||
|
||||
@@ -62,9 +62,6 @@ options:
|
||||
description:
|
||||
- Image UUID. Can either be a full UUID or V(*) for all images.
|
||||
type: str
|
||||
|
||||
requirements:
|
||||
- python >= 2.6
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
@@ -17,7 +17,6 @@ description:
|
||||
- Manage InfluxDB databases.
|
||||
author: "Kamil Szczygiel (@kamsz)"
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- "influxdb >= 0.9"
|
||||
- requests
|
||||
attributes:
|
||||
|
||||
@@ -16,7 +16,6 @@ description:
|
||||
- Query data points from InfluxDB.
|
||||
author: "René Moser (@resmo)"
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- "influxdb >= 0.9"
|
||||
attributes:
|
||||
check_mode:
|
||||
|
||||
@@ -17,7 +17,6 @@ description:
|
||||
- Manage InfluxDB retention policies.
|
||||
author: "Kamil Szczygiel (@kamsz)"
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- "influxdb >= 0.9"
|
||||
- requests
|
||||
attributes:
|
||||
@@ -115,7 +114,6 @@ EXAMPLES = r'''
|
||||
duration: INF
|
||||
replication: 1
|
||||
ssl: false
|
||||
validate_certs: false
|
||||
shard_group_duration: 1w
|
||||
state: present
|
||||
|
||||
@@ -127,7 +125,6 @@ EXAMPLES = r'''
|
||||
duration: 5d1h30m
|
||||
replication: 1
|
||||
ssl: false
|
||||
validate_certs: false
|
||||
shard_group_duration: 1d10h30m
|
||||
state: present
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user