mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-28 17:36:49 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6661917370 | ||
|
|
ec0bd3143a | ||
|
|
cce68def8b | ||
|
|
6f5ad22d28 | ||
|
|
6c53a09eef | ||
|
|
9b6e75f7f4 | ||
|
|
e09650140d | ||
|
|
67388be1a9 | ||
|
|
130d07948a | ||
|
|
5d6fcaef53 | ||
|
|
f044a83c49 | ||
|
|
e3f7e8dadf | ||
|
|
8d1a028dbd | ||
|
|
8823e5c061 | ||
|
|
102456d033 | ||
|
|
aad4c55d3d | ||
|
|
e31c98f17f | ||
|
|
6a5dfc5579 | ||
|
|
ab7efef9df | ||
|
|
ca9c763b57 | ||
|
|
cfeb40ed23 | ||
|
|
c495d136fa | ||
|
|
d9e2d6682b | ||
|
|
d7fe288ffd | ||
|
|
7de89699f7 | ||
|
|
b0a9cceeb5 | ||
|
|
b08f0b2f82 | ||
|
|
f23f409bd6 | ||
|
|
cfea62793f | ||
|
|
62bda91466 | ||
|
|
473d5fa2af | ||
|
|
cc76d684d5 | ||
|
|
7a6770c731 | ||
|
|
d2214af6e8 | ||
|
|
fad1220869 | ||
|
|
fe09516235 | ||
|
|
78cd8886f4 | ||
|
|
6b99d48f06 | ||
|
|
6e0e17a7e3 | ||
|
|
90de95c7b2 | ||
|
|
07c6b8b24e | ||
|
|
d106de6d51 | ||
|
|
e96101fb3f | ||
|
|
a60d55f03c | ||
|
|
d6a09ada98 | ||
|
|
9ddb75a3a2 | ||
|
|
b85ff2a997 | ||
|
|
3d1ca5638b | ||
|
|
35fd4700bf | ||
|
|
9add9df7d6 | ||
|
|
cdb747b41d |
@@ -24,14 +24,15 @@ schedules:
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-2
|
||||
- stable-3
|
||||
- stable-4
|
||||
- cron: 0 11 * * 0
|
||||
displayName: Weekly (old stable branches)
|
||||
always: true
|
||||
branches:
|
||||
include:
|
||||
- stable-1
|
||||
- stable-2
|
||||
|
||||
variables:
|
||||
- name: checkoutPath
|
||||
|
||||
16
.github/BOTMETA.yml
vendored
16
.github/BOTMETA.yml
vendored
@@ -156,7 +156,7 @@ files:
|
||||
maintainers: conloos
|
||||
$inventories/nmap.py: {}
|
||||
$inventories/online.py:
|
||||
maintainers: sieben
|
||||
maintainers: remyleone
|
||||
$inventories/opennebula.py:
|
||||
maintainers: feldsam
|
||||
labels: cloud opennebula
|
||||
@@ -341,7 +341,7 @@ files:
|
||||
$modules/cloud/oneandone/:
|
||||
maintainers: aajdinov edevenport
|
||||
$modules/cloud/online/:
|
||||
maintainers: sieben
|
||||
maintainers: remyleone
|
||||
$modules/cloud/opennebula/:
|
||||
maintainers: $team_opennebula
|
||||
$modules/cloud/opennebula/one_host.py:
|
||||
@@ -411,11 +411,11 @@ files:
|
||||
$modules/cloud/scaleway/scaleway_ip_info.py:
|
||||
maintainers: Spredzy
|
||||
$modules/cloud/scaleway/scaleway_organization_info.py:
|
||||
maintainers: sieben Spredzy
|
||||
maintainers: Spredzy
|
||||
$modules/cloud/scaleway/scaleway_security_group.py:
|
||||
maintainers: DenBeke
|
||||
$modules/cloud/scaleway/scaleway_security_group_info.py:
|
||||
maintainers: sieben Spredzy
|
||||
maintainers: Spredzy
|
||||
$modules/cloud/scaleway/scaleway_security_group_rule.py:
|
||||
maintainers: DenBeke
|
||||
$modules/cloud/scaleway/scaleway_server_info.py:
|
||||
@@ -619,6 +619,8 @@ files:
|
||||
labels: cloudflare_dns
|
||||
$modules/net_tools/dnsimple.py:
|
||||
maintainers: drcapulet
|
||||
$modules/net_tools/dnsimple_info.py:
|
||||
maintainers: edhilgendorf
|
||||
$modules/net_tools/dnsmadeeasy.py:
|
||||
maintainers: briceburg
|
||||
$modules/net_tools/gandi_livedns.py:
|
||||
@@ -951,6 +953,8 @@ files:
|
||||
maintainers: SamyCoenen
|
||||
$modules/source_control/gitlab/gitlab_user.py:
|
||||
maintainers: LennertMertens stgrace
|
||||
$modules/source_control/gitlab/gitlab_branch.py:
|
||||
maintainers: paytroff
|
||||
$modules/source_control/hg.py:
|
||||
maintainers: yeukhon
|
||||
$modules/storage/emc/emc_vnx_sg_member.py:
|
||||
@@ -1224,9 +1228,9 @@ macros:
|
||||
team_opennebula: ilicmilan meerkampdvv rsmontero xorel nilsding
|
||||
team_oracle: manojmeda mross22 nalsaber
|
||||
team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei
|
||||
team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06
|
||||
team_rhn: FlossWare alikins barnabycourt vritant
|
||||
team_scaleway: QuentinBrosse abarbare jerome-quere kindermoumoute remyleone sieben
|
||||
team_scaleway: remyleone abarbare
|
||||
team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
|
||||
team_suse: commel dcermak evrardjp lrupp toabctl AnderEnder alxgu andytom sealor
|
||||
team_virt: joshainglis karmab tleguern Thulium-Drake Ajpantuso
|
||||
|
||||
@@ -6,6 +6,88 @@ Community General Release Notes
|
||||
|
||||
This changelog describes changes after version 3.0.0.
|
||||
|
||||
v4.2.0
|
||||
======
|
||||
|
||||
Release Summary
|
||||
---------------
|
||||
|
||||
Regular bugfix and feature release.
|
||||
|
||||
Minor Changes
|
||||
-------------
|
||||
|
||||
- aix_filesystem - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3833).
|
||||
- aix_lvg - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3834).
|
||||
- gitlab - add more token authentication support with the new options ``api_oauth_token`` and ``api_job_token`` (https://github.com/ansible-collections/community.general/issues/705).
|
||||
- gitlab_group, gitlab_project - add new option ``avatar_path`` (https://github.com/ansible-collections/community.general/pull/3792).
|
||||
- gitlab_project - add new option ``default_branch`` to gitlab_project (if ``readme = true``) (https://github.com/ansible-collections/community.general/pull/3792).
|
||||
- hponcfg - revamped module using ModuleHelper (https://github.com/ansible-collections/community.general/pull/3840).
|
||||
- icinga2 inventory plugin - added the ``display_name`` field to variables (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- icinga2 inventory plugin - inventory object names are changable using ``inventory_attr`` in your config file to the host object name, address, or display_name fields (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- ip_netns - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3822).
|
||||
- iso_extract - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3805).
|
||||
- java_cert - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3835).
|
||||
- jira - add support for Bearer token auth (https://github.com/ansible-collections/community.general/pull/3838).
|
||||
- keycloak_user_federation - add sssd user federation support (https://github.com/ansible-collections/community.general/issues/3767).
|
||||
- logentries - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3807).
|
||||
- logstash_plugin - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3808).
|
||||
- lxc_container - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3851).
|
||||
- lxd connection plugin - make sure that ``ansible_lxd_host``, ``ansible_executable``, and ``ansible_lxd_executable`` work (https://github.com/ansible-collections/community.general/pull/3798).
|
||||
- lxd inventory plugin - support virtual machines (https://github.com/ansible-collections/community.general/pull/3519).
|
||||
- module_helper module utils - added decorators ``check_mode_skip`` and ``check_mode_skip_returns`` for skipping methods when ``check_mode=True`` (https://github.com/ansible-collections/community.general/pull/3849).
|
||||
- monit - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3821).
|
||||
- nmcli - add multiple addresses support for ``ip6`` parameter (https://github.com/ansible-collections/community.general/issues/1088).
|
||||
- nmcli - add support for ``eui64`` and ``ipv6privacy`` parameters (https://github.com/ansible-collections/community.general/issues/3357).
|
||||
- python_requirements_info - returns python version broken down into its components, and some minor refactoring (https://github.com/ansible-collections/community.general/pull/3797).
|
||||
- svc - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3829).
|
||||
- xattr - calling ``run_command`` with arguments as ``list`` instead of ``str`` (https://github.com/ansible-collections/community.general/pull/3806).
|
||||
- xfconf - minor refactor on the base class for the module (https://github.com/ansible-collections/community.general/pull/3919).
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
- module_helper module utils - deprecated the attribute ``ModuleHelper.VarDict`` (https://github.com/ansible-collections/community.general/pull/3801).
|
||||
|
||||
Bugfixes
|
||||
--------
|
||||
|
||||
- icinga2 inventory plugin - handle 404 error when filter produces no results (https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- interfaces_file - fixed the check for existing option in interface (https://github.com/ansible-collections/community.general/issues/3841).
|
||||
- jira - fixed bug where module returns error related to dictionary key ``body`` (https://github.com/ansible-collections/community.general/issues/3419).
|
||||
- nmcli - fix returning "changed" when no mask set for IPv4 or IPv6 addresses on task rerun (https://github.com/ansible-collections/community.general/issues/3768).
|
||||
- nmcli - pass ``flags``, ``ingress``, ``egress`` params to ``nmcli`` (https://github.com/ansible-collections/community.general/issues/1086).
|
||||
- nrdp callback plugin - fix error ``string arguments without an encoding`` (https://github.com/ansible-collections/community.general/issues/3903).
|
||||
- opentelemetry_plugin - honour ``ignore_errors`` when a task has failed instead of reporting an error (https://github.com/ansible-collections/community.general/pull/3837).
|
||||
- pipx - passes the correct command line option ``--include-apps`` (https://github.com/ansible-collections/community.general/issues/3791).
|
||||
- proxmox - fixed ``onboot`` parameter causing module failures when undefined (https://github.com/ansible-collections/community.general/issues/3844).
|
||||
- python_requirements_info - fails if version operator used without version (https://github.com/ansible-collections/community.general/pull/3785).
|
||||
|
||||
New Modules
|
||||
-----------
|
||||
|
||||
Net Tools
|
||||
~~~~~~~~~
|
||||
|
||||
- dnsimple_info - Pull basic info from DNSimple API
|
||||
|
||||
Remote Management
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
redfish
|
||||
^^^^^^^
|
||||
|
||||
- ilo_redfish_config - Sets or updates configuration attributes on HPE iLO with Redfish OEM extensions
|
||||
- ilo_redfish_info - Gathers server information through iLO using Redfish APIs
|
||||
|
||||
Source Control
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
gitlab
|
||||
^^^^^^
|
||||
|
||||
- gitlab_branch - Create or delete a branch
|
||||
|
||||
v4.1.0
|
||||
======
|
||||
|
||||
|
||||
@@ -1117,3 +1117,124 @@ releases:
|
||||
name: revbitspss
|
||||
namespace: null
|
||||
release_date: '2021-11-23'
|
||||
4.2.0:
|
||||
changes:
|
||||
bugfixes:
|
||||
- icinga2 inventory plugin - handle 404 error when filter produces no results
|
||||
(https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- interfaces_file - fixed the check for existing option in interface (https://github.com/ansible-collections/community.general/issues/3841).
|
||||
- jira - fixed bug where module returns error related to dictionary key ``body``
|
||||
(https://github.com/ansible-collections/community.general/issues/3419).
|
||||
- nmcli - fix returning "changed" when no mask set for IPv4 or IPv6 addresses
|
||||
on task rerun (https://github.com/ansible-collections/community.general/issues/3768).
|
||||
- nmcli - pass ``flags``, ``ingress``, ``egress`` params to ``nmcli`` (https://github.com/ansible-collections/community.general/issues/1086).
|
||||
- nrdp callback plugin - fix error ``string arguments without an encoding``
|
||||
(https://github.com/ansible-collections/community.general/issues/3903).
|
||||
- opentelemetry_plugin - honour ``ignore_errors`` when a task has failed instead
|
||||
of reporting an error (https://github.com/ansible-collections/community.general/pull/3837).
|
||||
- pipx - passes the correct command line option ``--include-apps`` (https://github.com/ansible-collections/community.general/issues/3791).
|
||||
- proxmox - fixed ``onboot`` parameter causing module failures when undefined
|
||||
(https://github.com/ansible-collections/community.general/issues/3844).
|
||||
- python_requirements_info - fails if version operator used without version
|
||||
(https://github.com/ansible-collections/community.general/pull/3785).
|
||||
deprecated_features:
|
||||
- module_helper module utils - deprecated the attribute ``ModuleHelper.VarDict``
|
||||
(https://github.com/ansible-collections/community.general/pull/3801).
|
||||
minor_changes:
|
||||
- aix_filesystem - calling ``run_command`` with arguments as ``list`` instead
|
||||
of ``str`` (https://github.com/ansible-collections/community.general/pull/3833).
|
||||
- aix_lvg - calling ``run_command`` with arguments as ``list`` instead of ``str``
|
||||
(https://github.com/ansible-collections/community.general/pull/3834).
|
||||
- gitlab - add more token authentication support with the new options ``api_oauth_token``
|
||||
and ``api_job_token`` (https://github.com/ansible-collections/community.general/issues/705).
|
||||
- gitlab_group, gitlab_project - add new option ``avatar_path`` (https://github.com/ansible-collections/community.general/pull/3792).
|
||||
- gitlab_project - add new option ``default_branch`` to gitlab_project (if ``readme
|
||||
= true``) (https://github.com/ansible-collections/community.general/pull/3792).
|
||||
- hponcfg - revamped module using ModuleHelper (https://github.com/ansible-collections/community.general/pull/3840).
|
||||
- icinga2 inventory plugin - added the ``display_name`` field to variables (https://github.com/ansible-collections/community.general/issues/3875,
|
||||
https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- icinga2 inventory plugin - inventory object names are changable using ``inventory_attr``
|
||||
in your config file to the host object name, address, or display_name fields
|
||||
(https://github.com/ansible-collections/community.general/issues/3875, https://github.com/ansible-collections/community.general/pull/3906).
|
||||
- ip_netns - calling ``run_command`` with arguments as ``list`` instead of ``str``
|
||||
(https://github.com/ansible-collections/community.general/pull/3822).
|
||||
- iso_extract - calling ``run_command`` with arguments as ``list`` instead of
|
||||
``str`` (https://github.com/ansible-collections/community.general/pull/3805).
|
||||
- java_cert - calling ``run_command`` with arguments as ``list`` instead of
|
||||
``str`` (https://github.com/ansible-collections/community.general/pull/3835).
|
||||
- jira - add support for Bearer token auth (https://github.com/ansible-collections/community.general/pull/3838).
|
||||
- keycloak_user_federation - add sssd user federation support (https://github.com/ansible-collections/community.general/issues/3767).
|
||||
- logentries - calling ``run_command`` with arguments as ``list`` instead of
|
||||
``str`` (https://github.com/ansible-collections/community.general/pull/3807).
|
||||
- logstash_plugin - calling ``run_command`` with arguments as ``list`` instead
|
||||
of ``str`` (https://github.com/ansible-collections/community.general/pull/3808).
|
||||
- lxc_container - calling ``run_command`` with arguments as ``list`` instead
|
||||
of ``str`` (https://github.com/ansible-collections/community.general/pull/3851).
|
||||
- lxd connection plugin - make sure that ``ansible_lxd_host``, ``ansible_executable``,
|
||||
and ``ansible_lxd_executable`` work (https://github.com/ansible-collections/community.general/pull/3798).
|
||||
- lxd inventory plugin - support virtual machines (https://github.com/ansible-collections/community.general/pull/3519).
|
||||
- module_helper module utils - added decorators ``check_mode_skip`` and ``check_mode_skip_returns``
|
||||
for skipping methods when ``check_mode=True`` (https://github.com/ansible-collections/community.general/pull/3849).
|
||||
- monit - calling ``run_command`` with arguments as ``list`` instead of ``str``
|
||||
(https://github.com/ansible-collections/community.general/pull/3821).
|
||||
- nmcli - add multiple addresses support for ``ip6`` parameter (https://github.com/ansible-collections/community.general/issues/1088).
|
||||
- nmcli - add support for ``eui64`` and ``ipv6privacy`` parameters (https://github.com/ansible-collections/community.general/issues/3357).
|
||||
- python_requirements_info - returns python version broken down into its components,
|
||||
and some minor refactoring (https://github.com/ansible-collections/community.general/pull/3797).
|
||||
- svc - calling ``run_command`` with arguments as ``list`` instead of ``str``
|
||||
(https://github.com/ansible-collections/community.general/pull/3829).
|
||||
- xattr - calling ``run_command`` with arguments as ``list`` instead of ``str``
|
||||
(https://github.com/ansible-collections/community.general/pull/3806).
|
||||
- xfconf - minor refactor on the base class for the module (https://github.com/ansible-collections/community.general/pull/3919).
|
||||
release_summary: Regular bugfix and feature release.
|
||||
fragments:
|
||||
- 1088-add_multiple_ipv6_address_support.yml
|
||||
- 3357-nmcli-eui64-and-ipv6privacy.yml
|
||||
- 3519-inventory-support-lxd-4.yml
|
||||
- 3768-nmcli_fix_changed_when_no_mask_set.yml
|
||||
- 3780-add-keycloak-sssd-user-federation.yml
|
||||
- 3785-python_requirements_info-versionless-op.yaml
|
||||
- 3792-improve_gitlab_group_and_project.yml
|
||||
- 3797-python_requirements_info-improvements.yaml
|
||||
- 3798-fix-lxd-connection-option-vars-support.yml
|
||||
- 3800-pipx-include-apps.yaml
|
||||
- 3801-mh-deprecate-vardict-attr.yaml
|
||||
- 3805-iso_extract-run_command-list.yaml
|
||||
- 3806-xattr-run_command-list.yaml
|
||||
- 3807-logentries-run_command-list.yaml
|
||||
- 3808-logstash_plugin-run_command-list.yaml
|
||||
- 3821-monit-run-list.yaml
|
||||
- 3822-ip_netns-run-list.yaml
|
||||
- 3829-svc-run-list.yaml
|
||||
- 3833-aix_filesystem-run-list.yaml
|
||||
- 3834-aix-lvg-run-list.yaml
|
||||
- 3835-java-cert-run-list.yaml
|
||||
- 3837-opentelemetry_plugin-honour_ignore_errors.yaml
|
||||
- 3838-jira-token.yaml
|
||||
- 3840-hponcfg-mh-revamp.yaml
|
||||
- 3849-mh-check-mode-decos.yaml
|
||||
- 3851-lxc-container-run-list.yaml
|
||||
- 3862-interfaces-file-fix-dup-option.yaml
|
||||
- 3867-jira-fix-body.yaml
|
||||
- 3874-proxmox-fix-onboot-param.yml
|
||||
- 3875-icinga2-inv-fix.yml
|
||||
- 3896-nmcli_vlan_missing_options.yaml
|
||||
- 3909-nrdp_fix_string_args_without_encoding.yaml
|
||||
- 3919-xfconf-baseclass.yaml
|
||||
- 4.2.0.yml
|
||||
- 705-gitlab-auth-support.yml
|
||||
modules:
|
||||
- description: Pull basic info from DNSimple API
|
||||
name: dnsimple_info
|
||||
namespace: net_tools
|
||||
- description: Create or delete a branch
|
||||
name: gitlab_branch
|
||||
namespace: source_control.gitlab
|
||||
- description: Sets or updates configuration attributes on HPE iLO with Redfish
|
||||
OEM extensions
|
||||
name: ilo_redfish_config
|
||||
namespace: remote_management.redfish
|
||||
- description: Gathers server information through iLO using Redfish APIs
|
||||
name: ilo_redfish_info
|
||||
namespace: remote_management.redfish
|
||||
release_date: '2021-12-21'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace: community
|
||||
name: general
|
||||
version: 4.1.0
|
||||
version: 4.2.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
@@ -70,6 +70,7 @@ import os
|
||||
import json
|
||||
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlencode
|
||||
from ansible.module_utils.common.text.converters import to_bytes
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
@@ -143,7 +144,7 @@ class CallbackModule(CallbackBase):
|
||||
body = {
|
||||
'cmd': 'submitcheck',
|
||||
'token': self.token,
|
||||
'XMLDATA': bytes(xmldata)
|
||||
'XMLDATA': to_bytes(xmldata)
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (C) 2021, Victor Martinez <VictorMartinezRubio@gmail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
@@ -267,6 +268,8 @@ class OpenTelemetrySource(object):
|
||||
elif host_data.status == 'skipped':
|
||||
message = res['skip_reason'] if 'skip_reason' in res else 'skipped'
|
||||
status = Status(status_code=StatusCode.UNSET)
|
||||
elif host_data.status == 'ignored':
|
||||
status = Status(status_code=StatusCode.UNSET)
|
||||
|
||||
span.set_status(status)
|
||||
if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action:
|
||||
@@ -462,10 +465,15 @@ class CallbackModule(CallbackBase):
|
||||
)
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
self.errors += 1
|
||||
if ignore_errors:
|
||||
status = 'ignored'
|
||||
else:
|
||||
status = 'failed'
|
||||
self.errors += 1
|
||||
|
||||
self.opentelemetry.finish_task(
|
||||
self.tasks_data,
|
||||
'failed',
|
||||
status,
|
||||
result
|
||||
)
|
||||
|
||||
|
||||
@@ -89,9 +89,9 @@ class Connection(ConnectionBase):
|
||||
local_cmd.extend(["--project", self.get_option("project")])
|
||||
local_cmd.extend([
|
||||
"exec",
|
||||
"%s:%s" % (self.get_option("remote"), self._host),
|
||||
"%s:%s" % (self.get_option("remote"), self.get_option("remote_addr")),
|
||||
"--",
|
||||
self._play_context.executable, "-c", cmd
|
||||
self.get_option("executable"), "-c", cmd
|
||||
])
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
@@ -126,7 +126,7 @@ class Connection(ConnectionBase):
|
||||
local_cmd.extend([
|
||||
"file", "push",
|
||||
in_path,
|
||||
"%s:%s/%s" % (self.get_option("remote"), self._host, out_path)
|
||||
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), out_path)
|
||||
])
|
||||
|
||||
local_cmd = [to_bytes(i, errors='surrogate_or_strict') for i in local_cmd]
|
||||
@@ -145,7 +145,7 @@ class Connection(ConnectionBase):
|
||||
local_cmd.extend(["--project", self.get_option("project")])
|
||||
local_cmd.extend([
|
||||
"file", "pull",
|
||||
"%s:%s/%s" % (self.get_option("remote"), self._host, in_path),
|
||||
"%s:%s/%s" % (self.get_option("remote"), self.get_option("remote_addr"), in_path),
|
||||
out_path
|
||||
])
|
||||
|
||||
|
||||
31
plugins/doc_fragments/gitlab.py
Normal file
31
plugins/doc_fragments/gitlab.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard files documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
requirements:
|
||||
- requests (Python library U(https://pypi.org/project/requests/))
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab access token with API permissions.
|
||||
type: str
|
||||
api_oauth_token:
|
||||
description:
|
||||
- GitLab OAuth token for logging in.
|
||||
type: str
|
||||
version_added: 4.2.0
|
||||
api_job_token:
|
||||
description:
|
||||
- GitLab CI job token for logging in.
|
||||
type: str
|
||||
version_added: 4.2.0
|
||||
'''
|
||||
@@ -35,13 +35,23 @@ DOCUMENTATION = '''
|
||||
type: string
|
||||
required: true
|
||||
host_filter:
|
||||
description: An Icinga2 API valid host filter.
|
||||
description:
|
||||
- An Icinga2 API valid host filter. Leave blank for no filtering
|
||||
type: string
|
||||
required: false
|
||||
validate_certs:
|
||||
description: Enables or disables SSL certificate verification.
|
||||
type: boolean
|
||||
default: true
|
||||
inventory_attr:
|
||||
description:
|
||||
- Allows the override of the inventory name based on different attributes.
|
||||
- This allows for changing the way limits are used.
|
||||
- The current default, C(address), is sometimes not unique or present. We recommend to use C(name) instead.
|
||||
type: string
|
||||
default: address
|
||||
choices: ['name', 'display_name', 'address']
|
||||
version_added: 4.2.0
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -52,6 +62,7 @@ user: ansible
|
||||
password: secure
|
||||
host_filter: \"linux-servers\" in host.groups
|
||||
validate_certs: false
|
||||
inventory_attr: name
|
||||
'''
|
||||
|
||||
import json
|
||||
@@ -59,6 +70,7 @@ import json
|
||||
from ansible.errors import AnsibleParserError
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
@@ -76,6 +88,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
self.icinga2_password = None
|
||||
self.ssl_verify = None
|
||||
self.host_filter = None
|
||||
self.inventory_attr = None
|
||||
|
||||
self.cache_key = None
|
||||
self.use_cache = None
|
||||
@@ -114,9 +127,21 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
if data is not None:
|
||||
request_args['data'] = json.dumps(data)
|
||||
self.display.vvv("Request Args: %s" % request_args)
|
||||
response = open_url(request_url, **request_args)
|
||||
try:
|
||||
response = open_url(request_url, **request_args)
|
||||
except HTTPError as e:
|
||||
try:
|
||||
error_body = json.loads(e.read().decode())
|
||||
self.display.vvv("Error returned: {0}".format(error_body))
|
||||
except Exception:
|
||||
error_body = {"status": None}
|
||||
if e.code == 404 and error_body.get('status') == "No objects found.":
|
||||
raise AnsibleParserError("Host filter returned no data. Please confirm your host_filter value is valid")
|
||||
raise AnsibleParserError("Unexpected data returned: {0} -- {1}".format(e, error_body))
|
||||
|
||||
response_body = response.read()
|
||||
json_data = json.loads(response_body.decode('utf-8'))
|
||||
self.display.vvv("Returned Data: %s" % json.dumps(json_data, indent=4, sort_keys=True))
|
||||
if 200 <= response.status <= 299:
|
||||
return json_data
|
||||
if response.status == 404 and json_data['status'] == "No objects found.":
|
||||
@@ -155,7 +180,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
"""Query for all hosts """
|
||||
self.display.vvv("Querying Icinga2 for inventory")
|
||||
query_args = {
|
||||
"attrs": ["address", "state_type", "state", "groups"],
|
||||
"attrs": ["address", "display_name", "state_type", "state", "groups"],
|
||||
}
|
||||
if self.host_filter is not None:
|
||||
query_args['host_filter'] = self.host_filter
|
||||
@@ -177,24 +202,35 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
"""Convert Icinga2 API data to JSON format for Ansible"""
|
||||
groups_dict = {"_meta": {"hostvars": {}}}
|
||||
for entry in json_data:
|
||||
host_name = entry['name']
|
||||
host_attrs = entry['attrs']
|
||||
if self.inventory_attr == "name":
|
||||
host_name = entry.get('name')
|
||||
if self.inventory_attr == "address":
|
||||
# When looking for address for inventory, if missing fallback to object name
|
||||
if host_attrs.get('address', '') != '':
|
||||
host_name = host_attrs.get('address')
|
||||
else:
|
||||
host_name = entry.get('name')
|
||||
if self.inventory_attr == "display_name":
|
||||
host_name = host_attrs.get('display_name')
|
||||
if host_attrs['state'] == 0:
|
||||
host_attrs['state'] = 'on'
|
||||
else:
|
||||
host_attrs['state'] = 'off'
|
||||
host_groups = host_attrs['groups']
|
||||
host_addr = host_attrs['address']
|
||||
self.inventory.add_host(host_addr)
|
||||
host_groups = host_attrs.get('groups')
|
||||
self.inventory.add_host(host_name)
|
||||
for group in host_groups:
|
||||
if group not in self.inventory.groups.keys():
|
||||
self.inventory.add_group(group)
|
||||
self.inventory.add_child(group, host_addr)
|
||||
self.inventory.set_variable(host_addr, 'address', host_addr)
|
||||
self.inventory.set_variable(host_addr, 'hostname', host_name)
|
||||
self.inventory.set_variable(host_addr, 'state',
|
||||
self.inventory.add_child(group, host_name)
|
||||
# If the address attribute is populated, override ansible_host with the value
|
||||
if host_attrs.get('address') != '':
|
||||
self.inventory.set_variable(host_name, 'ansible_host', host_attrs.get('address'))
|
||||
self.inventory.set_variable(host_name, 'hostname', entry.get('name'))
|
||||
self.inventory.set_variable(host_name, 'display_name', host_attrs.get('display_name'))
|
||||
self.inventory.set_variable(host_name, 'state',
|
||||
host_attrs['state'])
|
||||
self.inventory.set_variable(host_addr, 'state_type',
|
||||
self.inventory.set_variable(host_name, 'state_type',
|
||||
host_attrs['state_type'])
|
||||
return groups_dict
|
||||
|
||||
@@ -211,6 +247,7 @@ class InventoryModule(BaseInventoryPlugin, Constructable):
|
||||
self.icinga2_password = self.get_option('password')
|
||||
self.ssl_verify = self.get_option('validate_certs')
|
||||
self.host_filter = self.get_option('host_filter')
|
||||
self.inventory_attr = self.get_option('inventory_attr')
|
||||
# Not currently enabled
|
||||
# self.cache_key = self.get_cache_key(path)
|
||||
# self.use_cache = cache and self.get_option('cache')
|
||||
|
||||
@@ -15,6 +15,7 @@ DOCUMENTATION = r'''
|
||||
author: "Frank Dornheim (@conloos)"
|
||||
requirements:
|
||||
- ipaddress
|
||||
- lxd >= 4.0
|
||||
options:
|
||||
plugin:
|
||||
description: Token that ensures this is a source file for the 'lxd' plugin.
|
||||
@@ -49,26 +50,38 @@ DOCUMENTATION = r'''
|
||||
- If I(trust_password) is set, this module send a request for authentication before sending any requests.
|
||||
type: str
|
||||
state:
|
||||
description: Filter the container according to the current status.
|
||||
description: Filter the instance according to the current status.
|
||||
type: str
|
||||
default: none
|
||||
choices: [ 'STOPPED', 'STARTING', 'RUNNING', 'none' ]
|
||||
prefered_container_network_interface:
|
||||
type_filter:
|
||||
description:
|
||||
- If a container has multiple network interfaces, select which one is the prefered as pattern.
|
||||
- Filter the instances by type C(virtual-machine), C(container) or C(both).
|
||||
- The first version of the inventory only supported containers.
|
||||
type: str
|
||||
default: container
|
||||
choices: [ 'virtual-machine', 'container', 'both' ]
|
||||
version_added: 4.2.0
|
||||
prefered_instance_network_interface:
|
||||
description:
|
||||
- If an instance has multiple network interfaces, select which one is the prefered as pattern.
|
||||
- Combined with the first number that can be found e.g. 'eth' + 0.
|
||||
- The option has been renamed from I(prefered_container_network_interface) to I(prefered_instance_network_interface) in community.general 3.8.0.
|
||||
The old name still works as an alias.
|
||||
type: str
|
||||
default: eth
|
||||
prefered_container_network_family:
|
||||
aliases:
|
||||
- prefered_container_network_interface
|
||||
prefered_instance_network_family:
|
||||
description:
|
||||
- If a container has multiple network interfaces, which one is the prefered by family.
|
||||
- If an instance has multiple network interfaces, which one is the prefered by family.
|
||||
- Specify C(inet) for IPv4 and C(inet6) for IPv6.
|
||||
type: str
|
||||
default: inet
|
||||
choices: [ 'inet', 'inet6' ]
|
||||
groupby:
|
||||
description:
|
||||
- Create groups by the following keywords C(location), C(pattern), C(network_range), C(os), C(release), C(profile), C(vlanid).
|
||||
- Create groups by the following keywords C(location), C(network_range), C(os), C(pattern), C(profile), C(release), C(type), C(vlanid).
|
||||
- See example for syntax.
|
||||
type: dict
|
||||
'''
|
||||
@@ -83,38 +96,49 @@ plugin: community.general.lxd
|
||||
url: unix:/var/snap/lxd/common/lxd/unix.socket
|
||||
state: RUNNING
|
||||
|
||||
# simple lxd.yml including virtual machines and containers
|
||||
plugin: community.general.lxd
|
||||
url: unix:/var/snap/lxd/common/lxd/unix.socket
|
||||
type_filter: both
|
||||
|
||||
# grouping lxd.yml
|
||||
groupby:
|
||||
testpattern:
|
||||
type: pattern
|
||||
attribute: test
|
||||
vlan666:
|
||||
type: vlanid
|
||||
attribute: 666
|
||||
locationBerlin:
|
||||
type: location
|
||||
attribute: Berlin
|
||||
osUbuntu:
|
||||
type: os
|
||||
attribute: ubuntu
|
||||
releaseFocal:
|
||||
type: release
|
||||
attribute: focal
|
||||
releaseBionic:
|
||||
type: release
|
||||
attribute: bionic
|
||||
profileDefault:
|
||||
type: profile
|
||||
attribute: default
|
||||
profileX11:
|
||||
type: profile
|
||||
attribute: x11
|
||||
netRangeIPv4:
|
||||
type: network_range
|
||||
attribute: 10.98.143.0/24
|
||||
netRangeIPv6:
|
||||
type: network_range
|
||||
attribute: fd42:bd00:7b11:2167:216:3eff::/24
|
||||
osUbuntu:
|
||||
type: os
|
||||
attribute: ubuntu
|
||||
testpattern:
|
||||
type: pattern
|
||||
attribute: test
|
||||
profileDefault:
|
||||
type: profile
|
||||
attribute: default
|
||||
profileX11:
|
||||
type: profile
|
||||
attribute: x11
|
||||
releaseFocal:
|
||||
type: release
|
||||
attribute: focal
|
||||
releaseBionic:
|
||||
type: release
|
||||
attribute: bionic
|
||||
typeVM:
|
||||
type: type
|
||||
attribute: virtual-machine
|
||||
typeContainer:
|
||||
type: type
|
||||
attribute: container
|
||||
vlan666:
|
||||
type: vlanid
|
||||
attribute: 666
|
||||
'''
|
||||
|
||||
import binascii
|
||||
@@ -283,10 +307,10 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
network_configs = self.socket.do('GET', '/1.0/networks')
|
||||
return [m.split('/')[3] for m in network_configs['metadata']]
|
||||
|
||||
def _get_containers(self):
|
||||
"""Get Containernames
|
||||
def _get_instances(self):
|
||||
"""Get instancenames
|
||||
|
||||
Returns all containernames
|
||||
Returns all instancenames
|
||||
|
||||
Args:
|
||||
None
|
||||
@@ -295,25 +319,27 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
list(names): names of all containers"""
|
||||
# e.g. {'type': 'sync',
|
||||
# 'status': 'Success',
|
||||
# 'status_code': 200,
|
||||
# 'operation': '',
|
||||
# 'error_code': 0,
|
||||
# 'error': '',
|
||||
# 'metadata': ['/1.0/containers/udemy-ansible-ubuntu-2004']}
|
||||
containers = self.socket.do('GET', '/1.0/containers')
|
||||
return [m.split('/')[3] for m in containers['metadata']]
|
||||
list(names): names of all instances"""
|
||||
# e.g. {
|
||||
# "metadata": [
|
||||
# "/1.0/instances/foo",
|
||||
# "/1.0/instances/bar"
|
||||
# ],
|
||||
# "status": "Success",
|
||||
# "status_code": 200,
|
||||
# "type": "sync"
|
||||
# }
|
||||
instances = self.socket.do('GET', '/1.0/instances')
|
||||
return [m.split('/')[3] for m in instances['metadata']]
|
||||
|
||||
def _get_config(self, branch, name):
|
||||
"""Get inventory of container
|
||||
"""Get inventory of instance
|
||||
|
||||
Get config of container
|
||||
Get config of instance
|
||||
|
||||
Args:
|
||||
str(branch): Name oft the API-Branch
|
||||
str(name): Name of Container
|
||||
str(name): Name of instance
|
||||
Kwargs:
|
||||
None
|
||||
Source:
|
||||
@@ -321,7 +347,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
dict(config): Config of the container"""
|
||||
dict(config): Config of the instance"""
|
||||
config = {}
|
||||
if isinstance(branch, (tuple, list)):
|
||||
config[name] = {branch[1]: self.socket.do('GET', '/1.0/{0}/{1}/{2}'.format(to_native(branch[0]), to_native(name), to_native(branch[1])))}
|
||||
@@ -329,13 +355,13 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
config[name] = {branch: self.socket.do('GET', '/1.0/{0}/{1}'.format(to_native(branch), to_native(name)))}
|
||||
return config
|
||||
|
||||
def get_container_data(self, names):
|
||||
"""Create Inventory of the container
|
||||
def get_instance_data(self, names):
|
||||
"""Create Inventory of the instance
|
||||
|
||||
Iterate through the different branches of the containers and collect Informations.
|
||||
Iterate through the different branches of the instances and collect Informations.
|
||||
|
||||
Args:
|
||||
list(names): List of container names
|
||||
list(names): List of instance names
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
@@ -344,20 +370,20 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
None"""
|
||||
# tuple(('instances','metadata/templates')) to get section in branch
|
||||
# e.g. /1.0/instances/<name>/metadata/templates
|
||||
branches = ['containers', ('instances', 'state')]
|
||||
container_config = {}
|
||||
branches = ['instances', ('instances', 'state')]
|
||||
instance_config = {}
|
||||
for branch in branches:
|
||||
for name in names:
|
||||
container_config['containers'] = self._get_config(branch, name)
|
||||
self.data = dict_merge(container_config, self.data)
|
||||
instance_config['instances'] = self._get_config(branch, name)
|
||||
self.data = dict_merge(instance_config, self.data)
|
||||
|
||||
def get_network_data(self, names):
|
||||
"""Create Inventory of the container
|
||||
"""Create Inventory of the instance
|
||||
|
||||
Iterate through the different branches of the containers and collect Informations.
|
||||
Iterate through the different branches of the instances and collect Informations.
|
||||
|
||||
Args:
|
||||
list(names): List of container names
|
||||
list(names): List of instance names
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
@@ -376,26 +402,26 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
network_config['networks'] = {name: None}
|
||||
self.data = dict_merge(network_config, self.data)
|
||||
|
||||
def extract_network_information_from_container_config(self, container_name):
|
||||
def extract_network_information_from_instance_config(self, instance_name):
|
||||
"""Returns the network interface configuration
|
||||
|
||||
Returns the network ipv4 and ipv6 config of the container without local-link
|
||||
Returns the network ipv4 and ipv6 config of the instance without local-link
|
||||
|
||||
Args:
|
||||
str(container_name): Name oft he container
|
||||
str(instance_name): Name oft he instance
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
dict(network_configuration): network config"""
|
||||
container_network_interfaces = self._get_data_entry('containers/{0}/state/metadata/network'.format(container_name))
|
||||
instance_network_interfaces = self._get_data_entry('instances/{0}/state/metadata/network'.format(instance_name))
|
||||
network_configuration = None
|
||||
if container_network_interfaces:
|
||||
if instance_network_interfaces:
|
||||
network_configuration = {}
|
||||
gen_interface_names = [interface_name for interface_name in container_network_interfaces if interface_name != 'lo']
|
||||
gen_interface_names = [interface_name for interface_name in instance_network_interfaces if interface_name != 'lo']
|
||||
for interface_name in gen_interface_names:
|
||||
gen_address = [address for address in container_network_interfaces[interface_name]['addresses'] if address.get('scope') != 'link']
|
||||
gen_address = [address for address in instance_network_interfaces[interface_name]['addresses'] if address.get('scope') != 'link']
|
||||
network_configuration[interface_name] = []
|
||||
for address in gen_address:
|
||||
address_set = {}
|
||||
@@ -406,24 +432,24 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
network_configuration[interface_name].append(address_set)
|
||||
return network_configuration
|
||||
|
||||
def get_prefered_container_network_interface(self, container_name):
|
||||
"""Helper to get the prefered interface of thr container
|
||||
def get_prefered_instance_network_interface(self, instance_name):
|
||||
"""Helper to get the prefered interface of thr instance
|
||||
|
||||
Helper to get the prefered interface provide by neme pattern from 'prefered_container_network_interface'.
|
||||
Helper to get the prefered interface provide by neme pattern from 'prefered_instance_network_interface'.
|
||||
|
||||
Args:
|
||||
str(containe_name): name of container
|
||||
str(containe_name): name of instance
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
str(prefered_interface): None or interface name"""
|
||||
container_network_interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
|
||||
instance_network_interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name))
|
||||
prefered_interface = None # init
|
||||
if container_network_interfaces: # container have network interfaces
|
||||
if instance_network_interfaces: # instance have network interfaces
|
||||
# generator if interfaces which start with the desired pattern
|
||||
net_generator = [interface for interface in container_network_interfaces if interface.startswith(self.prefered_container_network_interface)]
|
||||
net_generator = [interface for interface in instance_network_interfaces if interface.startswith(self.prefered_instance_network_interface)]
|
||||
selected_interfaces = [] # init
|
||||
for interface in net_generator:
|
||||
selected_interfaces.append(interface)
|
||||
@@ -431,13 +457,13 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
prefered_interface = sorted(selected_interfaces)[0]
|
||||
return prefered_interface
|
||||
|
||||
def get_container_vlans(self, container_name):
|
||||
"""Get VLAN(s) from container
|
||||
def get_instance_vlans(self, instance_name):
|
||||
"""Get VLAN(s) from instance
|
||||
|
||||
Helper to get the VLAN_ID from the container
|
||||
Helper to get the VLAN_ID from the instance
|
||||
|
||||
Args:
|
||||
str(containe_name): name of container
|
||||
str(containe_name): name of instance
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
@@ -450,13 +476,13 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network)):
|
||||
network_vlans[network] = self._get_data_entry('state/metadata/vlan/vid', data=self.data['networks'].get(network))
|
||||
|
||||
# get networkdevices of container and return
|
||||
# get networkdevices of instance and return
|
||||
# e.g.
|
||||
# "eth0":{ "name":"eth0",
|
||||
# "network":"lxdbr0",
|
||||
# "type":"nic"},
|
||||
vlan_ids = {}
|
||||
devices = self._get_data_entry('containers/{0}/containers/metadata/expanded_devices'.format(to_native(container_name)))
|
||||
devices = self._get_data_entry('instances/{0}/instances/metadata/expanded_devices'.format(to_native(instance_name)))
|
||||
for device in devices:
|
||||
if 'network' in devices[device]:
|
||||
if devices[device]['network'] in network_vlans:
|
||||
@@ -492,14 +518,14 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def _set_data_entry(self, container_name, key, value, path=None):
|
||||
def _set_data_entry(self, instance_name, key, value, path=None):
|
||||
"""Helper to save data
|
||||
|
||||
Helper to save the data in self.data
|
||||
Detect if data is allready in branch and use dict_merge() to prevent that branch is overwritten.
|
||||
|
||||
Args:
|
||||
str(container_name): name of container
|
||||
str(instance_name): name of instance
|
||||
str(key): same as dict
|
||||
*(value): same as dict
|
||||
Kwargs:
|
||||
@@ -510,24 +536,24 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
None"""
|
||||
if not path:
|
||||
path = self.data['inventory']
|
||||
if container_name not in path:
|
||||
path[container_name] = {}
|
||||
if instance_name not in path:
|
||||
path[instance_name] = {}
|
||||
|
||||
try:
|
||||
if isinstance(value, dict) and key in path[container_name]:
|
||||
path[container_name] = dict_merge(value, path[container_name][key])
|
||||
if isinstance(value, dict) and key in path[instance_name]:
|
||||
path[instance_name] = dict_merge(value, path[instance_name][key])
|
||||
else:
|
||||
path[container_name][key] = value
|
||||
path[instance_name][key] = value
|
||||
except KeyError as err:
|
||||
raise AnsibleParserError("Unable to store Informations: {0}".format(to_native(err)))
|
||||
|
||||
def extract_information_from_container_configs(self):
|
||||
def extract_information_from_instance_configs(self):
|
||||
"""Process configuration information
|
||||
|
||||
Preparation of the data
|
||||
|
||||
Args:
|
||||
dict(configs): Container configurations
|
||||
dict(configs): instance configurations
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
@@ -538,33 +564,35 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if 'inventory' not in self.data:
|
||||
self.data['inventory'] = {}
|
||||
|
||||
for container_name in self.data['containers']:
|
||||
self._set_data_entry(container_name, 'os', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/config/image.os'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'release', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/config/image.release'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'version', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/config/image.version'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'profile', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/profiles'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'location', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/location'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'state', self._get_data_entry(
|
||||
'containers/{0}/containers/metadata/config/volatile.last_state.power'.format(container_name)))
|
||||
self._set_data_entry(container_name, 'network_interfaces', self.extract_network_information_from_container_config(container_name))
|
||||
self._set_data_entry(container_name, 'preferred_interface', self.get_prefered_container_network_interface(container_name))
|
||||
self._set_data_entry(container_name, 'vlan_ids', self.get_container_vlans(container_name))
|
||||
for instance_name in self.data['instances']:
|
||||
self._set_data_entry(instance_name, 'os', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/config/image.os'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'release', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/config/image.release'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'version', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/config/image.version'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'profile', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/profiles'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'location', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/location'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'state', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/config/volatile.last_state.power'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'type', self._get_data_entry(
|
||||
'instances/{0}/instances/metadata/type'.format(instance_name)))
|
||||
self._set_data_entry(instance_name, 'network_interfaces', self.extract_network_information_from_instance_config(instance_name))
|
||||
self._set_data_entry(instance_name, 'preferred_interface', self.get_prefered_instance_network_interface(instance_name))
|
||||
self._set_data_entry(instance_name, 'vlan_ids', self.get_instance_vlans(instance_name))
|
||||
|
||||
def build_inventory_network(self, container_name):
|
||||
"""Add the network interfaces of the container to the inventory
|
||||
def build_inventory_network(self, instance_name):
|
||||
"""Add the network interfaces of the instance to the inventory
|
||||
|
||||
Logic:
|
||||
- if the container have no interface -> 'ansible_connection: local'
|
||||
- get preferred_interface & prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
||||
- first Interface from: network_interfaces prefered_container_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
||||
- if the instance have no interface -> 'ansible_connection: local'
|
||||
- get preferred_interface & prefered_instance_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
||||
- first Interface from: network_interfaces prefered_instance_network_family -> 'ansible_connection: ssh' & 'ansible_host: <IP>'
|
||||
|
||||
Args:
|
||||
str(container_name): name of container
|
||||
str(instance_name): name of instance
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
@@ -572,45 +600,45 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
Returns:
|
||||
None"""
|
||||
|
||||
def interface_selection(container_name):
|
||||
"""Select container Interface for inventory
|
||||
def interface_selection(instance_name):
|
||||
"""Select instance Interface for inventory
|
||||
|
||||
Logic:
|
||||
- get preferred_interface & prefered_container_network_family -> str(IP)
|
||||
- first Interface from: network_interfaces prefered_container_network_family -> str(IP)
|
||||
- get preferred_interface & prefered_instance_network_family -> str(IP)
|
||||
- first Interface from: network_interfaces prefered_instance_network_family -> str(IP)
|
||||
|
||||
Args:
|
||||
str(container_name): name of container
|
||||
str(instance_name): name of instance
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
dict(interface_name: ip)"""
|
||||
prefered_interface = self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)) # name or None
|
||||
prefered_container_network_family = self.prefered_container_network_family
|
||||
prefered_interface = self._get_data_entry('inventory/{0}/preferred_interface'.format(instance_name)) # name or None
|
||||
prefered_instance_network_family = self.prefered_instance_network_family
|
||||
|
||||
ip_address = ''
|
||||
if prefered_interface:
|
||||
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(container_name, prefered_interface))
|
||||
interface = self._get_data_entry('inventory/{0}/network_interfaces/{1}'.format(instance_name, prefered_interface))
|
||||
for config in interface:
|
||||
if config['family'] == prefered_container_network_family:
|
||||
if config['family'] == prefered_instance_network_family:
|
||||
ip_address = config['address']
|
||||
break
|
||||
else:
|
||||
interface = self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name))
|
||||
for config in interface:
|
||||
if config['family'] == prefered_container_network_family:
|
||||
ip_address = config['address']
|
||||
break
|
||||
interfaces = self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name))
|
||||
for interface in interfaces.values():
|
||||
for config in interface:
|
||||
if config['family'] == prefered_instance_network_family:
|
||||
ip_address = config['address']
|
||||
break
|
||||
return ip_address
|
||||
|
||||
if self._get_data_entry('inventory/{0}/network_interfaces'.format(container_name)): # container have network interfaces
|
||||
if self._get_data_entry('inventory/{0}/preferred_interface'.format(container_name)): # container have a preferred interface
|
||||
self.inventory.set_variable(container_name, 'ansible_connection', 'ssh')
|
||||
self.inventory.set_variable(container_name, 'ansible_host', interface_selection(container_name))
|
||||
if self._get_data_entry('inventory/{0}/network_interfaces'.format(instance_name)): # instance have network interfaces
|
||||
self.inventory.set_variable(instance_name, 'ansible_connection', 'ssh')
|
||||
self.inventory.set_variable(instance_name, 'ansible_host', interface_selection(instance_name))
|
||||
else:
|
||||
self.inventory.set_variable(container_name, 'ansible_connection', 'local')
|
||||
self.inventory.set_variable(instance_name, 'ansible_connection', 'local')
|
||||
|
||||
def build_inventory_hosts(self):
|
||||
"""Build host-part dynamic inventory
|
||||
@@ -626,29 +654,33 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
None
|
||||
Returns:
|
||||
None"""
|
||||
for container_name in self.data['inventory']:
|
||||
# Only consider containers that match the "state" filter, if self.state is not None
|
||||
for instance_name in self.data['inventory']:
|
||||
instance_state = str(self._get_data_entry('inventory/{0}/state'.format(instance_name)) or "STOPPED").lower()
|
||||
|
||||
# Only consider instances that match the "state" filter, if self.state is not None
|
||||
if self.filter:
|
||||
if self.filter.lower() != self._get_data_entry('inventory/{0}/state'.format(container_name)).lower():
|
||||
if self.filter.lower() != instance_state:
|
||||
continue
|
||||
# add container
|
||||
self.inventory.add_host(container_name)
|
||||
# add instance
|
||||
self.inventory.add_host(instance_name)
|
||||
# add network informations
|
||||
self.build_inventory_network(container_name)
|
||||
self.build_inventory_network(instance_name)
|
||||
# add os
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(container_name)).lower())
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_os', self._get_data_entry('inventory/{0}/os'.format(instance_name)).lower())
|
||||
# add release
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(container_name)).lower())
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_release', self._get_data_entry('inventory/{0}/release'.format(instance_name)).lower())
|
||||
# add profile
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(container_name)))
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_profile', self._get_data_entry('inventory/{0}/profile'.format(instance_name)))
|
||||
# add state
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_state', self._get_data_entry('inventory/{0}/state'.format(container_name)).lower())
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_state', instance_state)
|
||||
# add type
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_type', self._get_data_entry('inventory/{0}/type'.format(instance_name)))
|
||||
# add location information
|
||||
if self._get_data_entry('inventory/{0}/location'.format(container_name)) != "none": # wrong type by lxd 'none' != 'None'
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(container_name)))
|
||||
if self._get_data_entry('inventory/{0}/location'.format(instance_name)) != "none": # wrong type by lxd 'none' != 'None'
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_location', self._get_data_entry('inventory/{0}/location'.format(instance_name)))
|
||||
# add VLAN_ID information
|
||||
if self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)):
|
||||
self.inventory.set_variable(container_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(container_name)))
|
||||
if self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)):
|
||||
self.inventory.set_variable(instance_name, 'ansible_lxd_vlan_ids', self._get_data_entry('inventory/{0}/vlan_ids'.format(instance_name)))
|
||||
|
||||
def build_inventory_groups_location(self, group_name):
|
||||
"""create group by attribute: location
|
||||
@@ -665,9 +697,9 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
for container_name in self.inventory.hosts:
|
||||
if 'ansible_lxd_location' in self.inventory.get_host(container_name).get_vars():
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
for instance_name in self.inventory.hosts:
|
||||
if 'ansible_lxd_location' in self.inventory.get_host(instance_name).get_vars():
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_pattern(self, group_name):
|
||||
"""create group by name pattern
|
||||
@@ -686,10 +718,10 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
|
||||
regex_pattern = self.groupby[group_name].get('attribute')
|
||||
|
||||
for container_name in self.inventory.hosts:
|
||||
result = re.search(regex_pattern, container_name)
|
||||
for instance_name in self.inventory.hosts:
|
||||
result = re.search(regex_pattern, instance_name)
|
||||
if result:
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_network_range(self, group_name):
|
||||
"""check if IP is in network-class
|
||||
@@ -712,14 +744,14 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
raise AnsibleParserError(
|
||||
'Error while parsing network range {0}: {1}'.format(self.groupby[group_name].get('attribute'), to_native(err)))
|
||||
|
||||
for container_name in self.inventory.hosts:
|
||||
if self.data['inventory'][container_name].get('network_interfaces') is not None:
|
||||
for interface in self.data['inventory'][container_name].get('network_interfaces'):
|
||||
for interface_family in self.data['inventory'][container_name].get('network_interfaces')[interface]:
|
||||
for instance_name in self.inventory.hosts:
|
||||
if self.data['inventory'][instance_name].get('network_interfaces') is not None:
|
||||
for interface in self.data['inventory'][instance_name].get('network_interfaces'):
|
||||
for interface_family in self.data['inventory'][instance_name].get('network_interfaces')[interface]:
|
||||
try:
|
||||
address = ipaddress.ip_address(to_text(interface_family['address']))
|
||||
if address.version == network.version and address in network:
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
except ValueError:
|
||||
# Ignore invalid IP addresses returned by lxd
|
||||
pass
|
||||
@@ -730,7 +762,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
Args:
|
||||
str(group_name): Group name
|
||||
Kwargs:
|
||||
Noneself.data['inventory'][container_name][interface]
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
@@ -739,12 +771,12 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
gen_containers = [
|
||||
container_name for container_name in self.inventory.hosts
|
||||
if 'ansible_lxd_os' in self.inventory.get_host(container_name).get_vars()]
|
||||
for container_name in gen_containers:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_os'):
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
gen_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts
|
||||
if 'ansible_lxd_os' in self.inventory.get_host(instance_name).get_vars()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_os'):
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_release(self, group_name):
|
||||
"""create group by attribute: release
|
||||
@@ -761,12 +793,12 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
gen_containers = [
|
||||
container_name for container_name in self.inventory.hosts
|
||||
if 'ansible_lxd_release' in self.inventory.get_host(container_name).get_vars()]
|
||||
for container_name in gen_containers:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(container_name).get_vars().get('ansible_lxd_release'):
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
gen_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts
|
||||
if 'ansible_lxd_release' in self.inventory.get_host(instance_name).get_vars()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_release'):
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_profile(self, group_name):
|
||||
"""create group by attribute: profile
|
||||
@@ -783,12 +815,12 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
gen_containers = [
|
||||
container_name for container_name in self.inventory.hosts.keys()
|
||||
if 'ansible_lxd_profile' in self.inventory.get_host(container_name).get_vars().keys()]
|
||||
for container_name in gen_containers:
|
||||
if self.groupby[group_name].get('attribute').lower() in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_profile'):
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
gen_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts.keys()
|
||||
if 'ansible_lxd_profile' in self.inventory.get_host(instance_name).get_vars().keys()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute').lower() in self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_profile'):
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_vlanid(self, group_name):
|
||||
"""create group by attribute: vlanid
|
||||
@@ -805,12 +837,34 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
gen_containers = [
|
||||
container_name for container_name in self.inventory.hosts.keys()
|
||||
if 'ansible_lxd_vlan_ids' in self.inventory.get_host(container_name).get_vars().keys()]
|
||||
for container_name in gen_containers:
|
||||
if self.groupby[group_name].get('attribute') in self.inventory.get_host(container_name).get_vars().get('ansible_lxd_vlan_ids').values():
|
||||
self.inventory.add_child(group_name, container_name)
|
||||
gen_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts.keys()
|
||||
if 'ansible_lxd_vlan_ids' in self.inventory.get_host(instance_name).get_vars().keys()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute') in self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_vlan_ids').values():
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups_type(self, group_name):
|
||||
"""create group by attribute: type
|
||||
|
||||
Args:
|
||||
str(group_name): Group name
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
None"""
|
||||
# maybe we just want to expand one group
|
||||
if group_name not in self.inventory.groups:
|
||||
self.inventory.add_group(group_name)
|
||||
|
||||
gen_instances = [
|
||||
instance_name for instance_name in self.inventory.hosts
|
||||
if 'ansible_lxd_type' in self.inventory.get_host(instance_name).get_vars()]
|
||||
for instance_name in gen_instances:
|
||||
if self.groupby[group_name].get('attribute').lower() == self.inventory.get_host(instance_name).get_vars().get('ansible_lxd_type'):
|
||||
self.inventory.add_child(group_name, instance_name)
|
||||
|
||||
def build_inventory_groups(self):
|
||||
"""Build group-part dynamic inventory
|
||||
@@ -839,6 +893,7 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
* 'release'
|
||||
* 'profile'
|
||||
* 'vlanid'
|
||||
* 'type'
|
||||
|
||||
Args:
|
||||
str(group_name): Group name
|
||||
@@ -864,6 +919,8 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
self.build_inventory_groups_profile(group_name)
|
||||
elif self.groupby[group_name].get('type') == 'vlanid':
|
||||
self.build_inventory_groups_vlanid(group_name)
|
||||
elif self.groupby[group_name].get('type') == 'type':
|
||||
self.build_inventory_groups_type(group_name)
|
||||
else:
|
||||
raise AnsibleParserError('Unknown group type: {0}'.format(to_native(group_name)))
|
||||
|
||||
@@ -890,10 +947,30 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
self.build_inventory_hosts()
|
||||
self.build_inventory_groups()
|
||||
|
||||
def cleandata(self):
|
||||
"""Clean the dynamic inventory
|
||||
|
||||
The first version of the inventory only supported container.
|
||||
This will change in the future.
|
||||
The following function cleans up the data and remove the all items with the wrong type.
|
||||
|
||||
Args:
|
||||
None
|
||||
Kwargs:
|
||||
None
|
||||
Raises:
|
||||
None
|
||||
Returns:
|
||||
None"""
|
||||
iter_keys = list(self.data['instances'].keys())
|
||||
for instance_name in iter_keys:
|
||||
if self._get_data_entry('instances/{0}/instances/metadata/type'.format(instance_name)) != self.type_filter:
|
||||
del self.data['instances'][instance_name]
|
||||
|
||||
def _populate(self):
|
||||
"""Return the hosts and groups
|
||||
|
||||
Returns the processed container configurations from the lxd import
|
||||
Returns the processed instance configurations from the lxd import
|
||||
|
||||
Args:
|
||||
None
|
||||
@@ -906,10 +983,16 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
|
||||
if len(self.data) == 0: # If no data is injected by unittests open socket
|
||||
self.socket = self._connect_to_socket()
|
||||
self.get_container_data(self._get_containers())
|
||||
self.get_instance_data(self._get_instances())
|
||||
self.get_network_data(self._get_networks())
|
||||
|
||||
self.extract_information_from_container_configs()
|
||||
# The first version of the inventory only supported containers.
|
||||
# This will change in the future.
|
||||
# The following function cleans up the data.
|
||||
if self.type_filter != 'both':
|
||||
self.cleandata()
|
||||
|
||||
self.extract_information_from_instance_configs()
|
||||
|
||||
# self.display.vvv(self.save_json_data([os.path.abspath(__file__)]))
|
||||
|
||||
@@ -948,8 +1031,9 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
self.data = {} # store for inventory-data
|
||||
self.groupby = self.get_option('groupby')
|
||||
self.plugin = self.get_option('plugin')
|
||||
self.prefered_container_network_family = self.get_option('prefered_container_network_family')
|
||||
self.prefered_container_network_interface = self.get_option('prefered_container_network_interface')
|
||||
self.prefered_instance_network_family = self.get_option('prefered_instance_network_family')
|
||||
self.prefered_instance_network_interface = self.get_option('prefered_instance_network_interface')
|
||||
self.type_filter = self.get_option('type_filter')
|
||||
if self.get_option('state').lower() == 'none': # none in config is str()
|
||||
self.filter = None
|
||||
else:
|
||||
|
||||
@@ -8,7 +8,7 @@ __metaclass__ = type
|
||||
DOCUMENTATION = r'''
|
||||
name: online
|
||||
author:
|
||||
- Remy Leone (@sieben)
|
||||
- Remy Leone (@remyleone)
|
||||
short_description: Scaleway (previously Online SAS or Online.net) inventory source
|
||||
description:
|
||||
- Get inventory hosts from Scaleway (previously Online SAS or Online.net).
|
||||
|
||||
@@ -9,7 +9,7 @@ __metaclass__ = type
|
||||
DOCUMENTATION = r'''
|
||||
name: scaleway
|
||||
author:
|
||||
- Remy Leone (@sieben)
|
||||
- Remy Leone (@remyleone)
|
||||
short_description: Scaleway inventory source
|
||||
description:
|
||||
- Get inventory hosts from Scaleway.
|
||||
|
||||
@@ -93,7 +93,7 @@ DOCUMENTATION = '''
|
||||
environment variable and keep I(endpoints), I(host), and I(port) unused.
|
||||
seealso:
|
||||
- module: community.general.etcd3
|
||||
- ref: etcd_lookup
|
||||
- ref: ansible_collections.community.general.etcd_lookup
|
||||
description: The etcd v2 lookup.
|
||||
|
||||
requirements:
|
||||
|
||||
@@ -7,29 +7,40 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
from distutils.version import StrictVersion
|
||||
|
||||
from ansible.module_utils.basic import missing_required_lib
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
try:
|
||||
from urllib import quote_plus # Python 2.X
|
||||
from urlparse import urljoin
|
||||
except ImportError:
|
||||
from urllib.parse import quote_plus # Python 3+
|
||||
from urllib.parse import quote_plus, urljoin # Python 3+
|
||||
|
||||
import traceback
|
||||
|
||||
GITLAB_IMP_ERR = None
|
||||
try:
|
||||
import gitlab
|
||||
import requests
|
||||
HAS_GITLAB_PACKAGE = True
|
||||
except Exception:
|
||||
GITLAB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
|
||||
def auth_argument_spec(spec=None):
|
||||
arg_spec = (dict(
|
||||
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),
|
||||
))
|
||||
if spec:
|
||||
arg_spec.update(spec)
|
||||
return arg_spec
|
||||
|
||||
|
||||
def find_project(gitlab_instance, identifier):
|
||||
try:
|
||||
project = gitlab_instance.projects.get(identifier)
|
||||
@@ -58,6 +69,8 @@ def gitlab_authentication(module):
|
||||
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']
|
||||
|
||||
if not HAS_GITLAB_PACKAGE:
|
||||
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
|
||||
@@ -70,7 +83,16 @@ def gitlab_authentication(module):
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
|
||||
private_token=gitlab_token, api_version=4)
|
||||
else:
|
||||
gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token, api_version=4)
|
||||
# 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_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,
|
||||
oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
|
||||
|
||||
gitlab_instance.auth()
|
||||
except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:
|
||||
|
||||
232
plugins/module_utils/ilo_redfish_utils.py
Normal file
232
plugins/module_utils/ilo_redfish_utils.py
Normal file
@@ -0,0 +1,232 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.redfish_utils import RedfishUtils
|
||||
|
||||
|
||||
class iLORedfishUtils(RedfishUtils):
|
||||
|
||||
def get_ilo_sessions(self):
|
||||
result = {}
|
||||
# listing all users has always been slower than other operations, why?
|
||||
session_list = []
|
||||
sessions_results = []
|
||||
# Get these entries, but does not fail if not found
|
||||
properties = ['Description', 'Id', 'Name', 'UserName']
|
||||
|
||||
# Changed self.sessions_uri to Hardcoded string.
|
||||
response = self.get_request(
|
||||
self.root_uri + self.service_root + "SessionService/Sessions/")
|
||||
if not response['ret']:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
|
||||
if 'Oem' in data:
|
||||
if data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]:
|
||||
current_session = data["Oem"]["Hpe"]["Links"]["MySession"]["@odata.id"]
|
||||
|
||||
for sessions in data[u'Members']:
|
||||
# session_list[] are URIs
|
||||
session_list.append(sessions[u'@odata.id'])
|
||||
# for each session, get details
|
||||
for uri in session_list:
|
||||
session = {}
|
||||
if uri != current_session:
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
data = response['data']
|
||||
for property in properties:
|
||||
if property in data:
|
||||
session[property] = data[property]
|
||||
sessions_results.append(session)
|
||||
result["msg"] = sessions_results
|
||||
result["ret"] = True
|
||||
return result
|
||||
|
||||
def set_ntp_server(self, mgr_attributes):
|
||||
result = {}
|
||||
setkey = mgr_attributes['mgr_attr_name']
|
||||
|
||||
nic_info = self.get_manager_ethernet_uri()
|
||||
ethuri = nic_info["nic_addr"]
|
||||
|
||||
response = self.get_request(self.root_uri + ethuri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
payload = {"DHCPv4": {
|
||||
"UseNTPServers": ""
|
||||
}}
|
||||
|
||||
if data["DHCPv4"]["UseNTPServers"]:
|
||||
payload["DHCPv4"]["UseNTPServers"] = False
|
||||
res_dhv4 = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not res_dhv4['ret']:
|
||||
return res_dhv4
|
||||
|
||||
payload = {"DHCPv6": {
|
||||
"UseNTPServers": ""
|
||||
}}
|
||||
|
||||
if data["DHCPv6"]["UseNTPServers"]:
|
||||
payload["DHCPv6"]["UseNTPServers"] = False
|
||||
res_dhv6 = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not res_dhv6['ret']:
|
||||
return res_dhv6
|
||||
|
||||
datetime_uri = self.manager_uri + "DateTime"
|
||||
|
||||
response = self.get_request(self.root_uri + datetime_uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
data = response['data']
|
||||
|
||||
ntp_list = data[setkey]
|
||||
if(len(ntp_list) == 2):
|
||||
ntp_list.pop(0)
|
||||
|
||||
ntp_list.append(mgr_attributes['mgr_attr_value'])
|
||||
|
||||
payload = {setkey: ntp_list}
|
||||
|
||||
response1 = self.patch_request(self.root_uri + datetime_uri, payload)
|
||||
if not response1['ret']:
|
||||
return response1
|
||||
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgr_attributes['mgr_attr_name']}
|
||||
|
||||
def set_time_zone(self, attr):
|
||||
key = attr['mgr_attr_name']
|
||||
|
||||
uri = self.manager_uri + "DateTime/"
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
data = response["data"]
|
||||
|
||||
if key not in data:
|
||||
return {'ret': False, 'changed': False, 'msg': "Key %s not found" % key}
|
||||
|
||||
timezones = data["TimeZoneList"]
|
||||
index = ""
|
||||
for tz in timezones:
|
||||
if attr['mgr_attr_value'] in tz["Name"]:
|
||||
index = tz["Index"]
|
||||
break
|
||||
|
||||
payload = {key: {"Index": index}}
|
||||
response = self.patch_request(self.root_uri + uri, payload)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
|
||||
|
||||
def set_dns_server(self, attr):
|
||||
key = attr['mgr_attr_name']
|
||||
nic_info = self.get_manager_ethernet_uri()
|
||||
uri = nic_info["nic_addr"]
|
||||
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
data = response['data']
|
||||
|
||||
dns_list = data["Oem"]["Hpe"]["IPv4"][key]
|
||||
|
||||
if len(dns_list) == 3:
|
||||
dns_list.pop(0)
|
||||
|
||||
dns_list.append(attr['mgr_attr_value'])
|
||||
|
||||
payload = {
|
||||
"Oem": {
|
||||
"Hpe": {
|
||||
"IPv4": {
|
||||
key: dns_list
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = self.patch_request(self.root_uri + uri, payload)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
|
||||
|
||||
def set_domain_name(self, attr):
|
||||
key = attr['mgr_attr_name']
|
||||
|
||||
nic_info = self.get_manager_ethernet_uri()
|
||||
ethuri = nic_info["nic_addr"]
|
||||
|
||||
response = self.get_request(self.root_uri + ethuri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
|
||||
data = response['data']
|
||||
|
||||
payload = {"DHCPv4": {
|
||||
"UseDomainName": ""
|
||||
}}
|
||||
|
||||
if data["DHCPv4"]["UseDomainName"]:
|
||||
payload["DHCPv4"]["UseDomainName"] = False
|
||||
res_dhv4 = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not res_dhv4['ret']:
|
||||
return res_dhv4
|
||||
|
||||
payload = {"DHCPv6": {
|
||||
"UseDomainName": ""
|
||||
}}
|
||||
|
||||
if data["DHCPv6"]["UseDomainName"]:
|
||||
payload["DHCPv6"]["UseDomainName"] = False
|
||||
res_dhv6 = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not res_dhv6['ret']:
|
||||
return res_dhv6
|
||||
|
||||
domain_name = attr['mgr_attr_value']
|
||||
|
||||
payload = {"Oem": {
|
||||
"Hpe": {
|
||||
key: domain_name
|
||||
}
|
||||
}}
|
||||
|
||||
response = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not response['ret']:
|
||||
return response
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % attr['mgr_attr_name']}
|
||||
|
||||
def set_wins_registration(self, mgrattr):
|
||||
Key = mgrattr['mgr_attr_name']
|
||||
|
||||
nic_info = self.get_manager_ethernet_uri()
|
||||
ethuri = nic_info["nic_addr"]
|
||||
|
||||
payload = {
|
||||
"Oem": {
|
||||
"Hpe": {
|
||||
"IPv4": {
|
||||
Key: False
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = self.patch_request(self.root_uri + ethuri, payload)
|
||||
if not response['ret']:
|
||||
return response
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified %s" % mgrattr['mgr_attr_name']}
|
||||
@@ -52,3 +52,36 @@ def module_fails_on_exception(func):
|
||||
self.module.fail_json(msg=msg, exception=traceback.format_exc(),
|
||||
output=self.output, vars=self.vars.output(), **self.output)
|
||||
return wrapper
|
||||
|
||||
|
||||
def check_mode_skip(func):
|
||||
@wraps(func)
|
||||
def wrapper(self, *args, **kwargs):
|
||||
if not self.module.check_mode:
|
||||
return func(self, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def check_mode_skip_returns(callable=None, value=None):
|
||||
|
||||
def deco(func):
|
||||
if callable is not None:
|
||||
@wraps(func)
|
||||
def wrapper_callable(self, *args, **kwargs):
|
||||
if self.module.check_mode:
|
||||
return callable(self, *args, **kwargs)
|
||||
return func(self, *args, **kwargs)
|
||||
return wrapper_callable
|
||||
|
||||
if value is not None:
|
||||
@wraps(func)
|
||||
def wrapper_value(self, *args, **kwargs):
|
||||
if self.module.check_mode:
|
||||
return value
|
||||
return func(self, *args, **kwargs)
|
||||
return wrapper_value
|
||||
|
||||
if callable is None and value is None:
|
||||
return check_mode_skip
|
||||
|
||||
return deco
|
||||
|
||||
61
plugins/module_utils/mh/mixins/deprecate_attrs.py
Normal file
61
plugins/module_utils/mh/mixins/deprecate_attrs.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2020, Alexei Znamensky <russoz@gmail.com>
|
||||
# Copyright: (c) 2020, Ansible Project
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
class DeprecateAttrsMixin(object):
|
||||
|
||||
def _deprecate_setup(self, attr, target, module):
|
||||
if target is None:
|
||||
target = self
|
||||
if not hasattr(target, attr):
|
||||
raise ValueError("Target {0} has no attribute {1}".format(target, attr))
|
||||
if module is None:
|
||||
if isinstance(target, AnsibleModule):
|
||||
module = target
|
||||
elif hasattr(target, "module") and isinstance(target.module, AnsibleModule):
|
||||
module = target.module
|
||||
else:
|
||||
raise ValueError("Failed to automatically discover the AnsibleModule instance. Pass 'module' parameter explicitly.")
|
||||
|
||||
# setup internal state dicts
|
||||
value_attr = "__deprecated_attr_value"
|
||||
trigger_attr = "__deprecated_attr_trigger"
|
||||
if not hasattr(target, value_attr):
|
||||
setattr(target, value_attr, {})
|
||||
if not hasattr(target, trigger_attr):
|
||||
setattr(target, trigger_attr, {})
|
||||
value_dict = getattr(target, value_attr)
|
||||
trigger_dict = getattr(target, trigger_attr)
|
||||
return target, module, value_dict, trigger_dict
|
||||
|
||||
def _deprecate_attr(self, attr, msg, version=None, date=None, collection_name=None, target=None, value=None, module=None):
|
||||
target, module, value_dict, trigger_dict = self._deprecate_setup(attr, target, module)
|
||||
|
||||
value_dict[attr] = getattr(target, attr, value)
|
||||
trigger_dict[attr] = False
|
||||
|
||||
def _trigger():
|
||||
if not trigger_dict[attr]:
|
||||
module.deprecate(msg, version=version, date=date, collection_name=collection_name)
|
||||
trigger_dict[attr] = True
|
||||
|
||||
def _getter(_self):
|
||||
_trigger()
|
||||
return value_dict[attr]
|
||||
|
||||
def _setter(_self, new_value):
|
||||
_trigger()
|
||||
value_dict[attr] = new_value
|
||||
|
||||
# override attribute
|
||||
prop = property(_getter)
|
||||
setattr(target, attr, prop)
|
||||
setattr(target, "_{0}_setter".format(attr), prop.setter(_setter))
|
||||
@@ -13,9 +13,10 @@ from ansible_collections.community.general.plugins.module_utils.mh.mixins.cmd im
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.mixins.state import StateMixin
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deps import DependencyMixin
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.mixins.vars import VarsMixin, VarDict as _VD
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin
|
||||
|
||||
|
||||
class ModuleHelper(VarsMixin, DependencyMixin, ModuleHelperBase):
|
||||
class ModuleHelper(DeprecateAttrsMixin, VarsMixin, DependencyMixin, ModuleHelperBase):
|
||||
_output_conflict_list = ('msg', 'exception', 'output', 'vars', 'changed')
|
||||
facts_name = None
|
||||
output_params = ()
|
||||
@@ -36,6 +37,15 @@ class ModuleHelper(VarsMixin, DependencyMixin, ModuleHelperBase):
|
||||
fact=name in self.facts_params,
|
||||
)
|
||||
|
||||
self._deprecate_attr(
|
||||
attr="VarDict",
|
||||
msg="ModuleHelper.VarDict attribute is deprecated, use VarDict from "
|
||||
"the ansible_collections.community.general.plugins.module_utils.mh.mixins.vars module instead",
|
||||
version="6.0.0",
|
||||
collection_name="community.general",
|
||||
target=ModuleHelper,
|
||||
module=self.module)
|
||||
|
||||
def update_output(self, **kwargs):
|
||||
self.update_vars(meta={"output": True}, **kwargs)
|
||||
|
||||
|
||||
@@ -54,6 +54,17 @@ def proxmox_to_ansible_bool(value):
|
||||
return True if value == 1 else False
|
||||
|
||||
|
||||
def ansible_to_proxmox_bool(value):
|
||||
'''Convert Ansible representation of a boolean to be proxmox-friendly'''
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
if not isinstance(value, bool):
|
||||
raise ValueError("%s must be of type bool not %s" % (value, type(value)))
|
||||
|
||||
return 1 if value else 0
|
||||
|
||||
|
||||
class ProxmoxAnsible(object):
|
||||
"""Base class for Proxmox modules"""
|
||||
def __init__(self, module):
|
||||
|
||||
@@ -1834,12 +1834,16 @@ class RedfishUtils(object):
|
||||
result['ret'] = True
|
||||
data = response['data']
|
||||
|
||||
for device in data[u'Fans']:
|
||||
fan = {}
|
||||
for property in properties:
|
||||
if property in device:
|
||||
fan[property] = device[property]
|
||||
fan_results.append(fan)
|
||||
# Checking if fans are present
|
||||
if u'Fans' in data:
|
||||
for device in data[u'Fans']:
|
||||
fan = {}
|
||||
for property in properties:
|
||||
if property in device:
|
||||
fan[property] = device[property]
|
||||
fan_results.append(fan)
|
||||
else:
|
||||
return {'ret': False, 'msg': "No Fans present"}
|
||||
result["entries"] = fan_results
|
||||
return result
|
||||
|
||||
@@ -2701,39 +2705,14 @@ class RedfishUtils(object):
|
||||
return self.aggregate_managers(self.get_manager_health_report)
|
||||
|
||||
def set_manager_nic(self, nic_addr, nic_config):
|
||||
# Get EthernetInterface collection
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'EthernetInterfaces' not in data:
|
||||
return {'ret': False, 'msg': "EthernetInterfaces resource not found"}
|
||||
ethernetinterfaces_uri = data["EthernetInterfaces"]["@odata.id"]
|
||||
response = self.get_request(self.root_uri + ethernetinterfaces_uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
uris = [a.get('@odata.id') for a in data.get('Members', []) if
|
||||
a.get('@odata.id')]
|
||||
# Get the manager ethernet interface uri
|
||||
nic_info = self.get_manager_ethernet_uri(nic_addr)
|
||||
|
||||
# Find target EthernetInterface
|
||||
target_ethernet_uri = None
|
||||
target_ethernet_current_setting = None
|
||||
if nic_addr == 'null':
|
||||
# Find root_uri matched EthernetInterface when nic_addr is not specified
|
||||
nic_addr = (self.root_uri).split('/')[-1]
|
||||
nic_addr = nic_addr.split(':')[0] # split port if existing
|
||||
for uri in uris:
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if response['ret'] is False:
|
||||
return response
|
||||
data = response['data']
|
||||
if '"' + nic_addr.lower() + '"' in str(data).lower() or "'" + nic_addr.lower() + "'" in str(data).lower():
|
||||
target_ethernet_uri = uri
|
||||
target_ethernet_current_setting = data
|
||||
break
|
||||
if target_ethernet_uri is None:
|
||||
return {'ret': False, 'msg': "No matched EthernetInterface found under Manager"}
|
||||
if nic_info.get('nic_addr') is None:
|
||||
return nic_info
|
||||
else:
|
||||
target_ethernet_uri = nic_info['nic_addr']
|
||||
target_ethernet_current_setting = nic_info['ethernet_setting']
|
||||
|
||||
# Convert input to payload and check validity
|
||||
payload = {}
|
||||
@@ -2797,6 +2776,50 @@ class RedfishUtils(object):
|
||||
return response
|
||||
return {'ret': True, 'changed': True, 'msg': "Modified Manager NIC"}
|
||||
|
||||
# A helper function to get the EthernetInterface URI
|
||||
def get_manager_ethernet_uri(self, nic_addr='null'):
|
||||
# Get EthernetInterface collection
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
data = response['data']
|
||||
if 'EthernetInterfaces' not in data:
|
||||
return {'ret': False, 'msg': "EthernetInterfaces resource not found"}
|
||||
ethernetinterfaces_uri = data["EthernetInterfaces"]["@odata.id"]
|
||||
response = self.get_request(self.root_uri + ethernetinterfaces_uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
data = response['data']
|
||||
uris = [a.get('@odata.id') for a in data.get('Members', []) if
|
||||
a.get('@odata.id')]
|
||||
|
||||
# Find target EthernetInterface
|
||||
target_ethernet_uri = None
|
||||
target_ethernet_current_setting = None
|
||||
if nic_addr == 'null':
|
||||
# Find root_uri matched EthernetInterface when nic_addr is not specified
|
||||
nic_addr = (self.root_uri).split('/')[-1]
|
||||
nic_addr = nic_addr.split(':')[0] # split port if existing
|
||||
for uri in uris:
|
||||
response = self.get_request(self.root_uri + uri)
|
||||
if not response['ret']:
|
||||
return response
|
||||
data = response['data']
|
||||
data_string = json.dumps(data)
|
||||
if nic_addr.lower() in data_string.lower():
|
||||
target_ethernet_uri = uri
|
||||
target_ethernet_current_setting = data
|
||||
break
|
||||
|
||||
nic_info = {}
|
||||
nic_info['nic_addr'] = target_ethernet_uri
|
||||
nic_info['ethernet_setting'] = target_ethernet_current_setting
|
||||
|
||||
if target_ethernet_uri is None:
|
||||
return {}
|
||||
else:
|
||||
return nic_info
|
||||
|
||||
def set_hostinterface_attributes(self, hostinterface_config, hostinterface_id=None):
|
||||
response = self.get_request(self.root_uri + self.manager_uri)
|
||||
if response['ret'] is False:
|
||||
|
||||
@@ -422,6 +422,7 @@ import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import shlex
|
||||
|
||||
try:
|
||||
import lxc
|
||||
@@ -661,9 +662,8 @@ class LxcContainerManagement(object):
|
||||
"""
|
||||
|
||||
for key, value in variables_dict.items():
|
||||
build_command.append(
|
||||
'%s %s' % (key, value)
|
||||
)
|
||||
build_command.append(str(key))
|
||||
build_command.append(str(value))
|
||||
return build_command
|
||||
|
||||
def _get_vars(self, variables):
|
||||
@@ -686,24 +686,6 @@ class LxcContainerManagement(object):
|
||||
return_dict[v] = _var
|
||||
return return_dict
|
||||
|
||||
def _run_command(self, build_command, unsafe_shell=False):
|
||||
"""Return information from running an Ansible Command.
|
||||
|
||||
This will squash the build command list into a string and then
|
||||
execute the command via Ansible. The output is returned to the method.
|
||||
This output is returned as `return_code`, `stdout`, `stderr`.
|
||||
|
||||
:param build_command: Used for the command and all options.
|
||||
:type build_command: ``list``
|
||||
:param unsafe_shell: Enable or Disable unsafe sell commands.
|
||||
:type unsafe_shell: ``bol``
|
||||
"""
|
||||
|
||||
return self.module.run_command(
|
||||
' '.join(build_command),
|
||||
use_unsafe_shell=unsafe_shell
|
||||
)
|
||||
|
||||
def _config(self):
|
||||
"""Configure an LXC container.
|
||||
|
||||
@@ -810,7 +792,7 @@ class LxcContainerManagement(object):
|
||||
elif self.module.params.get('backing_store') == 'overlayfs':
|
||||
build_command.append('--snapshot')
|
||||
|
||||
rc, return_data, err = self._run_command(build_command)
|
||||
rc, return_data, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
message = "Failed executing %s." % os.path.basename(clone_cmd)
|
||||
self.failure(
|
||||
@@ -843,7 +825,7 @@ class LxcContainerManagement(object):
|
||||
|
||||
build_command = [
|
||||
self.module.get_bin_path('lxc-create', True),
|
||||
'--name %s' % self.container_name,
|
||||
'--name', self.container_name,
|
||||
'--quiet'
|
||||
]
|
||||
|
||||
@@ -869,10 +851,12 @@ class LxcContainerManagement(object):
|
||||
log_path = os.getenv('HOME')
|
||||
|
||||
build_command.extend([
|
||||
'--logfile %s' % os.path.join(
|
||||
'--logfile',
|
||||
os.path.join(
|
||||
log_path, 'lxc-%s.log' % self.container_name
|
||||
),
|
||||
'--logpriority %s' % self.module.params.get(
|
||||
'--logpriority',
|
||||
self.module.params.get(
|
||||
'container_log_level'
|
||||
).upper()
|
||||
])
|
||||
@@ -880,9 +864,10 @@ class LxcContainerManagement(object):
|
||||
# Add the template commands to the end of the command if there are any
|
||||
template_options = self.module.params.get('template_options', None)
|
||||
if template_options:
|
||||
build_command.append('-- %s' % template_options)
|
||||
build_command.append('--')
|
||||
build_command += shlex.split(template_options)
|
||||
|
||||
rc, return_data, err = self._run_command(build_command)
|
||||
rc, return_data, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
message = "Failed executing lxc-create."
|
||||
self.failure(
|
||||
@@ -1186,7 +1171,7 @@ class LxcContainerManagement(object):
|
||||
self.module.get_bin_path('lxc-config', True),
|
||||
"lxc.bdev.lvm.vg"
|
||||
]
|
||||
rc, vg, err = self._run_command(build_command)
|
||||
rc, vg, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1204,7 +1189,7 @@ class LxcContainerManagement(object):
|
||||
build_command = [
|
||||
self.module.get_bin_path('lvs', True)
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1231,7 +1216,7 @@ class LxcContainerManagement(object):
|
||||
'--units',
|
||||
'g'
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1262,7 +1247,7 @@ class LxcContainerManagement(object):
|
||||
'--units',
|
||||
'g'
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1311,7 +1296,7 @@ class LxcContainerManagement(object):
|
||||
os.path.join(vg, source_lv),
|
||||
"-L%sg" % snapshot_size_gb
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1336,7 +1321,7 @@ class LxcContainerManagement(object):
|
||||
"/dev/%s/%s" % (vg, lv_name),
|
||||
mount_point,
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1380,9 +1365,8 @@ class LxcContainerManagement(object):
|
||||
'.'
|
||||
]
|
||||
|
||||
rc, stdout, err = self._run_command(
|
||||
build_command=build_command,
|
||||
unsafe_shell=True
|
||||
rc, stdout, err = self.module.run_command(
|
||||
build_command
|
||||
)
|
||||
|
||||
os.umask(old_umask)
|
||||
@@ -1410,7 +1394,7 @@ class LxcContainerManagement(object):
|
||||
"-f",
|
||||
"%s/%s" % (vg, lv_name),
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1442,11 +1426,10 @@ class LxcContainerManagement(object):
|
||||
self.module.get_bin_path('rsync', True),
|
||||
'-aHAX',
|
||||
fs_path,
|
||||
temp_dir
|
||||
temp_dir,
|
||||
]
|
||||
rc, stdout, err = self._run_command(
|
||||
rc, stdout, err = self.module.run_command(
|
||||
build_command,
|
||||
unsafe_shell=True
|
||||
)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
@@ -1467,7 +1450,7 @@ class LxcContainerManagement(object):
|
||||
self.module.get_bin_path('umount', True),
|
||||
mount_point,
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
@@ -1489,12 +1472,12 @@ class LxcContainerManagement(object):
|
||||
|
||||
build_command = [
|
||||
self.module.get_bin_path('mount', True),
|
||||
'-t overlayfs',
|
||||
'-o lowerdir=%s,upperdir=%s' % (lowerdir, upperdir),
|
||||
'-t', 'overlayfs',
|
||||
'-o', 'lowerdir=%s,upperdir=%s' % (lowerdir, upperdir),
|
||||
'overlayfs',
|
||||
mount_point,
|
||||
]
|
||||
rc, stdout, err = self._run_command(build_command)
|
||||
rc, stdout, err = self.module.run_command(build_command)
|
||||
if rc != 0:
|
||||
self.failure(
|
||||
err=err,
|
||||
|
||||
@@ -359,6 +359,10 @@ except ImportError:
|
||||
from ansible.module_utils.basic import AnsibleModule, env_fallback
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.proxmox import (
|
||||
ansible_to_proxmox_bool
|
||||
)
|
||||
|
||||
|
||||
VZ_TYPE = None
|
||||
|
||||
@@ -605,14 +609,14 @@ def main():
|
||||
netif=module.params['netif'],
|
||||
mounts=module.params['mounts'],
|
||||
ip_address=module.params['ip_address'],
|
||||
onboot=int(module.params['onboot']),
|
||||
onboot=ansible_to_proxmox_bool(module.params['onboot']),
|
||||
cpuunits=module.params['cpuunits'],
|
||||
nameserver=module.params['nameserver'],
|
||||
searchdomain=module.params['searchdomain'],
|
||||
force=int(module.params['force']),
|
||||
force=ansible_to_proxmox_bool(module.params['force']),
|
||||
pubkey=module.params['pubkey'],
|
||||
features=",".join(module.params['features']) if module.params['features'] is not None else None,
|
||||
unprivileged=int(module.params['unprivileged']),
|
||||
unprivileged=ansible_to_proxmox_bool(module.params['unprivileged']),
|
||||
description=module.params['description'],
|
||||
hookscript=module.params['hookscript'])
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the servers.
|
||||
- U(https://www.online.net/en/dedicated-server)
|
||||
author:
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.online
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ short_description: Gather information about Online user.
|
||||
description:
|
||||
- Gather information about the user.
|
||||
author:
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.online
|
||||
'''
|
||||
|
||||
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_compute
|
||||
short_description: Scaleway compute management module
|
||||
author: Remy Leone (@sieben)
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- "This module manages compute instances on Scaleway."
|
||||
extends_documentation_fragment:
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway images available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_ip
|
||||
short_description: Scaleway IP management module
|
||||
author: Remy Leone (@sieben)
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- This module manages IP on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway ips available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_lb
|
||||
short_description: Scaleway load-balancer management module
|
||||
author: Remy Leone (@sieben)
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- "This module manages load-balancers on Scaleway."
|
||||
extends_documentation_fragment:
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway organizations available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
options:
|
||||
api_url:
|
||||
description:
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway security groups available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
options:
|
||||
region:
|
||||
type: str
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway servers available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway snapshot available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_sshkey
|
||||
short_description: Scaleway SSH keys management module
|
||||
author: Remy Leone (@sieben)
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- This module manages SSH keys on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
|
||||
@@ -16,7 +16,7 @@ DOCUMENTATION = '''
|
||||
---
|
||||
module: scaleway_user_data
|
||||
short_description: Scaleway user_data management module
|
||||
author: Remy Leone (@sieben)
|
||||
author: Remy Leone (@remyleone)
|
||||
description:
|
||||
- "This module manages user_data on compute instances on Scaleway."
|
||||
- "It can be used to configure cloud-init for instance"
|
||||
|
||||
@@ -15,7 +15,7 @@ description:
|
||||
- Gather information about the Scaleway volumes available.
|
||||
author:
|
||||
- "Yanis Guenane (@Spredzy)"
|
||||
- "Remy Leone (@sieben)"
|
||||
- "Remy Leone (@remyleone)"
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ extends_documentation_fragment:
|
||||
- community.general.redis.documentation
|
||||
|
||||
seealso:
|
||||
- module: community.general.redis_data_incr
|
||||
- module: community.general.redis_data_info
|
||||
- module: community.general.redis
|
||||
'''
|
||||
|
||||
@@ -47,7 +47,7 @@ notes:
|
||||
run the C(GET) command on the key, otherwise the module will fail.
|
||||
|
||||
seealso:
|
||||
- module: community.general.redis_set
|
||||
- module: community.general.redis_data
|
||||
- module: community.general.redis_data_info
|
||||
- module: community.general.redis
|
||||
'''
|
||||
|
||||
@@ -26,6 +26,8 @@ extends_documentation_fragment:
|
||||
- community.general.redis
|
||||
|
||||
seealso:
|
||||
- module: community.general.redis_data
|
||||
- module: community.general.redis_data_incr
|
||||
- module: community.general.redis_info
|
||||
- module: community.general.redis
|
||||
'''
|
||||
|
||||
1
plugins/modules/dnsimple_info.py
Symbolic link
1
plugins/modules/dnsimple_info.py
Symbolic link
@@ -0,0 +1 @@
|
||||
./net_tools/dnsimple_info.py
|
||||
@@ -85,11 +85,6 @@ import os.path
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
try: # python 3.3+
|
||||
from shlex import quote
|
||||
except ImportError: # older python
|
||||
from pipes import quote
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
@@ -154,9 +149,9 @@ def main():
|
||||
|
||||
# Use 7zip when we have a binary, otherwise try to mount
|
||||
if binary:
|
||||
cmd = '%s x "%s" -o"%s" %s' % (binary, image, tmp_dir, ' '.join([quote(f) for f in extract_files]))
|
||||
cmd = [binary, 'x', image, '-o%s' % tmp_dir] + extract_files
|
||||
else:
|
||||
cmd = 'mount -o loop,ro "%s" "%s"' % (image, tmp_dir)
|
||||
cmd = [module.get_bin_path('mount'), '-o', 'loop,ro', image, tmp_dir]
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
@@ -201,7 +196,7 @@ def main():
|
||||
result['changed'] = True
|
||||
finally:
|
||||
if not binary:
|
||||
module.run_command('umount "%s"' % tmp_dir)
|
||||
module.run_command([module.get_bin_path('umount'), tmp_dir])
|
||||
|
||||
shutil.rmtree(tmp_dir)
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ DOCUMENTATION = '''
|
||||
module: xattr
|
||||
short_description: Manage user defined extended attributes
|
||||
description:
|
||||
- Manages filesystem user defined extended attributes.
|
||||
- Requires that extended attributes are enabled on the target filesystem
|
||||
and that the setfattr/getfattr utilities are present.
|
||||
- Manages filesystem user defined extended attributes.
|
||||
- Requires that extended attributes are enabled on the target filesystem
|
||||
and that the setfattr/getfattr utilities are present.
|
||||
options:
|
||||
path:
|
||||
description:
|
||||
@@ -34,13 +34,13 @@ options:
|
||||
type: str
|
||||
value:
|
||||
description:
|
||||
- The value to set the named name/key to, it automatically sets the C(state) to 'set'.
|
||||
- The value to set the named name/key to, it automatically sets the I(state) to C(present).
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- defines which state you want to do.
|
||||
C(read) retrieves the current value for a C(key) (default)
|
||||
C(present) sets C(name) to C(value), default if value is set
|
||||
C(read) retrieves the current value for a I(key) (default)
|
||||
C(present) sets I(path) to C(value), default if value is set
|
||||
C(all) dumps all data
|
||||
C(keys) retrieves all keys
|
||||
C(absent) deletes the key
|
||||
@@ -49,14 +49,14 @@ options:
|
||||
default: read
|
||||
follow:
|
||||
description:
|
||||
- If C(yes), dereferences symlinks and sets/gets attributes on symlink target,
|
||||
- If C(true), dereferences symlinks and sets/gets attributes on symlink target,
|
||||
otherwise acts on symlink itself.
|
||||
type: bool
|
||||
default: yes
|
||||
default: true
|
||||
notes:
|
||||
- As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well.
|
||||
author:
|
||||
- Brian Coca (@bcoca)
|
||||
- Brian Coca (@bcoca)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -116,7 +116,8 @@ def get_xattr(module, path, key, follow):
|
||||
if key is None:
|
||||
cmd.append('-d')
|
||||
else:
|
||||
cmd.append('-n %s' % key)
|
||||
cmd.append('-n')
|
||||
cmd.append(key)
|
||||
cmd.append(path)
|
||||
|
||||
return _run_xattr(module, cmd, False)
|
||||
@@ -127,8 +128,10 @@ def set_xattr(module, path, key, value, follow):
|
||||
cmd = [module.get_bin_path('setfattr', True)]
|
||||
if not follow:
|
||||
cmd.append('-h')
|
||||
cmd.append('-n %s' % key)
|
||||
cmd.append('-v %s' % value)
|
||||
cmd.append('-n')
|
||||
cmd.append(key)
|
||||
cmd.append('-v')
|
||||
cmd.append(value)
|
||||
cmd.append(path)
|
||||
|
||||
return _run_xattr(module, cmd)
|
||||
@@ -139,7 +142,8 @@ def rm_xattr(module, path, key, follow):
|
||||
cmd = [module.get_bin_path('setfattr', True)]
|
||||
if not follow:
|
||||
cmd.append('-h')
|
||||
cmd.append('-x %s' % key)
|
||||
cmd.append('-x')
|
||||
cmd.append(key)
|
||||
cmd.append(path)
|
||||
|
||||
return _run_xattr(module, cmd, False)
|
||||
@@ -148,7 +152,7 @@ def rm_xattr(module, path, key, follow):
|
||||
def _run_xattr(module, cmd, check_rc=True):
|
||||
|
||||
try:
|
||||
(rc, out, err) = module.run_command(' '.join(cmd), check_rc=check_rc)
|
||||
(rc, out, err) = module.run_command(cmd, check_rc=check_rc)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="%s!" % to_native(e))
|
||||
|
||||
|
||||
1
plugins/modules/gitlab_branch.py
Symbolic link
1
plugins/modules/gitlab_branch.py
Symbolic link
@@ -0,0 +1 @@
|
||||
source_control/gitlab/gitlab_branch.py
|
||||
@@ -64,6 +64,7 @@ options:
|
||||
choices:
|
||||
- ldap
|
||||
- kerberos
|
||||
- sssd
|
||||
|
||||
provider_type:
|
||||
description:
|
||||
@@ -83,9 +84,10 @@ options:
|
||||
config:
|
||||
description:
|
||||
- Dict specifying the configuration options for the provider; the contents differ depending on
|
||||
the value of I(provider_id). Examples are given below for C(ldap) and C(kerberos). It is easiest
|
||||
to obtain valid config values by dumping an already-existing user federation configuration
|
||||
through check-mode in the I(existing) field.
|
||||
the value of I(provider_id). Examples are given below for C(ldap), C(kerberos) and C(sssd).
|
||||
It is easiest to obtain valid config values by dumping an already-existing user federation
|
||||
configuration through check-mode in the I(existing) field.
|
||||
- The value C(sssd) has been supported since community.general 4.2.0.
|
||||
type: dict
|
||||
suboptions:
|
||||
enabled:
|
||||
@@ -531,6 +533,22 @@ EXAMPLES = '''
|
||||
allowPasswordAuthentication: false
|
||||
updateProfileFirstLogin: false
|
||||
|
||||
- name: Create sssd user federation
|
||||
community.general.keycloak_user_federation:
|
||||
auth_keycloak_url: https://keycloak.example.com/auth
|
||||
auth_realm: master
|
||||
auth_username: admin
|
||||
auth_password: password
|
||||
realm: my-realm
|
||||
name: my-sssd
|
||||
state: present
|
||||
provider_id: sssd
|
||||
provider_type: org.keycloak.storage.UserStorageProvider
|
||||
config:
|
||||
priority: 0
|
||||
enabled: true
|
||||
cachePolicy: DEFAULT
|
||||
|
||||
- name: Delete user federation
|
||||
community.general.keycloak_user_federation:
|
||||
auth_keycloak_url: https://keycloak.example.com/auth
|
||||
@@ -765,7 +783,7 @@ def main():
|
||||
realm=dict(type='str', default='master'),
|
||||
id=dict(type='str'),
|
||||
name=dict(type='str'),
|
||||
provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos']),
|
||||
provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos', 'sssd']),
|
||||
provider_type=dict(type='str', aliases=['providerType'], default='org.keycloak.storage.UserStorageProvider'),
|
||||
parent_id=dict(type='str', aliases=['parentId']),
|
||||
mappers=dict(type='list', elements='dict', options=mapper_spec),
|
||||
@@ -843,8 +861,8 @@ def main():
|
||||
|
||||
# special handling of mappers list to allow change detection
|
||||
if module.params.get('mappers') is not None:
|
||||
if module.params['provider_id'] == 'kerberos':
|
||||
module.fail_json(msg='Cannot configure mappers for Kerberos federations.')
|
||||
if module.params['provider_id'] in ['kerberos', 'sssd']:
|
||||
module.fail_json(msg='Cannot configure mappers for {type} provider.'.format(type=module.params['provider_id']))
|
||||
for change in module.params['mappers']:
|
||||
change = dict((k, v) for k, v in change.items() if change[k] is not None)
|
||||
if change.get('id') is None and change.get('name') is None:
|
||||
|
||||
1
plugins/modules/ilo_redfish_config.py
Symbolic link
1
plugins/modules/ilo_redfish_config.py
Symbolic link
@@ -0,0 +1 @@
|
||||
remote_management/redfish/ilo_redfish_config.py
|
||||
1
plugins/modules/ilo_redfish_info.py
Symbolic link
1
plugins/modules/ilo_redfish_info.py
Symbolic link
@@ -0,0 +1 @@
|
||||
remote_management/redfish/ilo_redfish_info.py
|
||||
@@ -63,7 +63,7 @@ def query_log_status(module, le_path, path, state="present"):
|
||||
""" Returns whether a log is followed or not. """
|
||||
|
||||
if state == "present":
|
||||
rc, out, err = module.run_command("%s followed %s" % (le_path, path))
|
||||
rc, out, err = module.run_command([le_path, "followed", path])
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
@@ -87,7 +87,7 @@ def follow_log(module, le_path, logs, name=None, logtype=None):
|
||||
cmd.extend(['--name', name])
|
||||
if logtype:
|
||||
cmd.extend(['--type', logtype])
|
||||
rc, out, err = module.run_command(' '.join(cmd))
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
if not query_log_status(module, le_path, log):
|
||||
module.fail_json(msg="failed to follow '%s': %s" % (log, err.strip()))
|
||||
|
||||
@@ -82,7 +82,7 @@ PACKAGE_STATE_MAP = dict(
|
||||
|
||||
def is_plugin_present(module, plugin_bin, plugin_name):
|
||||
cmd_args = [plugin_bin, "list", plugin_name]
|
||||
rc, out, err = module.run_command(" ".join(cmd_args))
|
||||
rc, out, err = module.run_command(cmd_args)
|
||||
return rc == 0
|
||||
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ class Monit(object):
|
||||
return self._monit_version
|
||||
|
||||
def _get_monit_version(self):
|
||||
rc, out, err = self.module.run_command('%s -V' % self.monit_bin_path, check_rc=True)
|
||||
rc, out, err = self.module.run_command([self.monit_bin_path, '-V'], check_rc=True)
|
||||
version_line = out.split('\n')[0]
|
||||
raw_version = re.search(r"([0-9]+\.){1,2}([0-9]+)?", version_line).group()
|
||||
return raw_version, tuple(map(int, raw_version.split('.')))
|
||||
@@ -140,7 +140,7 @@ class Monit(object):
|
||||
|
||||
@property
|
||||
def command_args(self):
|
||||
return "-B" if self.monit_version() > (5, 18) else ""
|
||||
return ["-B"] if self.monit_version() > (5, 18) else []
|
||||
|
||||
def get_status(self, validate=False):
|
||||
"""Return the status of the process in monit.
|
||||
@@ -149,7 +149,7 @@ class Monit(object):
|
||||
"""
|
||||
monit_command = "validate" if validate else "status"
|
||||
check_rc = False if validate else True # 'validate' always has rc = 1
|
||||
command = ' '.join([self.monit_bin_path, monit_command, self.command_args, self.process_name])
|
||||
command = [self.monit_bin_path, monit_command] + self.command_args + [self.process_name]
|
||||
rc, out, err = self.module.run_command(command, check_rc=check_rc)
|
||||
return self._parse_status(out, err)
|
||||
|
||||
@@ -182,7 +182,8 @@ class Monit(object):
|
||||
return status
|
||||
|
||||
def is_process_present(self):
|
||||
rc, out, err = self.module.run_command('%s summary %s' % (self.monit_bin_path, self.command_args), check_rc=True)
|
||||
command = [self.monit_bin_path, 'summary'] + self.command_args
|
||||
rc, out, err = self.module.run_command(command, check_rc=True)
|
||||
return bool(re.findall(r'\b%s\b' % self.process_name, out))
|
||||
|
||||
def is_process_running(self):
|
||||
@@ -190,7 +191,7 @@ class Monit(object):
|
||||
|
||||
def run_command(self, command):
|
||||
"""Runs a monit command, and returns the new status."""
|
||||
return self.module.run_command('%s %s %s' % (self.monit_bin_path, command, self.process_name), check_rc=True)
|
||||
return self.module.run_command([self.monit_bin_path, command, self.process_name], check_rc=True)
|
||||
|
||||
def wait_for_status_change(self, current_status):
|
||||
running_status = self.get_status()
|
||||
@@ -228,7 +229,7 @@ class Monit(object):
|
||||
return current_status
|
||||
|
||||
def reload(self):
|
||||
rc, out, err = self.module.run_command('%s reload' % self.monit_bin_path)
|
||||
rc, out, err = self.module.run_command([self.monit_bin_path, 'reload'])
|
||||
if rc != 0:
|
||||
self.exit_fail('monit reload failed', stdout=out, stderr=err)
|
||||
self.exit_success(state='reloaded')
|
||||
|
||||
335
plugins/modules/net_tools/dnsimple_info.py
Normal file
335
plugins/modules/net_tools/dnsimple_info.py
Normal file
@@ -0,0 +1,335 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: Edward Hilgendorf, <edward@hilgendorf.me>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: dnsimple_info
|
||||
|
||||
short_description: Pull basic info from DNSimple API
|
||||
|
||||
version_added: "4.2.0"
|
||||
|
||||
description: Retrieve existing records and domains from DNSimple API.
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The domain name to retrieve info from.
|
||||
- Will return all associated records for this domain if specified.
|
||||
- If not specified, will return all domains associated with the account ID.
|
||||
type: str
|
||||
|
||||
account_id:
|
||||
description: The account ID to query.
|
||||
required: true
|
||||
type: str
|
||||
|
||||
api_key:
|
||||
description: The API key to use.
|
||||
required: true
|
||||
type: str
|
||||
|
||||
record:
|
||||
description:
|
||||
- The record to find.
|
||||
- If specified, only this record will be returned instead of all records.
|
||||
required: false
|
||||
type: str
|
||||
|
||||
sandbox:
|
||||
description: Whether or not to use sandbox environment.
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
|
||||
author:
|
||||
- Edward Hilgendorf (@edhilgendorf)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Get all domains from an account
|
||||
community.general.dnsimple_info:
|
||||
account_id: "1234"
|
||||
api_key: "1234"
|
||||
|
||||
- name: Get all records from a domain
|
||||
community.general.dnsimple_info:
|
||||
name: "example.com"
|
||||
account_id: "1234"
|
||||
api_key: "1234"
|
||||
|
||||
- name: Get all info from a matching record
|
||||
community.general.dnsimple_info:
|
||||
name: "example.com"
|
||||
record: "subdomain"
|
||||
account_id: "1234"
|
||||
api_key: "1234"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
dnsimple_domain_info:
|
||||
description: Returns a list of dictionaries of all domains associated with the supplied account ID.
|
||||
type: list
|
||||
elements: dict
|
||||
returned: success when I(name) is not specified
|
||||
sample:
|
||||
- account_id: 1234
|
||||
created_at: '2021-10-16T21:25:42Z'
|
||||
id: 123456
|
||||
last_transferred_at:
|
||||
name: example.com
|
||||
reverse: false
|
||||
secondary: false
|
||||
updated_at: '2021-11-10T20:22:50Z'
|
||||
contains:
|
||||
account_id:
|
||||
description: The account ID.
|
||||
type: int
|
||||
created_at:
|
||||
description: When the domain entry was created.
|
||||
type: str
|
||||
id:
|
||||
description: ID of the entry.
|
||||
type: int
|
||||
last_transferred_at:
|
||||
description: Date the domain was transferred, or empty if not.
|
||||
type: str
|
||||
name:
|
||||
description: Name of the record.
|
||||
type: str
|
||||
reverse:
|
||||
description: Whether or not it is a reverse zone record.
|
||||
type: bool
|
||||
updated_at:
|
||||
description: When the domain entry was updated.
|
||||
type: str
|
||||
|
||||
dnsimple_records_info:
|
||||
description: Returns a list of dictionaries with all records for the domain supplied.
|
||||
type: list
|
||||
elements: dict
|
||||
returned: success when I(name) is specified, but I(record) is not
|
||||
sample:
|
||||
- content: ns1.dnsimple.com admin.dnsimple.com
|
||||
created_at: '2021-10-16T19:07:34Z'
|
||||
id: 12345
|
||||
name: 'catheadbiscuit'
|
||||
parent_id: null
|
||||
priority: null
|
||||
regions:
|
||||
- global
|
||||
system_record: true
|
||||
ttl: 3600
|
||||
type: SOA
|
||||
updated_at: '2021-11-15T23:55:51Z'
|
||||
zone_id: example.com
|
||||
contains:
|
||||
content:
|
||||
description: Content of the returned record.
|
||||
type: str
|
||||
created_at:
|
||||
description: When the domain entry was created.
|
||||
type: str
|
||||
id:
|
||||
description: ID of the entry.
|
||||
type: int
|
||||
name:
|
||||
description: Name of the record.
|
||||
type: str
|
||||
parent_id:
|
||||
description: Parent record or null.
|
||||
type: int
|
||||
priority:
|
||||
description: Priority setting of the record.
|
||||
type: str
|
||||
regions:
|
||||
description: List of regions where the record is available.
|
||||
type: list
|
||||
system_record:
|
||||
description: Whether or not it is a system record.
|
||||
type: bool
|
||||
ttl:
|
||||
description: Record TTL.
|
||||
type: int
|
||||
type:
|
||||
description: Record type.
|
||||
type: str
|
||||
updated_at:
|
||||
description: When the domain entry was updated.
|
||||
type: str
|
||||
zone_id:
|
||||
description: ID of the zone that the record is associated with.
|
||||
type: str
|
||||
dnsimple_record_info:
|
||||
description: Returns a list of dictionaries that match the record supplied.
|
||||
returned: success when I(name) and I(record) are specified
|
||||
type: list
|
||||
elements: dict
|
||||
sample:
|
||||
- content: 1.2.3.4
|
||||
created_at: '2021-11-15T23:55:51Z'
|
||||
id: 123456
|
||||
name: catheadbiscuit
|
||||
parent_id: null
|
||||
priority: null
|
||||
regions:
|
||||
- global
|
||||
system_record: false
|
||||
ttl: 3600
|
||||
type: A
|
||||
updated_at: '2021-11-15T23:55:51Z'
|
||||
zone_id: example.com
|
||||
contains:
|
||||
content:
|
||||
description: Content of the returned record.
|
||||
type: str
|
||||
created_at:
|
||||
description: When the domain entry was created.
|
||||
type: str
|
||||
id:
|
||||
description: ID of the entry.
|
||||
type: int
|
||||
name:
|
||||
description: Name of the record.
|
||||
type: str
|
||||
parent_id:
|
||||
description: Parent record or null.
|
||||
type: int
|
||||
priority:
|
||||
description: Priority setting of the record.
|
||||
type: str
|
||||
regions:
|
||||
description: List of regions where the record is available.
|
||||
type: list
|
||||
system_record:
|
||||
description: Whether or not it is a system record.
|
||||
type: bool
|
||||
ttl:
|
||||
description: Record TTL.
|
||||
type: int
|
||||
type:
|
||||
description: Record type.
|
||||
type: str
|
||||
updated_at:
|
||||
description: When the domain entry was updated.
|
||||
type: str
|
||||
zone_id:
|
||||
description: ID of the zone that the record is associated with.
|
||||
type: str
|
||||
'''
|
||||
|
||||
import traceback
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import missing_required_lib
|
||||
import json
|
||||
|
||||
try:
|
||||
from requests import Request, Session
|
||||
except ImportError:
|
||||
HAS_ANOTHER_LIBRARY = False
|
||||
ANOTHER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
|
||||
else:
|
||||
HAS_ANOTHER_LIBRARY = True
|
||||
|
||||
|
||||
def build_url(account, key, is_sandbox):
|
||||
headers = {'Accept': 'application/json',
|
||||
'Authorization': 'Bearer ' + key}
|
||||
url = 'https://api{sandbox}.dnsimple.com/'.format(
|
||||
sandbox=".sandbox" if is_sandbox else "") + 'v2/' + account
|
||||
req = Request(url=url, headers=headers)
|
||||
prepped_request = req.prepare()
|
||||
return prepped_request
|
||||
|
||||
|
||||
def iterate_data(module, request_object):
|
||||
base_url = request_object.url
|
||||
response = Session().send(request_object)
|
||||
if 'pagination' in response.json():
|
||||
data = response.json()["data"]
|
||||
pages = response.json()["pagination"]["total_pages"]
|
||||
if int(pages) > 1:
|
||||
for page in range(1, pages):
|
||||
page = page + 1
|
||||
request_object.url = base_url + '&page=' + str(page)
|
||||
new_results = Session().send(request_object)
|
||||
data = data + new_results.json()["data"]
|
||||
return(data)
|
||||
else:
|
||||
module.fail_json('API Call failed, check ID, key and sandbox values')
|
||||
|
||||
|
||||
def record_info(dnsimple_mod, req_obj):
|
||||
req_obj.url, req_obj.method = req_obj.url + '/zones/' + dnsimple_mod.params["name"] + '/records?name=' + dnsimple_mod.params["record"], 'GET'
|
||||
return iterate_data(dnsimple_mod, req_obj)
|
||||
|
||||
|
||||
def domain_info(dnsimple_mod, req_obj):
|
||||
req_obj.url, req_obj.method = req_obj.url + '/zones/' + dnsimple_mod.params["name"] + '/records?per_page=100', 'GET'
|
||||
return iterate_data(dnsimple_mod, req_obj)
|
||||
|
||||
|
||||
def account_info(dnsimple_mod, req_obj):
|
||||
req_obj.url, req_obj.method = req_obj.url + '/zones/?per_page=100', 'GET'
|
||||
return iterate_data(dnsimple_mod, req_obj)
|
||||
|
||||
|
||||
def main():
|
||||
# define available arguments/parameters a user can pass to the module
|
||||
fields = {
|
||||
"account_id": {"required": True, "type": "str"},
|
||||
"api_key": {"required": True, "type": "str", "no_log": True},
|
||||
"name": {"required": False, "type": "str"},
|
||||
"record": {"required": False, "type": "str"},
|
||||
"sandbox": {"required": False, "type": "bool", "default": False}
|
||||
}
|
||||
|
||||
result = {
|
||||
'changed': False
|
||||
}
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=fields,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
params = module.params
|
||||
req = build_url(params['account_id'],
|
||||
params['api_key'],
|
||||
params['sandbox'])
|
||||
|
||||
if not HAS_ANOTHER_LIBRARY:
|
||||
# Needs: from ansible.module_utils.basic import missing_required_lib
|
||||
module.exit_json(
|
||||
msg=missing_required_lib('another_library'),
|
||||
exception=ANOTHER_LIBRARY_IMPORT_ERROR)
|
||||
|
||||
# At minimum we need account and key
|
||||
if params['account_id'] and params['api_key']:
|
||||
# If we have a record return info on that record
|
||||
if params['name'] and params['record']:
|
||||
result['dnsimple_record_info'] = record_info(module, req)
|
||||
module.exit_json(**result)
|
||||
|
||||
# If we have the account only and domain, return records for the domain
|
||||
elif params['name']:
|
||||
result['dnsimple_records_info'] = domain_info(module, req)
|
||||
module.exit_json(**result)
|
||||
|
||||
# If we have the account only, return domains
|
||||
else:
|
||||
result['dnsimple_domain_info'] = account_info(module, req)
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
module.fail_json(msg="Need at least account_id and api_key")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -76,7 +76,7 @@ class Namespace(object):
|
||||
|
||||
def exists(self):
|
||||
'''Check if the namespace already exists'''
|
||||
rc, out, err = self.module.run_command('ip netns list')
|
||||
rc, out, err = self.module.run_command(['ip', 'netns', 'list'])
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg=to_text(err))
|
||||
return self.name in out
|
||||
|
||||
@@ -70,7 +70,7 @@ options:
|
||||
ip4:
|
||||
description:
|
||||
- List of IPv4 addresses to this interface.
|
||||
- Use the format C(192.0.2.24/24).
|
||||
- Use the format C(192.0.2.24/24) or C(192.0.2.24).
|
||||
- If defined and I(method4) is not specified, automatically set C(ipv4.method) to C(manual).
|
||||
type: list
|
||||
elements: str
|
||||
@@ -143,10 +143,11 @@ options:
|
||||
version_added: 3.3.0
|
||||
ip6:
|
||||
description:
|
||||
- The IPv6 address to this interface.
|
||||
- Use the format C(abbe::cafe).
|
||||
- List of IPv6 addresses to this interface.
|
||||
- Use the format C(abbe::cafe/128) or C(abbe::cafe).
|
||||
- If defined and I(method6) is not specified, automatically set C(ipv6.method) to C(manual).
|
||||
type: str
|
||||
type: list
|
||||
elements: str
|
||||
gw6:
|
||||
description:
|
||||
- The IPv6 gateway for this interface.
|
||||
@@ -183,6 +184,18 @@ options:
|
||||
type: str
|
||||
choices: [ignore, auto, dhcp, link-local, manual, shared, disabled]
|
||||
version_added: 2.2.0
|
||||
ip_privacy6:
|
||||
description:
|
||||
- If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one.
|
||||
type: str
|
||||
choices: [disabled, prefer-public-addr, prefer-temp-addr, unknown]
|
||||
version_added: 4.2.0
|
||||
addr_gen_mode6:
|
||||
description:
|
||||
- Configure method for creating the address for use with IPv6 Stateless Address Autoconfiguration.
|
||||
type: str
|
||||
choices: [eui64, stable-privacy]
|
||||
version_added: 4.2.0
|
||||
mtu:
|
||||
description:
|
||||
- The connection MTU, e.g. 9000. This can't be applied when creating the interface and is done once the interface has been created.
|
||||
@@ -1011,6 +1024,16 @@ EXAMPLES = r'''
|
||||
- 192.0.3.100/24
|
||||
state: present
|
||||
|
||||
- name: Add second ip6 address
|
||||
community.general.nmcli:
|
||||
conn_name: my-eth1
|
||||
ifname: eth1
|
||||
type: ethernet
|
||||
ip6:
|
||||
- 2001:db8::cafe
|
||||
- 2002:db8::cafe
|
||||
state: present
|
||||
|
||||
- name: Add VxLan
|
||||
community.general.nmcli:
|
||||
type: vxlan
|
||||
@@ -1171,6 +1194,8 @@ class Nmcli(object):
|
||||
self.dns6_search = module.params['dns6_search']
|
||||
self.dns6_ignore_auto = module.params['dns6_ignore_auto']
|
||||
self.method6 = module.params['method6']
|
||||
self.ip_privacy6 = module.params['ip_privacy6']
|
||||
self.addr_gen_mode6 = module.params['addr_gen_mode6']
|
||||
self.mtu = module.params['mtu']
|
||||
self.stp = module.params['stp']
|
||||
self.priority = module.params['priority']
|
||||
@@ -1255,7 +1280,7 @@ class Nmcli(object):
|
||||
# IP address options.
|
||||
if self.ip_conn_type and not self.master:
|
||||
options.update({
|
||||
'ipv4.addresses': self.ip4,
|
||||
'ipv4.addresses': self.enforce_ipv4_cidr_notation(self.ip4),
|
||||
'ipv4.dhcp-client-id': self.dhcp_client_id,
|
||||
'ipv4.dns': self.dns4,
|
||||
'ipv4.dns-search': self.dns4_search,
|
||||
@@ -1268,13 +1293,15 @@ class Nmcli(object):
|
||||
'ipv4.never-default': self.never_default4,
|
||||
'ipv4.method': self.ipv4_method,
|
||||
'ipv4.may-fail': self.may_fail4,
|
||||
'ipv6.addresses': self.ip6,
|
||||
'ipv6.addresses': self.enforce_ipv6_cidr_notation(self.ip6),
|
||||
'ipv6.dns': self.dns6,
|
||||
'ipv6.dns-search': self.dns6_search,
|
||||
'ipv6.ignore-auto-dns': self.dns6_ignore_auto,
|
||||
'ipv6.gateway': self.gw6,
|
||||
'ipv6.ignore-auto-routes': self.gw6_ignore_auto,
|
||||
'ipv6.method': self.ipv6_method,
|
||||
'ipv6.ip6-privacy': self.ip_privacy6,
|
||||
'ipv6.addr-gen-mode': self.addr_gen_mode6
|
||||
})
|
||||
|
||||
# Layer 2 options.
|
||||
@@ -1346,6 +1373,9 @@ class Nmcli(object):
|
||||
options.update({
|
||||
'vlan.id': self.vlanid,
|
||||
'vlan.parent': self.vlandev,
|
||||
'vlan.flags': self.flags,
|
||||
'vlan.ingress': self.ingress,
|
||||
'vlan.egress': self.egress,
|
||||
})
|
||||
elif self.type == 'vxlan':
|
||||
options.update({
|
||||
@@ -1388,6 +1418,8 @@ class Nmcli(object):
|
||||
elif setting == self.mtu_setting:
|
||||
# MTU is 'auto' by default when detecting changes.
|
||||
convert_func = self.mtu_to_string
|
||||
elif setting == 'ipv6.ip6-privacy':
|
||||
convert_func = self.ip6_privacy_to_num
|
||||
elif setting_type is list:
|
||||
# Convert lists to strings for nmcli create/modify commands.
|
||||
convert_func = self.list_to_string
|
||||
@@ -1441,6 +1473,23 @@ class Nmcli(object):
|
||||
else:
|
||||
return to_text(mtu)
|
||||
|
||||
@staticmethod
|
||||
def ip6_privacy_to_num(privacy):
|
||||
ip6_privacy_values = {
|
||||
'disabled': '0',
|
||||
'prefer-public-addr': '1 (enabled, prefer public IP)',
|
||||
'prefer-temp-addr': '2 (enabled, prefer temporary IP)',
|
||||
'unknown': '-1',
|
||||
}
|
||||
|
||||
if privacy is None:
|
||||
return None
|
||||
|
||||
if privacy not in ip6_privacy_values:
|
||||
raise AssertionError('{privacy} is invalid ip_privacy6 option'.format(privacy=privacy))
|
||||
|
||||
return ip6_privacy_values[privacy]
|
||||
|
||||
@property
|
||||
def slave_conn_type(self):
|
||||
return self.type in (
|
||||
@@ -1458,6 +1507,18 @@ class Nmcli(object):
|
||||
'sit',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def enforce_ipv4_cidr_notation(ip4_addresses):
|
||||
if ip4_addresses is None:
|
||||
return None
|
||||
return [address if '/' in address else address + '/32' for address in ip4_addresses]
|
||||
|
||||
@staticmethod
|
||||
def enforce_ipv6_cidr_notation(ip6_addresses):
|
||||
if ip6_addresses is None:
|
||||
return None
|
||||
return [address if '/' in address else address + '/128' for address in ip6_addresses]
|
||||
|
||||
@staticmethod
|
||||
def bool_to_string(boolean):
|
||||
if boolean:
|
||||
@@ -1483,6 +1544,7 @@ class Nmcli(object):
|
||||
'802-11-wireless.hidden'):
|
||||
return bool
|
||||
elif setting in ('ipv4.addresses',
|
||||
'ipv6.addresses',
|
||||
'ipv4.dns',
|
||||
'ipv4.dns-search',
|
||||
'ipv4.routes',
|
||||
@@ -1786,13 +1848,15 @@ def main():
|
||||
method4=dict(type='str', choices=['auto', 'link-local', 'manual', 'shared', 'disabled']),
|
||||
may_fail4=dict(type='bool', default=True),
|
||||
dhcp_client_id=dict(type='str'),
|
||||
ip6=dict(type='str'),
|
||||
ip6=dict(type='list', elements='str'),
|
||||
gw6=dict(type='str'),
|
||||
gw6_ignore_auto=dict(type='bool', default=False),
|
||||
dns6=dict(type='list', elements='str'),
|
||||
dns6_search=dict(type='list', elements='str'),
|
||||
dns6_ignore_auto=dict(type='bool', default=False),
|
||||
method6=dict(type='str', choices=['ignore', 'auto', 'dhcp', 'link-local', 'manual', 'shared', 'disabled']),
|
||||
ip_privacy6=dict(type='str', choices=['disabled', 'prefer-public-addr', 'prefer-temp-addr', 'unknown']),
|
||||
addr_gen_mode6=dict(type='str', choices=['eui64', 'stable-privacy']),
|
||||
# Bond Specific vars
|
||||
mode=dict(type='str', default='balance-rr',
|
||||
choices=['802.3ad', 'active-backup', 'balance-alb', 'balance-rr', 'balance-tlb', 'balance-xor', 'broadcast']),
|
||||
|
||||
@@ -127,7 +127,7 @@ ansible_sysname:
|
||||
type: str
|
||||
sample: ubuntu-user
|
||||
ansible_syslocation:
|
||||
description: The physical location of this node (e.g., `telephone closet, 3rd floor').
|
||||
description: The physical location of this node (e.g., C(telephone closet, 3rd floor)).
|
||||
returned: success
|
||||
type: str
|
||||
sample: Sitting on the Dock of the Bay
|
||||
|
||||
@@ -10,7 +10,7 @@ __metaclass__ = type
|
||||
DOCUMENTATION = """
|
||||
module: ansible_galaxy_install
|
||||
author:
|
||||
- "Alexei Znamensky (@russoz)"
|
||||
- "Alexei Znamensky (@russoz)"
|
||||
short_description: Install Ansible roles or collections using ansible-galaxy
|
||||
version_added: 3.5.0
|
||||
description:
|
||||
@@ -24,44 +24,46 @@ requirements:
|
||||
options:
|
||||
type:
|
||||
description:
|
||||
- The type of installation performed by C(ansible-galaxy).
|
||||
- If I(type) is C(both), then I(requirements_file) must be passed and it may contain both roles and collections.
|
||||
- "Note however that the opposite is not true: if using a I(requirements_file), then I(type) can be any of the three choices."
|
||||
- "B(Ansible 2.9): The option C(both) will have the same effect as C(role)."
|
||||
- The type of installation performed by C(ansible-galaxy).
|
||||
- If I(type) is C(both), then I(requirements_file) must be passed and it may contain both roles and collections.
|
||||
- "Note however that the opposite is not true: if using a I(requirements_file), then I(type) can be any of the three choices."
|
||||
- "B(Ansible 2.9): The option C(both) will have the same effect as C(role)."
|
||||
type: str
|
||||
choices: [collection, role, both]
|
||||
required: true
|
||||
name:
|
||||
description:
|
||||
- Name of the collection or role being installed.
|
||||
- Versions can be specified with C(ansible-galaxy) usual formats. For example, C(community.docker:1.6.1) or C(ansistrano.deploy,3.8.0).
|
||||
- I(name) and I(requirements_file) are mutually exclusive.
|
||||
- Name of the collection or role being installed.
|
||||
- >
|
||||
Versions can be specified with C(ansible-galaxy) usual formats.
|
||||
For example, the collection C(community.docker:1.6.1) or the role C(ansistrano.deploy,3.8.0).
|
||||
- I(name) and I(requirements_file) are mutually exclusive.
|
||||
type: str
|
||||
requirements_file:
|
||||
description:
|
||||
- Path to a file containing a list of requirements to be installed.
|
||||
- It works for I(type) equals to C(collection) and C(role).
|
||||
- I(name) and I(requirements_file) are mutually exclusive.
|
||||
- "B(Ansible 2.9): It can only be used to install either I(type=role) or I(type=collection), but not both at the same run."
|
||||
- Path to a file containing a list of requirements to be installed.
|
||||
- It works for I(type) equals to C(collection) and C(role).
|
||||
- I(name) and I(requirements_file) are mutually exclusive.
|
||||
- "B(Ansible 2.9): It can only be used to install either I(type=role) or I(type=collection), but not both at the same run."
|
||||
type: path
|
||||
dest:
|
||||
description:
|
||||
- The path to the directory containing your collections or roles, according to the value of I(type).
|
||||
- >
|
||||
Please notice that C(ansible-galaxy) will not install collections with I(type=both), when I(requirements_file)
|
||||
contains both roles and collections and I(dest) is specified.
|
||||
- The path to the directory containing your collections or roles, according to the value of I(type).
|
||||
- >
|
||||
Please notice that C(ansible-galaxy) will not install collections with I(type=both), when I(requirements_file)
|
||||
contains both roles and collections and I(dest) is specified.
|
||||
type: path
|
||||
force:
|
||||
description:
|
||||
- Force overwriting an existing role or collection.
|
||||
- Using I(force=true) is mandatory when downgrading.
|
||||
- "B(Ansible 2.9 and 2.10): Must be C(true) to upgrade roles and collections."
|
||||
- Force overwriting an existing role or collection.
|
||||
- Using I(force=true) is mandatory when downgrading.
|
||||
- "B(Ansible 2.9 and 2.10): Must be C(true) to upgrade roles and collections."
|
||||
type: bool
|
||||
default: false
|
||||
ack_ansible29:
|
||||
description:
|
||||
- Acknowledge using Ansible 2.9 with its limitations, and prevents the module from generating warnings about them.
|
||||
- This option is completely ignored if using a version Ansible greater than C(2.9.x).
|
||||
- Acknowledge using Ansible 2.9 with its limitations, and prevents the module from generating warnings about them.
|
||||
- This option is completely ignored if using a version of Ansible greater than C(2.9.x).
|
||||
type: bool
|
||||
default: false
|
||||
"""
|
||||
@@ -114,9 +116,9 @@ RETURN = """
|
||||
returned: always
|
||||
installed_roles:
|
||||
description:
|
||||
- If I(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
|
||||
- If I(name) is specified, returns that role name and the version installed per path.
|
||||
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
|
||||
- If I(requirements_file) is specified instead, returns dictionary with all the roles installed per path.
|
||||
- If I(name) is specified, returns that role name and the version installed per path.
|
||||
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
|
||||
type: dict
|
||||
returned: always when installing roles
|
||||
contains:
|
||||
@@ -131,9 +133,9 @@ RETURN = """
|
||||
ansistrano.deploy: 3.8.0
|
||||
installed_collections:
|
||||
description:
|
||||
- If I(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
|
||||
- If I(name) is specified, returns that collection name and the version installed per path.
|
||||
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
|
||||
- If I(requirements_file) is specified instead, returns dictionary with all the collections installed per path.
|
||||
- If I(name) is specified, returns that collection name and the version installed per path.
|
||||
- "B(Ansible 2.9): Returns empty because C(ansible-galaxy) has no C(list) subcommand."
|
||||
type: dict
|
||||
returned: always when installing collections
|
||||
contains:
|
||||
|
||||
@@ -167,7 +167,7 @@ class PipX(CmdStateModuleHelper):
|
||||
command_args_formats = dict(
|
||||
state=dict(fmt=lambda v: [_state_map.get(v, v)]),
|
||||
name_source=dict(fmt=lambda n, s: [s] if s else [n], stars=1),
|
||||
install_deps=dict(fmt="--install-deps", style=ArgFormat.BOOLEAN),
|
||||
install_deps=dict(fmt="--include-deps", style=ArgFormat.BOOLEAN),
|
||||
inject_packages=dict(fmt=lambda v: v),
|
||||
force=dict(fmt="--force", style=ArgFormat.BOOLEAN),
|
||||
include_injected=dict(fmt="--include-injected", style=ArgFormat.BOOLEAN),
|
||||
|
||||
@@ -69,12 +69,13 @@ EXAMPLES = r'''
|
||||
executable: /opt/hp/tools/hponcfg
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import (
|
||||
CmdModuleHelper, ArgFormat
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
class HPOnCfg(CmdModuleHelper):
|
||||
module = dict(
|
||||
argument_spec=dict(
|
||||
src=dict(type='path', required=True, aliases=['path']),
|
||||
minfw=dict(type='str'),
|
||||
@@ -82,29 +83,24 @@ def main():
|
||||
verbose=dict(default=False, type='bool'),
|
||||
)
|
||||
)
|
||||
command_args_formats = dict(
|
||||
src=dict(fmt=["-f", "{0}"]),
|
||||
verbose=dict(fmt="-v", style=ArgFormat.BOOLEAN),
|
||||
minfw=dict(fmt=["-m", "{0}"]),
|
||||
)
|
||||
check_rc = True
|
||||
|
||||
# Consider every action a change (not idempotent yet!)
|
||||
changed = True
|
||||
def __init_module__(self):
|
||||
self.command = self.vars.executable
|
||||
# Consider every action a change (not idempotent yet!)
|
||||
self.changed = True
|
||||
|
||||
src = module.params['src']
|
||||
minfw = module.params['minfw']
|
||||
executable = module.params['executable']
|
||||
verbose = module.params['verbose']
|
||||
def __run__(self):
|
||||
self.run_command(params=['src', 'verbose', 'minfw'])
|
||||
|
||||
options = ' -f %s' % src
|
||||
|
||||
if verbose:
|
||||
options += ' -v'
|
||||
|
||||
if minfw:
|
||||
options += ' -m %s' % minfw
|
||||
|
||||
rc, stdout, stderr = module.run_command('%s %s' % (executable, options))
|
||||
|
||||
if rc != 0:
|
||||
module.fail_json(rc=rc, msg="Failed to run hponcfg", stdout=stdout, stderr=stderr)
|
||||
|
||||
module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
|
||||
def main():
|
||||
HPOnCfg.execute()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
175
plugins/modules/remote_management/redfish/ilo_redfish_config.py
Normal file
175
plugins/modules/remote_management/redfish/ilo_redfish_config.py
Normal file
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ilo_redfish_config
|
||||
short_description: Sets or updates configuration attributes on HPE iLO with Redfish OEM extensions
|
||||
version_added: 4.2.0
|
||||
description:
|
||||
- Builds Redfish URIs locally and sends them to iLO to
|
||||
set or update a configuration attribute.
|
||||
- For use with HPE iLO operations that require Redfish OEM extensions.
|
||||
options:
|
||||
category:
|
||||
required: true
|
||||
type: str
|
||||
description:
|
||||
- Command category to execute on iLO.
|
||||
choices: ['Manager']
|
||||
command:
|
||||
required: true
|
||||
description:
|
||||
- List of commands to execute on iLO.
|
||||
type: list
|
||||
elements: str
|
||||
baseuri:
|
||||
required: true
|
||||
description:
|
||||
- Base URI of iLO.
|
||||
type: str
|
||||
username:
|
||||
description:
|
||||
- User for authentication with iLO.
|
||||
type: str
|
||||
password:
|
||||
description:
|
||||
- Password for authentication with iLO.
|
||||
type: str
|
||||
auth_token:
|
||||
description:
|
||||
- Security token for authentication with OOB controller.
|
||||
type: str
|
||||
timeout:
|
||||
description:
|
||||
- Timeout in seconds for URL requests to iLO controller.
|
||||
default: 10
|
||||
type: int
|
||||
attribute_name:
|
||||
required: true
|
||||
description:
|
||||
- Name of the attribute to be configured.
|
||||
type: str
|
||||
attribute_value:
|
||||
required: false
|
||||
description:
|
||||
- Value of the attribute to be configured.
|
||||
type: str
|
||||
author:
|
||||
- "Bhavya B (@bhavya06)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Disable WINS Registration
|
||||
community.general.ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetWINSReg
|
||||
baseuri: 15.X.X.X
|
||||
username: Admin
|
||||
password: Testpass123
|
||||
attribute_name: WINSRegistration
|
||||
|
||||
- name: Set Time Zone
|
||||
community.general.ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetTimeZone
|
||||
baseuri: 15.X.X.X
|
||||
username: Admin
|
||||
password: Testpass123
|
||||
attribute_name: TimeZone
|
||||
attribute_value: Chennai
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message with action result or error description
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Action was successful"
|
||||
'''
|
||||
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
"Manager": ["SetTimeZone", "SetDNSserver", "SetDomainName", "SetNTPServers", "SetWINSReg"]
|
||||
}
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True, choices=list(
|
||||
CATEGORY_COMMANDS_ALL.keys())),
|
||||
command=dict(required=True, type='list', elements='str'),
|
||||
baseuri=dict(required=True),
|
||||
username=dict(),
|
||||
password=dict(no_log=True),
|
||||
auth_token=dict(no_log=True),
|
||||
attribute_name=dict(required=True),
|
||||
attribute_value=dict(),
|
||||
timeout=dict(type='int', default=10)
|
||||
),
|
||||
required_together=[
|
||||
('username', 'password'),
|
||||
],
|
||||
required_one_of=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
mutually_exclusive=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
supports_check_mode=False
|
||||
)
|
||||
|
||||
category = module.params['category']
|
||||
command_list = module.params['command']
|
||||
|
||||
creds = {"user": module.params['username'],
|
||||
"pswd": module.params['password'],
|
||||
"token": module.params['auth_token']}
|
||||
|
||||
timeout = module.params['timeout']
|
||||
|
||||
root_uri = "https://" + module.params['baseuri']
|
||||
rf_utils = iLORedfishUtils(creds, root_uri, timeout, module)
|
||||
mgr_attributes = {'mgr_attr_name': module.params['attribute_name'],
|
||||
'mgr_attr_value': module.params['attribute_value']}
|
||||
changed = False
|
||||
|
||||
offending = [
|
||||
cmd for cmd in command_list if cmd not in CATEGORY_COMMANDS_ALL[category]]
|
||||
|
||||
if offending:
|
||||
module.fail_json(msg=to_native("Invalid Command(s): '%s'. Allowed Commands = %s" % (
|
||||
offending, CATEGORY_COMMANDS_ALL[category])))
|
||||
|
||||
if category == "Manager":
|
||||
resource = rf_utils._find_managers_resource()
|
||||
if not resource['ret']:
|
||||
module.fail_json(msg=to_native(resource['msg']))
|
||||
|
||||
dispatch = dict(
|
||||
SetTimeZone=rf_utils.set_time_zone,
|
||||
SetDNSserver=rf_utils.set_dns_server,
|
||||
SetDomainName=rf_utils.set_domain_name,
|
||||
SetNTPServers=rf_utils.set_ntp_server,
|
||||
SetWINSReg=rf_utils.set_wins_registration
|
||||
)
|
||||
|
||||
for command in command_list:
|
||||
result[command] = dispatch[command](mgr_attributes)
|
||||
if 'changed' in result[command]:
|
||||
changed |= result[command]['changed']
|
||||
|
||||
module.exit_json(ilo_redfish_config=result, changed=changed)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
186
plugins/modules/remote_management/redfish/ilo_redfish_info.py
Normal file
186
plugins/modules/remote_management/redfish/ilo_redfish_info.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021-2022 Hewlett Packard Enterprise, Inc. All rights reserved.
|
||||
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ilo_redfish_info
|
||||
short_description: Gathers server information through iLO using Redfish APIs
|
||||
version_added: 4.2.0
|
||||
description:
|
||||
- Builds Redfish URIs locally and sends them to iLO to
|
||||
get information back.
|
||||
- For use with HPE iLO operations that require Redfish OEM extensions.
|
||||
options:
|
||||
category:
|
||||
required: true
|
||||
description:
|
||||
- List of categories to execute on iLO.
|
||||
type: list
|
||||
elements: str
|
||||
command:
|
||||
required: true
|
||||
description:
|
||||
- List of commands to execute on iLO.
|
||||
type: list
|
||||
elements: str
|
||||
baseuri:
|
||||
required: true
|
||||
description:
|
||||
- Base URI of iLO.
|
||||
type: str
|
||||
username:
|
||||
description:
|
||||
- User for authentication with iLO.
|
||||
type: str
|
||||
password:
|
||||
description:
|
||||
- Password for authentication with iLO.
|
||||
type: str
|
||||
auth_token:
|
||||
description:
|
||||
- Security token for authentication with iLO.
|
||||
type: str
|
||||
timeout:
|
||||
description:
|
||||
- Timeout in seconds for URL requests to iLO.
|
||||
default: 10
|
||||
type: int
|
||||
author:
|
||||
- "Bhavya B (@bhavya06)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Get iLO Sessions
|
||||
community.general.ilo_redfish_info:
|
||||
category: Sessions
|
||||
command: GetiLOSessions
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
register: result_sessions
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
ilo_redfish_info:
|
||||
description: Returns iLO sessions.
|
||||
type: dict
|
||||
contains:
|
||||
GetiLOSessions:
|
||||
description: Returns the iLO session msg and whether the function executed successfully.
|
||||
type: dict
|
||||
contains:
|
||||
ret:
|
||||
description: Check variable to see if the information was succesfully retrived.
|
||||
type: bool
|
||||
msg:
|
||||
description: Information of all active iLO sessions.
|
||||
type: list
|
||||
elements: dict
|
||||
contains:
|
||||
Description:
|
||||
description: Provides a description of the resource.
|
||||
type: str
|
||||
Id:
|
||||
description: The sessionId.
|
||||
type: str
|
||||
Name:
|
||||
description: The name of the resource.
|
||||
type: str
|
||||
UserName:
|
||||
description: Name to use to log in to the management processor.
|
||||
type: str
|
||||
returned: always
|
||||
'''
|
||||
|
||||
CATEGORY_COMMANDS_ALL = {
|
||||
"Sessions": ["GetiLOSessions"]
|
||||
}
|
||||
|
||||
CATEGORY_COMMANDS_DEFAULT = {
|
||||
"Sessions": "GetiLOSessions"
|
||||
}
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible_collections.community.general.plugins.module_utils.ilo_redfish_utils import iLORedfishUtils
|
||||
|
||||
|
||||
def main():
|
||||
result = {}
|
||||
category_list = []
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
category=dict(required=True, type='list', elements='str'),
|
||||
command=dict(required=True, type='list', elements='str'),
|
||||
baseuri=dict(required=True),
|
||||
username=dict(),
|
||||
password=dict(no_log=True),
|
||||
auth_token=dict(no_log=True),
|
||||
timeout=dict(type='int', default=10)
|
||||
),
|
||||
required_together=[
|
||||
('username', 'password'),
|
||||
],
|
||||
required_one_of=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
mutually_exclusive=[
|
||||
('username', 'auth_token'),
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
creds = {"user": module.params['username'],
|
||||
"pswd": module.params['password'],
|
||||
"token": module.params['auth_token']}
|
||||
|
||||
timeout = module.params['timeout']
|
||||
|
||||
root_uri = "https://" + module.params['baseuri']
|
||||
rf_utils = iLORedfishUtils(creds, root_uri, timeout, module)
|
||||
|
||||
# Build Category list
|
||||
if "all" in module.params['category']:
|
||||
for entry in CATEGORY_COMMANDS_ALL:
|
||||
category_list.append(entry)
|
||||
else:
|
||||
# one or more categories specified
|
||||
category_list = module.params['category']
|
||||
|
||||
for category in category_list:
|
||||
command_list = []
|
||||
# Build Command list for each Category
|
||||
if category in CATEGORY_COMMANDS_ALL:
|
||||
if not module.params['command']:
|
||||
# True if we don't specify a command --> use default
|
||||
command_list.append(CATEGORY_COMMANDS_DEFAULT[category])
|
||||
elif "all" in module.params['command']:
|
||||
for entry in CATEGORY_COMMANDS_ALL[category]:
|
||||
command_list.append(entry)
|
||||
# one or more commands
|
||||
else:
|
||||
command_list = module.params['command']
|
||||
# Verify that all commands are valid
|
||||
for cmd in command_list:
|
||||
# Fail if even one command given is invalid
|
||||
if cmd not in CATEGORY_COMMANDS_ALL[category]:
|
||||
module.fail_json(msg="Invalid Command: %s" % cmd)
|
||||
else:
|
||||
# Fail if even one category given is invalid
|
||||
module.fail_json(msg="Invalid Category: %s" % category)
|
||||
|
||||
# Organize by Categories / Commands
|
||||
if category == "Sessions":
|
||||
for command in command_list:
|
||||
if command == "GetiLOSessions":
|
||||
result[command] = rf_utils.get_ilo_sessions()
|
||||
|
||||
module.exit_json(ilo_redfish_info=result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
184
plugins/modules/source_control/gitlab/gitlab_branch.py
Normal file
184
plugins/modules/source_control/gitlab/gitlab_branch.py
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2021, Werner Dijkerman (ikben@werner-dijkerman.nl)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: gitlab_branch
|
||||
short_description: Create or delete a branch
|
||||
version_added: 4.2.0
|
||||
description:
|
||||
- This module allows to create or delete branches.
|
||||
author:
|
||||
- paytroff (@paytroff)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- Create or delete branch.
|
||||
default: present
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
project:
|
||||
description:
|
||||
- The path or name of the project.
|
||||
required: true
|
||||
type: str
|
||||
branch:
|
||||
description:
|
||||
- The name of the branch that needs to be created.
|
||||
required: true
|
||||
type: str
|
||||
ref_branch:
|
||||
description:
|
||||
- Reference branch to create from.
|
||||
- This must be specified if I(state=present).
|
||||
type: str
|
||||
'''
|
||||
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create branch branch2 from main
|
||||
community.general.gitlab_branch:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "group1/project1"
|
||||
branch: branch2
|
||||
ref_branch: main
|
||||
state: present
|
||||
|
||||
- name: Delete branch branch2
|
||||
community.general.gitlab_branch:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "group1/project1"
|
||||
branch: branch2
|
||||
state: absent
|
||||
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
GITLAB_IMP_ERR = None
|
||||
try:
|
||||
import gitlab
|
||||
HAS_GITLAB_PACKAGE = True
|
||||
except Exception:
|
||||
GITLAB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
|
||||
class GitlabBranch(object):
|
||||
|
||||
def __init__(self, module, project, gitlab_instance):
|
||||
self.repo = gitlab_instance
|
||||
self._module = module
|
||||
self.project = self.get_project(project)
|
||||
|
||||
def get_project(self, project):
|
||||
try:
|
||||
return self.repo.projects.get(project)
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def get_branch(self, branch):
|
||||
try:
|
||||
return self.project.branches.get(branch)
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def create_branch(self, branch, ref_branch):
|
||||
return self.project.branches.create({'branch': branch, 'ref': ref_branch})
|
||||
|
||||
def delete_branch(self, branch):
|
||||
branch.unprotect()
|
||||
return branch.delete()
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(
|
||||
project=dict(type='str', required=True),
|
||||
branch=dict(type='str', required=True),
|
||||
ref_branch=dict(type='str', required=False),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
)
|
||||
|
||||
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'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
required_if=[
|
||||
['state', 'present', ['ref_branch'], True],
|
||||
],
|
||||
supports_check_mode=False
|
||||
)
|
||||
|
||||
project = module.params['project']
|
||||
branch = module.params['branch']
|
||||
ref_branch = module.params['ref_branch']
|
||||
state = module.params['state']
|
||||
|
||||
if not HAS_GITLAB_PACKAGE:
|
||||
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
|
||||
|
||||
gitlab_version = gitlab.__version__
|
||||
if LooseVersion(gitlab_version) < LooseVersion('2.3.0'):
|
||||
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)
|
||||
|
||||
if not this_branch and state == "present":
|
||||
r_branch = this_gitlab.get_branch(ref_branch)
|
||||
if not r_branch:
|
||||
module.fail_json(msg="Ref branch {b} not exist.".format(b=ref_branch))
|
||||
this_gitlab.create_branch(branch, ref_branch)
|
||||
module.exit_json(changed=True, msg="Created the branch {b}.".format(b=branch))
|
||||
elif this_branch and state == "present":
|
||||
module.exit_json(changed=False, msg="Branch {b} already exist".format(b=branch))
|
||||
elif this_branch and state == "absent":
|
||||
try:
|
||||
this_gitlab.delete_branch(this_branch)
|
||||
module.exit_json(changed=True, msg="Branch {b} deleted.".format(b=branch))
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Error delete branch.", exception=traceback.format_exc())
|
||||
else:
|
||||
module.exit_json(changed=False, msg="No changes are needed.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -14,7 +14,7 @@ DOCUMENTATION = '''
|
||||
module: gitlab_deploy_key
|
||||
short_description: Manages GitLab project deploy keys.
|
||||
description:
|
||||
- Adds, updates and removes project deploy keys
|
||||
- Adds, updates and removes project deploy keys
|
||||
author:
|
||||
- Marcus Watkins (@marwatk)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
@@ -22,13 +22,10 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab token for logging in.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- Id or Full path of project in the form of group/name.
|
||||
@@ -126,7 +123,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import find_project, gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_project, gitlab_authentication
|
||||
|
||||
|
||||
class GitLabDeployKey(object):
|
||||
@@ -238,8 +235,8 @@ class GitLabDeployKey(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
project=dict(type='str', required=True),
|
||||
key=dict(type='str', required=True, no_log=False),
|
||||
@@ -251,13 +248,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token']
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password']
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -22,13 +22,10 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab token for logging in.
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Name of the group you want to create.
|
||||
@@ -83,6 +80,12 @@ options:
|
||||
- Require all users in this group to setup two-factor authentication.
|
||||
type: bool
|
||||
version_added: 3.7.0
|
||||
avatar_path:
|
||||
description:
|
||||
- Absolute path image to configure avatar. File size should not exceed 200 kb.
|
||||
- This option is only used on creation, not for updates.
|
||||
type: path
|
||||
version_added: 4.2.0
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -169,7 +172,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, gitlab_authentication
|
||||
|
||||
|
||||
class GitLabGroup(object):
|
||||
@@ -212,6 +215,13 @@ class GitLabGroup(object):
|
||||
if options.get('require_two_factor_authentication'):
|
||||
payload['require_two_factor_authentication'] = options['require_two_factor_authentication']
|
||||
group = self.create_group(payload)
|
||||
|
||||
# add avatar to group
|
||||
if options['avatar_path']:
|
||||
try:
|
||||
group.avatar = open(options['avatar_path'], 'rb')
|
||||
except IOError as e:
|
||||
self._module.fail_json(msg='Cannot open {0}: {1}'.format(options['avatar_path'], e))
|
||||
changed = True
|
||||
else:
|
||||
changed, group = self.update_group(self.group_object, {
|
||||
@@ -296,8 +306,8 @@ class GitLabGroup(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
name=dict(type='str', required=True),
|
||||
path=dict(type='str'),
|
||||
description=dict(type='str'),
|
||||
@@ -308,19 +318,23 @@ def main():
|
||||
auto_devops_enabled=dict(type='bool'),
|
||||
subgroup_creation_level=dict(type='str', choices=['maintainer', 'owner']),
|
||||
require_two_factor_authentication=dict(type='bool'),
|
||||
avatar_path=dict(type='path'),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -335,6 +349,7 @@ def main():
|
||||
auto_devops_enabled = module.params['auto_devops_enabled']
|
||||
subgroup_creation_level = module.params['subgroup_creation_level']
|
||||
require_two_factor_authentication = module.params['require_two_factor_authentication']
|
||||
avatar_path = module.params['avatar_path']
|
||||
|
||||
if not HAS_GITLAB_PACKAGE:
|
||||
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
|
||||
@@ -373,6 +388,7 @@ def main():
|
||||
"auto_devops_enabled": auto_devops_enabled,
|
||||
"subgroup_creation_level": subgroup_creation_level,
|
||||
"require_two_factor_authentication": require_two_factor_authentication,
|
||||
"avatar_path": avatar_path,
|
||||
}):
|
||||
module.exit_json(changed=True, msg="Successfully created or updated the group %s" % group_name, group=gitlab_group.group_object._attrs)
|
||||
else:
|
||||
|
||||
@@ -12,78 +12,76 @@ DOCUMENTATION = r'''
|
||||
module: gitlab_group_members
|
||||
short_description: Manage group members on GitLab Server
|
||||
description:
|
||||
- This module allows to add and remove members to/from a group, or change a member's access level in a group on GitLab.
|
||||
- This module allows to add and remove members to/from a group, or change a member's access level in a group on GitLab.
|
||||
version_added: '1.2.0'
|
||||
author: Zainab Alsaffar (@zanssa)
|
||||
requirements:
|
||||
- python-gitlab python module <= 1.15.0
|
||||
- administrator rights on the GitLab server
|
||||
extends_documentation_fragment: community.general.auth_basic
|
||||
- python-gitlab python module <= 1.15.0
|
||||
- administrator rights on the GitLab server
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- A personal access token to authenticate with the GitLab API.
|
||||
required: true
|
||||
gitlab_group:
|
||||
description:
|
||||
- The C(full_path) of the GitLab group the member is added to/removed from.
|
||||
- Setting this to C(name) or C(path) is deprecated and will be removed in community.general 6.0.0. Use C(full_path) instead.
|
||||
required: true
|
||||
type: str
|
||||
gitlab_user:
|
||||
description:
|
||||
- A username or a list of usernames to add to/remove from the GitLab group.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
type: list
|
||||
elements: str
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
|
||||
gitlab_users_access:
|
||||
description:
|
||||
- Provide a list of user to access level mappings.
|
||||
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
|
||||
- Mutually exclusive with I(gitlab_user) and I(access_level).
|
||||
- Use together with I(purge_users) to remove all users not specified here from the group.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: A username or a list of usernames to add to/remove from the GitLab group.
|
||||
type: str
|
||||
gitlab_group:
|
||||
description:
|
||||
- The C(full_path) of the GitLab group the member is added to/removed from.
|
||||
- Setting this to C(name) or C(path) is deprecated and will be removed in community.general 6.0.0. Use C(full_path) instead.
|
||||
required: true
|
||||
type: str
|
||||
gitlab_user:
|
||||
access_level:
|
||||
description:
|
||||
- A username or a list of usernames to add to/remove from the GitLab group.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
type: list
|
||||
elements: str
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
|
||||
gitlab_users_access:
|
||||
description:
|
||||
- Provide a list of user to access level mappings.
|
||||
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
|
||||
- Mutually exclusive with I(gitlab_user) and I(access_level).
|
||||
- Use together with I(purge_users) to remove all users not specified here from the group.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: A username or a list of usernames to add to/remove from the GitLab group.
|
||||
type: str
|
||||
required: true
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
|
||||
required: true
|
||||
version_added: 3.6.0
|
||||
state:
|
||||
description:
|
||||
- State of the member in the group.
|
||||
- On C(present), it adds a user to a GitLab group.
|
||||
- On C(absent), it removes a user from a GitLab group.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
purge_users:
|
||||
description:
|
||||
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
|
||||
If omitted do not purge orphaned members.
|
||||
- Is only used when I(state=present).
|
||||
type: list
|
||||
elements: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
|
||||
version_added: 3.6.0
|
||||
required: true
|
||||
version_added: 3.6.0
|
||||
state:
|
||||
description:
|
||||
- State of the member in the group.
|
||||
- On C(present), it adds a user to a GitLab group.
|
||||
- On C(absent), it removes a user from a GitLab group.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
purge_users:
|
||||
description:
|
||||
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
|
||||
If omitted do not purge orphaned members.
|
||||
- Is only used when I(state=present).
|
||||
type: list
|
||||
elements: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer', 'owner']
|
||||
version_added: 3.6.0
|
||||
notes:
|
||||
- Supports C(check_mode).
|
||||
- Supports C(check_mode).
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -155,7 +153,7 @@ RETURN = r''' # '''
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
import traceback
|
||||
|
||||
@@ -241,8 +239,8 @@ class GitLabGroup(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', required=True, no_log=True),
|
||||
gitlab_group=dict(type='str', required=True),
|
||||
gitlab_user=dict(type='list', elements='str'),
|
||||
state=dict(type='str', default='present', choices=['present', 'absent']),
|
||||
@@ -262,16 +260,19 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['gitlab_user', 'gitlab_users_access'],
|
||||
['access_level', 'gitlab_users_access'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
['gitlab_user', 'access_level'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token'],
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
|
||||
['gitlab_user', 'gitlab_users_access'],
|
||||
],
|
||||
required_if=[
|
||||
|
||||
@@ -24,6 +24,7 @@ requirements:
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
state:
|
||||
@@ -32,11 +33,6 @@ options:
|
||||
default: present
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
api_token:
|
||||
description:
|
||||
- GitLab access token with API permissions.
|
||||
required: true
|
||||
type: str
|
||||
group:
|
||||
description:
|
||||
- The path and name of the group.
|
||||
@@ -144,7 +140,7 @@ except Exception:
|
||||
GITLAB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
|
||||
class GitlabGroupVariables(object):
|
||||
@@ -268,8 +264,8 @@ def native_python_main(this_gitlab, purge, var_list, state, module):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(
|
||||
api_token=dict(type='str', required=True, no_log=True),
|
||||
group=dict(type='str', required=True),
|
||||
purge=dict(type='bool', required=False, default=False),
|
||||
vars=dict(type='dict', required=False, default=dict(), no_log=True),
|
||||
@@ -280,13 +276,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ DOCUMENTATION = '''
|
||||
module: gitlab_hook
|
||||
short_description: Manages GitLab project hooks.
|
||||
description:
|
||||
- Adds, updates and removes project hook
|
||||
- Adds, updates and removes project hook
|
||||
author:
|
||||
- Marcus Watkins (@marwatk)
|
||||
- Guillaume Martinez (@Lunik)
|
||||
@@ -23,13 +23,10 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab token for logging in.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- Id or Full path of the project in the form of group/name.
|
||||
@@ -176,7 +173,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import find_project, gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_project, gitlab_authentication
|
||||
|
||||
|
||||
class GitLabHook(object):
|
||||
@@ -297,8 +294,8 @@ class GitLabHook(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
state=dict(type='str', default="present", choices=["absent", "present"]),
|
||||
project=dict(type='str', required=True),
|
||||
hook_url=dict(type='str', required=True),
|
||||
@@ -319,13 +316,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token']
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password']
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -23,13 +23,10 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab token for logging in.
|
||||
type: str
|
||||
group:
|
||||
description:
|
||||
- Id or the full path of the group of which this projects belongs to.
|
||||
@@ -162,6 +159,18 @@ options:
|
||||
- Enable shared runners for this project.
|
||||
type: bool
|
||||
version_added: "3.7.0"
|
||||
avatar_path:
|
||||
description:
|
||||
- Absolute path image to configure avatar. File size should not exceed 200 kb.
|
||||
- This option is only used on creation, not for updates.
|
||||
type: path
|
||||
version_added: "4.2.0"
|
||||
default_branch:
|
||||
description:
|
||||
- Default branch name for a new project.
|
||||
- This option is only used on creation, not for updates. This is also only used if I(initialize_with_readme=true).
|
||||
type: str
|
||||
version_added: "4.2.0"
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -197,6 +206,19 @@ EXAMPLES = r'''
|
||||
initialize_with_readme: true
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
|
||||
- name: get the initial root password
|
||||
ansible.builtin.shell: |
|
||||
grep 'Password:' /etc/gitlab/initial_root_password | sed -e 's/Password\: \(.*\)/\1/'
|
||||
register: initial_root_password
|
||||
|
||||
- name: Create a GitLab Project using a username/password via oauth_token
|
||||
community.general.gitlab_project:
|
||||
api_url: https://gitlab.example.com/
|
||||
api_username: root
|
||||
api_password: "{{ initial_root_password }}"
|
||||
name: my_second_project
|
||||
group: "10481470"
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
@@ -237,7 +259,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, find_project, gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, find_project, gitlab_authentication
|
||||
|
||||
|
||||
class GitLabProject(object):
|
||||
@@ -280,8 +302,19 @@ class GitLabProject(object):
|
||||
})
|
||||
if options['initialize_with_readme']:
|
||||
project_options['initialize_with_readme'] = options['initialize_with_readme']
|
||||
if options['default_branch']:
|
||||
project_options['default_branch'] = options['default_branch']
|
||||
|
||||
project_options = self.get_options_with_value(project_options)
|
||||
project = self.create_project(namespace, project_options)
|
||||
|
||||
# add avatar to project
|
||||
if options['avatar_path']:
|
||||
try:
|
||||
project.avatar = open(options['avatar_path'], 'rb')
|
||||
except IOError as e:
|
||||
self._module.fail_json(msg='Cannot open {0}: {1}'.format(options['avatar_path'], e))
|
||||
|
||||
changed = True
|
||||
else:
|
||||
changed, project = self.update_project(self.project_object, project_options)
|
||||
@@ -363,13 +396,14 @@ class GitLabProject(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
group=dict(type='str'),
|
||||
name=dict(type='str', required=True),
|
||||
path=dict(type='str'),
|
||||
description=dict(type='str'),
|
||||
initialize_with_readme=dict(type='bool', default=False),
|
||||
default_branch=dict(type='str'),
|
||||
issues_enabled=dict(type='bool', default=True),
|
||||
merge_requests_enabled=dict(type='bool', default=True),
|
||||
merge_method=dict(type='str', default='merge', choices=["merge", "rebase_merge", "ff"]),
|
||||
@@ -388,20 +422,24 @@ def main():
|
||||
squash_option=dict(type='str', choices=['never', 'always', 'default_off', 'default_on']),
|
||||
ci_config_path=dict(type='str'),
|
||||
shared_runners_enabled=dict(type='bool'),
|
||||
avatar_path=dict(type='path'),
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
['group', 'username'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -429,6 +467,11 @@ def main():
|
||||
squash_option = module.params['squash_option']
|
||||
ci_config_path = module.params['ci_config_path']
|
||||
shared_runners_enabled = module.params['shared_runners_enabled']
|
||||
avatar_path = module.params['avatar_path']
|
||||
default_branch = module.params['default_branch']
|
||||
|
||||
if default_branch and not initialize_with_readme:
|
||||
module.fail_json(msg="Param default_branch need param initialize_with_readme set to true")
|
||||
|
||||
if not HAS_GITLAB_PACKAGE:
|
||||
module.fail_json(msg=missing_required_lib("python-gitlab"), exception=GITLAB_IMP_ERR)
|
||||
@@ -480,6 +523,7 @@ def main():
|
||||
"path": project_path,
|
||||
"description": project_description,
|
||||
"initialize_with_readme": initialize_with_readme,
|
||||
"default_branch": default_branch,
|
||||
"issues_enabled": issues_enabled,
|
||||
"merge_requests_enabled": merge_requests_enabled,
|
||||
"merge_method": merge_method,
|
||||
@@ -496,6 +540,7 @@ def main():
|
||||
"squash_option": squash_option,
|
||||
"ci_config_path": ci_config_path,
|
||||
"shared_runners_enabled": shared_runners_enabled,
|
||||
"avatar_path": avatar_path,
|
||||
}):
|
||||
|
||||
module.exit_json(changed=True, msg="Successfully created or updated the project %s" % project_name, project=gitlab_project.project_object._attrs)
|
||||
|
||||
@@ -14,95 +14,75 @@ module: gitlab_project_members
|
||||
short_description: Manage project members on GitLab Server
|
||||
version_added: 2.2.0
|
||||
description:
|
||||
- This module allows to add and remove members to/from a project, or change a member's access level in a project on GitLab.
|
||||
- This module allows to add and remove members to/from a project, or change a member's access level in a project on GitLab.
|
||||
author:
|
||||
- Sergey Mikhaltsov (@metanovii)
|
||||
- Zainab Alsaffar (@zanssa)
|
||||
- Sergey Mikhaltsov (@metanovii)
|
||||
- Zainab Alsaffar (@zanssa)
|
||||
requirements:
|
||||
- python-gitlab python module <= 1.15.0
|
||||
- owner or maintainer rights to project on the GitLab server
|
||||
- python-gitlab python module <= 1.15.0
|
||||
- owner or maintainer rights to project on the GitLab server
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- A personal access token to authenticate with the GitLab API.
|
||||
project:
|
||||
description:
|
||||
- The name (or full path) of the GitLab project the member is added to/removed from.
|
||||
required: true
|
||||
type: str
|
||||
gitlab_user:
|
||||
description:
|
||||
- A username or a list of usernames to add to/remove from the GitLab project.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
type: list
|
||||
elements: str
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer']
|
||||
gitlab_users_access:
|
||||
description:
|
||||
- Provide a list of user to access level mappings.
|
||||
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
|
||||
- Mutually exclusive with I(gitlab_user) and I(access_level).
|
||||
- Use together with I(purge_users) to remove all users not specified here from the project.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: A username or a list of usernames to add to/remove from the GitLab project.
|
||||
type: str
|
||||
required: true
|
||||
type: str
|
||||
validate_certs:
|
||||
access_level:
|
||||
description:
|
||||
- Whether or not to validate TLS/SSL certificates when supplying a HTTPS endpoint.
|
||||
- Should only be set to C(false) if you can guarantee that you are talking to the correct server
|
||||
and no man-in-the-middle attack can happen.
|
||||
default: true
|
||||
type: bool
|
||||
api_username:
|
||||
description:
|
||||
- The username to use for authentication against the API.
|
||||
type: str
|
||||
api_password:
|
||||
description:
|
||||
- The password to use for authentication against the API.
|
||||
type: str
|
||||
api_url:
|
||||
description:
|
||||
- The resolvable endpoint for the API.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- The name (or full path) of the GitLab project the member is added to/removed from.
|
||||
required: true
|
||||
type: str
|
||||
gitlab_user:
|
||||
description:
|
||||
- A username or a list of usernames to add to/remove from the GitLab project.
|
||||
- Mutually exclusive with I(gitlab_users_access).
|
||||
type: list
|
||||
elements: str
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer']
|
||||
gitlab_users_access:
|
||||
description:
|
||||
- Provide a list of user to access level mappings.
|
||||
- Every dictionary in this list specifies a user (by username) and the access level the user should have.
|
||||
- Mutually exclusive with I(gitlab_user) and I(access_level).
|
||||
- Use together with I(purge_users) to remove all users not specified here from the project.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: A username or a list of usernames to add to/remove from the GitLab project.
|
||||
type: str
|
||||
required: true
|
||||
access_level:
|
||||
description:
|
||||
- The access level for the user.
|
||||
- Required if I(state=present), user state is set to present.
|
||||
type: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer']
|
||||
required: true
|
||||
version_added: 3.7.0
|
||||
state:
|
||||
description:
|
||||
- State of the member in the project.
|
||||
- On C(present), it adds a user to a GitLab project.
|
||||
- On C(absent), it removes a user from a GitLab project.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
purge_users:
|
||||
description:
|
||||
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
|
||||
If omitted do not purge orphaned members.
|
||||
- Is only used when I(state=present).
|
||||
type: list
|
||||
elements: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer']
|
||||
version_added: 3.7.0
|
||||
required: true
|
||||
version_added: 3.7.0
|
||||
state:
|
||||
description:
|
||||
- State of the member in the project.
|
||||
- On C(present), it adds a user to a GitLab project.
|
||||
- On C(absent), it removes a user from a GitLab project.
|
||||
choices: ['present', 'absent']
|
||||
default: 'present'
|
||||
type: str
|
||||
purge_users:
|
||||
description:
|
||||
- Adds/remove users of the given access_level to match the given I(gitlab_user)/I(gitlab_users_access) list.
|
||||
If omitted do not purge orphaned members.
|
||||
- Is only used when I(state=present).
|
||||
type: list
|
||||
elements: str
|
||||
choices: ['guest', 'reporter', 'developer', 'maintainer']
|
||||
version_added: 3.7.0
|
||||
notes:
|
||||
- Supports C(check_mode).
|
||||
- Supports C(check_mode).
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
@@ -176,7 +156,7 @@ RETURN = r''' # '''
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
import traceback
|
||||
|
||||
@@ -257,8 +237,8 @@ class GitLabProjectMembers(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', required=True, no_log=True),
|
||||
project=dict(type='str', required=True),
|
||||
gitlab_user=dict(type='list', elements='str'),
|
||||
state=dict(type='str', default='present', choices=['present', 'absent']),
|
||||
@@ -280,7 +260,10 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
['gitlab_user', 'gitlab_users_access'],
|
||||
['access_level', 'gitlab_users_access'],
|
||||
],
|
||||
@@ -289,7 +272,7 @@ def main():
|
||||
['gitlab_user', 'access_level'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token'],
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
|
||||
['gitlab_user', 'gitlab_users_access'],
|
||||
],
|
||||
required_if=[
|
||||
|
||||
@@ -20,7 +20,8 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab python module
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
state:
|
||||
@@ -30,11 +31,6 @@ options:
|
||||
default: present
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
api_token:
|
||||
description:
|
||||
- GitLab access token with API permissions.
|
||||
required: true
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- The path and name of the project.
|
||||
@@ -143,7 +139,7 @@ except Exception:
|
||||
GITLAB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
|
||||
class GitlabProjectVariables(object):
|
||||
@@ -270,8 +266,8 @@ def native_python_main(this_gitlab, purge, var_list, state, module):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(
|
||||
api_token=dict(type='str', required=True, no_log=True),
|
||||
project=dict(type='str', required=True),
|
||||
purge=dict(type='bool', required=False, default=False),
|
||||
vars=dict(type='dict', required=False, default=dict(), no_log=True),
|
||||
@@ -282,13 +278,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
@@ -18,7 +18,8 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 2.3.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
state:
|
||||
@@ -27,11 +28,6 @@ options:
|
||||
default: present
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
api_token:
|
||||
description:
|
||||
- GitLab access token with API permissions.
|
||||
required: true
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- The path and name of the project.
|
||||
@@ -87,7 +83,7 @@ except Exception:
|
||||
GITLAB_IMP_ERR = traceback.format_exc()
|
||||
HAS_GITLAB_PACKAGE = False
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
|
||||
class GitlabProtectedBranch(object):
|
||||
@@ -141,8 +137,8 @@ class GitlabProtectedBranch(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(
|
||||
api_token=dict(type='str', required=True, no_log=True),
|
||||
project=dict(type='str', required=True),
|
||||
name=dict(type='str', required=True),
|
||||
merge_access_levels=dict(type='str', default="maintainer", choices=["maintainer", "developer", "nobody"]),
|
||||
@@ -154,13 +150,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
@@ -32,13 +32,10 @@ requirements:
|
||||
- python >= 2.7
|
||||
- python-gitlab >= 1.5.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- Your private token to interact with the GitLab API.
|
||||
type: str
|
||||
project:
|
||||
description:
|
||||
- ID or full path of the project in the form of group/name.
|
||||
@@ -186,7 +183,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, gitlab_authentication
|
||||
|
||||
try:
|
||||
cmp
|
||||
@@ -323,8 +320,8 @@ class GitLabRunner(object):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
description=dict(type='str', required=True, aliases=["name"]),
|
||||
active=dict(type='bool', default=True),
|
||||
owned=dict(type='bool', default=False),
|
||||
@@ -342,13 +339,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token'],
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token'],
|
||||
],
|
||||
required_if=[
|
||||
('state', 'present', ['registration_token']),
|
||||
|
||||
@@ -30,13 +30,10 @@ requirements:
|
||||
- python-gitlab python module
|
||||
- administrator rights on the GitLab server
|
||||
extends_documentation_fragment:
|
||||
- community.general.auth_basic
|
||||
- community.general.auth_basic
|
||||
- community.general.gitlab
|
||||
|
||||
options:
|
||||
api_token:
|
||||
description:
|
||||
- GitLab token for logging in.
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Name of the user you want to create.
|
||||
@@ -238,7 +235,7 @@ from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import find_group, gitlab_authentication
|
||||
from ansible_collections.community.general.plugins.module_utils.gitlab import auth_argument_spec, find_group, gitlab_authentication
|
||||
|
||||
|
||||
class GitLabUser(object):
|
||||
@@ -579,8 +576,8 @@ def sanitize_arguments(arguments):
|
||||
|
||||
def main():
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(auth_argument_spec())
|
||||
argument_spec.update(dict(
|
||||
api_token=dict(type='str', no_log=True),
|
||||
name=dict(type='str'),
|
||||
state=dict(type='str', default="present", choices=["absent", "present", "blocked", "unblocked"]),
|
||||
username=dict(type='str', required=True),
|
||||
@@ -603,13 +600,16 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
mutually_exclusive=[
|
||||
['api_username', 'api_token'],
|
||||
['api_password', 'api_token'],
|
||||
['api_username', 'api_oauth_token'],
|
||||
['api_username', 'api_job_token'],
|
||||
['api_token', 'api_oauth_token'],
|
||||
['api_token', 'api_job_token'],
|
||||
],
|
||||
required_together=[
|
||||
['api_username', 'api_password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['api_username', 'api_token']
|
||||
['api_username', 'api_token', 'api_oauth_token', 'api_job_token']
|
||||
],
|
||||
supports_check_mode=True,
|
||||
required_if=(
|
||||
|
||||
@@ -183,7 +183,7 @@ def _fs_exists(module, filesystem):
|
||||
:return: True or False.
|
||||
"""
|
||||
lsfs_cmd = module.get_bin_path('lsfs', True)
|
||||
rc, lsfs_out, err = module.run_command("%s -l %s" % (lsfs_cmd, filesystem))
|
||||
rc, lsfs_out, err = module.run_command([lsfs_cmd, "-l", filesystem])
|
||||
if rc == 1:
|
||||
if re.findall("No record matching", err):
|
||||
return False
|
||||
@@ -206,8 +206,7 @@ def _check_nfs_device(module, nfs_host, device):
|
||||
:return: True or False.
|
||||
"""
|
||||
showmount_cmd = module.get_bin_path('showmount', True)
|
||||
rc, showmount_out, err = module.run_command(
|
||||
"%s -a %s" % (showmount_cmd, nfs_host))
|
||||
rc, showmount_out, err = module.run_command([showmount_cmd, "-a", nfs_host])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to run showmount. Error message: %s" % err)
|
||||
else:
|
||||
@@ -229,11 +228,11 @@ def _validate_vg(module, vg):
|
||||
None (VG does not exist), message.
|
||||
"""
|
||||
lsvg_cmd = module.get_bin_path('lsvg', True)
|
||||
rc, current_active_vgs, err = module.run_command("%s -o" % lsvg_cmd)
|
||||
rc, current_active_vgs, err = module.run_command([lsvg_cmd, "-o"])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing %s command." % lsvg_cmd)
|
||||
|
||||
rc, current_all_vgs, err = module.run_command("%s" % lsvg_cmd)
|
||||
rc, current_all_vgs, err = module.run_command([lsvg_cmd, "%s"])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing %s command." % lsvg_cmd)
|
||||
|
||||
@@ -253,7 +252,7 @@ def resize_fs(module, filesystem, size):
|
||||
|
||||
chfs_cmd = module.get_bin_path('chfs', True)
|
||||
if not module.check_mode:
|
||||
rc, chfs_out, err = module.run_command('%s -a size="%s" %s' % (chfs_cmd, size, filesystem))
|
||||
rc, chfs_out, err = module.run_command([chfs_cmd, "-a", "size=%s" % size, filesystem])
|
||||
|
||||
if rc == 28:
|
||||
changed = False
|
||||
@@ -338,8 +337,7 @@ def create_fs(
|
||||
# Creates a NFS file system.
|
||||
mknfsmnt_cmd = module.get_bin_path('mknfsmnt', True)
|
||||
if not module.check_mode:
|
||||
rc, mknfsmnt_out, err = module.run_command('%s -f "%s" %s -h "%s" -t "%s" "%s" -w "bg"' % (
|
||||
mknfsmnt_cmd, filesystem, device, nfs_server, permissions, auto_mount))
|
||||
rc, mknfsmnt_out, err = module.run_command([mknfsmnt_cmd, "-f", filesystem, device, "-h", nfs_server, "-t", permissions, auto_mount, "-w", "bg"])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to run mknfsmnt. Error message: %s" % err)
|
||||
else:
|
||||
@@ -357,8 +355,7 @@ def create_fs(
|
||||
# Creates a LVM file system.
|
||||
crfs_cmd = module.get_bin_path('crfs', True)
|
||||
if not module.check_mode:
|
||||
cmd = "%s -v %s -m %s %s %s %s %s %s -p %s %s -a %s" % (
|
||||
crfs_cmd, fs_type, filesystem, vg, device, mount_group, auto_mount, account_subsystem, permissions, size, attributes)
|
||||
cmd = [crfs_cmd, "-v", fs_type, "-m", filesystem, vg, device, mount_group, auto_mount, account_subsystem, "-p", permissions, size, "-a", attributes]
|
||||
rc, crfs_out, err = module.run_command(cmd)
|
||||
|
||||
if rc == 10:
|
||||
@@ -392,7 +389,7 @@ def remove_fs(module, filesystem, rm_mount_point):
|
||||
|
||||
rmfs_cmd = module.get_bin_path('rmfs', True)
|
||||
if not module.check_mode:
|
||||
cmd = "%s -r %s %s" % (rmfs_cmd, rm_mount_point, filesystem)
|
||||
cmd = [rmfs_cmd, "-r", rm_mount_point, filesystem]
|
||||
rc, rmfs_out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to run %s. Error message: %s" % (cmd, err))
|
||||
@@ -415,8 +412,7 @@ def mount_fs(module, filesystem):
|
||||
mount_cmd = module.get_bin_path('mount', True)
|
||||
|
||||
if not module.check_mode:
|
||||
rc, mount_out, err = module.run_command(
|
||||
"%s %s" % (mount_cmd, filesystem))
|
||||
rc, mount_out, err = module.run_command([mount_cmd, filesystem])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to run mount. Error message: %s" % err)
|
||||
else:
|
||||
@@ -436,7 +432,7 @@ def unmount_fs(module, filesystem):
|
||||
unmount_cmd = module.get_bin_path('unmount', True)
|
||||
|
||||
if not module.check_mode:
|
||||
rc, unmount_out, err = module.run_command("%s %s" % (unmount_cmd, filesystem))
|
||||
rc, unmount_out, err = module.run_command([unmount_cmd, filesystem])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to run unmount. Error message: %s" % err)
|
||||
else:
|
||||
|
||||
@@ -97,7 +97,7 @@ def _validate_pv(module, vg, pvs):
|
||||
"""
|
||||
|
||||
lspv_cmd = module.get_bin_path('lspv', True)
|
||||
rc, current_lspv, stderr = module.run_command("%s" % lspv_cmd)
|
||||
rc, current_lspv, stderr = module.run_command([lspv_cmd])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing 'lspv' command.", rc=rc, stdout=current_lspv, stderr=stderr)
|
||||
|
||||
@@ -116,7 +116,7 @@ def _validate_pv(module, vg, pvs):
|
||||
# Disk None, looks free.
|
||||
# Check if PV is not already in use by Oracle ASM.
|
||||
lquerypv_cmd = module.get_bin_path('lquerypv', True)
|
||||
rc, current_lquerypv, stderr = module.run_command("%s -h /dev/%s 20 10" % (lquerypv_cmd, pv))
|
||||
rc, current_lquerypv, stderr = module.run_command([lquerypv_cmd, "-h", "/dev/%s" % pv, "20", "10"])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing lquerypv command.", rc=rc, stdout=current_lquerypv, stderr=stderr)
|
||||
|
||||
@@ -144,11 +144,11 @@ def _validate_vg(module, vg):
|
||||
None (VG does not exist), message.
|
||||
"""
|
||||
lsvg_cmd = module.get_bin_path('lsvg', True)
|
||||
rc, current_active_vgs, err = module.run_command("%s -o" % lsvg_cmd)
|
||||
rc, current_active_vgs, err = module.run_command([lsvg_cmd, "-o"])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing '%s' command." % lsvg_cmd)
|
||||
|
||||
rc, current_all_vgs, err = module.run_command("%s" % lsvg_cmd)
|
||||
rc, current_all_vgs, err = module.run_command([lsvg_cmd])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed executing '%s' command." % lsvg_cmd)
|
||||
|
||||
@@ -197,7 +197,7 @@ def create_extend_vg(module, vg, pvs, pp_size, vg_type, force, vg_validation):
|
||||
|
||||
if not module.check_mode:
|
||||
extendvg_cmd = module.get_bin_path('extendvg', True)
|
||||
rc, output, err = module.run_command("%s %s %s" % (extendvg_cmd, vg, ' '.join(pvs)))
|
||||
rc, output, err = module.run_command([extendvg_cmd, vg] + pvs)
|
||||
if rc != 0:
|
||||
changed = False
|
||||
msg = "Extending volume group '%s' has failed." % vg
|
||||
@@ -213,7 +213,7 @@ def create_extend_vg(module, vg, pvs, pp_size, vg_type, force, vg_validation):
|
||||
|
||||
if not module.check_mode:
|
||||
mkvg_cmd = module.get_bin_path('mkvg', True)
|
||||
rc, output, err = module.run_command("%s %s %s %s -y %s %s" % (mkvg_cmd, vg_opt[vg_type], pp_size, force_opt[force], vg, ' '.join(pvs)))
|
||||
rc, output, err = module.run_command([mkvg_cmd, vg_opt[vg_type], pp_size, force_opt[force], "-y", vg] + pvs)
|
||||
if rc != 0:
|
||||
changed = False
|
||||
msg = "Creating volume group '%s' failed." % vg
|
||||
@@ -239,7 +239,7 @@ def reduce_vg(module, vg, pvs, vg_validation):
|
||||
# Remove VG if pvs are note informed.
|
||||
# Remark: AIX will permit remove only if the VG has not LVs.
|
||||
lsvg_cmd = module.get_bin_path('lsvg', True)
|
||||
rc, current_pvs, err = module.run_command("%s -p %s" % (lsvg_cmd, vg))
|
||||
rc, current_pvs, err = module.run_command([lsvg_cmd, "-p", vg])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failing to execute '%s' command." % lsvg_cmd)
|
||||
|
||||
@@ -263,7 +263,7 @@ def reduce_vg(module, vg, pvs, vg_validation):
|
||||
|
||||
if not module.check_mode:
|
||||
reducevg_cmd = module.get_bin_path('reducevg', True)
|
||||
rc, stdout, stderr = module.run_command("%s -df %s %s" % (reducevg_cmd, vg, ' '.join(pvs_to_remove)))
|
||||
rc, stdout, stderr = module.run_command([reducevg_cmd, "-df", vg] + pvs_to_remove)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Unable to remove '%s'." % vg, rc=rc, stdout=stdout, stderr=stderr)
|
||||
|
||||
@@ -286,7 +286,7 @@ def state_vg(module, vg, state, vg_validation):
|
||||
msg = ''
|
||||
if not module.check_mode:
|
||||
varyonvg_cmd = module.get_bin_path('varyonvg', True)
|
||||
rc, varyonvg_out, err = module.run_command("%s %s" % (varyonvg_cmd, vg))
|
||||
rc, varyonvg_out, err = module.run_command([varyonvg_cmd, vg])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Command 'varyonvg' failed.", rc=rc, err=err)
|
||||
|
||||
@@ -303,7 +303,7 @@ def state_vg(module, vg, state, vg_validation):
|
||||
|
||||
if not module.check_mode:
|
||||
varyonvg_cmd = module.get_bin_path('varyoffvg', True)
|
||||
rc, varyonvg_out, stderr = module.run_command("%s %s" % (varyonvg_cmd, vg))
|
||||
rc, varyonvg_out, stderr = module.run_command([varyonvg_cmd, vg])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Command 'varyoffvg' failed.", rc=rc, stdout=varyonvg_out, stderr=stderr)
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ def set_interface_option(module, lines, iface, option, raw_value, state, address
|
||||
last_line_dict = iface_lines[-1]
|
||||
return add_option_after_line(option, value, iface, lines, last_line_dict, iface_options, address_family)
|
||||
|
||||
if option in ["pre-up", "up", "down", "post-up"] and all(ito for ito in target_options if ito['value'] != value):
|
||||
if option in ["pre-up", "up", "down", "post-up"] and all(ito['value'] != value for ito in target_options):
|
||||
return add_option_after_line(option, value, iface, lines, target_options[-1], iface_options, address_family)
|
||||
|
||||
# if more than one option found edit the last one
|
||||
|
||||
@@ -439,7 +439,7 @@ def delete_cert(module, executable, keystore_path, keystore_pass, alias, keystor
|
||||
|
||||
def test_keytool(module, executable):
|
||||
''' Test if keytool is actually executable or not '''
|
||||
module.run_command("%s" % executable, check_rc=True)
|
||||
module.run_command([executable], check_rc=True)
|
||||
|
||||
|
||||
def test_keystore(module, keystore_path):
|
||||
|
||||
@@ -45,7 +45,7 @@ options:
|
||||
required: false
|
||||
type: bool
|
||||
description:
|
||||
- Enable or disable the service according to local preferences in *.preset files.
|
||||
- Enable or disable the service according to local preferences in C(*.preset) files.
|
||||
Mutually exclusive with I(enabled). Only has an effect if set to true. Will take
|
||||
effect prior to I(state=reset).
|
||||
user:
|
||||
|
||||
@@ -10,8 +10,8 @@ DOCUMENTATION = '''
|
||||
module: python_requirements_info
|
||||
short_description: Show python path and assert dependency versions
|
||||
description:
|
||||
- Get info about available Python requirements on the target host, including listing required libraries and gathering versions.
|
||||
- This module was called C(python_requirements_facts) before Ansible 2.9. The usage did not change.
|
||||
- Get info about available Python requirements on the target host, including listing required libraries and gathering versions.
|
||||
- This module was called C(python_requirements_facts) before Ansible 2.9. The usage did not change.
|
||||
options:
|
||||
dependencies:
|
||||
type: list
|
||||
@@ -21,9 +21,10 @@ options:
|
||||
Supported operators: <, >, <=, >=, or ==. The bare module name like
|
||||
I(ansible), the module with a specific version like I(boto3==1.6.1), or a
|
||||
partial version like I(requests>2) are all valid specifications.
|
||||
default: []
|
||||
author:
|
||||
- Will Thames (@willthames)
|
||||
- Ryan Scott Brown (@ryansb)
|
||||
- Will Thames (@willthames)
|
||||
- Ryan Scott Brown (@ryansb)
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -33,8 +34,8 @@ EXAMPLES = '''
|
||||
- name: Check for modern boto3 and botocore versions
|
||||
community.general.python_requirements_info:
|
||||
dependencies:
|
||||
- boto3>1.6
|
||||
- botocore<2
|
||||
- boto3>1.6
|
||||
- botocore<2
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
@@ -48,14 +49,44 @@ python_version:
|
||||
returned: always
|
||||
type: str
|
||||
sample: "2.7.15 (default, May 1 2018, 16:44:08)\n[GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.1)]"
|
||||
python_version_info:
|
||||
description: breakdown version of python
|
||||
returned: always
|
||||
type: dict
|
||||
contains:
|
||||
major:
|
||||
description: The C(major) component of the python interpreter version.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 3
|
||||
minor:
|
||||
description: The C(minor) component of the python interpreter version.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 8
|
||||
micro:
|
||||
description: The C(micro) component of the python interpreter version.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 10
|
||||
releaselevel:
|
||||
description: The C(releaselevel) component of the python interpreter version.
|
||||
returned: always
|
||||
type: str
|
||||
sample: final
|
||||
serial:
|
||||
description: The C(serial) component of the python interpreter version.
|
||||
returned: always
|
||||
type: int
|
||||
sample: 0
|
||||
version_added: 4.2.0
|
||||
python_system_path:
|
||||
description: List of paths python is looking for modules in
|
||||
returned: always
|
||||
type: list
|
||||
sample:
|
||||
- /usr/local/opt/python@2/site-packages/
|
||||
- /usr/lib/python/site-packages/
|
||||
- /usr/lib/python/site-packages/
|
||||
- /usr/local/opt/python@2/site-packages/
|
||||
- /usr/lib/python/site-packages/
|
||||
valid:
|
||||
description: A dictionary of dependencies that matched their desired versions. If no version was specified, then I(desired) will be null
|
||||
returned: always
|
||||
@@ -80,8 +111,8 @@ not_found:
|
||||
returned: always
|
||||
type: list
|
||||
sample:
|
||||
- boto4
|
||||
- requests
|
||||
- boto4
|
||||
- requests
|
||||
'''
|
||||
|
||||
import re
|
||||
@@ -106,11 +137,19 @@ operations = {
|
||||
'==': operator.eq,
|
||||
}
|
||||
|
||||
python_version_info = dict(
|
||||
major=sys.version_info[0],
|
||||
minor=sys.version_info[1],
|
||||
micro=sys.version_info[2],
|
||||
releaselevel=sys.version_info[3],
|
||||
serial=sys.version_info[4],
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
dependencies=dict(type='list', elements='str')
|
||||
dependencies=dict(type='list', elements='str', default=[])
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -119,9 +158,10 @@ def main():
|
||||
msg='Could not import "distutils" and "pkg_resources" libraries to introspect python environment.',
|
||||
python=sys.executable,
|
||||
python_version=sys.version,
|
||||
python_version_info=python_version_info,
|
||||
python_system_path=sys.path,
|
||||
)
|
||||
pkg_dep_re = re.compile(r'(^[a-zA-Z][a-zA-Z0-9_-]+)(==|[><]=?)?([0-9.]+)?$')
|
||||
pkg_dep_re = re.compile(r'(^[a-zA-Z][a-zA-Z0-9_-]+)(?:(==|[><]=?)([0-9.]+))?$')
|
||||
|
||||
results = dict(
|
||||
not_found=[],
|
||||
@@ -129,9 +169,9 @@ def main():
|
||||
valid={},
|
||||
)
|
||||
|
||||
for dep in (module.params.get('dependencies') or []):
|
||||
for dep in module.params['dependencies']:
|
||||
match = pkg_dep_re.match(dep)
|
||||
if match is None:
|
||||
if not match:
|
||||
module.fail_json(msg="Failed to parse version requirement '{0}'. Must be formatted like 'ansible>2.6'".format(dep))
|
||||
pkg, op, version = match.groups()
|
||||
if op is not None and op not in operations:
|
||||
@@ -161,6 +201,7 @@ def main():
|
||||
module.exit_json(
|
||||
python=sys.executable,
|
||||
python_version=sys.version,
|
||||
python_version_info=python_version_info,
|
||||
python_system_path=sys.path,
|
||||
**results
|
||||
)
|
||||
|
||||
@@ -172,7 +172,7 @@ class Svc(object):
|
||||
self.execute_command([self.svc_cmd, '-dx', src_log])
|
||||
|
||||
def get_status(self):
|
||||
(rc, out, err) = self.execute_command([self.svstat_cmd, self.svc_full])
|
||||
rc, out, err = self.execute_command([self.svstat_cmd, self.svc_full])
|
||||
|
||||
if err is not None and err:
|
||||
self.full_state = self.state = err
|
||||
@@ -223,7 +223,7 @@ class Svc(object):
|
||||
|
||||
def execute_command(self, cmd):
|
||||
try:
|
||||
(rc, out, err) = self.module.run_command(' '.join(cmd))
|
||||
rc, out, err = self.module.run_command(cmd)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg="failed to execute: %s" % to_native(e), exception=traceback.format_exc())
|
||||
return (rc, out, err)
|
||||
|
||||
@@ -19,6 +19,8 @@ description:
|
||||
For Linux it can use C(timedatectl) or edit C(/etc/sysconfig/clock) or C(/etc/timezone) and C(hwclock).
|
||||
On SmartOS, C(sm-set-timezone), for macOS, C(systemsetup), for BSD, C(/etc/localtime) is modified.
|
||||
On AIX, C(chtz) is used.
|
||||
- Make sure that the zoneinfo files are installed with the appropriate OS package, like C(tzdata) (usually always installed,
|
||||
when not using a minimal installation like Alpine Linux).
|
||||
- As of Ansible 2.3 support was added for SmartOS and BSDs.
|
||||
- As of Ansible 2.4 support was added for macOS.
|
||||
- As of Ansible 2.9 support was added for AIX 6.1+
|
||||
|
||||
@@ -128,7 +128,7 @@ RETURN = '''
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import (
|
||||
ModuleHelper, CmdMixin, StateMixin, ArgFormat, ModuleHelperException
|
||||
CmdStateModuleHelper, ArgFormat, ModuleHelperException
|
||||
)
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class XFConfException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class XFConfProperty(CmdMixin, StateMixin, ModuleHelper):
|
||||
class XFConfProperty(CmdStateModuleHelper):
|
||||
change_params = 'value',
|
||||
diff_params = 'value',
|
||||
output_params = ('property', 'channel', 'value')
|
||||
|
||||
@@ -36,15 +36,22 @@ options:
|
||||
|
||||
username:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- The username to log-in with.
|
||||
- Must be used with I(password). Mutually exclusive with I(token).
|
||||
|
||||
password:
|
||||
type: str
|
||||
required: true
|
||||
description:
|
||||
- The password to log-in with.
|
||||
- Must be used with I(username). Mutually exclusive with I(token).
|
||||
|
||||
token:
|
||||
type: str
|
||||
description:
|
||||
- The personal access token to log-in with.
|
||||
- Mutually exclusive with I(username) and I(password).
|
||||
version_added: 4.2.0
|
||||
|
||||
project:
|
||||
type: str
|
||||
@@ -206,7 +213,7 @@ options:
|
||||
done.
|
||||
|
||||
notes:
|
||||
- "Currently this only works with basic-auth."
|
||||
- "Currently this only works with basic-auth, or tokens."
|
||||
- "To use with JIRA Cloud, pass the login e-mail as the I(username) and the API token as I(password)."
|
||||
|
||||
author:
|
||||
@@ -408,8 +415,9 @@ class JIRA(StateModuleHelper):
|
||||
choices=['attach', 'create', 'comment', 'edit', 'update', 'fetch', 'transition', 'link', 'search'],
|
||||
aliases=['command'], required=True
|
||||
),
|
||||
username=dict(type='str', required=True),
|
||||
password=dict(type='str', required=True, no_log=True),
|
||||
username=dict(type='str'),
|
||||
password=dict(type='str', no_log=True),
|
||||
token=dict(type='str', no_log=True),
|
||||
project=dict(type='str', ),
|
||||
summary=dict(type='str', ),
|
||||
description=dict(type='str', ),
|
||||
@@ -432,6 +440,17 @@ class JIRA(StateModuleHelper):
|
||||
validate_certs=dict(default=True, type='bool'),
|
||||
account_id=dict(type='str'),
|
||||
),
|
||||
mutually_exclusive=[
|
||||
['username', 'token'],
|
||||
['password', 'token'],
|
||||
['assignee', 'account_id'],
|
||||
],
|
||||
required_together=[
|
||||
['username', 'password'],
|
||||
],
|
||||
required_one_of=[
|
||||
['username', 'token'],
|
||||
],
|
||||
required_if=(
|
||||
('operation', 'attach', ['issue', 'attachment']),
|
||||
('operation', 'create', ['project', 'issuetype', 'summary']),
|
||||
@@ -441,7 +460,6 @@ class JIRA(StateModuleHelper):
|
||||
('operation', 'link', ['linktype', 'inwardissue', 'outwardissue']),
|
||||
('operation', 'search', ['jql']),
|
||||
),
|
||||
mutually_exclusive=[('assignee', 'account_id')],
|
||||
supports_check_mode=False
|
||||
)
|
||||
|
||||
@@ -642,23 +660,30 @@ class JIRA(StateModuleHelper):
|
||||
if data and content_type == 'application/json':
|
||||
data = json.dumps(data)
|
||||
|
||||
headers = {}
|
||||
if isinstance(additional_headers, dict):
|
||||
headers = additional_headers.copy()
|
||||
|
||||
# NOTE: fetch_url uses a password manager, which follows the
|
||||
# standard request-then-challenge basic-auth semantics. However as
|
||||
# JIRA allows some unauthorised operations it doesn't necessarily
|
||||
# send the challenge, so the request occurs as the anonymous user,
|
||||
# resulting in unexpected results. To work around this we manually
|
||||
# inject the basic-auth header up-front to ensure that JIRA treats
|
||||
# inject the auth header up-front to ensure that JIRA treats
|
||||
# the requests as authorized for this user.
|
||||
auth = to_text(base64.b64encode(to_bytes('{0}:{1}'.format(self.vars.username, self.vars.password),
|
||||
errors='surrogate_or_strict')))
|
||||
|
||||
headers = {}
|
||||
if isinstance(additional_headers, dict):
|
||||
headers = additional_headers.copy()
|
||||
headers.update({
|
||||
"Content-Type": content_type,
|
||||
"Authorization": "Basic %s" % auth,
|
||||
})
|
||||
if self.vars.token is not None:
|
||||
headers.update({
|
||||
"Content-Type": content_type,
|
||||
"Authorization": "Bearer %s" % self.vars.token,
|
||||
})
|
||||
else:
|
||||
auth = to_text(base64.b64encode(to_bytes('{0}:{1}'.format(self.vars.username, self.vars.password),
|
||||
errors='surrogate_or_strict')))
|
||||
headers.update({
|
||||
"Content-Type": content_type,
|
||||
"Authorization": "Basic %s" % auth,
|
||||
})
|
||||
|
||||
response, info = fetch_url(
|
||||
self.module, url, data=data, method=method, timeout=self.vars.timeout, headers=headers
|
||||
@@ -669,7 +694,14 @@ class JIRA(StateModuleHelper):
|
||||
try:
|
||||
error = json.loads(info['body'])
|
||||
except Exception:
|
||||
self.module.fail_json(msg=to_native(info['body']), exception=traceback.format_exc())
|
||||
msg = 'The request "{method} {url}" returned the unexpected status code {status} {msg}\n{body}'.format(
|
||||
status=info['status'],
|
||||
msg=info['msg'],
|
||||
body=info.get('body'),
|
||||
url=url,
|
||||
method=method,
|
||||
)
|
||||
self.module.fail_json(msg=to_native(msg), exception=traceback.format_exc())
|
||||
if error:
|
||||
msg = []
|
||||
for key in ('errorMessages', 'errors'):
|
||||
|
||||
2
tests/integration/targets/gitlab_branch/aliases
Normal file
2
tests/integration/targets/gitlab_branch/aliases
Normal file
@@ -0,0 +1,2 @@
|
||||
shippable/posix/group1
|
||||
disabled
|
||||
@@ -0,0 +1,2 @@
|
||||
gitlab_branch: ansible_test_branch
|
||||
gitlab_project_name: ansible_test_project
|
||||
64
tests/integration/targets/gitlab_branch/tasks/main.yml
Normal file
64
tests/integration/targets/gitlab_branch/tasks/main.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
####################################################################
|
||||
# WARNING: These are designed specifically for Ansible tests #
|
||||
# and should not be used as examples of how to write Ansible roles #
|
||||
####################################################################
|
||||
|
||||
- name: Install required libs
|
||||
pip:
|
||||
name: python-gitlab
|
||||
state: present
|
||||
|
||||
- name: Create {{ gitlab_project_name }}
|
||||
gitlab_project:
|
||||
server_url: "{{ gitlab_host }}"
|
||||
validate_certs: False
|
||||
login_token: "{{ gitlab_login_token }}"
|
||||
name: "{{ gitlab_project_name }}"
|
||||
initialize_with_readme: True
|
||||
state: present
|
||||
|
||||
- name: Create branch {{ gitlab_branch }}
|
||||
community.general.gitlab_branch:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "{{ gitlab_project_name }}"
|
||||
branch: "{{ gitlab_branch }}"
|
||||
ref_branch: main
|
||||
state: present
|
||||
|
||||
- name: Create branch {{ gitlab_branch }} ( Idempotency test )
|
||||
community.general.gitlab_branch:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "{{ gitlab_project_name }}"
|
||||
branch: "{{ gitlab_branch }}"
|
||||
ref_branch: main
|
||||
state: present
|
||||
register: create_branch
|
||||
|
||||
- name: Test module is idempotent
|
||||
assert:
|
||||
that:
|
||||
- create_branch is not changed
|
||||
|
||||
- name: Cleanup branch {{ gitlab_branch }}
|
||||
community.general.gitlab_branch:
|
||||
api_url: https://gitlab.com
|
||||
api_token: secret_access_token
|
||||
project: "{{ gitlab_project_name }}"
|
||||
branch: "{{ gitlab_branch }}"
|
||||
state: absent
|
||||
register: delete_branch
|
||||
|
||||
- name: Test module is idempotent
|
||||
assert:
|
||||
that:
|
||||
- delete_branch is changed
|
||||
|
||||
- name: Clean up {{ gitlab_project_name }}
|
||||
gitlab_project:
|
||||
server_url: "{{ gitlab_host }}"
|
||||
validate_certs: False
|
||||
login_token: "{{ gitlab_login_token }}"
|
||||
name: "{{ gitlab_project_name }}"
|
||||
state: absent
|
||||
1
tests/integration/targets/ilo_redfish_config/aliases
Normal file
1
tests/integration/targets/ilo_redfish_config/aliases
Normal file
@@ -0,0 +1 @@
|
||||
unsupported
|
||||
48
tests/integration/targets/ilo_redfish_config/tasks/main.yml
Normal file
48
tests/integration/targets/ilo_redfish_config/tasks/main.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
- name: Set NTP Servers
|
||||
ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetNTPServers
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
attribute_name: StaticNTPServers
|
||||
attribute_value: 1.2.3.4
|
||||
|
||||
- name: Set DNS Server
|
||||
ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetDNSserver
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
attribute_name: DNSServers
|
||||
attribute_value: 192.168.1.1
|
||||
|
||||
- name: Set Domain name
|
||||
ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetDomainName
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
attribute_name: DomainName
|
||||
attribute_value: tst.sgp.hp.mfg
|
||||
|
||||
- name: Disable WINS Reg
|
||||
ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetWINSReg
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
attribute_name: WINSRegistration
|
||||
|
||||
- name: Set TimeZone
|
||||
ilo_redfish_config:
|
||||
category: Manager
|
||||
command: SetTimeZone
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
attribute_name: TimeZone
|
||||
attribute_value: Chennai
|
||||
1
tests/integration/targets/ilo_redfish_info/aliases
Normal file
1
tests/integration/targets/ilo_redfish_info/aliases
Normal file
@@ -0,0 +1 @@
|
||||
unsupported
|
||||
@@ -0,0 +1,8 @@
|
||||
- name: Get sessions
|
||||
ilo_redfish_info:
|
||||
category: Sessions
|
||||
command: GetiLOSessions
|
||||
baseuri: "{{ baseuri }}"
|
||||
username: "{{ username }}"
|
||||
password: "{{ password }}"
|
||||
register: result_sessions
|
||||
@@ -0,0 +1,7 @@
|
||||
iface eth0 inet static
|
||||
address 1.2.3.4
|
||||
netmask 255.255.255.0
|
||||
gateway 1.2.3.1
|
||||
up route add -net 1.2.3.4 netmask 255.255.255.0 gw 1.2.3.1 eth0
|
||||
up ip addr add 4.3.2.1/32 dev eth0
|
||||
down ip addr add 4.3.2.1/32 dev eth0
|
||||
@@ -2,6 +2,7 @@
|
||||
- name:
|
||||
set_fact:
|
||||
interfaces_testfile: '{{ remote_tmp_dir }}/interfaces'
|
||||
interfaces_testfile_3841: '{{ remote_tmp_dir }}/interfaces_3841'
|
||||
|
||||
- name: Copy interfaces file
|
||||
copy:
|
||||
@@ -31,3 +32,32 @@
|
||||
- assert:
|
||||
that:
|
||||
- ifile_2 is not changed
|
||||
|
||||
- name: 3841 - copy interfaces file
|
||||
copy:
|
||||
src: 'files/interfaces_ff_3841'
|
||||
dest: '{{ interfaces_testfile_3841 }}'
|
||||
|
||||
- name: 3841 - floating_ip_interface_up_ip 2a01:a:b:c::1/64 dev eth0
|
||||
interfaces_file:
|
||||
option: up
|
||||
iface: eth0
|
||||
dest: "{{ interfaces_testfile_3841 }}"
|
||||
value: 'ip addr add 2a01:a:b:c::1/64 dev eth0'
|
||||
state: present
|
||||
register: ifile_3841_a
|
||||
|
||||
- name: 3841 - floating_ip_interface_up_ip 2a01:a:b:c::1/64 dev eth0 (again)
|
||||
interfaces_file:
|
||||
option: up
|
||||
iface: eth0
|
||||
dest: "{{ interfaces_testfile_3841 }}"
|
||||
value: 'ip addr add 2a01:a:b:c::1/64 dev eth0'
|
||||
state: present
|
||||
register: ifile_3841_b
|
||||
|
||||
- name: 3841 - check assertions
|
||||
assert:
|
||||
that:
|
||||
- ifile_3841_a is changed
|
||||
- ifile_3841_b is not changed
|
||||
|
||||
@@ -30,30 +30,39 @@ EXAMPLES = ""
|
||||
RETURN = ""
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.deco import check_mode_skip
|
||||
|
||||
|
||||
class MSimple(ModuleHelper):
|
||||
output_params = ('a', 'b', 'c')
|
||||
module = dict(
|
||||
argument_spec=dict(
|
||||
a=dict(type='int'),
|
||||
a=dict(type='int', default=0),
|
||||
b=dict(type='str'),
|
||||
c=dict(type='str'),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
def __init_module__(self):
|
||||
self.vars.set('value', None)
|
||||
self.vars.set('abc', "abc", diff=True)
|
||||
|
||||
@check_mode_skip
|
||||
def process_a3_bc(self):
|
||||
if self.vars.a == 3:
|
||||
self.vars['b'] = str(self.vars.b) * 3
|
||||
self.vars['c'] = str(self.vars.c) * 3
|
||||
|
||||
def __run__(self):
|
||||
if (0 if self.vars.a is None else self.vars.a) >= 100:
|
||||
if self.vars.a >= 100:
|
||||
raise Exception("a >= 100")
|
||||
if self.vars.c == "abc change":
|
||||
self.vars['abc'] = "changed abc"
|
||||
if self.vars.get('a', 0) == 2:
|
||||
self.vars['b'] = str(self.vars.b) * 2
|
||||
self.vars['c'] = str(self.vars.c) * 2
|
||||
self.process_a3_bc()
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
64
tests/integration/targets/module_helper/library/msimpleda.py
Normal file
64
tests/integration/targets/module_helper/library/msimpleda.py
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2021, Alexei Znamensky <russoz@gmail.com>
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
import collections
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
module: msimpleda
|
||||
author: "Alexei Znamensky (@russoz)"
|
||||
short_description: Simple module for testing DeprecationAttrsMixin
|
||||
description:
|
||||
- Simple module test description.
|
||||
options:
|
||||
a:
|
||||
description: aaaa
|
||||
type: int
|
||||
'''
|
||||
|
||||
EXAMPLES = ""
|
||||
|
||||
RETURN = ""
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.module_helper import ModuleHelper
|
||||
from ansible_collections.community.general.plugins.module_utils.mh.mixins.deprecate_attrs import DeprecateAttrsMixin
|
||||
|
||||
|
||||
class MSimpleDA(ModuleHelper):
|
||||
output_params = ('a',)
|
||||
module = dict(
|
||||
argument_spec=dict(
|
||||
a=dict(type='int'),
|
||||
),
|
||||
)
|
||||
|
||||
attr1 = "abc"
|
||||
attr2 = "def"
|
||||
|
||||
def __init_module__(self):
|
||||
self._deprecate_attr(
|
||||
"attr2",
|
||||
msg="Attribute attr2 is deprecated",
|
||||
version="9.9.9",
|
||||
collection_name="community.general",
|
||||
target=self.__class__,
|
||||
module=self.module,
|
||||
)
|
||||
|
||||
def __run__(self):
|
||||
if self.vars.a == 1:
|
||||
self.vars.attr1 = self.attr1
|
||||
if self.vars.a == 2:
|
||||
self.vars.attr2 = self.attr2
|
||||
|
||||
|
||||
def main():
|
||||
MSimpleDA.execute()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -24,6 +24,10 @@ options:
|
||||
c:
|
||||
description: cccc
|
||||
type: str
|
||||
trigger_depr_attr:
|
||||
description: tries to access VarDict
|
||||
type: bool
|
||||
default: false
|
||||
state:
|
||||
description: test states
|
||||
type: str
|
||||
@@ -45,12 +49,15 @@ class MState(StateModuleHelper):
|
||||
a=dict(type='int', required=True),
|
||||
b=dict(type='str'),
|
||||
c=dict(type='str'),
|
||||
trigger_depr_attr=dict(type='bool', default=False),
|
||||
state=dict(type='str', choices=['join', 'b_x_a', 'c_x_a', 'both_x_a', 'nop'], default='join'),
|
||||
),
|
||||
)
|
||||
|
||||
def __init_module__(self):
|
||||
self.vars.set('result', "abc", diff=True)
|
||||
if self.vars.trigger_depr_attr:
|
||||
dummy = self.VarDict
|
||||
|
||||
def state_join(self):
|
||||
self.vars['result'] = "".join([str(self.vars.a), str(self.vars.b), str(self.vars.c)])
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
- include_tasks: msimple.yml
|
||||
- include_tasks: mdepfail.yml
|
||||
- include_tasks: mstate.yml
|
||||
- include_tasks: msimpleda.yml
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# (c) 2021, Alexei Znamensky
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: test msimple 1
|
||||
- name: test msimple (set a=80)
|
||||
msimple:
|
||||
a: 80
|
||||
register: simple1
|
||||
@@ -55,3 +55,30 @@
|
||||
- simple4.c == "abc change"
|
||||
- simple4.abc == "changed abc"
|
||||
- simple4 is changed
|
||||
|
||||
- name: test msimple 5a
|
||||
msimple:
|
||||
a: 3 # should triple b and c
|
||||
b: oh
|
||||
c: my
|
||||
register: simple5a
|
||||
|
||||
- name: test msimple 5b
|
||||
check_mode: true
|
||||
msimple:
|
||||
a: 3 # should triple b and c
|
||||
b: oh
|
||||
c: my
|
||||
register: simple5b
|
||||
|
||||
- name: assert simple5
|
||||
assert:
|
||||
that:
|
||||
- simple5a.a == 3
|
||||
- simple5a.b == "ohohoh"
|
||||
- simple5a.c == "mymymy"
|
||||
- simple5a is not changed
|
||||
- simple5b.a == 3
|
||||
- simple5b.b == "oh"
|
||||
- simple5b.c == "my"
|
||||
- simple5b is not changed
|
||||
|
||||
38
tests/integration/targets/module_helper/tasks/msimpleda.yml
Normal file
38
tests/integration/targets/module_helper/tasks/msimpleda.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
# (c) 2021, Alexei Znamensky
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- set_fact:
|
||||
attr2_d:
|
||||
msg: Attribute attr2 is deprecated
|
||||
version: 9.9.9
|
||||
collection_name: community.general
|
||||
attr2_d_29:
|
||||
msg: Attribute attr2 is deprecated
|
||||
version: 9.9.9
|
||||
- set_fact:
|
||||
attr2_depr_dict: "{{ ((ansible_version.major, ansible_version.minor) < (2, 10))|ternary(attr2_d_29, attr2_d) }}"
|
||||
|
||||
- name: test msimpleda 1
|
||||
msimpleda:
|
||||
a: 1
|
||||
register: simple1
|
||||
|
||||
- name: assert simple1
|
||||
assert:
|
||||
that:
|
||||
- simple1.a == 1
|
||||
- simple1.attr1 == "abc"
|
||||
- ("deprecations" not in simple1) or attr2_depr_dict not in simple1.deprecations
|
||||
|
||||
- name: test msimpleda 2
|
||||
msimpleda:
|
||||
a: 2
|
||||
register: simple2
|
||||
|
||||
- name: assert simple2
|
||||
assert:
|
||||
that:
|
||||
- simple2.a == 2
|
||||
- simple2.attr2 == "def"
|
||||
- '"deprecations" in simple2'
|
||||
- attr2_depr_dict in simple2.deprecations
|
||||
@@ -69,9 +69,25 @@
|
||||
a: 5
|
||||
b: foo
|
||||
c: bar
|
||||
trigger_depr_attr: true
|
||||
state: both_x_a
|
||||
register: state5
|
||||
|
||||
- ansible.builtin.set_fact:
|
||||
vardict_gt29:
|
||||
msg: >-
|
||||
ModuleHelper.VarDict attribute is deprecated, use VarDict from the
|
||||
ansible_collections.community.general.plugins.module_utils.mh.mixins.vars
|
||||
module instead
|
||||
version: 6.0.0
|
||||
collection_name: community.general
|
||||
vardict_29:
|
||||
msg: >-
|
||||
ModuleHelper.VarDict attribute is deprecated, use VarDict from the
|
||||
ansible_collections.community.general.plugins.module_utils.mh.mixins.vars
|
||||
module instead
|
||||
version: 6.0.0
|
||||
|
||||
- name: assert state5
|
||||
assert:
|
||||
that:
|
||||
@@ -80,3 +96,6 @@
|
||||
- state5.c == "bar"
|
||||
- state5.result == "foobarfoobarfoobarfoobarfoobar"
|
||||
- state5 is changed
|
||||
- vardict_depr in state5.deprecations
|
||||
vars:
|
||||
vardict_depr: '{{ (ansible_version.major == 2 and ansible_version.minor == 9) | ternary(vardict_29, vardict_gt29) }}'
|
||||
|
||||
@@ -124,3 +124,29 @@
|
||||
- '"ansible-lint" in inject_pkgs_ansible_lint.application'
|
||||
- '"licenses" in inject_pkgs_ansible_lint.application["ansible-lint"]["injected"]'
|
||||
- uninstall_ansible_lint is changed
|
||||
|
||||
##############################################################################
|
||||
- name: install jupyter - not working smoothly in freebsd
|
||||
block:
|
||||
- name: ensure application jupyter is uninstalled
|
||||
community.general.pipx:
|
||||
name: jupyter
|
||||
state: absent
|
||||
|
||||
- name: install application jupyter
|
||||
community.general.pipx:
|
||||
name: jupyter
|
||||
install_deps: true
|
||||
register: install_jupyter
|
||||
|
||||
- name: cleanup jupyter
|
||||
community.general.pipx:
|
||||
state: absent
|
||||
name: jupyter
|
||||
|
||||
- name: check assertions
|
||||
assert:
|
||||
that:
|
||||
- install_jupyter is changed
|
||||
- '"ipython" in install_jupyter.stdout'
|
||||
when: ansible_system != 'FreeBSD'
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
that:
|
||||
- "'python' in basic_info"
|
||||
- "'python_version' in basic_info"
|
||||
- basic_info.python_version_info == ansible_python.version
|
||||
|
||||
- name: run python_requirements_info module
|
||||
python_requirements_info:
|
||||
@@ -25,3 +26,15 @@
|
||||
that:
|
||||
- "'installed' in dep_info.valid.pip"
|
||||
- "'notreal' in dep_info.not_found"
|
||||
|
||||
- name: wrong specs
|
||||
python_requirements_info:
|
||||
dependencies:
|
||||
- ansible<
|
||||
register: wrong_spec1
|
||||
ignore_errors: true
|
||||
|
||||
- name: ensure wrong specs return error
|
||||
assert:
|
||||
that:
|
||||
- wrong_spec1 is failed
|
||||
|
||||
@@ -4,3 +4,4 @@ skip/freebsd
|
||||
skip/osx
|
||||
skip/macos
|
||||
skip/docker
|
||||
disabled # FIXME
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user