mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-04-28 17:36:49 +00:00
Compare commits
451 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
174b00cd29 | ||
|
|
a7c92f491d | ||
|
|
592cd3747b | ||
|
|
4295ee0bb4 | ||
|
|
7e1ff300f8 | ||
|
|
b3ddec2b29 | ||
|
|
227f6e333e | ||
|
|
94711ca506 | ||
|
|
d53052f27a | ||
|
|
95d57c338a | ||
|
|
4fd7a65a52 | ||
|
|
0e3c1f867d | ||
|
|
fa24edf89c | ||
|
|
ac3e803a36 | ||
|
|
8168ddca4f | ||
|
|
cc264be644 | ||
|
|
9bd2d1ec90 | ||
|
|
01b2c48161 | ||
|
|
a26792418e | ||
|
|
485834526f | ||
|
|
5e68ea41e9 | ||
|
|
29af59822d | ||
|
|
5b10f8234c | ||
|
|
c69810bf04 | ||
|
|
9eb638f651 | ||
|
|
01887bf359 | ||
|
|
927356dad3 | ||
|
|
0df41241dd | ||
|
|
aaa0f39f72 | ||
|
|
2324f350bc | ||
|
|
bd96616e6f | ||
|
|
b429c520f5 | ||
|
|
d6e14276c8 | ||
|
|
96de25fc94 | ||
|
|
753df78877 | ||
|
|
3b82a6ff99 | ||
|
|
ca5a2b291a | ||
|
|
38e0d97c8b | ||
|
|
cdfc4dcf49 | ||
|
|
9fb76efde0 | ||
|
|
40ccd1501b | ||
|
|
8ba7fd5d61 | ||
|
|
3a2f52c1db | ||
|
|
c40db6789a | ||
|
|
73acdaa489 | ||
|
|
a362879ff6 | ||
|
|
7e1412e5e1 | ||
|
|
996dc617ed | ||
|
|
9b4b175ca3 | ||
|
|
86a22b5ed2 | ||
|
|
45d3661ccf | ||
|
|
481fc48e51 | ||
|
|
e7e2ab94da | ||
|
|
a68445486e | ||
|
|
6580e7559b | ||
|
|
d9e8724b1d | ||
|
|
ef0b83fdf1 | ||
|
|
e8c37ca605 | ||
|
|
02c534bb8e | ||
|
|
3731064368 | ||
|
|
c3813d4533 | ||
|
|
191d2e08bb | ||
|
|
249d490f10 | ||
|
|
71ea99d10f | ||
|
|
18f8195983 | ||
|
|
d25554df9d | ||
|
|
9546bbb55e | ||
|
|
7038812465 | ||
|
|
316adebd68 | ||
|
|
ed2c1e4ac9 | ||
|
|
d44c85aa90 | ||
|
|
9772485d3c | ||
|
|
8ece0d3609 | ||
|
|
905f4dcfa2 | ||
|
|
9de01e04f2 | ||
|
|
d1f820ed06 | ||
|
|
293c7a9fb3 | ||
|
|
f0fcb221cd | ||
|
|
80bb42325b | ||
|
|
3a460751a4 | ||
|
|
e22fff2b12 | ||
|
|
57e5f8c7be | ||
|
|
f1807d3323 | ||
|
|
0bc4518f3b | ||
|
|
e95f63b067 | ||
|
|
106856ed86 | ||
|
|
5895e50185 | ||
|
|
774b2f642b | ||
|
|
316e1d6bf2 | ||
|
|
0d3c4de6a2 | ||
|
|
a14392fab0 | ||
|
|
3fee872d58 | ||
|
|
d0f82e2c27 | ||
|
|
7cfdc2ce8c | ||
|
|
53fc2c477b | ||
|
|
71a655193c | ||
|
|
845c406419 | ||
|
|
d6a1df3706 | ||
|
|
806f1ea3c9 | ||
|
|
d96b85af9f | ||
|
|
ef07f9b9ff | ||
|
|
1bb2ff5128 | ||
|
|
ba2917a7dc | ||
|
|
b6b7601615 | ||
|
|
43a9f09a17 | ||
|
|
147ca2fe66 | ||
|
|
3715b6ef46 | ||
|
|
d0563e34a6 | ||
|
|
935348ae78 | ||
|
|
0d2bcf545e | ||
|
|
ae6cbc2d82 | ||
|
|
e1cdad3537 | ||
|
|
98d071f61e | ||
|
|
8e7d49c1c6 | ||
|
|
424af85929 | ||
|
|
2ad7ed4f83 | ||
|
|
2589e9a030 | ||
|
|
02d0e3d286 | ||
|
|
9ce1009643 | ||
|
|
e48f9fdf74 | ||
|
|
7aae8d5386 | ||
|
|
8ab96d9533 | ||
|
|
7a2efb4775 | ||
|
|
331f5bdf24 | ||
|
|
06345839c6 | ||
|
|
b20fc7a7c3 | ||
|
|
517570a64f | ||
|
|
dc8d076a25 | ||
|
|
bd63da680d | ||
|
|
4e39a4b825 | ||
|
|
118c040879 | ||
|
|
0a5db85ad5 | ||
|
|
29e4066944 | ||
|
|
612543919e | ||
|
|
58d018ebbd | ||
|
|
05fe587a3e | ||
|
|
7c43cc3faa | ||
|
|
6b207bce4c | ||
|
|
dd25c0d3bf | ||
|
|
a20862797e | ||
|
|
0f9311c3d9 | ||
|
|
76317d1f64 | ||
|
|
3502f3b486 | ||
|
|
7c493eb4e5 | ||
|
|
c121e8685f | ||
|
|
bf8df21d27 | ||
|
|
135faf4421 | ||
|
|
fce562ad6d | ||
|
|
1f5345881d | ||
|
|
edd7b84285 | ||
|
|
2d6816e11e | ||
|
|
b2bb7e3f9c | ||
|
|
baa721ac22 | ||
|
|
58c6f6c95a | ||
|
|
97e2c3dec9 | ||
|
|
d9dcdcbbe4 | ||
|
|
1ce79db763 | ||
|
|
df8fdcda79 | ||
|
|
cf43356753 | ||
|
|
a91eb6ae4f | ||
|
|
69641d36e1 | ||
|
|
4e2d4e3c68 | ||
|
|
e77adff0b7 | ||
|
|
825e17c1cf | ||
|
|
cc458f7c37 | ||
|
|
b8a081b9b2 | ||
|
|
e40aa69e77 | ||
|
|
cbcb942b0e | ||
|
|
f2fa56b485 | ||
|
|
1ca9c35010 | ||
|
|
23e7ef0255 | ||
|
|
8a62b79ef2 | ||
|
|
bcccf4e388 | ||
|
|
c7fccb2c01 | ||
|
|
6ac410b3f6 | ||
|
|
41101e55a0 | ||
|
|
f19e191467 | ||
|
|
fccae19177 | ||
|
|
8a4cdd2b8a | ||
|
|
16945d3847 | ||
|
|
432c891487 | ||
|
|
25267b8094 | ||
|
|
f7dba23e50 | ||
|
|
e123623f5c | ||
|
|
1fec1d0c81 | ||
|
|
5855ef558a | ||
|
|
1e466df863 | ||
|
|
6033ce695b | ||
|
|
b5d6457611 | ||
|
|
1705335ba7 | ||
|
|
56b5be0630 | ||
|
|
429359e977 | ||
|
|
7f96b7df60 | ||
|
|
2831bc45f5 | ||
|
|
85bcef3f5a | ||
|
|
87ba15fa45 | ||
|
|
771e9de010 | ||
|
|
6bfa6e40f4 | ||
|
|
da11a98cb7 | ||
|
|
ff586f1105 | ||
|
|
16476f5cb9 | ||
|
|
e9494c12f2 | ||
|
|
a73720c103 | ||
|
|
3dba697e33 | ||
|
|
75688cb632 | ||
|
|
f2df1a7581 | ||
|
|
857d2eee50 | ||
|
|
afe2842b1b | ||
|
|
047b7ada3c | ||
|
|
73c27d6a0e | ||
|
|
789f06dffe | ||
|
|
5f8d6a73d3 | ||
|
|
9ccce82113 | ||
|
|
43fe26d83c | ||
|
|
d9533c44aa | ||
|
|
d974ca32ae | ||
|
|
2935b011ed | ||
|
|
cde9564163 | ||
|
|
549dfaae64 | ||
|
|
0b70b3baff | ||
|
|
5be4adc434 | ||
|
|
87baa5860a | ||
|
|
7da2c16b4a | ||
|
|
024e7419da | ||
|
|
4982eaf935 | ||
|
|
21d5668c97 | ||
|
|
ac03881002 | ||
|
|
c8b2d7c1e5 | ||
|
|
95ceb53676 | ||
|
|
20db4fc560 | ||
|
|
d54d2fa4a6 | ||
|
|
dc3e16113d | ||
|
|
20f46f7669 | ||
|
|
31189e9645 | ||
|
|
d057b2e3b2 | ||
|
|
99c28313e4 | ||
|
|
9631de4939 | ||
|
|
35e0a61217 | ||
|
|
32e9a0c250 | ||
|
|
38e70ae0e4 | ||
|
|
11cdb1b661 | ||
|
|
4a392372a8 | ||
|
|
d7c6ba89f8 | ||
|
|
a3607a745e | ||
|
|
9fd2ba60df | ||
|
|
7b9687f758 | ||
|
|
7734430f23 | ||
|
|
27ba98a68e | ||
|
|
9b1c6f0743 | ||
|
|
ea822c7bdd | ||
|
|
a3a40f6de3 | ||
|
|
28193b699b | ||
|
|
9ffc1ef393 | ||
|
|
3fc97bf80a | ||
|
|
5079ef0e82 | ||
|
|
d56d34bce6 | ||
|
|
c5cbe2943b | ||
|
|
7a41833e59 | ||
|
|
111c5de550 | ||
|
|
9023d4dba1 | ||
|
|
4ae392e5de | ||
|
|
0e90ff48b5 | ||
|
|
1990f79d8a | ||
|
|
ad8c4e4de6 | ||
|
|
288fe1cfc6 | ||
|
|
1b80a9c587 | ||
|
|
d97a9b5961 | ||
|
|
518ace2562 | ||
|
|
56acd4356f | ||
|
|
c0740ca398 | ||
|
|
b2b4877532 | ||
|
|
9b02230477 | ||
|
|
a0915036f9 | ||
|
|
ffe505a798 | ||
|
|
00aa1250ee | ||
|
|
c63dc624b7 | ||
|
|
a97d82be88 | ||
|
|
0e829e6a23 | ||
|
|
677e88b257 | ||
|
|
9c7b539ef6 | ||
|
|
2d1527a564 | ||
|
|
debb15efbe | ||
|
|
0a9cf38118 | ||
|
|
c7cf6f2eb7 | ||
|
|
199ead85d0 | ||
|
|
2fb0877577 | ||
|
|
9dd91f949a | ||
|
|
147425ef93 | ||
|
|
1b94d09209 | ||
|
|
acf7b106c9 | ||
|
|
fafabed9e6 | ||
|
|
d180390dbc | ||
|
|
d2a984ded1 | ||
|
|
2d1f5408d3 | ||
|
|
24c5d4320f | ||
|
|
24dabda95b | ||
|
|
860b2b89a3 | ||
|
|
07085785a3 | ||
|
|
d6d0b6f0c1 | ||
|
|
ce35d88094 | ||
|
|
519411e026 | ||
|
|
2768eda895 | ||
|
|
db713bd0f5 | ||
|
|
08f7ad06be | ||
|
|
67cabcb2aa | ||
|
|
1ed4394c5e | ||
|
|
ee23c26150 | ||
|
|
c9cf641188 | ||
|
|
e9f3455b62 | ||
|
|
13ab8f412d | ||
|
|
3997d5fcc8 | ||
|
|
4a47d121aa | ||
|
|
3ca98c2edd | ||
|
|
2f2f384b4e | ||
|
|
adf50b106a | ||
|
|
b1b34ee12e | ||
|
|
bccf317814 | ||
|
|
0bd345bfb0 | ||
|
|
a55c96d5c1 | ||
|
|
d4c4d00ad1 | ||
|
|
343339655d | ||
|
|
4b37b1bca6 | ||
|
|
19549058ce | ||
|
|
c2ce7a0752 | ||
|
|
f44300cec5 | ||
|
|
1e968bce27 | ||
|
|
dab5d941e6 | ||
|
|
eef645c3f7 | ||
|
|
9f344d7165 | ||
|
|
bb37b67166 | ||
|
|
94a53adff1 | ||
|
|
4c50f1add7 | ||
|
|
7c3f2ae4af | ||
|
|
1e34df7ca0 | ||
|
|
6a41fba2f8 | ||
|
|
f74b83663b | ||
|
|
463c576a67 | ||
|
|
9d8bea9d36 | ||
|
|
0e6d70697c | ||
|
|
1a4af9bfc3 | ||
|
|
c49a384a65 | ||
|
|
a343756e6f | ||
|
|
4396ec9631 | ||
|
|
d49783280e | ||
|
|
2e8746a8aa | ||
|
|
a4f46b881a | ||
|
|
5ddf0041ec | ||
|
|
d93bc039b2 | ||
|
|
efbda2389d | ||
|
|
fe5717c1aa | ||
|
|
ca1506fb26 | ||
|
|
1ad85849af | ||
|
|
3516acf8d4 | ||
|
|
b6c0cc0b61 | ||
|
|
bef3c04d1c | ||
|
|
f09c39b71e | ||
|
|
b281d3d699 | ||
|
|
c3cab7c68c | ||
|
|
14813a6287 | ||
|
|
14f13904d6 | ||
|
|
3afcf7e75d | ||
|
|
43c12b82fa | ||
|
|
95794f31e3 | ||
|
|
795125fec4 | ||
|
|
285639a4f9 | ||
|
|
7cd96d963e | ||
|
|
dc793ea32b | ||
|
|
b79969da68 | ||
|
|
909e9fe950 | ||
|
|
b45298bc43 | ||
|
|
4aa50962cb | ||
|
|
26757edfb2 | ||
|
|
0b4a2bea01 | ||
|
|
d0f8eac7fd | ||
|
|
4764a5deba | ||
|
|
aa74cf4d61 | ||
|
|
6df3685d42 | ||
|
|
d871399220 | ||
|
|
63012eef82 | ||
|
|
593d622438 | ||
|
|
cc293f90a2 | ||
|
|
d7e55db99b | ||
|
|
3100c32a00 | ||
|
|
8f083d5d85 | ||
|
|
852e240525 | ||
|
|
7a169af053 | ||
|
|
1403f5edcc | ||
|
|
452a185a23 | ||
|
|
c4624d3ad8 | ||
|
|
31687a524e | ||
|
|
2c1ab2d384 | ||
|
|
f6db0745fc | ||
|
|
d24fc92466 | ||
|
|
b89eb87ad6 | ||
|
|
2a376642dd | ||
|
|
2b1eff2783 | ||
|
|
dc0a56141f | ||
|
|
345d5f2dfa | ||
|
|
350380ba8c | ||
|
|
da7e4e1dc2 | ||
|
|
2cc848fe1a | ||
|
|
448b8cbcda | ||
|
|
ea200c9d8c | ||
|
|
5b77515308 | ||
|
|
c8f402806f | ||
|
|
a385cbb11d | ||
|
|
5d0a7f40f2 | ||
|
|
e2dfd42dd4 | ||
|
|
054eb90ae5 | ||
|
|
ee9770cff7 | ||
|
|
384655e15c | ||
|
|
23dda56913 | ||
|
|
265d034e31 | ||
|
|
83a0c32269 | ||
|
|
b9fa9116c1 | ||
|
|
0912e8cc7a | ||
|
|
d22dd5056e | ||
|
|
9d46ccf1b2 | ||
|
|
eea4f45965 | ||
|
|
624eb7171e | ||
|
|
8e7aff00b5 | ||
|
|
2e58dfe52a | ||
|
|
4cdff8654a | ||
|
|
7386326258 | ||
|
|
9906b9dbc7 | ||
|
|
188a4eeb0c | ||
|
|
aaa561163b | ||
|
|
1f41e66f09 | ||
|
|
06bdabcad9 | ||
|
|
7007c68ab7 | ||
|
|
5064aa8ec6 | ||
|
|
6a72c3b338 | ||
|
|
4b0d2dcfe0 | ||
|
|
7359b1fbe5 | ||
|
|
b5f8ae4320 | ||
|
|
26aba8e766 | ||
|
|
cd957fae4c | ||
|
|
c0221b75af | ||
|
|
4e90ee752e | ||
|
|
eb455c69a2 | ||
|
|
26c3bd25f6 | ||
|
|
276880aac1 | ||
|
|
ae21af8820 | ||
|
|
5fbe946c3a | ||
|
|
b3f436aa63 | ||
|
|
77d4bc2942 | ||
|
|
48ef05def3 | ||
|
|
9d13acd68e | ||
|
|
2ad004b97b | ||
|
|
cd116120ad | ||
|
|
9931cdc1e7 |
@@ -297,12 +297,10 @@ stages:
|
||||
targets:
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: CentOS 8
|
||||
test: centos8
|
||||
- name: Fedora 33
|
||||
test: fedora33
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: Fedora 35
|
||||
test: fedora35
|
||||
- name: openSUSE 15 py2
|
||||
test: opensuse15py2
|
||||
- name: openSUSE 15 py3
|
||||
@@ -325,8 +323,8 @@ stages:
|
||||
targets:
|
||||
- name: CentOS 6
|
||||
test: centos6
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: CentOS 8
|
||||
test: centos8
|
||||
- name: Fedora 34
|
||||
test: fedora34
|
||||
- name: openSUSE 15 py3
|
||||
@@ -345,8 +343,8 @@ stages:
|
||||
parameters:
|
||||
testFormat: 2.11/linux/{0}
|
||||
targets:
|
||||
- name: CentOS 8
|
||||
test: centos8
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: Fedora 33
|
||||
test: fedora33
|
||||
- name: openSUSE 15 py2
|
||||
|
||||
@@ -11,7 +11,7 @@ mkdir "${agent_temp_directory}/coverage/"
|
||||
|
||||
options=(--venv --venv-system-site-packages --color -v)
|
||||
|
||||
ansible-test coverage combine --export "${agent_temp_directory}/coverage/" "${options[@]}"
|
||||
ansible-test coverage combine --group-by command --export "${agent_temp_directory}/coverage/" "${options[@]}"
|
||||
|
||||
if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then
|
||||
# Only analyze coverage if the installed version of ansible-test supports it.
|
||||
|
||||
101
.azure-pipelines/scripts/publish-codecov.py
Executable file
101
.azure-pipelines/scripts/publish-codecov.py
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Upload code coverage reports to codecov.io.
|
||||
Multiple coverage files from multiple languages are accepted and aggregated after upload.
|
||||
Python coverage, as well as PowerShell and Python stubs can all be uploaded.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import dataclasses
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import typing as t
|
||||
import urllib.request
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CoverageFile:
|
||||
name: str
|
||||
path: pathlib.Path
|
||||
flags: t.List[str]
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Args:
|
||||
dry_run: bool
|
||||
path: pathlib.Path
|
||||
|
||||
|
||||
def parse_args() -> Args:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-n', '--dry-run', action='store_true')
|
||||
parser.add_argument('path', type=pathlib.Path)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Store arguments in a typed dataclass
|
||||
fields = dataclasses.fields(Args)
|
||||
kwargs = {field.name: getattr(args, field.name) for field in fields}
|
||||
|
||||
return Args(**kwargs)
|
||||
|
||||
|
||||
def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]:
|
||||
processed = []
|
||||
for file in directory.joinpath('reports').glob('coverage*.xml'):
|
||||
name = file.stem.replace('coverage=', '')
|
||||
|
||||
# Get flags from name
|
||||
flags = name.replace('-powershell', '').split('=') # Drop '-powershell' suffix
|
||||
flags = [flag if not flag.startswith('stub') else flag.split('-')[0] for flag in flags] # Remove "-01" from stub files
|
||||
|
||||
processed.append(CoverageFile(name, file, flags))
|
||||
|
||||
return tuple(processed)
|
||||
|
||||
|
||||
def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], dry_run: bool = False) -> None:
|
||||
for file in files:
|
||||
cmd = [
|
||||
str(codecov_bin),
|
||||
'--name', file.name,
|
||||
'--file', str(file.path),
|
||||
]
|
||||
for flag in file.flags:
|
||||
cmd.extend(['--flags', flag])
|
||||
|
||||
if dry_run:
|
||||
print(f'DRY-RUN: Would run command: {cmd}')
|
||||
continue
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
|
||||
def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = False) -> None:
|
||||
if dry_run:
|
||||
print(f'DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}')
|
||||
return
|
||||
|
||||
with urllib.request.urlopen(url) as resp:
|
||||
with dest.open('w+b') as f:
|
||||
# Read data in chunks rather than all at once
|
||||
shutil.copyfileobj(resp, f, 64 * 1024)
|
||||
|
||||
dest.chmod(flags)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
url = 'https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov'
|
||||
with tempfile.TemporaryDirectory(prefix='codecov-') as tmpdir:
|
||||
codecov_bin = pathlib.Path(tmpdir) / 'codecov'
|
||||
download_file(url, codecov_bin, 0o755, args.dry_run)
|
||||
|
||||
files = process_files(args.path)
|
||||
upload_files(codecov_bin, files, args.dry_run)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Upload code coverage reports to codecov.io.
|
||||
# Multiple coverage files from multiple languages are accepted and aggregated after upload.
|
||||
# Python coverage, as well as PowerShell and Python stubs can all be uploaded.
|
||||
|
||||
set -o pipefail -eu
|
||||
|
||||
output_path="$1"
|
||||
|
||||
curl --silent --show-error https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh > codecov.sh
|
||||
|
||||
for file in "${output_path}"/reports/coverage*.xml; do
|
||||
name="${file}"
|
||||
name="${name##*/}" # remove path
|
||||
name="${name##coverage=}" # remove 'coverage=' prefix if present
|
||||
name="${name%.xml}" # remove '.xml' suffix
|
||||
|
||||
bash codecov.sh \
|
||||
-f "${file}" \
|
||||
-n "${name}" \
|
||||
-X coveragepy \
|
||||
-X gcov \
|
||||
-X fix \
|
||||
-X search \
|
||||
-X xcode \
|
||||
|| echo "Failed to upload code coverage report to codecov.io: ${file}"
|
||||
done
|
||||
@@ -12,4 +12,4 @@ if ! ansible-test --help >/dev/null 2>&1; then
|
||||
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
|
||||
fi
|
||||
|
||||
ansible-test coverage xml --stub --venv --venv-system-site-packages --color -v
|
||||
ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
|
||||
displayName: Publish to Azure Pipelines
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
- bash: .azure-pipelines/scripts/publish-codecov.sh "$(outputPath)"
|
||||
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
|
||||
displayName: Publish to codecov.io
|
||||
condition: gt(variables.coverageFileCount, 0)
|
||||
continueOnError: true
|
||||
|
||||
50
.github/BOTMETA.yml
vendored
50
.github/BOTMETA.yml
vendored
@@ -175,6 +175,8 @@ files:
|
||||
labels: lookups
|
||||
$lookups/cartesian.py: {}
|
||||
$lookups/chef_databag.py: {}
|
||||
$lookups/collection_version.py:
|
||||
maintainers: felixfontein
|
||||
$lookups/consul_kv.py: {}
|
||||
$lookups/credstash.py: {}
|
||||
$lookups/cyberarkpassword.py:
|
||||
@@ -205,9 +207,6 @@ files:
|
||||
$lookups/manifold.py:
|
||||
maintainers: galanoff
|
||||
labels: manifold
|
||||
$lookups/nios:
|
||||
maintainers: $team_networking sganesh-infoblox
|
||||
labels: infoblox networking
|
||||
$lookups/onepass:
|
||||
maintainers: samdoran
|
||||
labels: onepassword
|
||||
@@ -220,6 +219,8 @@ files:
|
||||
maintainers: Akasurde
|
||||
$lookups/random_string.py:
|
||||
maintainers: Akasurde
|
||||
$lookups/random_words.py:
|
||||
maintainers: konstruktoid
|
||||
$lookups/redis.py:
|
||||
maintainers: $team_ansible_core jpmens
|
||||
$lookups/shelvefile.py: {}
|
||||
@@ -253,9 +254,6 @@ files:
|
||||
$module_utils/module_helper.py:
|
||||
maintainers: russoz
|
||||
labels: module_helper
|
||||
$module_utils/net_tools/nios/api.py:
|
||||
maintainers: $team_networking sganesh-infoblox
|
||||
labels: infoblox networking
|
||||
$module_utils/oracle/oci_utils.py:
|
||||
maintainers: $team_oracle
|
||||
labels: cloud
|
||||
@@ -477,11 +475,16 @@ files:
|
||||
maintainers: paginabianca
|
||||
$modules/database/misc/redis_data.py:
|
||||
maintainers: paginabianca
|
||||
$modules/database/misc/redis_data_incr.py:
|
||||
maintainers: paginabianca
|
||||
$modules/database/misc/riak.py:
|
||||
maintainers: drewkerrigan jsmartin
|
||||
$modules/database/mssql/mssql_db.py:
|
||||
maintainers: vedit Jmainguy kenichi-ogawa-1988
|
||||
labels: mssql_db
|
||||
$modules/database/mssql/mssql_script.py:
|
||||
maintainers: kbudde
|
||||
labels: mssql_script
|
||||
$modules/database/saphana/hana_query.py:
|
||||
maintainers: rainerleber
|
||||
$modules/database/vertica/:
|
||||
@@ -647,31 +650,6 @@ files:
|
||||
maintainers: amasolov nerzhul
|
||||
$modules/net_tools/pritunl/:
|
||||
maintainers: Lowess
|
||||
$modules/net_tools/nios/:
|
||||
maintainers: $team_networking
|
||||
labels: infoblox networking
|
||||
$modules/net_tools/nios/nios_a_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_aaaa_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_cname_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_fixed_address.py:
|
||||
maintainers: sjaiswal
|
||||
$modules/net_tools/nios/nios_member.py:
|
||||
maintainers: krisvasudevan
|
||||
$modules/net_tools/nios/nios_mx_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_naptr_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_nsgroup.py:
|
||||
maintainers: ebirn sjaiswal
|
||||
$modules/net_tools/nios/nios_ptr_record.py:
|
||||
maintainers: clementtrebuchet
|
||||
$modules/net_tools/nios/nios_srv_record.py:
|
||||
maintainers: brampling
|
||||
$modules/net_tools/nios/nios_txt_record.py:
|
||||
maintainers: coreywan
|
||||
$modules/net_tools/nmcli.py:
|
||||
maintainers: alcamie101
|
||||
$modules/net_tools/snmp_facts.py:
|
||||
@@ -775,6 +753,8 @@ files:
|
||||
maintainers: evgkrsk
|
||||
$modules/packaging/os/copr.py:
|
||||
maintainers: schlupov
|
||||
$modules/packaging/os/dnf_versionlock.py:
|
||||
maintainers: moreda
|
||||
$modules/packaging/os/flatpak.py:
|
||||
maintainers: $team_flatpak
|
||||
$modules/packaging/os/flatpak_remote.py:
|
||||
@@ -871,6 +851,9 @@ files:
|
||||
$modules/packaging/os/snap.py:
|
||||
maintainers: angristan vcarceler
|
||||
labels: snap
|
||||
$modules/packaging/os/snap_alias.py:
|
||||
maintainers: russoz
|
||||
labels: snap
|
||||
$modules/packaging/os/sorcery.py:
|
||||
maintainers: vaygr
|
||||
$modules/packaging/os/svr4pkg.py:
|
||||
@@ -1188,6 +1171,8 @@ files:
|
||||
maintainers: inetfuture mattupstate
|
||||
$modules/web_infrastructure/taiga_issue.py:
|
||||
maintainers: lekum
|
||||
$tests/a_module.py:
|
||||
maintainers: felixfontein
|
||||
#########################
|
||||
tests/:
|
||||
labels: tests
|
||||
@@ -1214,6 +1199,7 @@ macros:
|
||||
module_utils: plugins/module_utils
|
||||
modules: plugins/modules
|
||||
terminals: plugins/terminal
|
||||
tests: plugins/test
|
||||
team_ansible_core:
|
||||
team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross
|
||||
team_bsd: JoergFiedler MacLemon bcoca dch jasperla mekanix opoplawski overhacked tuxillo
|
||||
@@ -1221,7 +1207,7 @@ macros:
|
||||
team_cyberark_conjur: jvanderhoof ryanprior
|
||||
team_e_spirit: MatrixCrawler getjack
|
||||
team_flatpak: JayKayy oolongbrothers
|
||||
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii
|
||||
team_gitlab: Lunik Shaps dj-wasabi marwatk waheedi zanssa scodeman metanovii sh0shin
|
||||
team_hpux: bcoca davx8342
|
||||
team_huawei: QijunPan TommyLike edisonxiang freesky-edward hwDCN niuzhenguo xuxiaowei0512 yanzhangi zengchen1024 zhongjun2
|
||||
team_ipa: Akasurde Nosmoht fxfitz justchris1
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
14
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -62,6 +62,20 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Community.general Version
|
||||
description: >-
|
||||
Paste verbatim output from "ansible-galaxy collection list community.general"
|
||||
between tripple backticks.
|
||||
value: |
|
||||
```console (paste below)
|
||||
$ ansible-galaxy collection list community.general
|
||||
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Configuration
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
14
.github/ISSUE_TEMPLATE/documentation_report.yml
vendored
@@ -62,6 +62,20 @@ body:
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Community.general Version
|
||||
description: >-
|
||||
Paste verbatim output from "ansible-galaxy collection list community.general"
|
||||
between tripple backticks.
|
||||
value: |
|
||||
```console (paste below)
|
||||
$ ansible-galaxy collection list community.general
|
||||
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Configuration
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -21,7 +21,7 @@ body:
|
||||
placeholder: >-
|
||||
I am trying to do X with the collection from the main branch on GitHub and
|
||||
I think that implementing a feature Y would be very helpful for me and
|
||||
every other user of ansible-core because of Z.
|
||||
every other user of community.general because of Z.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
interval:
|
||||
schedule: "weekly"
|
||||
1501
CHANGELOG.rst
1501
CHANGELOG.rst
File diff suppressed because it is too large
Load Diff
12
README.md
12
README.md
@@ -1,6 +1,6 @@
|
||||
# Community General Collection
|
||||
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://dev.azure.com/ansible/community.general/_build?definitionId=31)
|
||||
[](https://codecov.io/gh/ansible-collections/community.general)
|
||||
|
||||
This repository contains the `community.general` Ansible Collection. The collection is a part of the Ansible package and includes many modules and plugins supported by Ansible community which are not part of more specialized community collections.
|
||||
@@ -64,13 +64,13 @@ We are actively accepting new contributors.
|
||||
|
||||
All types of contributions are very welcome.
|
||||
|
||||
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/main/CONTRIBUTING.md)!
|
||||
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.general/blob/stable-4/CONTRIBUTING.md)!
|
||||
|
||||
The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
|
||||
The current maintainers are listed in the [commit-rights.md](https://github.com/ansible-collections/community.general/blob/stable-4/commit-rights.md#people) file. If you have questions or need help, feel free to mention them in the proposals.
|
||||
|
||||
You can find more information in the [developer guide for collections](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections.html#contributing-to-collections), and in the [Ansible Community Guide](https://docs.ansible.com/ansible/latest/community/index.html).
|
||||
|
||||
Also for some notes specific to this collection see [our CONTRIBUTING documentation](https://github.com/ansible-collections/community.general/blob/main/CONTRIBUTING.md).
|
||||
Also for some notes specific to this collection see [our CONTRIBUTING documentation](https://github.com/ansible-collections/community.general/blob/stable-4/CONTRIBUTING.md).
|
||||
|
||||
### Running tests
|
||||
|
||||
@@ -80,7 +80,7 @@ See [here](https://docs.ansible.com/ansible/devel/dev_guide/developing_collectio
|
||||
|
||||
To learn how to maintain / become a maintainer of this collection, refer to:
|
||||
|
||||
* [Committer guidelines](https://github.com/ansible-collections/community.general/blob/main/commit-rights.md).
|
||||
* [Committer guidelines](https://github.com/ansible-collections/community.general/blob/stable-4/commit-rights.md).
|
||||
* [Maintainer guidelines](https://github.com/ansible/community-docs/blob/main/maintaining.rst).
|
||||
|
||||
It is necessary for maintainers of this collection to be subscribed to:
|
||||
@@ -108,7 +108,7 @@ See the [Releasing guidelines](https://github.com/ansible/community-docs/blob/ma
|
||||
|
||||
## Release notes
|
||||
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-3/CHANGELOG.rst).
|
||||
See the [changelog](https://github.com/ansible-collections/community.general/blob/stable-4/CHANGELOG.rst).
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,3 +3,4 @@ sections:
|
||||
- title: Guides
|
||||
toctree:
|
||||
- filter_guide
|
||||
- test_guide
|
||||
|
||||
28
docs/docsite/rst/test_guide.rst
Normal file
28
docs/docsite/rst/test_guide.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
.. _ansible_collections.community.general.docsite.test_guide:
|
||||
|
||||
community.general Test (Plugin) Guide
|
||||
=====================================
|
||||
|
||||
The :ref:`community.general collection <plugins_in_community.general>` offers currently one test plugin.
|
||||
|
||||
.. contents:: Topics
|
||||
|
||||
Feature Tests
|
||||
-------------
|
||||
|
||||
The ``a_module`` test allows to check whether a given string refers to an existing module or action plugin. This can be useful in roles, which can use this to ensure that required modules are present ahead of time.
|
||||
|
||||
.. code-block:: yaml+jinja
|
||||
|
||||
- name: Make sure that community.aws.route53 is available
|
||||
assert:
|
||||
that:
|
||||
- >
|
||||
'community.aws.route53' is community.general.a_module
|
||||
|
||||
- name: Make sure that community.general.does_not_exist is not a module or action plugin
|
||||
assert:
|
||||
that:
|
||||
- "'community.general.does_not_exist' is not community.general.a_module"
|
||||
|
||||
.. versionadded:: 4.0.0
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace: community
|
||||
name: general
|
||||
version: 3.8.0
|
||||
version: 4.0.2
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (https://github.com/ansible)
|
||||
|
||||
105
meta/runtime.yml
105
meta/runtime.yml
@@ -12,20 +12,11 @@ plugin_routing:
|
||||
hashi_vault:
|
||||
redirect: community.hashi_vault.hashi_vault
|
||||
nios:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios lookup plugin has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_lookup instead.
|
||||
redirect: infoblox.nios_modules.nios_lookup
|
||||
nios_next_ip:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_next_ip lookup plugin has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_next_ip instead.
|
||||
redirect: infoblox.nios_modules.nios_next_ip
|
||||
nios_next_network:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_next_network lookup plugin has been
|
||||
deprecated. Please use infoblox.nios_modules.nios_next_network instead.
|
||||
redirect: infoblox.nios_modules.nios_next_network
|
||||
modules:
|
||||
ali_instance_facts:
|
||||
tombstone:
|
||||
@@ -266,85 +257,37 @@ plugin_routing:
|
||||
removal_version: 3.0.0
|
||||
warning_text: Use community.general.nginx_status_info instead.
|
||||
nios_a_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_a_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_a_record instead.
|
||||
redirect: infoblox.nios_modules.nios_a_record
|
||||
nios_aaaa_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_aaaa_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_aaaa_record instead.
|
||||
redirect: infoblox.nios_modules.nios_aaaa_record
|
||||
nios_cname_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_cname_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_cname_record instead.
|
||||
redirect: infoblox.nios_modules.nios_cname_record
|
||||
nios_dns_view:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_dns_view module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_dns_view instead.
|
||||
redirect: infoblox.nios_modules.nios_dns_view
|
||||
nios_fixed_address:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_fixed_address module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_fixed_address instead.
|
||||
redirect: infoblox.nios_modules.nios_fixed_address
|
||||
nios_host_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_host_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_host_record instead.
|
||||
redirect: infoblox.nios_modules.nios_host_record
|
||||
nios_member:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_member module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_member instead.
|
||||
redirect: infoblox.nios_modules.nios_member
|
||||
nios_mx_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_mx_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_mx_record instead.
|
||||
redirect: infoblox.nios_modules.nios_mx_record
|
||||
nios_naptr_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_naptr_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_naptr_record instead.
|
||||
redirect: infoblox.nios_modules.nios_naptr_record
|
||||
nios_network:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_network module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_network instead.
|
||||
redirect: infoblox.nios_modules.nios_network
|
||||
nios_network_view:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_network_view module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_network_view instead.
|
||||
redirect: infoblox.nios_modules.nios_network_view
|
||||
nios_nsgroup:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_nsgroup module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_nsgroup instead.
|
||||
redirect: infoblox.nios_modules.nios_nsgroup
|
||||
nios_ptr_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_ptr_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_ptr_record instead.
|
||||
redirect: infoblox.nios_modules.nios_ptr_record
|
||||
nios_srv_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_srv_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_srv_record instead.
|
||||
redirect: infoblox.nios_modules.nios_srv_record
|
||||
nios_txt_record:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_txt_record module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_txt_record instead.
|
||||
redirect: infoblox.nios_modules.nios_txt_record
|
||||
nios_zone:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios_zone module has been deprecated.
|
||||
Please use infoblox.nios_modules.nios_zone instead.
|
||||
redirect: infoblox.nios_modules.nios_zone
|
||||
ome_device_info:
|
||||
redirect: dellemc.openmanage.ome_device_info
|
||||
one_image_facts:
|
||||
@@ -628,10 +571,7 @@ plugin_routing:
|
||||
kubevirt_vm_options:
|
||||
redirect: community.kubevirt.kubevirt_vm_options
|
||||
nios:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.nios document fragment has been deprecated.
|
||||
Please use infoblox.nios_modules.nios instead.
|
||||
redirect: infoblox.nios_modules.nios
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
module_utils:
|
||||
@@ -650,10 +590,7 @@ plugin_routing:
|
||||
kubevirt:
|
||||
redirect: community.kubevirt.kubevirt
|
||||
net_tools.nios.api:
|
||||
deprecation:
|
||||
removal_version: 5.0.0
|
||||
warning_text: The community.general.net_tools.nios.api module_utils has been
|
||||
deprecated. Please use infoblox.nios_modules.api instead.
|
||||
redirect: infoblox.nios_modules.api
|
||||
postgresql:
|
||||
redirect: community.postgresql.postgresql
|
||||
remote_management.dellemc.dellemc_idrac:
|
||||
|
||||
@@ -45,6 +45,8 @@ class CallbackModule(CallbackBase):
|
||||
_task_total = 0
|
||||
_host_counter = 1
|
||||
_host_total = 0
|
||||
_current_batch_total = 0
|
||||
_previous_batch_total = 0
|
||||
|
||||
def __init__(self):
|
||||
super(CallbackModule, self).__init__()
|
||||
@@ -76,8 +78,11 @@ class CallbackModule(CallbackBase):
|
||||
self._display.banner(msg)
|
||||
self._play = play
|
||||
|
||||
self._previous_batch_total = self._current_batch_total
|
||||
self._current_batch_total = self._previous_batch_total + len(self._all_vars()['vars']['ansible_play_batch'])
|
||||
self._host_total = len(self._all_vars()['vars']['ansible_play_hosts_all'])
|
||||
self._task_total = len(self._play.get_tasks()[0])
|
||||
self._task_counter = 1
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
self._display.banner("PLAY RECAP")
|
||||
@@ -145,7 +150,7 @@ class CallbackModule(CallbackBase):
|
||||
path = task.get_path()
|
||||
if path:
|
||||
self._display.display("task path: %s" % path, color=C.COLOR_DEBUG)
|
||||
self._host_counter = 0
|
||||
self._host_counter = self._previous_batch_total
|
||||
self._task_counter += 1
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
|
||||
@@ -226,18 +226,15 @@ class ElasticSource(object):
|
||||
|
||||
message = "success"
|
||||
status = "success"
|
||||
enriched_error_message = None
|
||||
if host_data.status == 'included':
|
||||
rc = 0
|
||||
else:
|
||||
res = host_data.result._result
|
||||
rc = res.get('rc', 0)
|
||||
if host_data.status == 'failed':
|
||||
if res.get('exception') is not None:
|
||||
message = res['exception'].strip().split('\n')[-1]
|
||||
elif 'msg' in res:
|
||||
message = res['msg']
|
||||
else:
|
||||
message = 'failed'
|
||||
message = self.get_error_message(res)
|
||||
enriched_error_message = self.enrich_error_message(res)
|
||||
status = "failure"
|
||||
elif host_data.status == 'skipped':
|
||||
if 'skip_reason' in res:
|
||||
@@ -259,7 +256,7 @@ class ElasticSource(object):
|
||||
"ansible.task.host.status": host_data.status}) as span:
|
||||
span.outcome = status
|
||||
if 'failure' in status:
|
||||
exception = AnsibleRuntimeError(message="{0}: {1} failed with error message {2}".format(task_data.action, name, message))
|
||||
exception = AnsibleRuntimeError(message="{0}: {1} failed with error message {2}".format(task_data.action, name, enriched_error_message))
|
||||
apm_cli.capture_exception(exc_info=(type(exception), exception, exception.__traceback__), handled=True)
|
||||
|
||||
def init_apm_client(self, apm_server_url, apm_service_name, apm_verify_server_cert, apm_secret_token, apm_api_key):
|
||||
@@ -272,6 +269,24 @@ class ElasticSource(object):
|
||||
use_elastic_traceparent_header=True,
|
||||
debug=True)
|
||||
|
||||
@staticmethod
|
||||
def get_error_message(result):
|
||||
if result.get('exception') is not None:
|
||||
return ElasticSource._last_line(result['exception'])
|
||||
return result.get('msg', 'failed')
|
||||
|
||||
@staticmethod
|
||||
def _last_line(text):
|
||||
lines = text.strip().split('\n')
|
||||
return lines[-1]
|
||||
|
||||
@staticmethod
|
||||
def enrich_error_message(result):
|
||||
message = result.get('msg', 'failed')
|
||||
exception = result.get('exception')
|
||||
stderr = result.get('stderr')
|
||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
|
||||
@@ -79,6 +79,7 @@ from os.path import basename
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.six import raise_from
|
||||
from ansible.module_utils.six.moves.urllib.parse import urlparse
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
try:
|
||||
@@ -90,8 +91,6 @@ try:
|
||||
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import (
|
||||
ConsoleSpanExporter,
|
||||
SimpleSpanProcessor,
|
||||
BatchSpanProcessor
|
||||
)
|
||||
from opentelemetry.util._time import _time_ns
|
||||
@@ -179,7 +178,7 @@ class OpenTelemetrySource(object):
|
||||
args = None
|
||||
|
||||
if not task.no_log and not hide_task_arguments:
|
||||
args = ', '.join(('%s=%s' % a for a in task.args.items()))
|
||||
args = task.args
|
||||
|
||||
tasks_data[uuid] = TaskData(uuid, name, path, play_name, action, args)
|
||||
|
||||
@@ -246,32 +245,43 @@ class OpenTelemetrySource(object):
|
||||
name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
|
||||
|
||||
message = 'success'
|
||||
res = {}
|
||||
rc = 0
|
||||
status = Status(status_code=StatusCode.OK)
|
||||
if host_data.status == 'included':
|
||||
rc = 0
|
||||
else:
|
||||
res = host_data.result._result
|
||||
rc = res.get('rc', 0)
|
||||
if host_data.status == 'failed':
|
||||
if host_data.status != 'included':
|
||||
# Support loops
|
||||
if 'results' in host_data.result._result:
|
||||
if host_data.status == 'failed':
|
||||
message = self.get_error_message_from_results(host_data.result._result['results'], task_data.action)
|
||||
enriched_error_message = self.enrich_error_message_from_results(host_data.result._result['results'], task_data.action)
|
||||
else:
|
||||
res = host_data.result._result
|
||||
rc = res.get('rc', 0)
|
||||
message = self.get_error_message(res)
|
||||
enriched_error_message = self.enrich_error_message(res)
|
||||
|
||||
if host_data.status == 'failed':
|
||||
status = Status(status_code=StatusCode.ERROR, description=message)
|
||||
# Record an exception with the task message
|
||||
span.record_exception(BaseException(self.enrich_error_message(res)))
|
||||
span.record_exception(BaseException(enriched_error_message))
|
||||
elif host_data.status == 'skipped':
|
||||
if 'skip_reason' in res:
|
||||
message = res['skip_reason']
|
||||
else:
|
||||
message = 'skipped'
|
||||
message = res['skip_reason'] if 'skip_reason' in res else 'skipped'
|
||||
status = Status(status_code=StatusCode.UNSET)
|
||||
|
||||
span.set_status(status)
|
||||
self.set_span_attribute(span, "ansible.task.args", task_data.args)
|
||||
if isinstance(task_data.args, dict) and "gather_facts" not in task_data.action:
|
||||
names = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.keys())
|
||||
values = tuple(self.transform_ansible_unicode_to_str(k) for k in task_data.args.values())
|
||||
self.set_span_attribute(span, ("ansible.task.args.name"), names)
|
||||
self.set_span_attribute(span, ("ansible.task.args.value"), values)
|
||||
self.set_span_attribute(span, "ansible.task.module", task_data.action)
|
||||
self.set_span_attribute(span, "ansible.task.message", message)
|
||||
self.set_span_attribute(span, "ansible.task.name", name)
|
||||
self.set_span_attribute(span, "ansible.task.result", rc)
|
||||
self.set_span_attribute(span, "ansible.task.host.name", host_data.name)
|
||||
self.set_span_attribute(span, "ansible.task.host.status", host_data.status)
|
||||
# This will allow to enrich the service map
|
||||
self.add_attributes_for_service_map_if_possible(span, task_data)
|
||||
span.end(end_time=host_data.finish)
|
||||
|
||||
def set_span_attribute(self, span, attributeName, attributeValue):
|
||||
@@ -283,12 +293,64 @@ class OpenTelemetrySource(object):
|
||||
if attributeValue is not None:
|
||||
span.set_attribute(attributeName, attributeValue)
|
||||
|
||||
def add_attributes_for_service_map_if_possible(self, span, task_data):
|
||||
"""Update the span attributes with the service that the task interacted with, if possible."""
|
||||
|
||||
redacted_url = self.parse_and_redact_url_if_possible(task_data.args)
|
||||
if redacted_url:
|
||||
self.set_span_attribute(span, "http.url", redacted_url.geturl())
|
||||
|
||||
@staticmethod
|
||||
def parse_and_redact_url_if_possible(args):
|
||||
"""Parse and redact the url, if possible."""
|
||||
|
||||
try:
|
||||
parsed_url = urlparse(OpenTelemetrySource.url_from_args(args))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if OpenTelemetrySource.is_valid_url(parsed_url):
|
||||
return OpenTelemetrySource.redact_user_password(parsed_url)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def url_from_args(args):
|
||||
# the order matters
|
||||
url_args = ("url", "api_url", "baseurl", "repo", "server_url", "chart_repo_url")
|
||||
for arg in url_args:
|
||||
if args.get(arg):
|
||||
return args.get(arg)
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def redact_user_password(url):
|
||||
return url._replace(netloc=url.hostname) if url.password else url
|
||||
|
||||
@staticmethod
|
||||
def is_valid_url(url):
|
||||
if all([url.scheme, url.netloc, url.hostname]):
|
||||
return "{{" not in url.hostname
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def transform_ansible_unicode_to_str(value):
|
||||
parsed_url = urlparse(str(value))
|
||||
if OpenTelemetrySource.is_valid_url(parsed_url):
|
||||
return OpenTelemetrySource.redact_user_password(parsed_url).geturl()
|
||||
return str(value)
|
||||
|
||||
@staticmethod
|
||||
def get_error_message(result):
|
||||
if result.get('exception') is not None:
|
||||
return OpenTelemetrySource._last_line(result['exception'])
|
||||
return result.get('msg', 'failed')
|
||||
|
||||
@staticmethod
|
||||
def get_error_message_from_results(results, action):
|
||||
for result in results:
|
||||
if result.get('failed', False):
|
||||
return ('{0}({1}) - {2}').format(action, result.get('item', 'none'), OpenTelemetrySource.get_error_message(result))
|
||||
|
||||
@staticmethod
|
||||
def _last_line(text):
|
||||
lines = text.strip().split('\n')
|
||||
@@ -301,6 +363,14 @@ class OpenTelemetrySource(object):
|
||||
stderr = result.get('stderr')
|
||||
return ('message: "{0}"\nexception: "{1}"\nstderr: "{2}"').format(message, exception, stderr)
|
||||
|
||||
@staticmethod
|
||||
def enrich_error_message_from_results(results, action):
|
||||
message = ""
|
||||
for result in results:
|
||||
if result.get('failed', False):
|
||||
message = ('{0}({1}) - {2}\n{3}').format(action, result.get('item', 'none'), OpenTelemetrySource.enrich_error_message(result), message)
|
||||
return message
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
"""
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2018, Sumit Kumar <sumit4@netapp.com>, chris Archibald <carchi@netapp.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
- See respective platform section for more details
|
||||
requirements:
|
||||
- See respective platform section for more details
|
||||
notes:
|
||||
- Ansible modules are available for the following NetApp Storage Platforms: E-Series, ONTAP, SolidFire
|
||||
'''
|
||||
|
||||
# Documentation fragment for ONTAP (na_cdot)
|
||||
ONTAP = r'''
|
||||
options:
|
||||
hostname:
|
||||
required: true
|
||||
description:
|
||||
- The hostname or IP address of the ONTAP instance.
|
||||
username:
|
||||
required: true
|
||||
description:
|
||||
- This can be a Cluster-scoped or SVM-scoped account, depending on whether a Cluster-level or SVM-level API is required.
|
||||
For more information, please read the documentation U(https://mysupport.netapp.com/NOW/download/software/nmsdk/9.4/).
|
||||
aliases: ['user']
|
||||
password:
|
||||
required: true
|
||||
description:
|
||||
- Password for the specified user.
|
||||
aliases: ['pass']
|
||||
requirements:
|
||||
- A physical or virtual clustered Data ONTAP system. The modules were developed with Clustered Data ONTAP 8.3
|
||||
- Ansible 2.2
|
||||
- netapp-lib (2015.9.25). Install using 'pip install netapp-lib'
|
||||
|
||||
notes:
|
||||
- The modules prefixed with na\\_cdot are built to support the ONTAP storage platform.
|
||||
|
||||
'''
|
||||
|
||||
# Documentation fragment for SolidFire
|
||||
SOLIDFIRE = r'''
|
||||
options:
|
||||
hostname:
|
||||
required: true
|
||||
description:
|
||||
- The hostname or IP address of the SolidFire cluster.
|
||||
username:
|
||||
required: true
|
||||
description:
|
||||
- Please ensure that the user has the adequate permissions. For more information, please read the official documentation
|
||||
U(https://mysupport.netapp.com/documentation/docweb/index.html?productID=62636&language=en-US).
|
||||
aliases: ['user']
|
||||
password:
|
||||
required: true
|
||||
description:
|
||||
- Password for the specified user.
|
||||
aliases: ['pass']
|
||||
|
||||
requirements:
|
||||
- The modules were developed with SolidFire 10.1
|
||||
- solidfire-sdk-python (1.1.0.92) or greater. Install using 'pip install solidfire-sdk-python'
|
||||
|
||||
notes:
|
||||
- The modules prefixed with na\\_elementsw are built to support the SolidFire storage platform.
|
||||
|
||||
'''
|
||||
|
||||
# Documentation fragment for ONTAP (na_ontap)
|
||||
NA_ONTAP = r'''
|
||||
options:
|
||||
hostname:
|
||||
description:
|
||||
- The hostname or IP address of the ONTAP instance.
|
||||
type: str
|
||||
required: true
|
||||
username:
|
||||
description:
|
||||
- This can be a Cluster-scoped or SVM-scoped account, depending on whether a Cluster-level or SVM-level API is required.
|
||||
For more information, please read the documentation U(https://mysupport.netapp.com/NOW/download/software/nmsdk/9.4/).
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ user ]
|
||||
password:
|
||||
description:
|
||||
- Password for the specified user.
|
||||
type: str
|
||||
required: true
|
||||
aliases: [ pass ]
|
||||
https:
|
||||
description:
|
||||
- Enable and disable https
|
||||
type: bool
|
||||
default: no
|
||||
validate_certs:
|
||||
description:
|
||||
- If set to C(no), the SSL certificates will not be validated.
|
||||
- This should only set to C(False) used on personally controlled sites using self-signed certificates.
|
||||
type: bool
|
||||
default: yes
|
||||
http_port:
|
||||
description:
|
||||
- Override the default port (80 or 443) with this port
|
||||
type: int
|
||||
ontapi:
|
||||
description:
|
||||
- The ontap api version to use
|
||||
type: int
|
||||
use_rest:
|
||||
description:
|
||||
- REST API if supported by the target system for all the resources and attributes the module requires. Otherwise will revert to ZAPI.
|
||||
- Always -- will always use the REST API
|
||||
- Never -- will always use the ZAPI
|
||||
- Auto -- will try to use the REST Api
|
||||
default: Auto
|
||||
choices: ['Never', 'Always', 'Auto']
|
||||
type: str
|
||||
|
||||
|
||||
requirements:
|
||||
- A physical or virtual clustered Data ONTAP system. The modules support Data ONTAP 9.1 and onward
|
||||
- Ansible 2.6
|
||||
- Python2 netapp-lib (2017.10.30) or later. Install using 'pip install netapp-lib'
|
||||
- Python3 netapp-lib (2018.11.13) or later. Install using 'pip install netapp-lib'
|
||||
- To enable http on the cluster you must run the following commands 'set -privilege advanced;' 'system services web modify -http-enabled true;'
|
||||
|
||||
notes:
|
||||
- The modules prefixed with na\\_ontap are built to support the ONTAP storage platform.
|
||||
|
||||
'''
|
||||
41
plugins/doc_fragments/bitbucket.py
Normal file
41
plugins/doc_fragments/bitbucket.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2019, Evgeniy Krysanov <evgeniy.krysanov@gmail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
client_id:
|
||||
description:
|
||||
- The OAuth consumer key.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_ID) will be used.
|
||||
type: str
|
||||
client_secret:
|
||||
description:
|
||||
- The OAuth consumer secret.
|
||||
- If not set the environment variable C(BITBUCKET_CLIENT_SECRET) will be used.
|
||||
type: str
|
||||
user:
|
||||
description:
|
||||
- The username.
|
||||
- If not set the environment variable C(BITBUCKET_USERNAME) will be used.
|
||||
type: str
|
||||
version_added: 4.0.0
|
||||
password:
|
||||
description:
|
||||
- The App password.
|
||||
- If not set the environment variable C(BITBUCKET_PASSWORD) will be used.
|
||||
type: str
|
||||
version_added: 4.0.0
|
||||
notes:
|
||||
- Bitbucket OAuth consumer key and secret can be obtained from Bitbucket profile -> Settings -> Access Management -> OAuth.
|
||||
- Bitbucket App password can be created from Bitbucket profile -> Personal Settings -> App passwords.
|
||||
- If both OAuth and Basic Auth credentials are passed, OAuth credentials take precedence.
|
||||
'''
|
||||
@@ -1,103 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
|
||||
class ModuleDocFragment(object):
|
||||
|
||||
# Standard files documentation fragment
|
||||
DOCUMENTATION = r'''
|
||||
options:
|
||||
provider:
|
||||
description:
|
||||
- A dict object containing connection details.
|
||||
type: dict
|
||||
suboptions:
|
||||
host:
|
||||
description:
|
||||
- Specifies the DNS host name or address for connecting to the remote
|
||||
instance of NIOS WAPI over REST
|
||||
- Value can also be specified using C(INFOBLOX_HOST) environment
|
||||
variable.
|
||||
type: str
|
||||
username:
|
||||
description:
|
||||
- Configures the username to use to authenticate the connection to
|
||||
the remote instance of NIOS.
|
||||
- Value can also be specified using C(INFOBLOX_USERNAME) environment
|
||||
variable.
|
||||
type: str
|
||||
password:
|
||||
description:
|
||||
- Specifies the password to use to authenticate the connection to
|
||||
the remote instance of NIOS.
|
||||
- Value can also be specified using C(INFOBLOX_PASSWORD) environment
|
||||
variable.
|
||||
type: str
|
||||
validate_certs:
|
||||
description:
|
||||
- Boolean value to enable or disable verifying SSL certificates
|
||||
- Value can also be specified using C(INFOBLOX_SSL_VERIFY) environment
|
||||
variable.
|
||||
type: bool
|
||||
default: no
|
||||
aliases: [ ssl_verify ]
|
||||
http_request_timeout:
|
||||
description:
|
||||
- The amount of time before to wait before receiving a response
|
||||
- Value can also be specified using C(INFOBLOX_HTTP_REQUEST_TIMEOUT) environment
|
||||
variable.
|
||||
type: int
|
||||
default: 10
|
||||
max_retries:
|
||||
description:
|
||||
- Configures the number of attempted retries before the connection
|
||||
is declared usable
|
||||
- Value can also be specified using C(INFOBLOX_MAX_RETRIES) environment
|
||||
variable.
|
||||
type: int
|
||||
default: 3
|
||||
wapi_version:
|
||||
description:
|
||||
- Specifies the version of WAPI to use
|
||||
- Value can also be specified using C(INFOBLOX_WAP_VERSION) environment
|
||||
variable.
|
||||
- Until ansible 2.8 the default WAPI was 1.4
|
||||
type: str
|
||||
default: '2.1'
|
||||
max_results:
|
||||
description:
|
||||
- Specifies the maximum number of objects to be returned,
|
||||
if set to a negative number the appliance will return an error when the
|
||||
number of returned objects would exceed the setting.
|
||||
- Value can also be specified using C(INFOBLOX_MAX_RESULTS) environment
|
||||
variable.
|
||||
type: int
|
||||
default: 1000
|
||||
http_pool_connections:
|
||||
description:
|
||||
- Number of pools to be used by the C(infoblox_client.Connector) object.
|
||||
- This is passed as-is to the underlying C(requests.adapters.HTTPAdapter) class.
|
||||
type: int
|
||||
default: 10
|
||||
http_pool_maxsize:
|
||||
description:
|
||||
- Maximum number of connections per pool to be used by the C(infoblox_client.Connector) object.
|
||||
- This is passed as-is to the underlying C(requests.adapters.HTTPAdapter) class.
|
||||
type: int
|
||||
default: 10
|
||||
silent_ssl_warnings:
|
||||
description:
|
||||
- Disable C(urllib3) SSL warnings in the C(infoblox_client.Connector) object.
|
||||
- This is passed as-is to the underlying C(requests.adapters.HTTPAdapter) class.
|
||||
type: bool
|
||||
default: true
|
||||
notes:
|
||||
- "This module must be run locally, which can be achieved by specifying C(connection: local)."
|
||||
- Please read the :ref:`nios_guide` for more detailed information on how to use Infoblox with Ansible.
|
||||
|
||||
'''
|
||||
@@ -13,6 +13,8 @@ DOCUMENTATION = r'''
|
||||
- Uses a YAML configuration file that ends with 'lxd.(yml|yaml)'.
|
||||
version_added: "3.0.0"
|
||||
author: "Frank Dornheim (@conloos)"
|
||||
requirements:
|
||||
- ipaddress
|
||||
options:
|
||||
plugin:
|
||||
description: Token that ensures this is a source file for the 'lxd' plugin.
|
||||
@@ -124,10 +126,17 @@ import socket
|
||||
from ansible.plugins.inventory import BaseInventoryPlugin
|
||||
from ansible.module_utils.common.text.converters import to_native, to_text
|
||||
from ansible.module_utils.common.dict_transformations import dict_merge
|
||||
from ansible.module_utils.six import raise_from
|
||||
from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible_collections.community.general.plugins.module_utils.compat import ipaddress
|
||||
from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException
|
||||
|
||||
try:
|
||||
import ipaddress
|
||||
except ImportError as exc:
|
||||
IPADDRESS_IMPORT_ERROR = exc
|
||||
else:
|
||||
IPADDRESS_IMPORT_ERROR = None
|
||||
|
||||
|
||||
class InventoryModule(BaseInventoryPlugin):
|
||||
DEBUG = 4
|
||||
@@ -924,6 +933,10 @@ class InventoryModule(BaseInventoryPlugin):
|
||||
AnsibleParserError
|
||||
Returns:
|
||||
None"""
|
||||
if IPADDRESS_IMPORT_ERROR:
|
||||
raise_from(
|
||||
AnsibleError('another_library must be installed to use this plugin'),
|
||||
IPADDRESS_IMPORT_ERROR)
|
||||
|
||||
super(InventoryModule, self).parse(inventory, loader, path, cache=False)
|
||||
# Read the inventory YAML file
|
||||
|
||||
138
plugins/lookup/collection_version.py
Normal file
138
plugins/lookup/collection_version.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# (c) 2021, Felix Fontein <felix@fontein.de>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
name: collection_version
|
||||
author: Felix Fontein (@felixfontein)
|
||||
version_added: "4.0.0"
|
||||
short_description: Retrieves the version of an installed collection
|
||||
description:
|
||||
- This lookup allows to query the version of an installed collection, and to determine whether a
|
||||
collection is installed at all.
|
||||
- By default it returns C(none) for non-existing collections and C(*) for collections without a
|
||||
version number. The latter should only happen in development environments, or when installing
|
||||
a collection from git which has no version in its C(galaxy.yml). This behavior can be adjusted
|
||||
by providing other values with I(result_not_found) and I(result_no_version).
|
||||
options:
|
||||
_terms:
|
||||
description:
|
||||
- The collections to look for.
|
||||
- For example C(community.general).
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
result_not_found:
|
||||
description:
|
||||
- The value to return when the collection could not be found.
|
||||
- By default, C(none) is returned.
|
||||
type: string
|
||||
default: ~
|
||||
result_no_version:
|
||||
description:
|
||||
- The value to return when the collection has no version number.
|
||||
- This can happen for collections installed from git which do not have a version number
|
||||
in C(galaxy.yml).
|
||||
- By default, C(*) is returned.
|
||||
type: string
|
||||
default: '*'
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Check version of community.general
|
||||
ansible.builtin.debug:
|
||||
msg: "community.general version {{ lookup('community.general.collection_version', 'community.general') }}"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description:
|
||||
- The version number of the collections listed as input.
|
||||
- If a collection can not be found, it will return the value provided in I(result_not_found).
|
||||
By default, this is C(none).
|
||||
- If a collection can be found, but the version not identified, it will return the value provided in
|
||||
I(result_no_version). By default, this is C(*). This can happen for collections installed
|
||||
from git which do not have a version number in C(galaxy.yml).
|
||||
type: list
|
||||
elements: str
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
import yaml
|
||||
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.module_utils.compat.importlib import import_module
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
|
||||
FQCN_RE = re.compile(r'^[A-Za-z0-9_]+\.[A-Za-z0-9_]+$')
|
||||
|
||||
|
||||
def load_collection_meta_manifest(manifest_path):
|
||||
with open(manifest_path, 'rb') as f:
|
||||
meta = json.load(f)
|
||||
return {
|
||||
'version': meta['collection_info']['version'],
|
||||
}
|
||||
|
||||
|
||||
def load_collection_meta_galaxy(galaxy_path, no_version='*'):
|
||||
with open(galaxy_path, 'rb') as f:
|
||||
meta = yaml.safe_load(f)
|
||||
return {
|
||||
'version': meta.get('version') or no_version,
|
||||
}
|
||||
|
||||
|
||||
def load_collection_meta(collection_pkg, no_version='*'):
|
||||
path = os.path.dirname(collection_pkg.__file__)
|
||||
|
||||
# Try to load MANIFEST.json
|
||||
manifest_path = os.path.join(path, 'MANIFEST.json')
|
||||
if os.path.exists(manifest_path):
|
||||
return load_collection_meta_manifest(manifest_path)
|
||||
|
||||
# Try to load galaxy.y(a)ml
|
||||
galaxy_path = os.path.join(path, 'galaxy.yml')
|
||||
galaxy_alt_path = os.path.join(path, 'galaxy.yaml')
|
||||
# galaxy.yaml was only supported in ansible-base 2.10 and ansible-core 2.11. Support was removed
|
||||
# in https://github.com/ansible/ansible/commit/595413d11346b6f26bb3d9df2d8e05f2747508a3 for
|
||||
# ansible-core 2.12.
|
||||
for path in (galaxy_path, galaxy_alt_path):
|
||||
if os.path.exists(path):
|
||||
return load_collection_meta_galaxy(path, no_version=no_version)
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
result = []
|
||||
self.set_options(var_options=variables, direct=kwargs)
|
||||
not_found = self.get_option('result_not_found')
|
||||
no_version = self.get_option('result_no_version')
|
||||
|
||||
for term in terms:
|
||||
if not FQCN_RE.match(term):
|
||||
raise AnsibleLookupError('"{term}" is not a FQCN'.format(term=term))
|
||||
|
||||
try:
|
||||
collection_pkg = import_module('ansible_collections.{fqcn}'.format(fqcn=term))
|
||||
except ImportError:
|
||||
# Collection not found
|
||||
result.append(not_found)
|
||||
continue
|
||||
|
||||
try:
|
||||
data = load_collection_meta(collection_pkg, no_version=no_version)
|
||||
except Exception as exc:
|
||||
raise AnsibleLookupError('Error while loading metadata for {fqcn}: {error}'.format(fqcn=term, error=exc))
|
||||
|
||||
result.append(data.get('version', no_version))
|
||||
|
||||
return result
|
||||
@@ -1,126 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2018 Red Hat | Ansible
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: nios
|
||||
short_description: Query Infoblox NIOS objects
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
|
||||
alternative: infoblox.nios_modules.nios_lookup
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Uses the Infoblox WAPI API to fetch NIOS specified objects. This lookup
|
||||
supports adding additional keywords to filter the return data and specify
|
||||
the desired set of returned fields.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
_terms:
|
||||
description: The name of the object to return from NIOS
|
||||
required: True
|
||||
return_fields:
|
||||
description: The list of field names to return for the specified object.
|
||||
filter:
|
||||
description: a dict object that is used to filter the return objects
|
||||
extattrs:
|
||||
description: a dict object that is used to filter on extattrs
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
- name: fetch all networkview objects
|
||||
ansible.builtin.set_fact:
|
||||
networkviews: "{{ lookup('community.general.nios', 'networkview',
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
- name: fetch the default dns view
|
||||
ansible.builtin.set_fact:
|
||||
dns_views: "{{ lookup('community.general.nios', 'view', filter={'name': 'default'},
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
# all of the examples below use credentials that are set using env variables
|
||||
# export INFOBLOX_HOST=nios01
|
||||
# export INFOBLOX_USERNAME=admin
|
||||
# export INFOBLOX_PASSWORD=admin
|
||||
|
||||
- name: fetch all host records and include extended attributes
|
||||
ansible.builtin.set_fact:
|
||||
host_records: "{{ lookup('community.general.nios', 'record:host', return_fields=['extattrs', 'name', 'view', 'comment']}) }}"
|
||||
|
||||
|
||||
- name: use env variables to pass credentials
|
||||
ansible.builtin.set_fact:
|
||||
networkviews: "{{ lookup('community.general.nios', 'networkview') }}"
|
||||
|
||||
- name: get a host record
|
||||
ansible.builtin.set_fact:
|
||||
host: "{{ lookup('community.general.nios', 'record:host', filter={'name': 'hostname.ansible.com'}) }}"
|
||||
|
||||
- name: get the authoritative zone from a non default dns view
|
||||
ansible.builtin.set_fact:
|
||||
host: "{{ lookup('community.general.nios', 'zone_auth', filter={'fqdn': 'ansible.com', 'view': 'ansible-dns'}) }}"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
obj_type:
|
||||
description:
|
||||
- The object type specified in the terms argument
|
||||
type: dictionary
|
||||
contains:
|
||||
obj_field:
|
||||
description:
|
||||
- One or more obj_type fields as specified by return_fields argument or
|
||||
the default set of fields as per the object type
|
||||
"""
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiLookup
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_extattrs, flatten_extattrs
|
||||
from ansible.errors import AnsibleError
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
try:
|
||||
obj_type = terms[0]
|
||||
except IndexError:
|
||||
raise AnsibleError('the object_type must be specified')
|
||||
|
||||
return_fields = kwargs.pop('return_fields', None)
|
||||
filter_data = kwargs.pop('filter', {})
|
||||
extattrs = normalize_extattrs(kwargs.pop('extattrs', {}))
|
||||
provider = kwargs.pop('provider', {})
|
||||
wapi = WapiLookup(provider)
|
||||
res = wapi.get_object(obj_type, filter_data, return_fields=return_fields, extattrs=extattrs)
|
||||
if res is not None:
|
||||
for obj in res:
|
||||
if 'extattrs' in obj:
|
||||
obj['extattrs'] = flatten_extattrs(obj['extattrs'])
|
||||
else:
|
||||
res = []
|
||||
return res
|
||||
@@ -1,105 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2018 Red Hat | Ansible
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: nios_next_ip
|
||||
short_description: Return the next available IP address for a network
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
|
||||
alternative: infoblox.nios_modules.nios_next_ip
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Uses the Infoblox WAPI API to return the next available IP addresses
|
||||
for a given network CIDR
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
_terms:
|
||||
description: The CIDR network to retrieve the next addresses from
|
||||
required: True
|
||||
num:
|
||||
description: The number of IP addresses to return
|
||||
required: false
|
||||
default: 1
|
||||
exclude:
|
||||
description: List of IP's that need to be excluded from returned IP addresses
|
||||
required: false
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
- name: return next available IP address for network 192.168.10.0/24
|
||||
ansible.builtin.set_fact:
|
||||
ipaddr: "{{ lookup('community.general.nios_next_ip', '192.168.10.0/24', provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
- name: return the next 3 available IP addresses for network 192.168.10.0/24
|
||||
ansible.builtin.set_fact:
|
||||
ipaddr: "{{ lookup('community.general.nios_next_ip', '192.168.10.0/24', num=3, provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
- name: return the next 3 available IP addresses for network 192.168.10.0/24 excluding ip addresses - ['192.168.10.1', '192.168.10.2']
|
||||
ansible.builtin.set_fact:
|
||||
ipaddr: "{{ lookup('community.general.nios_next_ip', '192.168.10.0/24', num=3, exclude=['192.168.10.1', '192.168.10.2'],
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_list:
|
||||
description:
|
||||
- The list of next IP addresses available
|
||||
type: list
|
||||
"""
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiLookup
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.errors import AnsibleError
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
try:
|
||||
network = terms[0]
|
||||
except IndexError:
|
||||
raise AnsibleError('missing argument in the form of A.B.C.D/E')
|
||||
|
||||
provider = kwargs.pop('provider', {})
|
||||
wapi = WapiLookup(provider)
|
||||
|
||||
network_obj = wapi.get_object('network', {'network': network})
|
||||
if network_obj is None:
|
||||
raise AnsibleError('unable to find network object %s' % network)
|
||||
|
||||
num = kwargs.get('num', 1)
|
||||
exclude_ip = kwargs.get('exclude', [])
|
||||
|
||||
try:
|
||||
ref = network_obj[0]['_ref']
|
||||
avail_ips = wapi.call_func('next_available_ip', ref, {'num': num, 'exclude': exclude_ip})
|
||||
return [avail_ips['ips']]
|
||||
except Exception as exc:
|
||||
raise AnsibleError(to_text(exc))
|
||||
@@ -1,118 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2018 Red Hat | Ansible
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
author: Unknown (!UNKNOWN)
|
||||
name: nios_next_network
|
||||
short_description: Return the next available network range for a network-container
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding lookup from it.
|
||||
alternative: infoblox.nios_modules.nios_next_network
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Uses the Infoblox WAPI API to return the next available network addresses for
|
||||
a given network CIDR
|
||||
requirements:
|
||||
- infoblox_client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
_terms:
|
||||
description: The CIDR network to retrieve the next network from next available network within the specified
|
||||
container.
|
||||
required: True
|
||||
cidr:
|
||||
description:
|
||||
- The CIDR of the network to retrieve the next network from next available network within the
|
||||
specified container. Also, Requested CIDR must be specified and greater than the parent CIDR.
|
||||
required: True
|
||||
default: 24
|
||||
num:
|
||||
description: The number of network addresses to return from network-container
|
||||
required: false
|
||||
default: 1
|
||||
exclude:
|
||||
description: Network addresses returned from network-container excluding list of user's input network range
|
||||
required: false
|
||||
default: ''
|
||||
'''
|
||||
|
||||
EXAMPLES = """
|
||||
- name: return next available network for network-container 192.168.10.0/24
|
||||
ansible.builtin.set_fact:
|
||||
networkaddr: "{{ lookup('community.general.nios_next_network', '192.168.10.0/24', cidr=25,
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
- name: return the next 2 available network addresses for network-container 192.168.10.0/24
|
||||
ansible.builtin.set_fact:
|
||||
networkaddr: "{{ lookup('community.general.nios_next_network', '192.168.10.0/24', cidr=25, num=2,
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
|
||||
- name: return the available network addresses for network-container 192.168.10.0/24 excluding network range '192.168.10.0/25'
|
||||
ansible.builtin.set_fact:
|
||||
networkaddr: "{{ lookup('community.general.nios_next_network', '192.168.10.0/24', cidr=25, exclude=['192.168.10.0/25'],
|
||||
provider={'host': 'nios01', 'username': 'admin', 'password': 'password'}) }}"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_list:
|
||||
description:
|
||||
- The list of next network addresses available
|
||||
type: list
|
||||
"""
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiLookup
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.errors import AnsibleError
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
try:
|
||||
network = terms[0]
|
||||
except IndexError:
|
||||
raise AnsibleError('missing network argument in the form of A.B.C.D/E')
|
||||
try:
|
||||
cidr = kwargs.get('cidr', 24)
|
||||
except IndexError:
|
||||
raise AnsibleError('missing CIDR argument in the form of xx')
|
||||
|
||||
provider = kwargs.pop('provider', {})
|
||||
wapi = WapiLookup(provider)
|
||||
network_obj = wapi.get_object('networkcontainer', {'network': network})
|
||||
|
||||
if network_obj is None:
|
||||
raise AnsibleError('unable to find network-container object %s' % network)
|
||||
num = kwargs.get('num', 1)
|
||||
exclude_ip = kwargs.get('exclude', [])
|
||||
|
||||
try:
|
||||
ref = network_obj[0]['_ref']
|
||||
avail_nets = wapi.call_func('next_available_network', ref, {'cidr': cidr, 'num': num, 'exclude': exclude_ip})
|
||||
return [avail_nets['networks']]
|
||||
except Exception as exc:
|
||||
raise AnsibleError(to_text(exc))
|
||||
119
plugins/lookup/random_words.py
Normal file
119
plugins/lookup/random_words.py
Normal file
@@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
"""The community.general.random_words Ansible lookup plugin."""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = r"""
|
||||
name: random_words
|
||||
author:
|
||||
- Thomas Sjögren (@konstruktoid)
|
||||
short_description: Return a number of random words
|
||||
version_added: "4.0.0"
|
||||
requirements:
|
||||
- xkcdpass U(https://github.com/redacted/XKCD-password-generator)
|
||||
description:
|
||||
- Returns a number of random words. The output can for example be used for
|
||||
passwords.
|
||||
- See U(https://xkcd.com/936/) for background.
|
||||
options:
|
||||
numwords:
|
||||
description:
|
||||
- The number of words.
|
||||
default: 6
|
||||
type: int
|
||||
min_length:
|
||||
description:
|
||||
- Minimum length of words to make password.
|
||||
default: 5
|
||||
type: int
|
||||
max_length:
|
||||
description:
|
||||
- Maximum length of words to make password.
|
||||
default: 9
|
||||
type: int
|
||||
delimiter:
|
||||
description:
|
||||
- The delimiter character between words.
|
||||
default: " "
|
||||
type: str
|
||||
case:
|
||||
description:
|
||||
- The method for setting the case of each word in the passphrase.
|
||||
choices: ["alternating", "upper", "lower", "random", "capitalize"]
|
||||
default: "lower"
|
||||
type: str
|
||||
"""
|
||||
|
||||
EXAMPLES = r"""
|
||||
- name: Generate password with default settings
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_words')
|
||||
# Example result: 'traitor gigabyte cesarean unless aspect clear'
|
||||
|
||||
- name: Generate password with six, five character, words
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_words', min_length=5, max_length=5)
|
||||
# Example result: 'brink banjo getup staff trump comfy'
|
||||
|
||||
- name: Generate password with three capitalized words and the '-' delimiter
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_words', numwords=3, delimiter='-', case='capitalize')
|
||||
# Example result: 'Overlabor-Faucet-Coastline'
|
||||
|
||||
- name: Generate password with three words without any delimiter
|
||||
ansible.builtin.debug:
|
||||
var: lookup('community.general.random_words', numwords=3, delimiter='')
|
||||
# Example result: 'deskworkmonopolystriking'
|
||||
# https://www.ncsc.gov.uk/blog-post/the-logic-behind-three-random-words
|
||||
"""
|
||||
|
||||
RETURN = r"""
|
||||
_raw:
|
||||
description: A single-element list containing random words.
|
||||
type: list
|
||||
elements: str
|
||||
"""
|
||||
|
||||
from ansible.errors import AnsibleLookupError
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
try:
|
||||
from xkcdpass import xkcd_password as xp
|
||||
|
||||
HAS_XKCDPASS = True
|
||||
except ImportError:
|
||||
HAS_XKCDPASS = False
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
"""The random_words Ansible lookup class."""
|
||||
|
||||
def run(self, terms, variables=None, **kwargs):
|
||||
|
||||
if not HAS_XKCDPASS:
|
||||
raise AnsibleLookupError(
|
||||
"Python xkcdpass library is required. "
|
||||
'Please install using "pip install xkcdpass"'
|
||||
)
|
||||
|
||||
self.set_options(var_options=variables, direct=kwargs)
|
||||
method = self.get_option("case")
|
||||
delimiter = self.get_option("delimiter")
|
||||
max_length = self.get_option("max_length")
|
||||
min_length = self.get_option("min_length")
|
||||
numwords = self.get_option("numwords")
|
||||
|
||||
words = xp.locate_wordfile()
|
||||
wordlist = xp.generate_wordlist(
|
||||
max_length=max_length, min_length=min_length, wordfile=words
|
||||
)
|
||||
|
||||
values = xp.generate_xkcdpassword(
|
||||
wordlist, case=method, delimiter=delimiter, numwords=numwords
|
||||
)
|
||||
|
||||
return [values]
|
||||
@@ -1,748 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This code is part of Ansible, but is an independent component.
|
||||
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# Copyright (c) 2017, Sumit Kumar <sumit4@netapp.com>
|
||||
# Copyright (c) 2017, Michael Price <michael.price@netapp.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import mimetypes
|
||||
|
||||
from pprint import pformat
|
||||
from ansible.module_utils import six
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
|
||||
from ansible.module_utils.urls import open_url
|
||||
from ansible.module_utils.api import basic_auth_argument_spec
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
|
||||
try:
|
||||
from ansible.module_utils.ansible_release import __version__ as ansible_version
|
||||
except ImportError:
|
||||
ansible_version = 'unknown'
|
||||
|
||||
try:
|
||||
from netapp_lib.api.zapi import zapi
|
||||
HAS_NETAPP_LIB = True
|
||||
except ImportError:
|
||||
HAS_NETAPP_LIB = False
|
||||
|
||||
try:
|
||||
import requests
|
||||
HAS_REQUESTS = True
|
||||
except ImportError:
|
||||
HAS_REQUESTS = False
|
||||
|
||||
import ssl
|
||||
try:
|
||||
from urlparse import urlparse, urlunparse
|
||||
except ImportError:
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
|
||||
HAS_SF_SDK = False
|
||||
SF_BYTE_MAP = dict(
|
||||
# Management GUI displays 1024 ** 3 as 1.1 GB, thus use 1000.
|
||||
bytes=1,
|
||||
b=1,
|
||||
kb=1000,
|
||||
mb=1000 ** 2,
|
||||
gb=1000 ** 3,
|
||||
tb=1000 ** 4,
|
||||
pb=1000 ** 5,
|
||||
eb=1000 ** 6,
|
||||
zb=1000 ** 7,
|
||||
yb=1000 ** 8
|
||||
)
|
||||
|
||||
POW2_BYTE_MAP = dict(
|
||||
# Here, 1 kb = 1024
|
||||
bytes=1,
|
||||
b=1,
|
||||
kb=1024,
|
||||
mb=1024 ** 2,
|
||||
gb=1024 ** 3,
|
||||
tb=1024 ** 4,
|
||||
pb=1024 ** 5,
|
||||
eb=1024 ** 6,
|
||||
zb=1024 ** 7,
|
||||
yb=1024 ** 8
|
||||
)
|
||||
|
||||
try:
|
||||
from solidfire.factory import ElementFactory
|
||||
from solidfire.custom.models import TimeIntervalFrequency
|
||||
from solidfire.models import Schedule, ScheduleInfo
|
||||
|
||||
HAS_SF_SDK = True
|
||||
except Exception:
|
||||
HAS_SF_SDK = False
|
||||
|
||||
|
||||
def has_netapp_lib():
|
||||
return HAS_NETAPP_LIB
|
||||
|
||||
|
||||
def has_sf_sdk():
|
||||
return HAS_SF_SDK
|
||||
|
||||
|
||||
def na_ontap_host_argument_spec():
|
||||
|
||||
return dict(
|
||||
hostname=dict(required=True, type='str'),
|
||||
username=dict(required=True, type='str', aliases=['user']),
|
||||
password=dict(required=True, type='str', aliases=['pass'], no_log=True),
|
||||
https=dict(required=False, type='bool', default=False),
|
||||
validate_certs=dict(required=False, type='bool', default=True),
|
||||
http_port=dict(required=False, type='int'),
|
||||
ontapi=dict(required=False, type='int'),
|
||||
use_rest=dict(required=False, type='str', default='Auto', choices=['Never', 'Always', 'Auto'])
|
||||
)
|
||||
|
||||
|
||||
def ontap_sf_host_argument_spec():
|
||||
|
||||
return dict(
|
||||
hostname=dict(required=True, type='str'),
|
||||
username=dict(required=True, type='str', aliases=['user']),
|
||||
password=dict(required=True, type='str', aliases=['pass'], no_log=True)
|
||||
)
|
||||
|
||||
|
||||
def aws_cvs_host_argument_spec():
|
||||
|
||||
return dict(
|
||||
api_url=dict(required=True, type='str'),
|
||||
validate_certs=dict(required=False, type='bool', default=True),
|
||||
api_key=dict(required=True, type='str', no_log=True),
|
||||
secret_key=dict(required=True, type='str', no_log=True)
|
||||
)
|
||||
|
||||
|
||||
def create_sf_connection(module, port=None):
|
||||
hostname = module.params['hostname']
|
||||
username = module.params['username']
|
||||
password = module.params['password']
|
||||
|
||||
if HAS_SF_SDK and hostname and username and password:
|
||||
try:
|
||||
return_val = ElementFactory.create(hostname, username, password, port=port)
|
||||
return return_val
|
||||
except Exception:
|
||||
raise Exception("Unable to create SF connection")
|
||||
else:
|
||||
module.fail_json(msg="the python SolidFire SDK module is required")
|
||||
|
||||
|
||||
def setup_na_ontap_zapi(module, vserver=None):
|
||||
hostname = module.params['hostname']
|
||||
username = module.params['username']
|
||||
password = module.params['password']
|
||||
https = module.params['https']
|
||||
validate_certs = module.params['validate_certs']
|
||||
port = module.params['http_port']
|
||||
version = module.params['ontapi']
|
||||
|
||||
if HAS_NETAPP_LIB:
|
||||
# set up zapi
|
||||
server = zapi.NaServer(hostname)
|
||||
server.set_username(username)
|
||||
server.set_password(password)
|
||||
if vserver:
|
||||
server.set_vserver(vserver)
|
||||
if version:
|
||||
minor = version
|
||||
else:
|
||||
minor = 110
|
||||
server.set_api_version(major=1, minor=minor)
|
||||
# default is HTTP
|
||||
if https:
|
||||
if port is None:
|
||||
port = 443
|
||||
transport_type = 'HTTPS'
|
||||
# HACK to bypass certificate verification
|
||||
if validate_certs is False:
|
||||
if not os.environ.get('PYTHONHTTPSVERIFY', '') and getattr(ssl, '_create_unverified_context', None):
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
else:
|
||||
if port is None:
|
||||
port = 80
|
||||
transport_type = 'HTTP'
|
||||
server.set_transport_type(transport_type)
|
||||
server.set_port(port)
|
||||
server.set_server_type('FILER')
|
||||
return server
|
||||
else:
|
||||
module.fail_json(msg="the python NetApp-Lib module is required")
|
||||
|
||||
|
||||
def setup_ontap_zapi(module, vserver=None):
|
||||
hostname = module.params['hostname']
|
||||
username = module.params['username']
|
||||
password = module.params['password']
|
||||
|
||||
if HAS_NETAPP_LIB:
|
||||
# set up zapi
|
||||
server = zapi.NaServer(hostname)
|
||||
server.set_username(username)
|
||||
server.set_password(password)
|
||||
if vserver:
|
||||
server.set_vserver(vserver)
|
||||
# Todo : Replace hard-coded values with configurable parameters.
|
||||
server.set_api_version(major=1, minor=110)
|
||||
server.set_port(80)
|
||||
server.set_server_type('FILER')
|
||||
server.set_transport_type('HTTP')
|
||||
return server
|
||||
else:
|
||||
module.fail_json(msg="the python NetApp-Lib module is required")
|
||||
|
||||
|
||||
def eseries_host_argument_spec():
|
||||
"""Retrieve a base argument specification common to all NetApp E-Series modules"""
|
||||
argument_spec = basic_auth_argument_spec()
|
||||
argument_spec.update(dict(
|
||||
api_username=dict(type='str', required=True),
|
||||
api_password=dict(type='str', required=True, no_log=True),
|
||||
api_url=dict(type='str', required=True),
|
||||
ssid=dict(type='str', required=False, default='1'),
|
||||
validate_certs=dict(type='bool', required=False, default=True)
|
||||
))
|
||||
return argument_spec
|
||||
|
||||
|
||||
class NetAppESeriesModule(object):
|
||||
"""Base class for all NetApp E-Series modules.
|
||||
|
||||
Provides a set of common methods for NetApp E-Series modules, including version checking, mode (proxy, embedded)
|
||||
verification, http requests, secure http redirection for embedded web services, and logging setup.
|
||||
|
||||
Be sure to add the following lines in the module's documentation section:
|
||||
extends_documentation_fragment:
|
||||
- netapp.eseries
|
||||
|
||||
:param dict(dict) ansible_options: dictionary of ansible option definitions
|
||||
:param str web_services_version: minimally required web services rest api version (default value: "02.00.0000.0000")
|
||||
:param bool supports_check_mode: whether the module will support the check_mode capabilities (default=False)
|
||||
:param list(list) mutually_exclusive: list containing list(s) of mutually exclusive options (optional)
|
||||
:param list(list) required_if: list containing list(s) containing the option, the option value, and then
|
||||
a list of required options. (optional)
|
||||
:param list(list) required_one_of: list containing list(s) of options for which at least one is required. (optional)
|
||||
:param list(list) required_together: list containing list(s) of options that are required together. (optional)
|
||||
:param bool log_requests: controls whether to log each request (default: True)
|
||||
"""
|
||||
DEFAULT_TIMEOUT = 60
|
||||
DEFAULT_SECURE_PORT = "8443"
|
||||
DEFAULT_REST_API_PATH = "devmgr/v2/"
|
||||
DEFAULT_REST_API_ABOUT_PATH = "devmgr/utils/about"
|
||||
DEFAULT_HEADERS = {"Content-Type": "application/json", "Accept": "application/json",
|
||||
"netapp-client-type": "Ansible-%s" % ansible_version}
|
||||
HTTP_AGENT = "Ansible / %s" % ansible_version
|
||||
SIZE_UNIT_MAP = dict(bytes=1, b=1, kb=1024, mb=1024**2, gb=1024**3, tb=1024**4,
|
||||
pb=1024**5, eb=1024**6, zb=1024**7, yb=1024**8)
|
||||
|
||||
def __init__(self, ansible_options, web_services_version=None, supports_check_mode=False,
|
||||
mutually_exclusive=None, required_if=None, required_one_of=None, required_together=None,
|
||||
log_requests=True):
|
||||
argument_spec = eseries_host_argument_spec()
|
||||
argument_spec.update(ansible_options)
|
||||
|
||||
self.module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=supports_check_mode,
|
||||
mutually_exclusive=mutually_exclusive, required_if=required_if,
|
||||
required_one_of=required_one_of, required_together=required_together)
|
||||
|
||||
args = self.module.params
|
||||
self.web_services_version = web_services_version if web_services_version else "02.00.0000.0000"
|
||||
self.ssid = args["ssid"]
|
||||
self.url = args["api_url"]
|
||||
self.log_requests = log_requests
|
||||
self.creds = dict(url_username=args["api_username"],
|
||||
url_password=args["api_password"],
|
||||
validate_certs=args["validate_certs"])
|
||||
|
||||
if not self.url.endswith("/"):
|
||||
self.url += "/"
|
||||
|
||||
self.is_embedded_mode = None
|
||||
self.is_web_services_valid_cache = None
|
||||
|
||||
def _check_web_services_version(self):
|
||||
"""Verify proxy or embedded web services meets minimum version required for module.
|
||||
|
||||
The minimum required web services version is evaluated against version supplied through the web services rest
|
||||
api. AnsibleFailJson exception will be raised when the minimum is not met or exceeded.
|
||||
|
||||
This helper function will update the supplied api url if secure http is not used for embedded web services
|
||||
|
||||
:raise AnsibleFailJson: raised when the contacted api service does not meet the minimum required version.
|
||||
"""
|
||||
if not self.is_web_services_valid_cache:
|
||||
|
||||
url_parts = urlparse(self.url)
|
||||
if not url_parts.scheme or not url_parts.netloc:
|
||||
self.module.fail_json(msg="Failed to provide valid API URL. Example: https://192.168.1.100:8443/devmgr/v2. URL [%s]." % self.url)
|
||||
|
||||
if url_parts.scheme not in ["http", "https"]:
|
||||
self.module.fail_json(msg="Protocol must be http or https. URL [%s]." % self.url)
|
||||
|
||||
self.url = "%s://%s/" % (url_parts.scheme, url_parts.netloc)
|
||||
about_url = self.url + self.DEFAULT_REST_API_ABOUT_PATH
|
||||
rc, data = request(about_url, timeout=self.DEFAULT_TIMEOUT, headers=self.DEFAULT_HEADERS, ignore_errors=True, **self.creds)
|
||||
|
||||
if rc != 200:
|
||||
self.module.warn("Failed to retrieve web services about information! Retrying with secure ports. Array Id [%s]." % self.ssid)
|
||||
self.url = "https://%s:8443/" % url_parts.netloc.split(":")[0]
|
||||
about_url = self.url + self.DEFAULT_REST_API_ABOUT_PATH
|
||||
try:
|
||||
rc, data = request(about_url, timeout=self.DEFAULT_TIMEOUT, headers=self.DEFAULT_HEADERS, **self.creds)
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to retrieve the webservices about information! Array Id [%s]. Error [%s]."
|
||||
% (self.ssid, to_native(error)))
|
||||
|
||||
major, minor, other, revision = data["version"].split(".")
|
||||
minimum_major, minimum_minor, other, minimum_revision = self.web_services_version.split(".")
|
||||
|
||||
if not (major > minimum_major or
|
||||
(major == minimum_major and minor > minimum_minor) or
|
||||
(major == minimum_major and minor == minimum_minor and revision >= minimum_revision)):
|
||||
self.module.fail_json(msg="Web services version does not meet minimum version required. Current version: [%s]."
|
||||
" Version required: [%s]." % (data["version"], self.web_services_version))
|
||||
|
||||
self.module.log("Web services rest api version met the minimum required version.")
|
||||
self.is_web_services_valid_cache = True
|
||||
|
||||
def is_embedded(self):
|
||||
"""Determine whether web services server is the embedded web services.
|
||||
|
||||
If web services about endpoint fails based on an URLError then the request will be attempted again using
|
||||
secure http.
|
||||
|
||||
:raise AnsibleFailJson: raised when web services about endpoint failed to be contacted.
|
||||
:return bool: whether contacted web services is running from storage array (embedded) or from a proxy.
|
||||
"""
|
||||
self._check_web_services_version()
|
||||
|
||||
if self.is_embedded_mode is None:
|
||||
about_url = self.url + self.DEFAULT_REST_API_ABOUT_PATH
|
||||
try:
|
||||
rc, data = request(about_url, timeout=self.DEFAULT_TIMEOUT, headers=self.DEFAULT_HEADERS, **self.creds)
|
||||
self.is_embedded_mode = not data["runningAsProxy"]
|
||||
except Exception as error:
|
||||
self.module.fail_json(msg="Failed to retrieve the webservices about information! Array Id [%s]. Error [%s]."
|
||||
% (self.ssid, to_native(error)))
|
||||
|
||||
return self.is_embedded_mode
|
||||
|
||||
def request(self, path, data=None, method='GET', headers=None, ignore_errors=False):
|
||||
"""Issue an HTTP request to a url, retrieving an optional JSON response.
|
||||
|
||||
:param str path: web services rest api endpoint path (Example: storage-systems/1/graph). Note that when the
|
||||
full url path is specified then that will be used without supplying the protocol, hostname, port and rest path.
|
||||
:param data: data required for the request (data may be json or any python structured data)
|
||||
:param str method: request method such as GET, POST, DELETE.
|
||||
:param dict headers: dictionary containing request headers.
|
||||
:param bool ignore_errors: forces the request to ignore any raised exceptions.
|
||||
"""
|
||||
self._check_web_services_version()
|
||||
|
||||
if headers is None:
|
||||
headers = self.DEFAULT_HEADERS
|
||||
|
||||
if not isinstance(data, str) and headers["Content-Type"] == "application/json":
|
||||
data = json.dumps(data)
|
||||
|
||||
if path.startswith("/"):
|
||||
path = path[1:]
|
||||
request_url = self.url + self.DEFAULT_REST_API_PATH + path
|
||||
|
||||
# if self.log_requests:
|
||||
self.module.log(pformat(dict(url=request_url, data=data, method=method)))
|
||||
|
||||
return request(url=request_url, data=data, method=method, headers=headers, use_proxy=True, force=False, last_mod_time=None,
|
||||
timeout=self.DEFAULT_TIMEOUT, http_agent=self.HTTP_AGENT, force_basic_auth=True, ignore_errors=ignore_errors, **self.creds)
|
||||
|
||||
|
||||
def create_multipart_formdata(files, fields=None, send_8kb=False):
|
||||
"""Create the data for a multipart/form request.
|
||||
|
||||
:param list(list) files: list of lists each containing (name, filename, path).
|
||||
:param list(list) fields: list of lists each containing (key, value).
|
||||
:param bool send_8kb: only sends the first 8kb of the files (default: False).
|
||||
"""
|
||||
boundary = "---------------------------" + "".join([str(random.randint(0, 9)) for x in range(27)])
|
||||
data_parts = list()
|
||||
data = None
|
||||
|
||||
if six.PY2: # Generate payload for Python 2
|
||||
newline = "\r\n"
|
||||
if fields is not None:
|
||||
for key, value in fields:
|
||||
data_parts.extend(["--%s" % boundary,
|
||||
'Content-Disposition: form-data; name="%s"' % key,
|
||||
"",
|
||||
value])
|
||||
|
||||
for name, filename, path in files:
|
||||
with open(path, "rb") as fh:
|
||||
value = fh.read(8192) if send_8kb else fh.read()
|
||||
|
||||
data_parts.extend(["--%s" % boundary,
|
||||
'Content-Disposition: form-data; name="%s"; filename="%s"' % (name, filename),
|
||||
"Content-Type: %s" % (mimetypes.guess_type(path)[0] or "application/octet-stream"),
|
||||
"",
|
||||
value])
|
||||
data_parts.extend(["--%s--" % boundary, ""])
|
||||
data = newline.join(data_parts)
|
||||
|
||||
else:
|
||||
newline = six.b("\r\n")
|
||||
if fields is not None:
|
||||
for key, value in fields:
|
||||
data_parts.extend([six.b("--%s" % boundary),
|
||||
six.b('Content-Disposition: form-data; name="%s"' % key),
|
||||
six.b(""),
|
||||
six.b(value)])
|
||||
|
||||
for name, filename, path in files:
|
||||
with open(path, "rb") as fh:
|
||||
value = fh.read(8192) if send_8kb else fh.read()
|
||||
|
||||
data_parts.extend([six.b("--%s" % boundary),
|
||||
six.b('Content-Disposition: form-data; name="%s"; filename="%s"' % (name, filename)),
|
||||
six.b("Content-Type: %s" % (mimetypes.guess_type(path)[0] or "application/octet-stream")),
|
||||
six.b(""),
|
||||
value])
|
||||
data_parts.extend([six.b("--%s--" % boundary), b""])
|
||||
data = newline.join(data_parts)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "multipart/form-data; boundary=%s" % boundary,
|
||||
"Content-Length": str(len(data))}
|
||||
|
||||
return headers, data
|
||||
|
||||
|
||||
def request(url, data=None, headers=None, method='GET', use_proxy=True,
|
||||
force=False, last_mod_time=None, timeout=10, validate_certs=True,
|
||||
url_username=None, url_password=None, http_agent=None, force_basic_auth=True, ignore_errors=False):
|
||||
"""Issue an HTTP request to a url, retrieving an optional JSON response."""
|
||||
|
||||
if headers is None:
|
||||
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||
headers.update({"netapp-client-type": "Ansible-%s" % ansible_version})
|
||||
|
||||
if not http_agent:
|
||||
http_agent = "Ansible / %s" % ansible_version
|
||||
|
||||
try:
|
||||
r = open_url(url=url, data=data, headers=headers, method=method, use_proxy=use_proxy,
|
||||
force=force, last_mod_time=last_mod_time, timeout=timeout, validate_certs=validate_certs,
|
||||
url_username=url_username, url_password=url_password, http_agent=http_agent,
|
||||
force_basic_auth=force_basic_auth)
|
||||
except HTTPError as err:
|
||||
r = err.fp
|
||||
|
||||
try:
|
||||
raw_data = r.read()
|
||||
if raw_data:
|
||||
data = json.loads(raw_data)
|
||||
else:
|
||||
raw_data = None
|
||||
except Exception:
|
||||
if ignore_errors:
|
||||
pass
|
||||
else:
|
||||
raise Exception(raw_data)
|
||||
|
||||
resp_code = r.getcode()
|
||||
|
||||
if resp_code >= 400 and not ignore_errors:
|
||||
raise Exception(resp_code, data)
|
||||
else:
|
||||
return resp_code, data
|
||||
|
||||
|
||||
def ems_log_event(source, server, name="Ansible", id="12345", version=ansible_version,
|
||||
category="Information", event="setup", autosupport="false"):
|
||||
ems_log = zapi.NaElement('ems-autosupport-log')
|
||||
# Host name invoking the API.
|
||||
ems_log.add_new_child("computer-name", name)
|
||||
# ID of event. A user defined event-id, range [0..2^32-2].
|
||||
ems_log.add_new_child("event-id", id)
|
||||
# Name of the application invoking the API.
|
||||
ems_log.add_new_child("event-source", source)
|
||||
# Version of application invoking the API.
|
||||
ems_log.add_new_child("app-version", version)
|
||||
# Application defined category of the event.
|
||||
ems_log.add_new_child("category", category)
|
||||
# Description of event to log. An application defined message to log.
|
||||
ems_log.add_new_child("event-description", event)
|
||||
ems_log.add_new_child("log-level", "6")
|
||||
ems_log.add_new_child("auto-support", autosupport)
|
||||
server.invoke_successfully(ems_log, True)
|
||||
|
||||
|
||||
def get_cserver_zapi(server):
|
||||
vserver_info = zapi.NaElement('vserver-get-iter')
|
||||
query_details = zapi.NaElement.create_node_with_children('vserver-info', **{'vserver-type': 'admin'})
|
||||
query = zapi.NaElement('query')
|
||||
query.add_child_elem(query_details)
|
||||
vserver_info.add_child_elem(query)
|
||||
result = server.invoke_successfully(vserver_info,
|
||||
enable_tunneling=False)
|
||||
attribute_list = result.get_child_by_name('attributes-list')
|
||||
vserver_list = attribute_list.get_child_by_name('vserver-info')
|
||||
return vserver_list.get_child_content('vserver-name')
|
||||
|
||||
|
||||
def get_cserver(connection, is_rest=False):
|
||||
if not is_rest:
|
||||
return get_cserver_zapi(connection)
|
||||
|
||||
params = {'fields': 'type'}
|
||||
api = "private/cli/vserver"
|
||||
json, error = connection.get(api, params)
|
||||
if json is None or error is not None:
|
||||
# exit if there is an error or no data
|
||||
return None
|
||||
vservers = json.get('records')
|
||||
if vservers is not None:
|
||||
for vserver in vservers:
|
||||
if vserver['type'] == 'admin': # cluster admin
|
||||
return vserver['vserver']
|
||||
if len(vservers) == 1: # assume vserver admin
|
||||
return vservers[0]['vserver']
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class OntapRestAPI(object):
|
||||
def __init__(self, module, timeout=60):
|
||||
self.module = module
|
||||
self.username = self.module.params['username']
|
||||
self.password = self.module.params['password']
|
||||
self.hostname = self.module.params['hostname']
|
||||
self.use_rest = self.module.params['use_rest']
|
||||
self.verify = self.module.params['validate_certs']
|
||||
self.timeout = timeout
|
||||
self.url = 'https://' + self.hostname + '/api/'
|
||||
self.errors = list()
|
||||
self.debug_logs = list()
|
||||
self.check_required_library()
|
||||
|
||||
def check_required_library(self):
|
||||
if not HAS_REQUESTS:
|
||||
self.module.fail_json(msg=missing_required_lib('requests'))
|
||||
|
||||
def send_request(self, method, api, params, json=None, return_status_code=False):
|
||||
''' send http request and process reponse, including error conditions '''
|
||||
url = self.url + api
|
||||
status_code = None
|
||||
content = None
|
||||
json_dict = None
|
||||
json_error = None
|
||||
error_details = None
|
||||
|
||||
def get_json(response):
|
||||
''' extract json, and error message if present '''
|
||||
try:
|
||||
json = response.json()
|
||||
except ValueError:
|
||||
return None, None
|
||||
error = json.get('error')
|
||||
return json, error
|
||||
|
||||
try:
|
||||
response = requests.request(method, url, verify=self.verify, auth=(self.username, self.password), params=params, timeout=self.timeout, json=json)
|
||||
content = response.content # for debug purposes
|
||||
status_code = response.status_code
|
||||
# If the response was successful, no Exception will be raised
|
||||
response.raise_for_status()
|
||||
json_dict, json_error = get_json(response)
|
||||
except requests.exceptions.HTTPError as err:
|
||||
__, json_error = get_json(response)
|
||||
if json_error is None:
|
||||
self.log_error(status_code, 'HTTP error: %s' % err)
|
||||
error_details = str(err)
|
||||
# If an error was reported in the json payload, it is handled below
|
||||
except requests.exceptions.ConnectionError as err:
|
||||
self.log_error(status_code, 'Connection error: %s' % err)
|
||||
error_details = str(err)
|
||||
except Exception as err:
|
||||
self.log_error(status_code, 'Other error: %s' % err)
|
||||
error_details = str(err)
|
||||
if json_error is not None:
|
||||
self.log_error(status_code, 'Endpoint error: %d: %s' % (status_code, json_error))
|
||||
error_details = json_error
|
||||
self.log_debug(status_code, content)
|
||||
if return_status_code:
|
||||
return status_code, error_details
|
||||
return json_dict, error_details
|
||||
|
||||
def get(self, api, params):
|
||||
method = 'GET'
|
||||
return self.send_request(method, api, params)
|
||||
|
||||
def post(self, api, data, params=None):
|
||||
method = 'POST'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def patch(self, api, data, params=None):
|
||||
method = 'PATCH'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def delete(self, api, data, params=None):
|
||||
method = 'DELETE'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def _is_rest(self, used_unsupported_rest_properties=None):
|
||||
if self.use_rest == "Always":
|
||||
if used_unsupported_rest_properties:
|
||||
error = "REST API currently does not support '%s'" % \
|
||||
', '.join(used_unsupported_rest_properties)
|
||||
return True, error
|
||||
else:
|
||||
return True, None
|
||||
if self.use_rest == 'Never' or used_unsupported_rest_properties:
|
||||
# force ZAPI if requested or if some parameter requires it
|
||||
return False, None
|
||||
method = 'HEAD'
|
||||
api = 'cluster/software'
|
||||
status_code, __ = self.send_request(method, api, params=None, return_status_code=True)
|
||||
if status_code == 200:
|
||||
return True, None
|
||||
return False, None
|
||||
|
||||
def is_rest(self, used_unsupported_rest_properties=None):
|
||||
''' only return error if there is a reason to '''
|
||||
use_rest, error = self._is_rest(used_unsupported_rest_properties)
|
||||
if used_unsupported_rest_properties is None:
|
||||
return use_rest
|
||||
return use_rest, error
|
||||
|
||||
def log_error(self, status_code, message):
|
||||
self.errors.append(message)
|
||||
self.debug_logs.append((status_code, message))
|
||||
|
||||
def log_debug(self, status_code, content):
|
||||
self.debug_logs.append((status_code, content))
|
||||
|
||||
|
||||
class AwsCvsRestAPI(object):
|
||||
def __init__(self, module, timeout=60):
|
||||
self.module = module
|
||||
self.api_key = self.module.params['api_key']
|
||||
self.secret_key = self.module.params['secret_key']
|
||||
self.api_url = self.module.params['api_url']
|
||||
self.verify = self.module.params['validate_certs']
|
||||
self.timeout = timeout
|
||||
self.url = 'https://' + self.api_url + '/v1/'
|
||||
self.check_required_library()
|
||||
|
||||
def check_required_library(self):
|
||||
if not HAS_REQUESTS:
|
||||
self.module.fail_json(msg=missing_required_lib('requests'))
|
||||
|
||||
def send_request(self, method, api, params, json=None):
|
||||
''' send http request and process reponse, including error conditions '''
|
||||
url = self.url + api
|
||||
status_code = None
|
||||
content = None
|
||||
json_dict = None
|
||||
json_error = None
|
||||
error_details = None
|
||||
headers = {
|
||||
'Content-type': "application/json",
|
||||
'api-key': self.api_key,
|
||||
'secret-key': self.secret_key,
|
||||
'Cache-Control': "no-cache",
|
||||
}
|
||||
|
||||
def get_json(response):
|
||||
''' extract json, and error message if present '''
|
||||
try:
|
||||
json = response.json()
|
||||
|
||||
except ValueError:
|
||||
return None, None
|
||||
success_code = [200, 201, 202]
|
||||
if response.status_code not in success_code:
|
||||
error = json.get('message')
|
||||
else:
|
||||
error = None
|
||||
return json, error
|
||||
try:
|
||||
response = requests.request(method, url, headers=headers, timeout=self.timeout, json=json)
|
||||
status_code = response.status_code
|
||||
# If the response was successful, no Exception will be raised
|
||||
json_dict, json_error = get_json(response)
|
||||
except requests.exceptions.HTTPError as err:
|
||||
__, json_error = get_json(response)
|
||||
if json_error is None:
|
||||
error_details = str(err)
|
||||
except requests.exceptions.ConnectionError as err:
|
||||
error_details = str(err)
|
||||
except Exception as err:
|
||||
error_details = str(err)
|
||||
if json_error is not None:
|
||||
error_details = json_error
|
||||
|
||||
return json_dict, error_details
|
||||
|
||||
# If an error was reported in the json payload, it is handled below
|
||||
def get(self, api, params=None):
|
||||
method = 'GET'
|
||||
return self.send_request(method, api, params)
|
||||
|
||||
def post(self, api, data, params=None):
|
||||
method = 'POST'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def patch(self, api, data, params=None):
|
||||
method = 'PATCH'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def put(self, api, data, params=None):
|
||||
method = 'PUT'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def delete(self, api, data, params=None):
|
||||
method = 'DELETE'
|
||||
return self.send_request(method, api, params, json=data)
|
||||
|
||||
def get_state(self, jobId):
|
||||
""" Method to get the state of the job """
|
||||
method = 'GET'
|
||||
response, status_code = self.get('Jobs/%s' % jobId)
|
||||
while str(response['state']) not in 'done':
|
||||
response, status_code = self.get('Jobs/%s' % jobId)
|
||||
return 'done'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,6 +31,7 @@ def _env_then_dns_fallback(*args, **kwargs):
|
||||
result = env_fallback(*args, **kwargs)
|
||||
if result == '':
|
||||
raise AnsibleFallbackNotFound
|
||||
return result
|
||||
except AnsibleFallbackNotFound:
|
||||
# If no host was given, we try to guess it from IPA.
|
||||
# The ipa-ca entry is a standard entry that IPA will have set for
|
||||
@@ -178,10 +179,10 @@ class IPAClient(object):
|
||||
result.append(key)
|
||||
return result
|
||||
|
||||
def modify_if_diff(self, name, ipa_list, module_list, add_method, remove_method, item=None):
|
||||
def modify_if_diff(self, name, ipa_list, module_list, add_method, remove_method, item=None, append=None):
|
||||
changed = False
|
||||
diff = list(set(ipa_list) - set(module_list))
|
||||
if len(diff) > 0:
|
||||
if append is not True and len(diff) > 0:
|
||||
changed = True
|
||||
if not self.module.check_mode:
|
||||
if item:
|
||||
|
||||
@@ -141,11 +141,7 @@ class CmdMixin(object):
|
||||
fmt = find_format(param)
|
||||
value = extra_params[param]
|
||||
else:
|
||||
self.module.deprecate("Cannot determine value for parameter: {0}. "
|
||||
"From version 4.0.0 onwards this will generate an exception".format(param),
|
||||
version="4.0.0", collection_name="community.general")
|
||||
continue
|
||||
|
||||
raise self.ModuleHelperException('Cannot determine value for parameter: {0}'.format(param))
|
||||
else:
|
||||
raise self.ModuleHelperException("run_command parameter must be either a str or a dict: {0}".format(param))
|
||||
cmd_args = add_arg_formatted_param(cmd_args, fmt, value)
|
||||
@@ -162,8 +158,9 @@ class CmdMixin(object):
|
||||
publish_rc=True,
|
||||
publish_out=True,
|
||||
publish_err=True,
|
||||
publish_cmd=True,
|
||||
*args, **kwargs):
|
||||
self.vars.cmd_args = self._calculate_args(extra_params, params)
|
||||
cmd_args = self._calculate_args(extra_params, params)
|
||||
options = dict(self.run_command_fixed_options)
|
||||
options['check_rc'] = options.get('check_rc', self.check_rc)
|
||||
options.update(kwargs)
|
||||
@@ -175,13 +172,15 @@ class CmdMixin(object):
|
||||
})
|
||||
self.update_output(force_lang=self.force_lang)
|
||||
options['environ_update'] = env_update
|
||||
rc, out, err = self.module.run_command(self.vars.cmd_args, *args, **options)
|
||||
rc, out, err = self.module.run_command(cmd_args, *args, **options)
|
||||
if publish_rc:
|
||||
self.update_output(rc=rc)
|
||||
if publish_out:
|
||||
self.update_output(stdout=out)
|
||||
if publish_err:
|
||||
self.update_output(stderr=err)
|
||||
if publish_cmd:
|
||||
self.update_output(cmd_args=cmd_args)
|
||||
if process_output is None:
|
||||
_process = self.process_command_output
|
||||
else:
|
||||
|
||||
@@ -1,598 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This code is part of Ansible, but is an independent component.
|
||||
# This particular file snippet, and this file snippet only, is BSD licensed.
|
||||
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
||||
# still belong to the author of the module, and may assign their own license
|
||||
# to the complete work.
|
||||
#
|
||||
# (c) 2018 Red Hat Inc.
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
import os
|
||||
from functools import partial
|
||||
from ansible.module_utils.common.text.converters import to_native
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.basic import env_fallback
|
||||
from ansible.module_utils.common.validation import check_type_dict
|
||||
|
||||
try:
|
||||
from infoblox_client.connector import Connector
|
||||
from infoblox_client.exceptions import InfobloxException
|
||||
HAS_INFOBLOX_CLIENT = True
|
||||
except ImportError:
|
||||
HAS_INFOBLOX_CLIENT = False
|
||||
|
||||
# defining nios constants
|
||||
NIOS_DNS_VIEW = 'view'
|
||||
NIOS_NETWORK_VIEW = 'networkview'
|
||||
NIOS_HOST_RECORD = 'record:host'
|
||||
NIOS_IPV4_NETWORK = 'network'
|
||||
NIOS_IPV6_NETWORK = 'ipv6network'
|
||||
NIOS_ZONE = 'zone_auth'
|
||||
NIOS_PTR_RECORD = 'record:ptr'
|
||||
NIOS_A_RECORD = 'record:a'
|
||||
NIOS_AAAA_RECORD = 'record:aaaa'
|
||||
NIOS_CNAME_RECORD = 'record:cname'
|
||||
NIOS_MX_RECORD = 'record:mx'
|
||||
NIOS_SRV_RECORD = 'record:srv'
|
||||
NIOS_NAPTR_RECORD = 'record:naptr'
|
||||
NIOS_TXT_RECORD = 'record:txt'
|
||||
NIOS_NSGROUP = 'nsgroup'
|
||||
NIOS_IPV4_FIXED_ADDRESS = 'fixedaddress'
|
||||
NIOS_IPV6_FIXED_ADDRESS = 'ipv6fixedaddress'
|
||||
NIOS_NEXT_AVAILABLE_IP = 'func:nextavailableip'
|
||||
NIOS_IPV4_NETWORK_CONTAINER = 'networkcontainer'
|
||||
NIOS_IPV6_NETWORK_CONTAINER = 'ipv6networkcontainer'
|
||||
NIOS_MEMBER = 'member'
|
||||
|
||||
NIOS_PROVIDER_SPEC = {
|
||||
'host': dict(fallback=(env_fallback, ['INFOBLOX_HOST'])),
|
||||
'username': dict(fallback=(env_fallback, ['INFOBLOX_USERNAME'])),
|
||||
'password': dict(fallback=(env_fallback, ['INFOBLOX_PASSWORD']), no_log=True),
|
||||
'validate_certs': dict(type='bool', default=False, fallback=(env_fallback, ['INFOBLOX_SSL_VERIFY']), aliases=['ssl_verify']),
|
||||
'silent_ssl_warnings': dict(type='bool', default=True),
|
||||
'http_request_timeout': dict(type='int', default=10, fallback=(env_fallback, ['INFOBLOX_HTTP_REQUEST_TIMEOUT'])),
|
||||
'http_pool_connections': dict(type='int', default=10),
|
||||
'http_pool_maxsize': dict(type='int', default=10),
|
||||
'max_retries': dict(type='int', default=3, fallback=(env_fallback, ['INFOBLOX_MAX_RETRIES'])),
|
||||
'wapi_version': dict(default='2.1', fallback=(env_fallback, ['INFOBLOX_WAP_VERSION'])),
|
||||
'max_results': dict(type='int', default=1000, fallback=(env_fallback, ['INFOBLOX_MAX_RETRIES']))
|
||||
}
|
||||
|
||||
|
||||
def get_connector(*args, **kwargs):
|
||||
''' Returns an instance of infoblox_client.connector.Connector
|
||||
:params args: positional arguments are silently ignored
|
||||
:params kwargs: dict that is passed to Connector init
|
||||
:returns: Connector
|
||||
'''
|
||||
if not HAS_INFOBLOX_CLIENT:
|
||||
raise Exception('infoblox-client is required but does not appear '
|
||||
'to be installed. It can be installed using the '
|
||||
'command `pip install infoblox-client`')
|
||||
|
||||
if not set(kwargs.keys()).issubset(list(NIOS_PROVIDER_SPEC.keys()) + ['ssl_verify']):
|
||||
raise Exception('invalid or unsupported keyword argument for connector')
|
||||
for key, value in iteritems(NIOS_PROVIDER_SPEC):
|
||||
if key not in kwargs:
|
||||
# apply default values from NIOS_PROVIDER_SPEC since we cannot just
|
||||
# assume the provider values are coming from AnsibleModule
|
||||
if 'default' in value:
|
||||
kwargs[key] = value['default']
|
||||
|
||||
# override any values with env variables unless they were
|
||||
# explicitly set
|
||||
env = ('INFOBLOX_%s' % key).upper()
|
||||
if env in os.environ:
|
||||
kwargs[key] = os.environ.get(env)
|
||||
|
||||
if 'validate_certs' in kwargs.keys():
|
||||
kwargs['ssl_verify'] = kwargs['validate_certs']
|
||||
kwargs.pop('validate_certs', None)
|
||||
|
||||
return Connector(kwargs)
|
||||
|
||||
|
||||
def normalize_extattrs(value):
|
||||
''' Normalize extattrs field to expected format
|
||||
The module accepts extattrs as key/value pairs. This method will
|
||||
transform the key/value pairs into a structure suitable for
|
||||
sending across WAPI in the format of:
|
||||
extattrs: {
|
||||
key: {
|
||||
value: <value>
|
||||
}
|
||||
}
|
||||
'''
|
||||
return dict([(k, {'value': v}) for k, v in iteritems(value)])
|
||||
|
||||
|
||||
def flatten_extattrs(value):
|
||||
''' Flatten the key/value struct for extattrs
|
||||
WAPI returns extattrs field as a dict in form of:
|
||||
extattrs: {
|
||||
key: {
|
||||
value: <value>
|
||||
}
|
||||
}
|
||||
This method will flatten the structure to:
|
||||
extattrs: {
|
||||
key: value
|
||||
}
|
||||
'''
|
||||
return dict([(k, v['value']) for k, v in iteritems(value)])
|
||||
|
||||
|
||||
def member_normalize(member_spec):
|
||||
''' Transforms the member module arguments into a valid WAPI struct
|
||||
This function will transform the arguments into a structure that
|
||||
is a valid WAPI structure in the format of:
|
||||
{
|
||||
key: <value>,
|
||||
}
|
||||
It will remove any arguments that are set to None since WAPI will error on
|
||||
that condition.
|
||||
The remainder of the value validation is performed by WAPI
|
||||
Some parameters in ib_spec are passed as a list in order to pass the validation for elements.
|
||||
In this function, they are converted to dictionary.
|
||||
'''
|
||||
member_elements = ['vip_setting', 'ipv6_setting', 'lan2_port_setting', 'mgmt_port_setting',
|
||||
'pre_provisioning', 'network_setting', 'v6_network_setting',
|
||||
'ha_port_setting', 'lan_port_setting', 'lan2_physical_setting',
|
||||
'lan_ha_port_setting', 'mgmt_network_setting', 'v6_mgmt_network_setting']
|
||||
for key in list(member_spec.keys()):
|
||||
if key in member_elements and member_spec[key] is not None:
|
||||
member_spec[key] = member_spec[key][0]
|
||||
if isinstance(member_spec[key], dict):
|
||||
member_spec[key] = member_normalize(member_spec[key])
|
||||
elif isinstance(member_spec[key], list):
|
||||
for x in member_spec[key]:
|
||||
if isinstance(x, dict):
|
||||
x = member_normalize(x)
|
||||
elif member_spec[key] is None:
|
||||
del member_spec[key]
|
||||
return member_spec
|
||||
|
||||
|
||||
def normalize_ib_spec(ib_spec):
|
||||
result = {}
|
||||
for arg in ib_spec:
|
||||
result[arg] = dict([(k, v)
|
||||
for k, v in iteritems(ib_spec[arg])
|
||||
if k not in ('ib_req', 'transform', 'update')])
|
||||
return result
|
||||
|
||||
|
||||
class WapiBase(object):
|
||||
''' Base class for implementing Infoblox WAPI API '''
|
||||
provider_spec = {'provider': dict(type='dict', options=NIOS_PROVIDER_SPEC)}
|
||||
|
||||
def __init__(self, provider):
|
||||
self.connector = get_connector(**provider)
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self.__dict__[name]
|
||||
except KeyError:
|
||||
if name.startswith('_'):
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))
|
||||
return partial(self._invoke_method, name)
|
||||
|
||||
def _invoke_method(self, name, *args, **kwargs):
|
||||
try:
|
||||
method = getattr(self.connector, name)
|
||||
return method(*args, **kwargs)
|
||||
except InfobloxException as exc:
|
||||
if hasattr(self, 'handle_exception'):
|
||||
self.handle_exception(name, exc)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
class WapiLookup(WapiBase):
|
||||
''' Implements WapiBase for lookup plugins '''
|
||||
def handle_exception(self, method_name, exc):
|
||||
if ('text' in exc.response):
|
||||
raise Exception(exc.response['text'])
|
||||
else:
|
||||
raise Exception(exc)
|
||||
|
||||
|
||||
class WapiInventory(WapiBase):
|
||||
''' Implements WapiBase for dynamic inventory script '''
|
||||
pass
|
||||
|
||||
|
||||
class WapiModule(WapiBase):
|
||||
''' Implements WapiBase for executing a NIOS module '''
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
provider = module.params['provider']
|
||||
try:
|
||||
super(WapiModule, self).__init__(provider)
|
||||
except Exception as exc:
|
||||
self.module.fail_json(msg=to_text(exc))
|
||||
|
||||
def handle_exception(self, method_name, exc):
|
||||
''' Handles any exceptions raised
|
||||
This method will be called if an InfobloxException is raised for
|
||||
any call to the instance of Connector and also, in case of generic
|
||||
exception. This method will then gracefully fail the module.
|
||||
:args exc: instance of InfobloxException
|
||||
'''
|
||||
if ('text' in exc.response):
|
||||
self.module.fail_json(
|
||||
msg=exc.response['text'],
|
||||
type=exc.response['Error'].split(':')[0],
|
||||
code=exc.response.get('code'),
|
||||
operation=method_name
|
||||
)
|
||||
else:
|
||||
self.module.fail_json(msg=to_native(exc))
|
||||
|
||||
def run(self, ib_obj_type, ib_spec):
|
||||
''' Runs the module and performans configuration tasks
|
||||
:args ib_obj_type: the WAPI object type to operate against
|
||||
:args ib_spec: the specification for the WAPI object as a dict
|
||||
:returns: a results dict
|
||||
'''
|
||||
|
||||
update = new_name = None
|
||||
state = self.module.params['state']
|
||||
if state not in ('present', 'absent'):
|
||||
self.module.fail_json(msg='state must be one of `present`, `absent`, got `%s`' % state)
|
||||
|
||||
result = {'changed': False}
|
||||
|
||||
obj_filter = dict([(k, self.module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')])
|
||||
|
||||
# get object reference
|
||||
ib_obj_ref, update, new_name = self.get_object_ref(self.module, ib_obj_type, obj_filter, ib_spec)
|
||||
proposed_object = {}
|
||||
for key, value in iteritems(ib_spec):
|
||||
if self.module.params[key] is not None:
|
||||
if 'transform' in value:
|
||||
proposed_object[key] = value['transform'](self.module)
|
||||
else:
|
||||
proposed_object[key] = self.module.params[key]
|
||||
|
||||
# If configure_by_dns is set to False and view is 'default', then delete the default dns
|
||||
if not proposed_object.get('configure_for_dns') and proposed_object.get('view') == 'default'\
|
||||
and ib_obj_type == NIOS_HOST_RECORD:
|
||||
del proposed_object['view']
|
||||
|
||||
if ib_obj_ref:
|
||||
if len(ib_obj_ref) > 1:
|
||||
for each in ib_obj_ref:
|
||||
# To check for existing A_record with same name with input A_record by IP
|
||||
if each.get('ipv4addr') and each.get('ipv4addr') == proposed_object.get('ipv4addr'):
|
||||
current_object = each
|
||||
# To check for existing Host_record with same name with input Host_record by IP
|
||||
elif each.get('ipv4addrs')[0].get('ipv4addr') and each.get('ipv4addrs')[0].get('ipv4addr')\
|
||||
== proposed_object.get('ipv4addrs')[0].get('ipv4addr'):
|
||||
current_object = each
|
||||
# Else set the current_object with input value
|
||||
else:
|
||||
current_object = obj_filter
|
||||
ref = None
|
||||
else:
|
||||
current_object = ib_obj_ref[0]
|
||||
if 'extattrs' in current_object:
|
||||
current_object['extattrs'] = flatten_extattrs(current_object['extattrs'])
|
||||
if current_object.get('_ref'):
|
||||
ref = current_object.pop('_ref')
|
||||
else:
|
||||
current_object = obj_filter
|
||||
ref = None
|
||||
# checks if the object type is member to normalize the attributes being passed
|
||||
if (ib_obj_type == NIOS_MEMBER):
|
||||
proposed_object = member_normalize(proposed_object)
|
||||
|
||||
# checks if the name's field has been updated
|
||||
if update and new_name:
|
||||
proposed_object['name'] = new_name
|
||||
|
||||
check_remove = []
|
||||
if (ib_obj_type == NIOS_HOST_RECORD):
|
||||
# this check is for idempotency, as if the same ip address shall be passed
|
||||
# add param will be removed, and same exists true for remove case as well.
|
||||
if 'ipv4addrs' in [current_object and proposed_object]:
|
||||
for each in current_object['ipv4addrs']:
|
||||
if each['ipv4addr'] == proposed_object['ipv4addrs'][0]['ipv4addr']:
|
||||
if 'add' in proposed_object['ipv4addrs'][0]:
|
||||
del proposed_object['ipv4addrs'][0]['add']
|
||||
break
|
||||
check_remove += each.values()
|
||||
if proposed_object['ipv4addrs'][0]['ipv4addr'] not in check_remove:
|
||||
if 'remove' in proposed_object['ipv4addrs'][0]:
|
||||
del proposed_object['ipv4addrs'][0]['remove']
|
||||
|
||||
res = None
|
||||
modified = not self.compare_objects(current_object, proposed_object)
|
||||
if 'extattrs' in proposed_object:
|
||||
proposed_object['extattrs'] = normalize_extattrs(proposed_object['extattrs'])
|
||||
|
||||
# Checks if nios_next_ip param is passed in ipv4addrs/ipv4addr args
|
||||
proposed_object = self.check_if_nios_next_ip_exists(proposed_object)
|
||||
|
||||
if state == 'present':
|
||||
if ref is None:
|
||||
if not self.module.check_mode:
|
||||
self.create_object(ib_obj_type, proposed_object)
|
||||
result['changed'] = True
|
||||
# Check if NIOS_MEMBER and the flag to call function create_token is set
|
||||
elif (ib_obj_type == NIOS_MEMBER) and (proposed_object['create_token']):
|
||||
proposed_object = None
|
||||
# the function creates a token that can be used by a pre-provisioned member to join the grid
|
||||
result['api_results'] = self.call_func('create_token', ref, proposed_object)
|
||||
result['changed'] = True
|
||||
elif modified:
|
||||
if 'ipv4addrs' in proposed_object:
|
||||
if ('add' not in proposed_object['ipv4addrs'][0]) and ('remove' not in proposed_object['ipv4addrs'][0]):
|
||||
self.check_if_recordname_exists(obj_filter, ib_obj_ref, ib_obj_type, current_object, proposed_object)
|
||||
|
||||
if (ib_obj_type in (NIOS_HOST_RECORD, NIOS_NETWORK_VIEW, NIOS_DNS_VIEW)):
|
||||
run_update = True
|
||||
proposed_object = self.on_update(proposed_object, ib_spec)
|
||||
if 'ipv4addrs' in proposed_object:
|
||||
if ('add' or 'remove') in proposed_object['ipv4addrs'][0]:
|
||||
run_update, proposed_object = self.check_if_add_remove_ip_arg_exists(proposed_object)
|
||||
if run_update:
|
||||
res = self.update_object(ref, proposed_object)
|
||||
result['changed'] = True
|
||||
else:
|
||||
res = ref
|
||||
if (ib_obj_type in (NIOS_A_RECORD, NIOS_AAAA_RECORD, NIOS_PTR_RECORD, NIOS_SRV_RECORD)):
|
||||
# popping 'view' key as update of 'view' is not supported with respect to a:record/aaaa:record/srv:record/ptr:record
|
||||
proposed_object = self.on_update(proposed_object, ib_spec)
|
||||
del proposed_object['view']
|
||||
if not self.module.check_mode:
|
||||
res = self.update_object(ref, proposed_object)
|
||||
result['changed'] = True
|
||||
elif 'network_view' in proposed_object:
|
||||
proposed_object.pop('network_view')
|
||||
result['changed'] = True
|
||||
if not self.module.check_mode and res is None:
|
||||
proposed_object = self.on_update(proposed_object, ib_spec)
|
||||
self.update_object(ref, proposed_object)
|
||||
result['changed'] = True
|
||||
|
||||
elif state == 'absent':
|
||||
if ref is not None:
|
||||
if 'ipv4addrs' in proposed_object:
|
||||
if 'remove' in proposed_object['ipv4addrs'][0]:
|
||||
self.check_if_add_remove_ip_arg_exists(proposed_object)
|
||||
self.update_object(ref, proposed_object)
|
||||
result['changed'] = True
|
||||
elif not self.module.check_mode:
|
||||
self.delete_object(ref)
|
||||
result['changed'] = True
|
||||
|
||||
return result
|
||||
|
||||
def check_if_recordname_exists(self, obj_filter, ib_obj_ref, ib_obj_type, current_object, proposed_object):
|
||||
''' Send POST request if host record input name and retrieved ref name is same,
|
||||
but input IP and retrieved IP is different'''
|
||||
|
||||
if 'name' in (obj_filter and ib_obj_ref[0]) and ib_obj_type == NIOS_HOST_RECORD:
|
||||
obj_host_name = obj_filter['name']
|
||||
ref_host_name = ib_obj_ref[0]['name']
|
||||
if 'ipv4addrs' in (current_object and proposed_object):
|
||||
current_ip_addr = current_object['ipv4addrs'][0]['ipv4addr']
|
||||
proposed_ip_addr = proposed_object['ipv4addrs'][0]['ipv4addr']
|
||||
elif 'ipv6addrs' in (current_object and proposed_object):
|
||||
current_ip_addr = current_object['ipv6addrs'][0]['ipv6addr']
|
||||
proposed_ip_addr = proposed_object['ipv6addrs'][0]['ipv6addr']
|
||||
|
||||
if obj_host_name == ref_host_name and current_ip_addr != proposed_ip_addr:
|
||||
self.create_object(ib_obj_type, proposed_object)
|
||||
|
||||
def check_if_nios_next_ip_exists(self, proposed_object):
|
||||
''' Check if nios_next_ip argument is passed in ipaddr while creating
|
||||
host record, if yes then format proposed object ipv4addrs and pass
|
||||
func:nextavailableip and ipaddr range to create hostrecord with next
|
||||
available ip in one call to avoid any race condition '''
|
||||
|
||||
if 'ipv4addrs' in proposed_object:
|
||||
if 'nios_next_ip' in proposed_object['ipv4addrs'][0]['ipv4addr']:
|
||||
ip_range = check_type_dict(proposed_object['ipv4addrs'][0]['ipv4addr'])['nios_next_ip']
|
||||
proposed_object['ipv4addrs'][0]['ipv4addr'] = NIOS_NEXT_AVAILABLE_IP + ':' + ip_range
|
||||
elif 'ipv4addr' in proposed_object:
|
||||
if 'nios_next_ip' in proposed_object['ipv4addr']:
|
||||
ip_range = check_type_dict(proposed_object['ipv4addr'])['nios_next_ip']
|
||||
proposed_object['ipv4addr'] = NIOS_NEXT_AVAILABLE_IP + ':' + ip_range
|
||||
|
||||
return proposed_object
|
||||
|
||||
def check_if_add_remove_ip_arg_exists(self, proposed_object):
|
||||
'''
|
||||
This function shall check if add/remove param is set to true and
|
||||
is passed in the args, then we will update the proposed dictionary
|
||||
to add/remove IP to existing host_record, if the user passes false
|
||||
param with the argument nothing shall be done.
|
||||
:returns: True if param is changed based on add/remove, and also the
|
||||
changed proposed_object.
|
||||
'''
|
||||
update = False
|
||||
if 'add' in proposed_object['ipv4addrs'][0]:
|
||||
if proposed_object['ipv4addrs'][0]['add']:
|
||||
proposed_object['ipv4addrs+'] = proposed_object['ipv4addrs']
|
||||
del proposed_object['ipv4addrs']
|
||||
del proposed_object['ipv4addrs+'][0]['add']
|
||||
update = True
|
||||
else:
|
||||
del proposed_object['ipv4addrs'][0]['add']
|
||||
elif 'remove' in proposed_object['ipv4addrs'][0]:
|
||||
if proposed_object['ipv4addrs'][0]['remove']:
|
||||
proposed_object['ipv4addrs-'] = proposed_object['ipv4addrs']
|
||||
del proposed_object['ipv4addrs']
|
||||
del proposed_object['ipv4addrs-'][0]['remove']
|
||||
update = True
|
||||
else:
|
||||
del proposed_object['ipv4addrs'][0]['remove']
|
||||
return update, proposed_object
|
||||
|
||||
def issubset(self, item, objects):
|
||||
''' Checks if item is a subset of objects
|
||||
:args item: the subset item to validate
|
||||
:args objects: superset list of objects to validate against
|
||||
:returns: True if item is a subset of one entry in objects otherwise
|
||||
this method will return None
|
||||
'''
|
||||
for obj in objects:
|
||||
if isinstance(item, dict):
|
||||
if all(entry in obj.items() for entry in item.items()):
|
||||
return True
|
||||
else:
|
||||
if item in obj:
|
||||
return True
|
||||
|
||||
def compare_objects(self, current_object, proposed_object):
|
||||
for key, proposed_item in iteritems(proposed_object):
|
||||
current_item = current_object.get(key)
|
||||
|
||||
# if proposed has a key that current doesn't then the objects are
|
||||
# not equal and False will be immediately returned
|
||||
if current_item is None:
|
||||
return False
|
||||
|
||||
elif isinstance(proposed_item, list):
|
||||
if key == 'aliases':
|
||||
if set(current_item) != set(proposed_item):
|
||||
return False
|
||||
for subitem in proposed_item:
|
||||
if not self.issubset(subitem, current_item):
|
||||
return False
|
||||
|
||||
elif isinstance(proposed_item, dict):
|
||||
return self.compare_objects(current_item, proposed_item)
|
||||
|
||||
else:
|
||||
if current_item != proposed_item:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def get_object_ref(self, module, ib_obj_type, obj_filter, ib_spec):
|
||||
''' this function gets the reference object of pre-existing nios objects '''
|
||||
|
||||
update = False
|
||||
old_name = new_name = None
|
||||
if ('name' in obj_filter):
|
||||
# gets and returns the current object based on name/old_name passed
|
||||
try:
|
||||
name_obj = check_type_dict(obj_filter['name'])
|
||||
old_name = name_obj['old_name']
|
||||
new_name = name_obj['new_name']
|
||||
except TypeError:
|
||||
name = obj_filter['name']
|
||||
|
||||
if old_name and new_name:
|
||||
if (ib_obj_type == NIOS_HOST_RECORD):
|
||||
test_obj_filter = dict([('name', old_name), ('view', obj_filter['view'])])
|
||||
elif (ib_obj_type in (NIOS_AAAA_RECORD, NIOS_A_RECORD)):
|
||||
test_obj_filter = obj_filter
|
||||
else:
|
||||
test_obj_filter = dict([('name', old_name)])
|
||||
# get the object reference
|
||||
ib_obj = self.get_object(ib_obj_type, test_obj_filter, return_fields=list(ib_spec.keys()))
|
||||
if ib_obj:
|
||||
obj_filter['name'] = new_name
|
||||
else:
|
||||
test_obj_filter['name'] = new_name
|
||||
ib_obj = self.get_object(ib_obj_type, test_obj_filter, return_fields=list(ib_spec.keys()))
|
||||
update = True
|
||||
return ib_obj, update, new_name
|
||||
if (ib_obj_type == NIOS_HOST_RECORD):
|
||||
# to check only by name if dns bypassing is set
|
||||
if not obj_filter['configure_for_dns']:
|
||||
test_obj_filter = dict([('name', name)])
|
||||
else:
|
||||
test_obj_filter = dict([('name', name), ('view', obj_filter['view'])])
|
||||
elif (ib_obj_type == NIOS_IPV4_FIXED_ADDRESS or ib_obj_type == NIOS_IPV6_FIXED_ADDRESS and 'mac' in obj_filter):
|
||||
test_obj_filter = dict([['mac', obj_filter['mac']]])
|
||||
elif (ib_obj_type == NIOS_A_RECORD):
|
||||
# resolves issue where a_record with uppercase name was returning null and was failing
|
||||
test_obj_filter = obj_filter
|
||||
test_obj_filter['name'] = test_obj_filter['name'].lower()
|
||||
# resolves issue where multiple a_records with same name and different IP address
|
||||
try:
|
||||
ipaddr_obj = check_type_dict(obj_filter['ipv4addr'])
|
||||
ipaddr = ipaddr_obj['old_ipv4addr']
|
||||
except TypeError:
|
||||
ipaddr = obj_filter['ipv4addr']
|
||||
test_obj_filter['ipv4addr'] = ipaddr
|
||||
elif (ib_obj_type == NIOS_TXT_RECORD):
|
||||
# resolves issue where multiple txt_records with same name and different text
|
||||
test_obj_filter = obj_filter
|
||||
try:
|
||||
text_obj = check_type_dict(obj_filter['text'])
|
||||
txt = text_obj['old_text']
|
||||
except TypeError:
|
||||
txt = obj_filter['text']
|
||||
test_obj_filter['text'] = txt
|
||||
# check if test_obj_filter is empty copy passed obj_filter
|
||||
else:
|
||||
test_obj_filter = obj_filter
|
||||
ib_obj = self.get_object(ib_obj_type, test_obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
elif (ib_obj_type == NIOS_A_RECORD):
|
||||
# resolves issue where multiple a_records with same name and different IP address
|
||||
test_obj_filter = obj_filter
|
||||
try:
|
||||
ipaddr_obj = check_type_dict(obj_filter['ipv4addr'])
|
||||
ipaddr = ipaddr_obj['old_ipv4addr']
|
||||
except TypeError:
|
||||
ipaddr = obj_filter['ipv4addr']
|
||||
test_obj_filter['ipv4addr'] = ipaddr
|
||||
ib_obj = self.get_object(ib_obj_type, test_obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
elif (ib_obj_type == NIOS_TXT_RECORD):
|
||||
# resolves issue where multiple txt_records with same name and different text
|
||||
test_obj_filter = obj_filter
|
||||
try:
|
||||
text_obj = check_type_dict(obj_filter['text'])
|
||||
txt = text_obj['old_text']
|
||||
except TypeError:
|
||||
txt = obj_filter['text']
|
||||
test_obj_filter['text'] = txt
|
||||
ib_obj = self.get_object(ib_obj_type, test_obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
elif (ib_obj_type == NIOS_ZONE):
|
||||
# del key 'restart_if_needed' as nios_zone get_object fails with the key present
|
||||
temp = ib_spec['restart_if_needed']
|
||||
del ib_spec['restart_if_needed']
|
||||
ib_obj = self.get_object(ib_obj_type, obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
# reinstate restart_if_needed if ib_obj is none, meaning there's no existing nios_zone ref
|
||||
if not ib_obj:
|
||||
ib_spec['restart_if_needed'] = temp
|
||||
elif (ib_obj_type == NIOS_MEMBER):
|
||||
# del key 'create_token' as nios_member get_object fails with the key present
|
||||
temp = ib_spec['create_token']
|
||||
del ib_spec['create_token']
|
||||
ib_obj = self.get_object(ib_obj_type, obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
if temp:
|
||||
# reinstate 'create_token' key
|
||||
ib_spec['create_token'] = temp
|
||||
else:
|
||||
ib_obj = self.get_object(ib_obj_type, obj_filter.copy(), return_fields=list(ib_spec.keys()))
|
||||
return ib_obj, update, new_name
|
||||
|
||||
def on_update(self, proposed_object, ib_spec):
|
||||
''' Event called before the update is sent to the API endpoing
|
||||
This method will allow the final proposed object to be changed
|
||||
and/or keys filtered before it is sent to the API endpoint to
|
||||
be processed.
|
||||
:args proposed_object: A dict item that will be encoded and sent
|
||||
the API endpoint with the updated data structure
|
||||
:returns: updated object to be sent to API endpoint
|
||||
'''
|
||||
keys = set()
|
||||
for key, value in iteritems(proposed_object):
|
||||
update = ib_spec[key].get('update', True)
|
||||
if not update:
|
||||
keys.add(key)
|
||||
return dict([(k, v) for k, v in iteritems(proposed_object) if k not in keys])
|
||||
@@ -1605,9 +1605,6 @@ class RedfishUtils(object):
|
||||
cur_boot_next = boot.get('BootNext')
|
||||
cur_override_mode = boot.get('BootSourceOverrideMode')
|
||||
|
||||
if not boot_override_mode:
|
||||
boot_override_mode = cur_override_mode
|
||||
|
||||
if override_enabled == 'Disabled':
|
||||
payload = {
|
||||
'Boot': {
|
||||
@@ -1643,16 +1640,18 @@ class RedfishUtils(object):
|
||||
}
|
||||
}
|
||||
else:
|
||||
if cur_enabled == override_enabled and target == bootdevice and cur_override_mode == boot_override_mode:
|
||||
if (cur_enabled == override_enabled and target == bootdevice and
|
||||
(cur_override_mode == boot_override_mode or not boot_override_mode)):
|
||||
# If properties are already set, no changes needed
|
||||
return {'ret': True, 'changed': False}
|
||||
payload = {
|
||||
'Boot': {
|
||||
'BootSourceOverrideEnabled': override_enabled,
|
||||
'BootSourceOverrideMode': boot_override_mode,
|
||||
'BootSourceOverrideTarget': bootdevice
|
||||
}
|
||||
}
|
||||
if boot_override_mode:
|
||||
payload['Boot']['BootSourceOverrideMode'] = boot_override_mode
|
||||
|
||||
response = self.patch_request(self.root_uri + self.systems_uri, payload)
|
||||
if response['ret'] is False:
|
||||
@@ -2762,7 +2761,9 @@ class RedfishUtils(object):
|
||||
if isinstance(set_value, dict):
|
||||
for subprop in payload[property].keys():
|
||||
if subprop not in target_ethernet_current_setting[property]:
|
||||
return {'ret': False, 'msg': "Sub-property %s in nic_config is invalid" % subprop}
|
||||
# Not configured already; need to apply the request
|
||||
need_change = True
|
||||
break
|
||||
sub_set_value = payload[property][subprop]
|
||||
sub_cur_value = target_ethernet_current_setting[property][subprop]
|
||||
if sub_set_value != sub_cur_value:
|
||||
@@ -2776,7 +2777,9 @@ class RedfishUtils(object):
|
||||
for i in range(len(set_value)):
|
||||
for subprop in payload[property][i].keys():
|
||||
if subprop not in target_ethernet_current_setting[property][i]:
|
||||
return {'ret': False, 'msg': "Sub-property %s in nic_config is invalid" % subprop}
|
||||
# Not configured already; need to apply the request
|
||||
need_change = True
|
||||
break
|
||||
sub_set_value = payload[property][i][subprop]
|
||||
sub_cur_value = target_ethernet_current_setting[property][i][subprop]
|
||||
if sub_set_value != sub_cur_value:
|
||||
|
||||
@@ -15,13 +15,6 @@ from ansible.module_utils.urls import fetch_url, basic_auth_header
|
||||
class BitbucketHelper:
|
||||
BITBUCKET_API_URL = 'https://api.bitbucket.org'
|
||||
|
||||
error_messages = {
|
||||
'required_client_id': '`client_id` must be specified as a parameter or '
|
||||
'BITBUCKET_CLIENT_ID environment variable',
|
||||
'required_client_secret': '`client_secret` must be specified as a parameter or '
|
||||
'BITBUCKET_CLIENT_SECRET environment variable',
|
||||
}
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.access_token = None
|
||||
@@ -29,35 +22,40 @@ class BitbucketHelper:
|
||||
@staticmethod
|
||||
def bitbucket_argument_spec():
|
||||
return dict(
|
||||
client_id=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_CLIENT_ID'])),
|
||||
client_id=dict(type='str', fallback=(env_fallback, ['BITBUCKET_CLIENT_ID'])),
|
||||
client_secret=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_CLIENT_SECRET'])),
|
||||
# TODO:
|
||||
# - Rename user to username once current usage of username is removed
|
||||
# - Alias user to username and deprecate it
|
||||
user=dict(type='str', fallback=(env_fallback, ['BITBUCKET_USERNAME'])),
|
||||
password=dict(type='str', no_log=True, fallback=(env_fallback, ['BITBUCKET_PASSWORD'])),
|
||||
)
|
||||
|
||||
def check_arguments(self):
|
||||
if self.module.params['client_id'] is None:
|
||||
self.module.fail_json(msg=self.error_messages['required_client_id'])
|
||||
@staticmethod
|
||||
def bitbucket_required_one_of():
|
||||
return [['client_id', 'client_secret', 'user', 'password']]
|
||||
|
||||
if self.module.params['client_secret'] is None:
|
||||
self.module.fail_json(msg=self.error_messages['required_client_secret'])
|
||||
@staticmethod
|
||||
def bitbucket_required_together():
|
||||
return [['client_id', 'client_secret'], ['user', 'password']]
|
||||
|
||||
def fetch_access_token(self):
|
||||
self.check_arguments()
|
||||
if self.module.params['client_id'] and self.module.params['client_secret']:
|
||||
headers = {
|
||||
'Authorization': basic_auth_header(self.module.params['client_id'], self.module.params['client_secret']),
|
||||
}
|
||||
|
||||
headers = {
|
||||
'Authorization': basic_auth_header(self.module.params['client_id'], self.module.params['client_secret'])
|
||||
}
|
||||
info, content = self.request(
|
||||
api_url='https://bitbucket.org/site/oauth2/access_token',
|
||||
method='POST',
|
||||
data='grant_type=client_credentials',
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
info, content = self.request(
|
||||
api_url='https://bitbucket.org/site/oauth2/access_token',
|
||||
method='POST',
|
||||
data='grant_type=client_credentials',
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
if info['status'] == 200:
|
||||
self.access_token = content['access_token']
|
||||
else:
|
||||
self.module.fail_json(msg='Failed to retrieve access token: {0}'.format(info))
|
||||
if info['status'] == 200:
|
||||
self.access_token = content['access_token']
|
||||
else:
|
||||
self.module.fail_json(msg='Failed to retrieve access token: {0}'.format(info))
|
||||
|
||||
def request(self, api_url, method, data=None, headers=None):
|
||||
headers = headers or {}
|
||||
@@ -66,6 +64,10 @@ class BitbucketHelper:
|
||||
headers.update({
|
||||
'Authorization': 'Bearer {0}'.format(self.access_token),
|
||||
})
|
||||
elif self.module.params['user'] and self.module.params['password']:
|
||||
headers.update({
|
||||
'Authorization': basic_auth_header(self.module.params['user'], self.module.params['password']),
|
||||
})
|
||||
|
||||
if isinstance(data, dict):
|
||||
data = self.module.jsonify(data)
|
||||
|
||||
@@ -43,10 +43,9 @@ options:
|
||||
- If set to C(true), options starting with C(volatile.) are ignored. As a result,
|
||||
they are reapplied for each execution.
|
||||
- This default behavior can be changed by setting this option to C(false).
|
||||
- The default value C(true) will be deprecated in community.general 4.0.0,
|
||||
and will change to C(false) in community.general 5.0.0.
|
||||
- The current default value C(true) is deprecated since community.general 4.0.0,
|
||||
and will change to C(false) in community.general 6.0.0.
|
||||
type: bool
|
||||
default: true
|
||||
required: false
|
||||
version_added: 3.7.0
|
||||
profiles:
|
||||
@@ -674,7 +673,6 @@ def main():
|
||||
),
|
||||
ignore_volatile_options=dict(
|
||||
type='bool',
|
||||
default=True
|
||||
),
|
||||
devices=dict(
|
||||
type='dict',
|
||||
@@ -728,13 +726,16 @@ def main():
|
||||
),
|
||||
supports_check_mode=False,
|
||||
)
|
||||
# if module.params['ignore_volatile_options'] is None:
|
||||
# module.params['ignore_volatile_options'] = True
|
||||
# module.deprecate(
|
||||
# 'If the keyword "volatile" is used in a playbook in the config section, a
|
||||
# "changed" message will appear with every run, even without a change to the playbook.
|
||||
# This will change in the future.
|
||||
# Please test your scripts by "ignore_volatile_options: false"', version='5.0.0', collection_name='community.general')
|
||||
|
||||
if module.params['ignore_volatile_options'] is None:
|
||||
module.params['ignore_volatile_options'] = True
|
||||
module.deprecate(
|
||||
'If the keyword "volatile" is used in a playbook in the config'
|
||||
'section, a "changed" message will appear with every run, even without a change'
|
||||
'to the playbook.'
|
||||
'This will change in the future. Please test your scripts'
|
||||
'by "ignore_volatile_options: false". To keep the old behavior, set that option explicitly to "true"',
|
||||
version='6.0.0', collection_name='community.general')
|
||||
lxd_manage = LXDContainerManagement(module=module)
|
||||
lxd_manage.run()
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ short_description: management of instances in Proxmox VE cluster
|
||||
description:
|
||||
- allows you to create/delete/stop instances in Proxmox VE cluster
|
||||
- Starting in Ansible 2.1, it automatically detects containerization type (lxc for PVE 4, openvz for older)
|
||||
- From community.general 4.0.0 on, there will be no default values, see I(proxmox_default_behavior).
|
||||
- Since community.general 4.0.0 on, there are no more default values, see I(proxmox_default_behavior).
|
||||
options:
|
||||
password:
|
||||
description:
|
||||
@@ -40,37 +40,27 @@ options:
|
||||
comma-delimited list C([volume=]<volume> [,acl=<1|0>] [,mountoptions=<opt[;opt...]>] [,quota=<1|0>]
|
||||
[,replicate=<1|0>] [,ro=<1|0>] [,shared=<1|0>] [,size=<DiskSize>])."
|
||||
- See U(https://pve.proxmox.com/wiki/Linux_Container) for a full description.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(3). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(3).
|
||||
type: str
|
||||
cores:
|
||||
description:
|
||||
- Specify number of cores per socket.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
|
||||
type: int
|
||||
cpus:
|
||||
description:
|
||||
- numbers of allocated cpus for instance
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
|
||||
type: int
|
||||
memory:
|
||||
description:
|
||||
- memory size in MB for instance
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(512). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(512).
|
||||
type: int
|
||||
swap:
|
||||
description:
|
||||
- swap memory size in MB for instance
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(0). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(0).
|
||||
type: int
|
||||
netif:
|
||||
description:
|
||||
@@ -94,9 +84,7 @@ options:
|
||||
onboot:
|
||||
description:
|
||||
- specifies whether a VM will be started during system bootup
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(no). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(no).
|
||||
type: bool
|
||||
storage:
|
||||
description:
|
||||
@@ -106,9 +94,7 @@ options:
|
||||
cpuunits:
|
||||
description:
|
||||
- CPU weight for a VM
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1000). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1000).
|
||||
type: int
|
||||
nameserver:
|
||||
description:
|
||||
@@ -168,16 +154,15 @@ options:
|
||||
version_added: '0.2.0'
|
||||
proxmox_default_behavior:
|
||||
description:
|
||||
- Various module options used to have default values. This cause problems when
|
||||
user expects different behavior from proxmox by default or fill options which cause
|
||||
problems when they have been set.
|
||||
- The default value is C(compatibility), which will ensure that the default values
|
||||
are used when the values are not explicitly specified by the user.
|
||||
- From community.general 4.0.0 on, the default value will switch to C(no_defaults). To avoid
|
||||
deprecation warnings, please set I(proxmox_default_behavior) to an explicit
|
||||
value.
|
||||
- As of community.general 4.0.0, various options no longer have default values.
|
||||
These default values caused problems when users expected different behavior from Proxmox
|
||||
by default or filled options which caused problems when set.
|
||||
- The value C(compatibility) (default before community.general 4.0.0) will ensure that the default values
|
||||
are used when the values are not explicitly specified by the user. The new default is C(no_defaults),
|
||||
which makes sure these options have no defaults.
|
||||
- This affects the I(disk), I(cores), I(cpus), I(memory), I(onboot), I(swap), I(cpuunits) options.
|
||||
type: str
|
||||
default: no_defaults
|
||||
choices:
|
||||
- compatibility
|
||||
- no_defaults
|
||||
@@ -529,7 +514,7 @@ def main():
|
||||
unprivileged=dict(type='bool', default=False),
|
||||
description=dict(type='str'),
|
||||
hookscript=dict(type='str'),
|
||||
proxmox_default_behavior=dict(type='str', choices=['compatibility', 'no_defaults']),
|
||||
proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults']),
|
||||
),
|
||||
required_if=[('state', 'present', ['node', 'hostname', 'ostemplate'])],
|
||||
required_together=[('api_token_id', 'api_token_secret')],
|
||||
@@ -558,13 +543,6 @@ def main():
|
||||
template_store = module.params['ostemplate'].split(":")[0]
|
||||
timeout = module.params['timeout']
|
||||
|
||||
if module.params['proxmox_default_behavior'] is None:
|
||||
module.params['proxmox_default_behavior'] = 'compatibility'
|
||||
module.deprecate(
|
||||
'The proxmox_default_behavior option will change its default value from "compatibility" to '
|
||||
'"no_defaults" in community.general 4.0.0. To remove this warning, please specify an explicit value for it now',
|
||||
version='4.0.0', collection_name='community.general'
|
||||
)
|
||||
if module.params['proxmox_default_behavior'] == 'compatibility':
|
||||
old_default_values = dict(
|
||||
disk="3",
|
||||
|
||||
@@ -131,7 +131,7 @@ def main():
|
||||
group = module.params['group']
|
||||
|
||||
if group:
|
||||
groups = [proxmox.get_group(group=group)]
|
||||
groups = [proxmox.get_group(groupid=group)]
|
||||
else:
|
||||
groups = proxmox.get_groups()
|
||||
result['proxmox_groups'] = [group.group for group in groups]
|
||||
|
||||
@@ -13,15 +13,13 @@ module: proxmox_kvm
|
||||
short_description: Management of Qemu(KVM) Virtual Machines in Proxmox VE cluster.
|
||||
description:
|
||||
- Allows you to create/delete/stop Qemu(KVM) Virtual Machines in Proxmox VE cluster.
|
||||
- From community.general 4.0.0 on, there will be no default values, see I(proxmox_default_behavior).
|
||||
- Since community.general 4.0.0 on, there are no more default values, see I(proxmox_default_behavior).
|
||||
author: "Abdoul Bah (@helldorado) <bahabdoul at gmail.com>"
|
||||
options:
|
||||
acpi:
|
||||
description:
|
||||
- Specify if ACPI should be enabled/disabled.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(yes). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(yes).
|
||||
type: bool
|
||||
agent:
|
||||
description:
|
||||
@@ -31,24 +29,19 @@ options:
|
||||
description:
|
||||
- Pass arbitrary arguments to kvm.
|
||||
- This option is for experts only!
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(-serial unix:/var/run/qemu-server/<vmid>.serial,server,nowait).
|
||||
Note that the default value of I(proxmox_default_behavior) changes in community.general 4.0.0.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity), this option has a default of
|
||||
C(-serial unix:/var/run/qemu-server/<vmid>.serial,server,nowait).
|
||||
type: str
|
||||
autostart:
|
||||
description:
|
||||
- Specify if the VM should be automatically restarted after crash (currently ignored in PVE API).
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(no). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(no).
|
||||
type: bool
|
||||
balloon:
|
||||
description:
|
||||
- Specify the amount of RAM for the VM in MB.
|
||||
- Using zero disables the balloon driver.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(0). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(0).
|
||||
type: int
|
||||
bios:
|
||||
description:
|
||||
@@ -59,9 +52,7 @@ options:
|
||||
description:
|
||||
- Specify the boot order -> boot on floppy C(a), hard disk C(c), CD-ROM C(d), or network C(n).
|
||||
- You can combine to set order.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(cnd). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(cnd).
|
||||
type: str
|
||||
bootdisk:
|
||||
description:
|
||||
@@ -97,16 +88,12 @@ options:
|
||||
cores:
|
||||
description:
|
||||
- Specify number of cores per socket.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
|
||||
type: int
|
||||
cpu:
|
||||
description:
|
||||
- Specify emulated CPU type.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(kvm64). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(kvm64).
|
||||
type: str
|
||||
cpulimit:
|
||||
description:
|
||||
@@ -117,9 +104,7 @@ options:
|
||||
description:
|
||||
- Specify CPU weight for a VM.
|
||||
- You can disable fair-scheduler configuration by setting this to 0
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1000). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1000).
|
||||
type: int
|
||||
delete:
|
||||
description:
|
||||
@@ -139,19 +124,15 @@ options:
|
||||
description:
|
||||
- Allow to force stop VM.
|
||||
- Can be used with states C(stopped), C(restarted) and C(absent).
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(no). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(no).
|
||||
type: bool
|
||||
format:
|
||||
description:
|
||||
- Target drive's backing file's data format.
|
||||
- Used only with clone
|
||||
- Use I(format=unspecified) and I(full=false) for a linked clone.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(qcow2). If I(proxmox_default_behavior) is set to C(no_defaults),
|
||||
not specifying this option is equivalent to setting it to C(unspecified).
|
||||
Note that the default value of I(proxmox_default_behavior) changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(qcow2).
|
||||
If I(proxmox_default_behavior) is set to C(no_defaults), not specifying this option is equivalent to setting it to C(unspecified).
|
||||
type: str
|
||||
choices: [ "cloop", "cow", "qcow", "qcow2", "qed", "raw", "vmdk", "unspecified" ]
|
||||
freeze:
|
||||
@@ -216,9 +197,7 @@ options:
|
||||
kvm:
|
||||
description:
|
||||
- Enable/disable KVM hardware virtualization.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(yes). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(yes).
|
||||
type: bool
|
||||
localtime:
|
||||
description:
|
||||
@@ -238,9 +217,7 @@ options:
|
||||
memory:
|
||||
description:
|
||||
- Memory size in MB for instance.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(512). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(512).
|
||||
type: int
|
||||
migrate_downtime:
|
||||
description:
|
||||
@@ -296,17 +273,13 @@ options:
|
||||
onboot:
|
||||
description:
|
||||
- Specifies whether a VM will be started during system bootup.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(yes). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(yes).
|
||||
type: bool
|
||||
ostype:
|
||||
description:
|
||||
- Specifies guest operating system. This is used to enable special optimization/features for specific operating systems.
|
||||
- The l26 is Linux 2.6/3.X Kernel.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(l26). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(l26).
|
||||
type: str
|
||||
choices: ['other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7', 'win8', 'win10', 'l24', 'l26', 'solaris']
|
||||
parallel:
|
||||
@@ -387,9 +360,7 @@ options:
|
||||
sockets:
|
||||
description:
|
||||
- Sets the number of CPU sockets. (1 - N).
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(1). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(1).
|
||||
type: int
|
||||
sshkeys:
|
||||
description:
|
||||
@@ -421,9 +392,7 @@ options:
|
||||
tablet:
|
||||
description:
|
||||
- Enables/disables the USB tablet device.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(no). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(no).
|
||||
type: bool
|
||||
tags:
|
||||
description:
|
||||
@@ -445,9 +414,7 @@ options:
|
||||
template:
|
||||
description:
|
||||
- Enables/disables the template.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(no). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(no).
|
||||
type: bool
|
||||
timeout:
|
||||
description:
|
||||
@@ -469,9 +436,7 @@ options:
|
||||
vga:
|
||||
description:
|
||||
- Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'.
|
||||
- If I(proxmox_default_behavior) is set to C(compatiblity) (the default value), this
|
||||
option has a default of C(std). Note that the default value of I(proxmox_default_behavior)
|
||||
changes in community.general 4.0.0.
|
||||
- This option has no default unless I(proxmox_default_behavior) is set to C(compatiblity); then the default is C(std).
|
||||
type: str
|
||||
choices: ['std', 'cirrus', 'vmware', 'qxl', 'serial0', 'serial1', 'serial2', 'serial3', 'qxl2', 'qxl3', 'qxl4']
|
||||
virtio:
|
||||
@@ -489,18 +454,17 @@ options:
|
||||
type: str
|
||||
proxmox_default_behavior:
|
||||
description:
|
||||
- Various module options used to have default values. This cause problems when
|
||||
user expects different behavior from proxmox by default or fill options which cause
|
||||
problems when they have been set.
|
||||
- The default value is C(compatibility), which will ensure that the default values
|
||||
are used when the values are not explicitly specified by the user.
|
||||
- From community.general 4.0.0 on, the default value will switch to C(no_defaults). To avoid
|
||||
deprecation warnings, please set I(proxmox_default_behavior) to an explicit
|
||||
value.
|
||||
- As of community.general 4.0.0, various options no longer have default values.
|
||||
These default values caused problems when users expected different behavior from Proxmox
|
||||
by default or filled options which caused problems when set.
|
||||
- The value C(compatibility) (default before community.general 4.0.0) will ensure that the default values
|
||||
are used when the values are not explicitly specified by the user. The new default is C(no_defaults),
|
||||
which makes sure these options have no defaults.
|
||||
- This affects the I(acpi), I(autostart), I(balloon), I(boot), I(cores), I(cpu),
|
||||
I(cpuunits), I(force), I(format), I(kvm), I(memory), I(onboot), I(ostype), I(sockets),
|
||||
I(tablet), I(template), I(vga), options.
|
||||
type: str
|
||||
default: no_defaults
|
||||
choices:
|
||||
- compatibility
|
||||
- no_defaults
|
||||
@@ -1091,7 +1055,7 @@ def main():
|
||||
virtio=dict(type='dict'),
|
||||
vmid=dict(type='int'),
|
||||
watchdog=dict(),
|
||||
proxmox_default_behavior=dict(type='str', choices=['compatibility', 'no_defaults']),
|
||||
proxmox_default_behavior=dict(type='str', default='no_defaults', choices=['compatibility', 'no_defaults']),
|
||||
),
|
||||
mutually_exclusive=[('delete', 'revert'), ('delete', 'update'), ('revert', 'update'), ('clone', 'update'), ('clone', 'delete'), ('clone', 'revert')],
|
||||
required_together=[('api_token_id', 'api_token_secret')],
|
||||
@@ -1122,13 +1086,6 @@ def main():
|
||||
vmid = module.params['vmid']
|
||||
validate_certs = module.params['validate_certs']
|
||||
|
||||
if module.params['proxmox_default_behavior'] is None:
|
||||
module.params['proxmox_default_behavior'] = 'compatibility'
|
||||
module.deprecate(
|
||||
'The proxmox_default_behavior option will change its default value from "compatibility" to '
|
||||
'"no_defaults" in community.general 4.0.0. To remove this warning, please specify an explicit value for it now',
|
||||
version='4.0.0', collection_name='community.general'
|
||||
)
|
||||
if module.params['proxmox_default_behavior'] == 'compatibility':
|
||||
old_default_values = dict(
|
||||
acpi=True,
|
||||
|
||||
@@ -306,7 +306,7 @@ def rename_image(module, client, image, new_name):
|
||||
|
||||
tmp_image = get_image_by_name(module, client, new_name)
|
||||
if tmp_image:
|
||||
module.fail_json(msg="Name '" + new_name + "' is already taken by IMAGE with id=" + str(tmp_image.id))
|
||||
module.fail_json(msg="Name '" + new_name + "' is already taken by IMAGE with id=" + str(tmp_image.ID))
|
||||
|
||||
if not module.check_mode:
|
||||
client.image.rename(image.ID, new_name)
|
||||
|
||||
@@ -18,11 +18,12 @@ module: scaleway_security_group_rule
|
||||
short_description: Scaleway Security Group Rule management module
|
||||
author: Antoine Barbare (@abarbare)
|
||||
description:
|
||||
- This module manages Security Group Rule on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
- This module manages Security Group Rule on Scaleway account
|
||||
U(https://developer.scaleway.com)
|
||||
extends_documentation_fragment:
|
||||
- community.general.scaleway
|
||||
|
||||
- community.general.scaleway
|
||||
requirements:
|
||||
- ipaddress
|
||||
|
||||
options:
|
||||
state:
|
||||
@@ -130,10 +131,19 @@ data:
|
||||
}
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway, payload_from_object
|
||||
from ansible_collections.community.general.plugins.module_utils.compat.ipaddress import ip_network
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
|
||||
try:
|
||||
from ipaddress import ip_network
|
||||
except ImportError:
|
||||
IPADDRESS_IMP_ERR = traceback.format_exc()
|
||||
HAS_IPADDRESS = False
|
||||
else:
|
||||
HAS_IPADDRESS = True
|
||||
|
||||
|
||||
def get_sgr_from_api(security_group_rules, security_group_rule):
|
||||
@@ -256,6 +266,8 @@ def main():
|
||||
argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
)
|
||||
if not HAS_IPADDRESS:
|
||||
module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR)
|
||||
|
||||
core(module)
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ options:
|
||||
description:
|
||||
- the address to advertise that the service will be listening on.
|
||||
This value will be passed as the I(address) parameter to Consul's
|
||||
U(/v1/agent/service/register) API method, so refer to the Consul API
|
||||
C(/v1/agent/service/register) API method, so refer to the Consul API
|
||||
documentation for further details.
|
||||
tags:
|
||||
type: list
|
||||
|
||||
187
plugins/modules/database/misc/redis_data_incr.py
Normal file
187
plugins/modules/database/misc/redis_data_incr.py
Normal file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2021, Andreas Botzner <andreas at botzner dot com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: redis_data_incr
|
||||
short_description: Increment keys in Redis
|
||||
version_added: 4.0.0
|
||||
description:
|
||||
- Increment integers or float keys in Redis database and get new value.
|
||||
- Default increment for all keys is 1. For specific increments use the
|
||||
I(increment_int) and I(increment_float) options.
|
||||
- When using I(check_mode) the module will try to calculate the value that
|
||||
Redis would return. If the key is not present, 0.0 is used as value.
|
||||
author: "Andreas Botzner (@paginabianca)"
|
||||
options:
|
||||
key:
|
||||
description:
|
||||
- Database key.
|
||||
type: str
|
||||
required: true
|
||||
increment_int:
|
||||
description:
|
||||
- Integer amount to increment the key by.
|
||||
required: false
|
||||
type: int
|
||||
increment_float:
|
||||
description:
|
||||
- Float amount to increment the key by.
|
||||
- This only works with keys that contain float values
|
||||
in their string representation.
|
||||
type: float
|
||||
required: false
|
||||
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.redis.documentation
|
||||
|
||||
notes:
|
||||
- For C(check_mode) to work, the specified I(redis_user) needs permission to
|
||||
run the C(GET) command on the key, otherwise the module will fail.
|
||||
|
||||
seealso:
|
||||
- module: community.general.redis_set
|
||||
- module: community.general.redis_data_info
|
||||
- module: community.general.redis
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Increment integer key foo on localhost with no username and print new value
|
||||
community.general.redis_data_incr:
|
||||
login_host: localhost
|
||||
login_password: supersecret
|
||||
key: foo
|
||||
increment_int: 1
|
||||
register: result
|
||||
- name: Print new value
|
||||
debug:
|
||||
var: result.value
|
||||
|
||||
- name: Increment float key foo by 20.4
|
||||
community.general.redis_data_incr:
|
||||
login_host: redishost
|
||||
login_user: redisuser
|
||||
login_password: somepass
|
||||
key: foo
|
||||
increment_float: '20.4'
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
value:
|
||||
description: Incremented value of key
|
||||
returned: on success
|
||||
type: float
|
||||
sample: '4039.4'
|
||||
msg:
|
||||
description: A short message.
|
||||
returned: always
|
||||
type: str
|
||||
sample: 'Incremented key: foo by 20.4 to 65.9'
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.redis import (
|
||||
fail_imports, redis_auth_argument_spec, RedisAnsible)
|
||||
|
||||
|
||||
def main():
|
||||
redis_auth_args = redis_auth_argument_spec()
|
||||
module_args = dict(
|
||||
key=dict(type='str', required=True, no_log=False),
|
||||
increment_int=dict(type='int', required=False),
|
||||
increment_float=dict(type='float', required=False),
|
||||
)
|
||||
module_args.update(redis_auth_args)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=[['increment_int', 'increment_float']],
|
||||
)
|
||||
fail_imports(module)
|
||||
|
||||
redis = RedisAnsible(module)
|
||||
key = module.params['key']
|
||||
increment_float = module.params['increment_float']
|
||||
increment_int = module.params['increment_int']
|
||||
increment = 1
|
||||
if increment_float is not None:
|
||||
increment = increment_float
|
||||
elif increment_int is not None:
|
||||
increment = increment_int
|
||||
|
||||
result = {'changed': False}
|
||||
if module.check_mode:
|
||||
value = 0.0
|
||||
try:
|
||||
res = redis.connection.get(key)
|
||||
if res is not None:
|
||||
value = float(res)
|
||||
except ValueError as e:
|
||||
msg = 'Value: {0} of key: {1} is not incrementable(int or float)'.format(
|
||||
res, key)
|
||||
result['msg'] = msg
|
||||
module.fail_json(**result)
|
||||
except Exception as e:
|
||||
msg = 'Failed to get value of key: {0} with exception: {1}'.format(
|
||||
key, str(e))
|
||||
result['msg'] = msg
|
||||
module.fail_json(**result)
|
||||
msg = 'Incremented key: {0} by {1} to {2}'.format(
|
||||
key, increment, value + increment)
|
||||
result['msg'] = msg
|
||||
result['value'] = float(value + increment)
|
||||
module.exit_json(**result)
|
||||
|
||||
if increment_float is not None:
|
||||
try:
|
||||
value = redis.connection.incrbyfloat(key, increment)
|
||||
msg = 'Incremented key: {0} by {1} to {2}'.format(
|
||||
key, increment, value)
|
||||
result['msg'] = msg
|
||||
result['value'] = float(value)
|
||||
result['changed'] = True
|
||||
module.exit_json(**result)
|
||||
except Exception as e:
|
||||
msg = 'Failed to increment key: {0} by {1} with exception: {2}'.format(
|
||||
key, increment, str(e))
|
||||
result['msg'] = msg
|
||||
module.fail_json(**result)
|
||||
elif increment_int is not None:
|
||||
try:
|
||||
value = redis.connection.incrby(key, increment)
|
||||
msg = 'Incremented key: {0} by {1} to {2}'.format(
|
||||
key, increment, value)
|
||||
result['msg'] = msg
|
||||
result['value'] = float(value)
|
||||
result['changed'] = True
|
||||
module.exit_json(**result)
|
||||
except Exception as e:
|
||||
msg = 'Failed to increment key: {0} by {1} with exception: {2}'.format(
|
||||
key, increment, str(e))
|
||||
result['msg'] = msg
|
||||
module.fail_json(**result)
|
||||
else:
|
||||
try:
|
||||
value = redis.connection.incr(key)
|
||||
msg = 'Incremented key: {0} to {1}'.format(key, value)
|
||||
result['msg'] = msg
|
||||
result['value'] = float(value)
|
||||
result['changed'] = True
|
||||
module.exit_json(**result)
|
||||
except Exception as e:
|
||||
msg = 'Failed to increment key: {0} with exception: {1}'.format(
|
||||
key, str(e))
|
||||
result['msg'] = msg
|
||||
module.fail_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
301
plugins/modules/database/mssql/mssql_script.py
Normal file
301
plugins/modules/database/mssql/mssql_script.py
Normal file
@@ -0,0 +1,301 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright: (c) 2021, Kris Budde <kris@budd.ee
|
||||
# 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: mssql_script
|
||||
|
||||
short_description: Execute SQL scripts on a MSSQL database
|
||||
|
||||
version_added: "4.0.0"
|
||||
|
||||
description:
|
||||
- Execute SQL scripts on a MSSQL database.
|
||||
|
||||
options:
|
||||
name:
|
||||
description: Database to run script against.
|
||||
aliases: [ db ]
|
||||
default: ''
|
||||
type: str
|
||||
login_user:
|
||||
description: The username used to authenticate with.
|
||||
type: str
|
||||
login_password:
|
||||
description: The password used to authenticate with.
|
||||
type: str
|
||||
login_host:
|
||||
description: Host running the database.
|
||||
type: str
|
||||
required: true
|
||||
login_port:
|
||||
description: Port of the MSSQL server. Requires I(login_host) be defined as well.
|
||||
default: 1433
|
||||
type: int
|
||||
script:
|
||||
description:
|
||||
- The SQL script to be executed.
|
||||
- Script can contain multiple SQL statements. Multiple Batches can be separated by C(GO) command.
|
||||
- Each batch must return at least one result set.
|
||||
required: true
|
||||
type: str
|
||||
output:
|
||||
description:
|
||||
- With C(default) each row will be returned as a list of values. See C(query_results).
|
||||
- Output format C(dict) will return dictionary with the column names as keys. See C(query_results_dict).
|
||||
- C(dict) requires named columns to be returned by each query otherwise an error is thrown.
|
||||
choices: [ "dict", "default" ]
|
||||
default: 'default'
|
||||
type: str
|
||||
params:
|
||||
description: |
|
||||
Parameters passed to the script as SQL parameters. ('SELECT %(name)s"' with C(example: '{"name": "John Doe"}).)'
|
||||
type: dict
|
||||
notes:
|
||||
- Requires the pymssql Python package on the remote host. For Ubuntu, this
|
||||
is as easy as C(pip install pymssql) (See M(ansible.builtin.pip).)
|
||||
requirements:
|
||||
- python >= 2.7
|
||||
- pymssql
|
||||
|
||||
author:
|
||||
- Kris Budde (@kbudde)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Check DB connection
|
||||
community.general.mssql_script:
|
||||
login_user: "{{ mssql_login_user }}"
|
||||
login_password: "{{ mssql_login_password }}"
|
||||
login_host: "{{ mssql_host }}"
|
||||
login_port: "{{ mssql_port }}"
|
||||
db: master
|
||||
script: "SELECT 1"
|
||||
|
||||
- name: Query with parameter
|
||||
community.general.mssql_script:
|
||||
login_user: "{{ mssql_login_user }}"
|
||||
login_password: "{{ mssql_login_password }}"
|
||||
login_host: "{{ mssql_host }}"
|
||||
login_port: "{{ mssql_port }}"
|
||||
script: |
|
||||
SELECT name, state_desc FROM sys.databases WHERE name = %(dbname)s
|
||||
params:
|
||||
dbname: msdb
|
||||
register: result_params
|
||||
- assert:
|
||||
that:
|
||||
- result_params.query_results[0][0][0][0] == 'msdb'
|
||||
- result_params.query_results[0][0][0][1] == 'ONLINE'
|
||||
|
||||
- name: two batches with default output
|
||||
community.general.mssql_script:
|
||||
login_user: "{{ mssql_login_user }}"
|
||||
login_password: "{{ mssql_login_password }}"
|
||||
login_host: "{{ mssql_host }}"
|
||||
login_port: "{{ mssql_port }}"
|
||||
script: |
|
||||
SELECT 'Batch 0 - Select 0'
|
||||
SELECT 'Batch 0 - Select 1'
|
||||
GO
|
||||
SELECT 'Batch 1 - Select 0'
|
||||
register: result_batches
|
||||
- assert:
|
||||
that:
|
||||
- result_batches.query_results | length == 2 # two batch results
|
||||
- result_batches.query_results[0] | length == 2 # two selects in first batch
|
||||
- result_batches.query_results[0][0] | length == 1 # one row in first select
|
||||
- result_batches.query_results[0][0][0] | length == 1 # one column in first row
|
||||
- result_batches.query_results[0][0][0][0] == 'Batch 0 - Select 0' # each row contains a list of values.
|
||||
|
||||
- name: two batches with dict output
|
||||
community.general.mssql_script:
|
||||
login_user: "{{ mssql_login_user }}"
|
||||
login_password: "{{ mssql_login_password }}"
|
||||
login_host: "{{ mssql_host }}"
|
||||
login_port: "{{ mssql_port }}"
|
||||
output: dict
|
||||
script: |
|
||||
SELECT 'Batch 0 - Select 0' as b0s0
|
||||
SELECT 'Batch 0 - Select 1' as b0s1
|
||||
GO
|
||||
SELECT 'Batch 1 - Select 0' as b1s0
|
||||
register: result_batches_dict
|
||||
- assert:
|
||||
that:
|
||||
- result_batches_dict.query_results_dict | length == 2 # two batch results
|
||||
- result_batches_dict.query_results_dict[0] | length == 2 # two selects in first batch
|
||||
- result_batches_dict.query_results_dict[0][0] | length == 1 # one row in first select
|
||||
- result_batches_dict.query_results_dict[0][0][0]['b0s0'] == 'Batch 0 - Select 0' # column 'b0s0' of first row
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
query_results:
|
||||
description: List of batches (queries separated by C(GO) keyword).
|
||||
type: list
|
||||
elements: list
|
||||
returned: success and I(output=default)
|
||||
sample: [[[["Batch 0 - Select 0"]], [["Batch 0 - Select 1"]]], [[["Batch 1 - Select 0"]]]]
|
||||
contains:
|
||||
queries:
|
||||
description:
|
||||
- List of result sets of each query.
|
||||
- If a query returns no results, the results of this and all the following queries will not be included in the output.
|
||||
- Use the C(GO) keyword in I(script) to separate queries.
|
||||
type: list
|
||||
elements: list
|
||||
contains:
|
||||
rows:
|
||||
description: List of rows returned by query.
|
||||
type: list
|
||||
elements: list
|
||||
contains:
|
||||
column_value:
|
||||
description:
|
||||
- List of column values.
|
||||
- Any non-standard JSON type is converted to string.
|
||||
type: list
|
||||
example: ["Batch 0 - Select 0"]
|
||||
returned: success, if output is default
|
||||
query_results_dict:
|
||||
description: List of batches (queries separated by C(GO) keyword).
|
||||
type: list
|
||||
elements: list
|
||||
returned: success and I(output=dict)
|
||||
sample: [[[["Batch 0 - Select 0"]], [["Batch 0 - Select 1"]]], [[["Batch 1 - Select 0"]]]]
|
||||
contains:
|
||||
queries:
|
||||
description:
|
||||
- List of result sets of each query.
|
||||
- If a query returns no results, the results of this and all the following queries will not be included in the output.
|
||||
Use 'GO' keyword to separate queries.
|
||||
type: list
|
||||
elements: list
|
||||
contains:
|
||||
rows:
|
||||
description: List of rows returned by query.
|
||||
type: list
|
||||
elements: list
|
||||
contains:
|
||||
column_dict:
|
||||
description:
|
||||
- Dictionary of column names and values.
|
||||
- Any non-standard JSON type is converted to string.
|
||||
type: dict
|
||||
example: {"col_name": "Batch 0 - Select 0"}
|
||||
returned: success, if output is dict
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
import traceback
|
||||
import json
|
||||
PYMSSQL_IMP_ERR = None
|
||||
try:
|
||||
import pymssql
|
||||
except ImportError:
|
||||
PYMSSQL_IMP_ERR = traceback.format_exc()
|
||||
MSSQL_FOUND = False
|
||||
else:
|
||||
MSSQL_FOUND = True
|
||||
|
||||
|
||||
def clean_output(o):
|
||||
return str(o)
|
||||
|
||||
|
||||
def run_module():
|
||||
module_args = dict(
|
||||
name=dict(required=False, aliases=['db'], default=''),
|
||||
login_user=dict(),
|
||||
login_password=dict(no_log=True),
|
||||
login_host=dict(required=True),
|
||||
login_port=dict(type='int', default=1433),
|
||||
script=dict(required=True),
|
||||
output=dict(default='default', choices=['dict', 'default']),
|
||||
params=dict(type='dict'),
|
||||
)
|
||||
|
||||
result = dict(
|
||||
changed=False,
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
if not MSSQL_FOUND:
|
||||
module.fail_json(msg=missing_required_lib(
|
||||
'pymssql'), exception=PYMSSQL_IMP_ERR)
|
||||
|
||||
db = module.params['name']
|
||||
login_user = module.params['login_user']
|
||||
login_password = module.params['login_password']
|
||||
login_host = module.params['login_host']
|
||||
login_port = module.params['login_port']
|
||||
script = module.params['script']
|
||||
output = module.params['output']
|
||||
sql_params = module.params['params']
|
||||
|
||||
login_querystring = login_host
|
||||
if login_port != 1433:
|
||||
login_querystring = "%s:%s" % (login_host, login_port)
|
||||
|
||||
if login_user is not None and login_password is None:
|
||||
module.fail_json(
|
||||
msg="when supplying login_user argument, login_password must also be provided")
|
||||
|
||||
try:
|
||||
conn = pymssql.connect(
|
||||
user=login_user, password=login_password, host=login_querystring, database=db)
|
||||
cursor = conn.cursor()
|
||||
except Exception as e:
|
||||
if "Unknown database" in str(e):
|
||||
errno, errstr = e.args
|
||||
module.fail_json(msg="ERROR: %s %s" % (errno, errstr))
|
||||
else:
|
||||
module.fail_json(msg="unable to connect, check login_user and login_password are correct, or alternatively check your "
|
||||
"@sysconfdir@/freetds.conf / ${HOME}/.freetds.conf")
|
||||
|
||||
conn.autocommit(True)
|
||||
|
||||
query_results_key = 'query_results'
|
||||
if output == 'dict':
|
||||
cursor = conn.cursor(as_dict=True)
|
||||
query_results_key = 'query_results_dict'
|
||||
|
||||
queries = script.split('\nGO\n')
|
||||
result['changed'] = True
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
query_results = []
|
||||
try:
|
||||
for query in queries:
|
||||
cursor.execute(query, sql_params)
|
||||
qry_result = []
|
||||
rows = cursor.fetchall()
|
||||
while rows:
|
||||
qry_result.append(rows)
|
||||
rows = cursor.fetchall()
|
||||
query_results.append(qry_result)
|
||||
except Exception as e:
|
||||
return module.fail_json(msg="query failed", query=query, error=str(e), **result)
|
||||
|
||||
# ensure that the result is json serializable
|
||||
qry_results = json.loads(json.dumps(query_results, default=clean_output))
|
||||
|
||||
result[query_results_key] = qry_results
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
1
plugins/modules/dnf_versionlock.py
Symbolic link
1
plugins/modules/dnf_versionlock.py
Symbolic link
@@ -0,0 +1 @@
|
||||
./packaging/os/dnf_versionlock.py
|
||||
@@ -182,6 +182,7 @@ import zipfile
|
||||
from fnmatch import fnmatch
|
||||
from sys import version_info
|
||||
from traceback import format_exc
|
||||
from zlib import crc32
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
||||
@@ -234,10 +235,6 @@ def expand_paths(paths):
|
||||
return expanded_path, is_globby
|
||||
|
||||
|
||||
def legacy_filter(path, exclusion_patterns):
|
||||
return matches_exclusion_patterns(path, exclusion_patterns)
|
||||
|
||||
|
||||
def matches_exclusion_patterns(path, exclusion_patterns):
|
||||
return any(fnmatch(path, p) for p in exclusion_patterns)
|
||||
|
||||
@@ -313,6 +310,7 @@ class Archive(object):
|
||||
if self.remove:
|
||||
self._check_removal_safety()
|
||||
|
||||
self.original_checksums = self.destination_checksums()
|
||||
self.original_size = self.destination_size()
|
||||
|
||||
def add(self, path, archive_name):
|
||||
@@ -377,8 +375,16 @@ class Archive(object):
|
||||
msg='Errors when writing archive at %s: %s' % (_to_native(self.destination), '; '.join(self.errors))
|
||||
)
|
||||
|
||||
def compare_with_original(self):
|
||||
self.changed |= self.original_size != self.destination_size()
|
||||
def is_different_from_original(self):
|
||||
if self.original_checksums is None:
|
||||
return self.original_size != self.destination_size()
|
||||
else:
|
||||
return self.original_checksums != self.destination_checksums()
|
||||
|
||||
def destination_checksums(self):
|
||||
if self.destination_exists() and self.destination_readable():
|
||||
return self._get_checksums(self.destination)
|
||||
return None
|
||||
|
||||
def destination_exists(self):
|
||||
return self.destination and os.path.exists(self.destination)
|
||||
@@ -494,6 +500,10 @@ class Archive(object):
|
||||
def _add(self, path, archive_name):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def _get_checksums(self, path):
|
||||
pass
|
||||
|
||||
|
||||
class ZipArchive(Archive):
|
||||
def __init__(self, module):
|
||||
@@ -513,9 +523,18 @@ class ZipArchive(Archive):
|
||||
self.file = zipfile.ZipFile(_to_native_ascii(self.destination), 'w', zipfile.ZIP_DEFLATED, True)
|
||||
|
||||
def _add(self, path, archive_name):
|
||||
if not legacy_filter(path, self.exclusion_patterns):
|
||||
if not matches_exclusion_patterns(path, self.exclusion_patterns):
|
||||
self.file.write(path, archive_name)
|
||||
|
||||
def _get_checksums(self, path):
|
||||
try:
|
||||
archive = zipfile.ZipFile(_to_native_ascii(path), 'r')
|
||||
checksums = set((info.filename, info.CRC) for info in archive.infolist())
|
||||
archive.close()
|
||||
except zipfile.BadZipfile:
|
||||
checksums = set()
|
||||
return checksums
|
||||
|
||||
|
||||
class TarArchive(Archive):
|
||||
def __init__(self, module):
|
||||
@@ -554,13 +573,35 @@ class TarArchive(Archive):
|
||||
return None if matches_exclusion_patterns(tarinfo.name, self.exclusion_patterns) else tarinfo
|
||||
|
||||
def py26_filter(path):
|
||||
return legacy_filter(path, self.exclusion_patterns)
|
||||
return matches_exclusion_patterns(path, self.exclusion_patterns)
|
||||
|
||||
if PY27:
|
||||
self.file.add(path, archive_name, recursive=False, filter=py27_filter)
|
||||
else:
|
||||
self.file.add(path, archive_name, recursive=False, exclude=py26_filter)
|
||||
|
||||
def _get_checksums(self, path):
|
||||
try:
|
||||
if self.format == 'xz':
|
||||
with lzma.open(_to_native_ascii(path), 'r') as f:
|
||||
archive = tarfile.open(fileobj=f)
|
||||
checksums = set((info.name, info.chksum) for info in archive.getmembers())
|
||||
archive.close()
|
||||
else:
|
||||
archive = tarfile.open(_to_native_ascii(path), 'r|' + self.format)
|
||||
checksums = set((info.name, info.chksum) for info in archive.getmembers())
|
||||
archive.close()
|
||||
except (lzma.LZMAError, tarfile.ReadError, tarfile.CompressionError):
|
||||
try:
|
||||
# The python implementations of gzip, bz2, and lzma do not support restoring compressed files
|
||||
# to their original names so only file checksum is returned
|
||||
f = self._open_compressed_file(_to_native_ascii(path), 'r')
|
||||
checksums = set([(b'', crc32(f.read()))])
|
||||
f.close()
|
||||
except Exception:
|
||||
checksums = set()
|
||||
return checksums
|
||||
|
||||
|
||||
def get_archive(module):
|
||||
if module.params['format'] == 'zip':
|
||||
@@ -603,7 +644,7 @@ def main():
|
||||
else:
|
||||
archive.add_targets()
|
||||
archive.destination_state = STATE_INCOMPLETE if archive.has_unfound_targets() else STATE_ARCHIVED
|
||||
archive.compare_with_original()
|
||||
archive.changed |= archive.is_different_from_original()
|
||||
if archive.remove:
|
||||
archive.remove_targets()
|
||||
else:
|
||||
@@ -613,7 +654,7 @@ def main():
|
||||
else:
|
||||
path = archive.paths[0]
|
||||
archive.add_single_target(path)
|
||||
archive.compare_with_original()
|
||||
archive.changed |= archive.is_different_from_original()
|
||||
if archive.remove:
|
||||
archive.remove_single_target(path)
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ def _run_xattr(module, cmd, check_rc=True):
|
||||
if line.startswith('#') or line == '':
|
||||
pass
|
||||
elif '=' in line:
|
||||
(key, val) = line.split('=')
|
||||
(key, val) = line.split('=', 1)
|
||||
result[key] = val.strip('"')
|
||||
else:
|
||||
result[line] = ''
|
||||
|
||||
@@ -14,6 +14,13 @@ short_description: Manage FreeIPA group
|
||||
description:
|
||||
- Add, modify and delete group within IPA server
|
||||
options:
|
||||
append:
|
||||
description:
|
||||
- If C(yes), add the listed I(user) and I(group) to the group members.
|
||||
- If C(no), only the listed I(user) and I(group) will be group members, removing any other members.
|
||||
default: no
|
||||
type: bool
|
||||
version_added: 4.0.0
|
||||
cn:
|
||||
description:
|
||||
- Canonical name.
|
||||
@@ -37,9 +44,10 @@ options:
|
||||
group:
|
||||
description:
|
||||
- List of group names assigned to this group.
|
||||
- If an empty list is passed all groups will be removed from this group.
|
||||
- If option is omitted assigned groups will not be checked or changed.
|
||||
- If I(append=no) and an empty list is passed all groups will be removed from this group.
|
||||
- Groups that are already assigned but not passed will be removed.
|
||||
- If I(append=yes) the listed groups will be assigned without removing other groups.
|
||||
- If option is omitted assigned groups will not be checked or changed.
|
||||
type: list
|
||||
elements: str
|
||||
nonposix:
|
||||
@@ -49,9 +57,10 @@ options:
|
||||
user:
|
||||
description:
|
||||
- List of user names assigned to this group.
|
||||
- If an empty list is passed all users will be removed from this group.
|
||||
- If option is omitted assigned users will not be checked or changed.
|
||||
- If I(append=no) and an empty list is passed all users will be removed from this group.
|
||||
- Users that are already assigned but not passed will be removed.
|
||||
- If I(append=yes) the listed users will be assigned without removing other users.
|
||||
- If option is omitted assigned users will not be checked or changed.
|
||||
type: list
|
||||
elements: str
|
||||
state:
|
||||
@@ -95,6 +104,17 @@ EXAMPLES = r'''
|
||||
ipa_user: admin
|
||||
ipa_pass: topsecret
|
||||
|
||||
- name: Ensure that new starter named john is member of the group, without removing other members
|
||||
community.general.ipa_group:
|
||||
name: developers
|
||||
user:
|
||||
- john
|
||||
append: yes
|
||||
state: present
|
||||
ipa_host: ipa.example.com
|
||||
ipa_user: admin
|
||||
ipa_pass: topsecret
|
||||
|
||||
- name: Ensure group is absent
|
||||
community.general.ipa_group:
|
||||
name: sysops
|
||||
@@ -187,6 +207,7 @@ def ensure(module, client):
|
||||
name = module.params['cn']
|
||||
group = module.params['group']
|
||||
user = module.params['user']
|
||||
append = module.params['append']
|
||||
|
||||
module_group = get_group_dict(description=module.params['description'], external=module.params['external'],
|
||||
gid=module.params['gidnumber'], nonposix=module.params['nonposix'])
|
||||
@@ -211,12 +232,14 @@ def ensure(module, client):
|
||||
if group is not None:
|
||||
changed = client.modify_if_diff(name, ipa_group.get('member_group', []), group,
|
||||
client.group_add_member_group,
|
||||
client.group_remove_member_group) or changed
|
||||
client.group_remove_member_group,
|
||||
append=append) or changed
|
||||
|
||||
if user is not None:
|
||||
changed = client.modify_if_diff(name, ipa_group.get('member_user', []), user,
|
||||
client.group_add_member_user,
|
||||
client.group_remove_member_user) or changed
|
||||
client.group_remove_member_user,
|
||||
append=append) or changed
|
||||
|
||||
else:
|
||||
if ipa_group:
|
||||
@@ -236,7 +259,8 @@ def main():
|
||||
group=dict(type='list', elements='str'),
|
||||
nonposix=dict(type='bool'),
|
||||
state=dict(type='str', default='present', choices=['present', 'absent']),
|
||||
user=dict(type='list', elements='str'))
|
||||
user=dict(type='list', elements='str'),
|
||||
append=dict(type='bool', default=False))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
|
||||
@@ -9,11 +9,15 @@ __metaclass__ = type
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: keycloak_authentication
|
||||
|
||||
short_description: Configure authentication in Keycloak
|
||||
|
||||
description:
|
||||
- This module actually can only make a copy of an existing authentication flow, add an execution to it and configure it.
|
||||
- It can also delete the flow.
|
||||
|
||||
version_added: "3.3.0"
|
||||
|
||||
options:
|
||||
realm:
|
||||
description:
|
||||
@@ -79,6 +83,7 @@ options:
|
||||
default: false
|
||||
description:
|
||||
- If C(true), allows to remove the authentication flow and recreate it.
|
||||
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
@@ -162,10 +167,74 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
|
||||
flow:
|
||||
description: JSON representation for the authentication.
|
||||
returned: on success
|
||||
type: dict
|
||||
description:
|
||||
- JSON representation for the authentication.
|
||||
- Deprecated return value, it will be removed in community.general 6.0.0. Please use the return value I(end_state) instead.
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"alias": "Copy of first broker login",
|
||||
"authenticationExecutions": [
|
||||
{
|
||||
"alias": "review profile config",
|
||||
"authenticationConfig": {
|
||||
"alias": "review profile config",
|
||||
"config": { "update.profile.on.first.login": "missing" },
|
||||
"id": "6f09e4fb-aad4-496a-b873-7fa9779df6d7"
|
||||
},
|
||||
"configurable": true,
|
||||
"displayName": "Review Profile",
|
||||
"id": "8f77dab8-2008-416f-989e-88b09ccf0b4c",
|
||||
"index": 0,
|
||||
"level": 0,
|
||||
"providerId": "idp-review-profile",
|
||||
"requirement": "REQUIRED",
|
||||
"requirementChoices": [ "REQUIRED", "ALTERNATIVE", "DISABLED" ]
|
||||
}
|
||||
],
|
||||
"builtIn": false,
|
||||
"description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
|
||||
"id": "bc228863-5887-4297-b898-4d988f8eaa5c",
|
||||
"providerId": "basic-flow",
|
||||
"topLevel": true
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: Representation of the authentication after module execution.
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"alias": "Copy of first broker login",
|
||||
"authenticationExecutions": [
|
||||
{
|
||||
"alias": "review profile config",
|
||||
"authenticationConfig": {
|
||||
"alias": "review profile config",
|
||||
"config": { "update.profile.on.first.login": "missing" },
|
||||
"id": "6f09e4fb-aad4-496a-b873-7fa9779df6d7"
|
||||
},
|
||||
"configurable": true,
|
||||
"displayName": "Review Profile",
|
||||
"id": "8f77dab8-2008-416f-989e-88b09ccf0b4c",
|
||||
"index": 0,
|
||||
"level": 0,
|
||||
"providerId": "idp-review-profile",
|
||||
"requirement": "REQUIRED",
|
||||
"requirementChoices": [ "REQUIRED", "ALTERNATIVE", "DISABLED" ]
|
||||
}
|
||||
],
|
||||
"builtIn": false,
|
||||
"description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
|
||||
"id": "bc228863-5887-4297-b898-4d988f8eaa5c",
|
||||
"providerId": "basic-flow",
|
||||
"topLevel": true
|
||||
}
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak \
|
||||
@@ -271,9 +340,11 @@ def create_or_update_executions(kc, config, realm='master'):
|
||||
def main():
|
||||
"""
|
||||
Module execution
|
||||
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
meta_args = dict(
|
||||
realm=dict(type='str', required=True),
|
||||
alias=dict(type='str', required=True),
|
||||
@@ -292,6 +363,7 @@ def main():
|
||||
state=dict(choices=["absent", "present"], default='present'),
|
||||
force=dict(type='bool', default=False),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
@@ -301,6 +373,7 @@ def main():
|
||||
)
|
||||
|
||||
result = dict(changed=False, msg='', flow={})
|
||||
|
||||
# Obtain access token, initialize API
|
||||
try:
|
||||
connection_header = get_token(module.params)
|
||||
@@ -308,6 +381,7 @@ def main():
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
realm = module.params.get('realm')
|
||||
state = module.params.get('state')
|
||||
force = module.params.get('force')
|
||||
@@ -323,35 +397,54 @@ def main():
|
||||
}
|
||||
|
||||
auth_repr = kc.get_authentication_flow_by_alias(alias=new_auth_repr["alias"], realm=realm)
|
||||
if auth_repr == {}: # Authentication flow does not exist
|
||||
if state == 'present': # If desired state is present
|
||||
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not auth_repr:
|
||||
if state == 'absent':
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['flow'] = result['end_state']
|
||||
result['msg'] = new_auth_repr["alias"] + ' absent'
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'present':
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=new_auth_repr)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# If copyFrom is defined, create authentication flow from a copy
|
||||
if "copyFrom" in new_auth_repr and new_auth_repr["copyFrom"] is not None:
|
||||
auth_repr = kc.copy_auth_flow(config=new_auth_repr, realm=realm)
|
||||
else: # Create an empty authentication flow
|
||||
auth_repr = kc.create_empty_auth_flow(config=new_auth_repr, realm=realm)
|
||||
|
||||
# If the authentication still not exist on the server, raise an exception.
|
||||
if auth_repr is None:
|
||||
result['msg'] = "Authentication just created not found: " + str(new_auth_repr)
|
||||
module.fail_json(**result)
|
||||
|
||||
# Configure the executions for the flow
|
||||
create_or_update_executions(kc=kc, config=new_auth_repr, realm=realm)
|
||||
|
||||
# Get executions created
|
||||
exec_repr = kc.get_executions_representation(config=new_auth_repr, realm=realm)
|
||||
if exec_repr is not None:
|
||||
auth_repr["authenticationExecutions"] = exec_repr
|
||||
result['flow'] = auth_repr
|
||||
elif state == 'absent': # If desired state is absent.
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['msg'] = new_auth_repr["alias"] + ' absent'
|
||||
else: # The authentication flow already exist
|
||||
if state == 'present': # if desired state is present
|
||||
result['end_state'] = auth_repr
|
||||
result['flow'] = result['end_state']
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
if force: # If force option is true
|
||||
# Delete the actual authentication flow
|
||||
result['changed'] = True
|
||||
@@ -370,25 +463,35 @@ def main():
|
||||
result['msg'] = "Authentication just created not found: " + str(new_auth_repr)
|
||||
module.fail_json(**result)
|
||||
# Configure the executions for the flow
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
changed, diff = create_or_update_executions(kc=kc, config=new_auth_repr, realm=realm)
|
||||
result['changed'] |= changed
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = diff
|
||||
|
||||
# Get executions created
|
||||
exec_repr = kc.get_executions_representation(config=new_auth_repr, realm=realm)
|
||||
if exec_repr is not None:
|
||||
auth_repr["authenticationExecutions"] = exec_repr
|
||||
result['flow'] = auth_repr
|
||||
elif state == 'absent': # If desired state is absent
|
||||
result['end_state'] = auth_repr
|
||||
result['flow'] = result['end_state']
|
||||
|
||||
else:
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
# Delete the authentication flow alias.
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=auth_repr, after='')
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete it
|
||||
kc.delete_authentication_flow_by_id(id=auth_repr["id"], realm=realm)
|
||||
|
||||
result['msg'] = 'Authentication flow: {alias} id: {id} is deleted'.format(alias=new_auth_repr['alias'],
|
||||
id=auth_repr["id"])
|
||||
|
||||
|
||||
@@ -62,17 +62,17 @@ options:
|
||||
|
||||
name:
|
||||
description:
|
||||
- Name of the client (this is not the same as I(client_id))
|
||||
- Name of the client (this is not the same as I(client_id)).
|
||||
type: str
|
||||
|
||||
description:
|
||||
description:
|
||||
- Description of the client in Keycloak
|
||||
- Description of the client in Keycloak.
|
||||
type: str
|
||||
|
||||
root_url:
|
||||
description:
|
||||
- Root URL appended to relative URLs for this client
|
||||
- Root URL appended to relative URLs for this client.
|
||||
This is 'rootUrl' in the Keycloak REST API.
|
||||
aliases:
|
||||
- rootUrl
|
||||
@@ -80,7 +80,7 @@ options:
|
||||
|
||||
admin_url:
|
||||
description:
|
||||
- URL to the admin interface of the client
|
||||
- URL to the admin interface of the client.
|
||||
This is 'adminUrl' in the Keycloak REST API.
|
||||
aliases:
|
||||
- adminUrl
|
||||
@@ -357,7 +357,7 @@ options:
|
||||
|
||||
protocol:
|
||||
description:
|
||||
- This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper
|
||||
- This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper.
|
||||
is active.
|
||||
choices: ['openid-connect', 'saml']
|
||||
type: str
|
||||
@@ -513,7 +513,6 @@ options:
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
|
||||
author:
|
||||
- Eike Frost (@eikef)
|
||||
'''
|
||||
@@ -645,20 +644,21 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client testclient has been updated"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client testclient has been updated"
|
||||
|
||||
proposed:
|
||||
description: client representation of proposed changes to client
|
||||
description: Representation of proposed client.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
clientId: "test"
|
||||
}
|
||||
|
||||
existing:
|
||||
description: client representation of existing client (sample is truncated)
|
||||
description: Representation of existing client (sample is truncated).
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -667,9 +667,10 @@ existing:
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: client representation of client after module execution (sample is truncated)
|
||||
returned: always
|
||||
description: Representation of client after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
@@ -684,8 +685,38 @@ from ansible_collections.community.general.plugins.module_utils.identity.keycloa
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def normalise_cr(clientrep, remove_ids=False):
|
||||
""" Re-sorts any properties where the order so that diff's is minimised, and adds default values where appropriate so that the
|
||||
the change detection is more effective.
|
||||
|
||||
:param clientrep: the clientrep dict to be sanitized
|
||||
:param remove_ids: If set to true, then the unique ID's of objects is removed to make the diff and checks for changed
|
||||
not alert when the ID's of objects are not usually known, (e.g. for protocol_mappers)
|
||||
:return: normalised clientrep dict
|
||||
"""
|
||||
# Avoid the dict passed in to be modified
|
||||
clientrep = clientrep.copy()
|
||||
|
||||
if 'attributes' in clientrep:
|
||||
clientrep['attributes'] = list(sorted(clientrep['attributes']))
|
||||
|
||||
if 'redirectUris' in clientrep:
|
||||
clientrep['redirectUris'] = list(sorted(clientrep['redirectUris']))
|
||||
|
||||
if 'protocolMappers' in clientrep:
|
||||
clientrep['protocolMappers'] = sorted(clientrep['protocolMappers'], key=lambda x: (x.get('name'), x.get('protocol'), x.get('protocolMapper')))
|
||||
for mapper in clientrep['protocolMappers']:
|
||||
if remove_ids:
|
||||
mapper.pop('id', None)
|
||||
|
||||
# Set to a default value.
|
||||
mapper['consentRequired'] = mapper.get('consentRequired', False)
|
||||
|
||||
return clientrep
|
||||
|
||||
|
||||
def sanitize_cr(clientrep):
|
||||
""" Removes probably sensitive details from a client representation
|
||||
""" Removes probably sensitive details from a client representation.
|
||||
|
||||
:param clientrep: the clientrep dict to be sanitized
|
||||
:return: sanitized clientrep dict
|
||||
@@ -696,7 +727,7 @@ def sanitize_cr(clientrep):
|
||||
if 'attributes' in result:
|
||||
if 'saml.signing.private.key' in result['attributes']:
|
||||
result['attributes']['saml.signing.private.key'] = 'no_log'
|
||||
return result
|
||||
return normalise_cr(result)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -759,6 +790,7 @@ def main():
|
||||
protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec, aliases=['protocolMappers']),
|
||||
authorization_settings=dict(type='dict', aliases=['authorizationSettings']),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
@@ -781,12 +813,12 @@ def main():
|
||||
cid = module.params.get('id')
|
||||
state = module.params.get('state')
|
||||
|
||||
# convert module parameters to client representation parameters (if they belong in there)
|
||||
# Filter and map the parameters names that apply to the client
|
||||
client_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and
|
||||
module.params.get(x) is not None]
|
||||
keycloak_argument_spec().keys()
|
||||
# See whether the client already exists in Keycloak
|
||||
|
||||
# See if it already exists in Keycloak
|
||||
if cid is None:
|
||||
before_client = kc.get_client_by_clientid(module.params.get('client_id'), realm=realm)
|
||||
if before_client is not None:
|
||||
@@ -795,10 +827,10 @@ def main():
|
||||
before_client = kc.get_client_by_id(cid, realm=realm)
|
||||
|
||||
if before_client is None:
|
||||
before_client = dict()
|
||||
before_client = {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
changeset = {}
|
||||
|
||||
for client_param in client_params:
|
||||
new_param_value = module.params.get(client_param)
|
||||
@@ -817,54 +849,63 @@ def main():
|
||||
|
||||
changeset[camel(client_param)] = new_param_value
|
||||
|
||||
# Whether creating or updating a client, take the before-state and merge the changeset into it
|
||||
updated_client = before_client.copy()
|
||||
updated_client.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_client = before_client.copy()
|
||||
desired_client.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize_cr(changeset)
|
||||
result['existing'] = sanitize_cr(before_client)
|
||||
|
||||
# If the client does not exist yet, before_client is still empty
|
||||
if before_client == dict():
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_client:
|
||||
if state == 'absent':
|
||||
# do nothing and exit
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['msg'] = 'Client does not exist, doing nothing.'
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Client does not exist; doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# create new client
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
if 'clientId' not in updated_client:
|
||||
|
||||
if 'clientId' not in desired_client:
|
||||
module.fail_json(msg='client_id needs to be specified when creating a new client')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize_cr(updated_client))
|
||||
result['diff'] = dict(before='', after=sanitize_cr(desired_client))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.create_client(updated_client, realm=realm)
|
||||
after_client = kc.get_client_by_clientid(updated_client['clientId'], realm=realm)
|
||||
# create it
|
||||
kc.create_client(desired_client, realm=realm)
|
||||
after_client = kc.get_client_by_clientid(desired_client['clientId'], realm=realm)
|
||||
|
||||
result['end_state'] = sanitize_cr(after_client)
|
||||
|
||||
result['msg'] = 'Client %s has been created.' % updated_client['clientId']
|
||||
result['msg'] = 'Client %s has been created.' % desired_client['clientId']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# update existing client
|
||||
# Process an update
|
||||
result['changed'] = True
|
||||
|
||||
if module.check_mode:
|
||||
# We can only compare the current client with the proposed updates we have
|
||||
before_norm = normalise_cr(before_client, remove_ids=True)
|
||||
desired_norm = normalise_cr(desired_client, remove_ids=True)
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_client),
|
||||
after=sanitize_cr(updated_client))
|
||||
result['changed'] = (before_client != updated_client)
|
||||
result['diff'] = dict(before=sanitize_cr(before_norm),
|
||||
after=sanitize_cr(desired_norm))
|
||||
result['changed'] = (before_norm != desired_norm)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.update_client(cid, updated_client, realm=realm)
|
||||
# do the update
|
||||
kc.update_client(cid, desired_client, realm=realm)
|
||||
|
||||
after_client = kc.get_client_by_id(cid, realm=realm)
|
||||
if before_client == after_client:
|
||||
@@ -872,25 +913,29 @@ def main():
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_client),
|
||||
after=sanitize_cr(after_client))
|
||||
|
||||
result['end_state'] = sanitize_cr(after_client)
|
||||
|
||||
result['msg'] = 'Client %s has been updated.' % updated_client['clientId']
|
||||
result['msg'] = 'Client %s has been updated.' % desired_client['clientId']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
# Delete existing client
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff']['before'] = sanitize_cr(before_client)
|
||||
result['diff']['after'] = ''
|
||||
result['diff'] = dict(before=sanitize_cr(before_client), after='')
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete it
|
||||
kc.delete_client(cid, realm=realm)
|
||||
result['proposed'] = dict()
|
||||
result['end_state'] = dict()
|
||||
result['proposed'] = {}
|
||||
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = 'Client %s has been deleted.' % before_client['clientId']
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ DOCUMENTATION = '''
|
||||
module: keycloak_client_rolemapping
|
||||
|
||||
short_description: Allows administration of Keycloak client_rolemapping with the Keycloak API
|
||||
|
||||
version_added: 3.5.0
|
||||
|
||||
description:
|
||||
@@ -158,21 +159,22 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Role role1 assigned to group group1."
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Role role1 assigned to group group1."
|
||||
|
||||
proposed:
|
||||
description: role_representation representation of proposed changes to client_rolemapping.
|
||||
description: Representation of proposed client role mapping.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
clientId: "test"
|
||||
}
|
||||
|
||||
existing:
|
||||
description:
|
||||
- role_representation representation of existing role_representation.
|
||||
- Representation of existing client role mapping.
|
||||
- The sample is truncated.
|
||||
returned: always
|
||||
type: dict
|
||||
@@ -182,11 +184,12 @@ existing:
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
|
||||
end_state:
|
||||
description:
|
||||
- role_representation representation of role_representation after module execution.
|
||||
- Representation of client role mapping after module execution.
|
||||
- The sample is truncated.
|
||||
returned: always
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
|
||||
@@ -86,7 +86,7 @@ options:
|
||||
suboptions:
|
||||
protocol:
|
||||
description:
|
||||
- This specifies for which protocol this protocol mapper
|
||||
- This specifies for which protocol this protocol mapper.
|
||||
- is active.
|
||||
choices: ['openid-connect', 'saml', 'wsfed']
|
||||
type: str
|
||||
@@ -256,20 +256,21 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client_scope testclientscope has been updated"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client_scope testclientscope has been updated"
|
||||
|
||||
proposed:
|
||||
description: client_scope representation of proposed changes to client_scope
|
||||
description: Representation of proposed client scope.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
clientId: "test"
|
||||
}
|
||||
|
||||
existing:
|
||||
description: client_scope representation of existing client_scope (sample is truncated)
|
||||
description: Representation of existing client scope (sample is truncated).
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -278,9 +279,10 @@ existing:
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: client_scope representation of client_scope after module execution (sample is truncated)
|
||||
returned: always
|
||||
description: Representation of client scope after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
@@ -296,7 +298,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def sanitize_cr(clientscoperep):
|
||||
""" Removes probably sensitive details from a clientscoperep representation
|
||||
""" Removes probably sensitive details from a clientscoperep representation.
|
||||
|
||||
:param clientscoperep: the clientscoperep dict to be sanitized
|
||||
:return: sanitized clientrep dict
|
||||
@@ -361,22 +363,22 @@ def main():
|
||||
name = module.params.get('name')
|
||||
protocol_mappers = module.params.get('protocol_mappers')
|
||||
|
||||
before_clientscope = None # current state of the clientscope, for merging.
|
||||
# Filter and map the parameters names that apply to the client scope
|
||||
clientscope_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# does the clientscope already exist?
|
||||
# See if it already exists in Keycloak
|
||||
if cid is None:
|
||||
before_clientscope = kc.get_clientscope_by_name(name, realm=realm)
|
||||
else:
|
||||
before_clientscope = kc.get_clientscope_by_clientscopeid(cid, realm=realm)
|
||||
|
||||
before_clientscope = {} if before_clientscope is None else before_clientscope
|
||||
|
||||
clientscope_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and
|
||||
module.params.get(x) is not None]
|
||||
if before_clientscope is None:
|
||||
before_clientscope = {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
changeset = {}
|
||||
|
||||
for clientscope_param in clientscope_params:
|
||||
new_param_value = module.params.get(clientscope_param)
|
||||
@@ -394,81 +396,87 @@ def main():
|
||||
new_param_value = [dict((k, v) for k, v in x.items() if x[k] is not None) for x in new_param_value]
|
||||
changeset[camel(clientscope_param)] = new_param_value
|
||||
|
||||
# prepare the new clientscope
|
||||
updated_clientscope = before_clientscope.copy()
|
||||
updated_clientscope.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_clientscope = before_clientscope.copy()
|
||||
desired_clientscope.update(changeset)
|
||||
|
||||
# if before_clientscope is none, the clientscope doesn't exist.
|
||||
if before_clientscope == {}:
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_clientscope:
|
||||
if state == 'absent':
|
||||
# nothing to do.
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Clientscope does not exist; doing nothing.'
|
||||
result['end_state'] = dict()
|
||||
module.exit_json(**result)
|
||||
|
||||
# for 'present', create a new clientscope.
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if name is None:
|
||||
module.fail_json(msg='name must be specified when creating a new clientscope')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize_cr(updated_clientscope))
|
||||
result['diff'] = dict(before='', after=sanitize_cr(desired_clientscope))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do it for real!
|
||||
kc.create_clientscope(updated_clientscope, realm=realm)
|
||||
# create it
|
||||
kc.create_clientscope(desired_clientscope, realm=realm)
|
||||
after_clientscope = kc.get_clientscope_by_name(name, realm)
|
||||
|
||||
result['end_state'] = sanitize_cr(after_clientscope)
|
||||
|
||||
result['msg'] = 'Clientscope {name} has been created with ID {id}'.format(name=after_clientscope['name'],
|
||||
id=after_clientscope['id'])
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
# no changes
|
||||
if updated_clientscope == before_clientscope:
|
||||
if desired_clientscope == before_clientscope:
|
||||
result['changed'] = False
|
||||
result['end_state'] = sanitize_cr(updated_clientscope)
|
||||
result['end_state'] = sanitize_cr(desired_clientscope)
|
||||
result['msg'] = "No changes required to clientscope {name}.".format(name=before_clientscope['name'])
|
||||
module.exit_json(**result)
|
||||
|
||||
# update the existing clientscope
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_clientscope), after=sanitize_cr(updated_clientscope))
|
||||
result['diff'] = dict(before=sanitize_cr(before_clientscope), after=sanitize_cr(desired_clientscope))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the clientscope update
|
||||
kc.update_clientscope(updated_clientscope, realm=realm)
|
||||
# do the update
|
||||
kc.update_clientscope(desired_clientscope, realm=realm)
|
||||
|
||||
# do the protocolmappers update
|
||||
if protocol_mappers is not None:
|
||||
for protocol_mapper in protocol_mappers:
|
||||
# update if protocolmapper exist
|
||||
current_protocolmapper = kc.get_clientscope_protocolmapper_by_name(updated_clientscope['id'], protocol_mapper['name'], realm=realm)
|
||||
current_protocolmapper = kc.get_clientscope_protocolmapper_by_name(desired_clientscope['id'], protocol_mapper['name'], realm=realm)
|
||||
if current_protocolmapper is not None:
|
||||
protocol_mapper['id'] = current_protocolmapper['id']
|
||||
kc.update_clientscope_protocolmappers(updated_clientscope['id'], protocol_mapper, realm=realm)
|
||||
kc.update_clientscope_protocolmappers(desired_clientscope['id'], protocol_mapper, realm=realm)
|
||||
# create otherwise
|
||||
else:
|
||||
kc.create_clientscope_protocolmapper(updated_clientscope['id'], protocol_mapper, realm=realm)
|
||||
kc.create_clientscope_protocolmapper(desired_clientscope['id'], protocol_mapper, realm=realm)
|
||||
|
||||
after_clientscope = kc.get_clientscope_by_clientscopeid(updated_clientscope['id'], realm=realm)
|
||||
after_clientscope = kc.get_clientscope_by_clientscopeid(desired_clientscope['id'], realm=realm)
|
||||
|
||||
result['end_state'] = after_clientscope
|
||||
result['msg'] = "Clientscope {id} has been updated".format(id=after_clientscope['id'])
|
||||
|
||||
result['msg'] = "Clientscope {id} has been updated".format(id=after_clientscope['id'])
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'absent':
|
||||
result['end_state'] = dict()
|
||||
else:
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize_cr(before_clientscope), after='')
|
||||
@@ -476,14 +484,13 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete for real
|
||||
# delete it
|
||||
cid = before_clientscope['id']
|
||||
kc.delete_clientscope(cid=cid, realm=realm)
|
||||
|
||||
result['changed'] = True
|
||||
result['msg'] = "Clientscope {name} has been deleted".format(name=before_clientscope['name'])
|
||||
result['end_state'] = {}
|
||||
|
||||
module.exit_json(**result)
|
||||
result['msg'] = "Clientscope {name} has been deleted".format(name=before_clientscope['name'])
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ description:
|
||||
options:
|
||||
state:
|
||||
description:
|
||||
- State of the client template
|
||||
- State of the client template.
|
||||
- On C(present), the client template will be created (or updated if it exists already).
|
||||
- On C(absent), the client template will be removed if it exists
|
||||
choices: ['present', 'absent']
|
||||
@@ -51,12 +51,12 @@ options:
|
||||
|
||||
name:
|
||||
description:
|
||||
- Name of the client template
|
||||
- Name of the client template.
|
||||
type: str
|
||||
|
||||
description:
|
||||
description:
|
||||
- Description of the client template in Keycloak
|
||||
- Description of the client template in Keycloak.
|
||||
type: str
|
||||
|
||||
protocol:
|
||||
@@ -100,7 +100,7 @@ options:
|
||||
|
||||
protocol:
|
||||
description:
|
||||
- is either 'openid-connect' or 'saml', this specifies for which protocol this protocol mapper
|
||||
- This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper.
|
||||
is active.
|
||||
choices: ['openid-connect', 'saml']
|
||||
type: str
|
||||
@@ -143,7 +143,7 @@ options:
|
||||
contents differ depending on the value of I(protocolMapper) and are not documented
|
||||
other than by the source of the mappers and its parent class(es). An example is given
|
||||
below. It is easiest to obtain valid config values by dumping an already-existing
|
||||
protocol mapper configuration through check-mode in the "existing" field.
|
||||
protocol mapper configuration through check-mode in the I(existing) field.
|
||||
type: dict
|
||||
|
||||
attributes:
|
||||
@@ -163,7 +163,6 @@ notes:
|
||||
extends_documentation_fragment:
|
||||
- community.general.keycloak
|
||||
|
||||
|
||||
author:
|
||||
- Eike Frost (@eikef)
|
||||
'''
|
||||
@@ -231,20 +230,21 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client template testclient has been updated"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Client template testclient has been updated"
|
||||
|
||||
proposed:
|
||||
description: client template representation of proposed changes to client template
|
||||
description: Representation of proposed client template.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
name: "test01"
|
||||
}
|
||||
|
||||
existing:
|
||||
description: client template representation of existing client template (sample is truncated)
|
||||
description: Representation of existing client template (sample is truncated).
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -254,9 +254,10 @@ existing:
|
||||
"name": "test01",
|
||||
"protocol": "saml"
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: client template representation of client template after module execution (sample is truncated)
|
||||
returned: always
|
||||
description: Representation of client template after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"description": "test01",
|
||||
@@ -302,6 +303,7 @@ def main():
|
||||
full_scope_allowed=dict(type='bool'),
|
||||
protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
@@ -317,19 +319,20 @@ def main():
|
||||
connection_header = get_token(module.params)
|
||||
except KeycloakError as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
kc = KeycloakAPI(module, connection_header)
|
||||
|
||||
realm = module.params.get('realm')
|
||||
state = module.params.get('state')
|
||||
cid = module.params.get('id')
|
||||
|
||||
# convert module parameters to client representation parameters (if they belong in there)
|
||||
# Filter and map the parameters names that apply to the client template
|
||||
clientt_params = [x for x in module.params
|
||||
if x not in ['state', 'auth_keycloak_url', 'auth_client_id', 'auth_realm',
|
||||
'auth_client_secret', 'auth_username', 'auth_password',
|
||||
'validate_certs', 'realm'] and module.params.get(x) is not None]
|
||||
|
||||
# See whether the client template already exists in Keycloak
|
||||
# See if it already exists in Keycloak
|
||||
if cid is None:
|
||||
before_clientt = kc.get_client_template_by_name(module.params.get('name'), realm=realm)
|
||||
if before_clientt is not None:
|
||||
@@ -338,12 +341,12 @@ def main():
|
||||
before_clientt = kc.get_client_template_by_id(cid, realm=realm)
|
||||
|
||||
if before_clientt is None:
|
||||
before_clientt = dict()
|
||||
before_clientt = {}
|
||||
|
||||
result['existing'] = before_clientt
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
changeset = {}
|
||||
|
||||
for clientt_param in clientt_params:
|
||||
# lists in the Keycloak API are sorted
|
||||
@@ -355,78 +358,89 @@ def main():
|
||||
pass
|
||||
changeset[camel(clientt_param)] = new_param_value
|
||||
|
||||
# Whether creating or updating a client, take the before-state and merge the changeset into it
|
||||
updated_clientt = before_clientt.copy()
|
||||
updated_clientt.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_clientt = before_clientt.copy()
|
||||
desired_clientt.update(changeset)
|
||||
|
||||
result['proposed'] = changeset
|
||||
|
||||
# If the client template does not exist yet, before_client is still empty
|
||||
if before_clientt == dict():
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_clientt:
|
||||
if state == 'absent':
|
||||
# do nothing and exit
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Client template does not exist, doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# create new client template
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
if 'name' not in updated_clientt:
|
||||
|
||||
if 'name' not in desired_clientt:
|
||||
module.fail_json(msg='name needs to be specified when creating a new client')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=updated_clientt)
|
||||
result['diff'] = dict(before='', after=desired_clientt)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.create_client_template(updated_clientt, realm=realm)
|
||||
after_clientt = kc.get_client_template_by_name(updated_clientt['name'], realm=realm)
|
||||
# create it
|
||||
kc.create_client_template(desired_clientt, realm=realm)
|
||||
after_clientt = kc.get_client_template_by_name(desired_clientt['name'], realm=realm)
|
||||
|
||||
result['end_state'] = after_clientt
|
||||
|
||||
result['msg'] = 'Client template %s has been created.' % updated_clientt['name']
|
||||
result['msg'] = 'Client template %s has been created.' % desired_clientt['name']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# update existing client template
|
||||
# Process an update
|
||||
|
||||
result['changed'] = True
|
||||
if module.check_mode:
|
||||
# We can only compare the current client template with the proposed updates we have
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_clientt,
|
||||
after=updated_clientt)
|
||||
after=desired_clientt)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.update_client_template(cid, updated_clientt, realm=realm)
|
||||
# do the update
|
||||
kc.update_client_template(cid, desired_clientt, realm=realm)
|
||||
|
||||
after_clientt = kc.get_client_template_by_id(cid, realm=realm)
|
||||
if before_clientt == after_clientt:
|
||||
result['changed'] = False
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_clientt,
|
||||
after=after_clientt)
|
||||
|
||||
result['end_state'] = after_clientt
|
||||
|
||||
result['msg'] = 'Client template %s has been updated.' % updated_clientt['name']
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
# Delete existing client
|
||||
result['changed'] = True
|
||||
if module._diff:
|
||||
result['diff']['before'] = before_clientt
|
||||
result['diff']['after'] = ''
|
||||
result['diff'] = dict(before=before_clientt, after=after_clientt)
|
||||
|
||||
result['msg'] = 'Client template %s has been updated.' % desired_clientt['name']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_clientt, after='')
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete it
|
||||
kc.delete_client_template(cid, realm=realm)
|
||||
result['proposed'] = dict()
|
||||
result['end_state'] = dict()
|
||||
result['proposed'] = {}
|
||||
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = 'Client template %s has been deleted.' % before_clientt['name']
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -159,34 +159,91 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
|
||||
end_state:
|
||||
description: Representation of the group after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: complex
|
||||
contains:
|
||||
id:
|
||||
description: GUID that identifies the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: 23f38145-3195-462c-97e7-97041ccea73e
|
||||
name:
|
||||
description: Name of the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: grp-test-123
|
||||
attributes:
|
||||
description: Attributes applied to this group.
|
||||
type: dict
|
||||
returned: always
|
||||
sample:
|
||||
attr1: ["val1", "val2", "val3"]
|
||||
path:
|
||||
description: URI path to the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: /grp-test-123
|
||||
realmRoles:
|
||||
description: An array of the realm-level roles granted to this group.
|
||||
type: list
|
||||
returned: always
|
||||
sample: []
|
||||
subGroups:
|
||||
description: A list of groups that are children of this group. These groups will have the same parameters as
|
||||
documented here.
|
||||
type: list
|
||||
returned: always
|
||||
clientRoles:
|
||||
description: A list of client-level roles granted to this group.
|
||||
type: list
|
||||
returned: always
|
||||
sample: []
|
||||
access:
|
||||
description: A dict describing the accesses you have to this group based on the credentials used.
|
||||
type: dict
|
||||
returned: always
|
||||
sample:
|
||||
manage: true
|
||||
manageMembership: true
|
||||
view: true
|
||||
|
||||
group:
|
||||
description: Group representation of the group after module execution (sample is truncated).
|
||||
description:
|
||||
- Representation of the group after module execution.
|
||||
- Deprecated return value, it will be removed in community.general 6.0.0. Please use the return value I(end_state) instead.
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
id:
|
||||
description: GUID that identifies the group
|
||||
description: GUID that identifies the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: 23f38145-3195-462c-97e7-97041ccea73e
|
||||
name:
|
||||
description: Name of the group
|
||||
description: Name of the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: grp-test-123
|
||||
attributes:
|
||||
description: Attributes applied to this group
|
||||
description: Attributes applied to this group.
|
||||
type: dict
|
||||
returned: always
|
||||
sample:
|
||||
attr1: ["val1", "val2", "val3"]
|
||||
path:
|
||||
description: URI path to the group
|
||||
description: URI path to the group.
|
||||
type: str
|
||||
returned: always
|
||||
sample: /grp-test-123
|
||||
realmRoles:
|
||||
description: An array of the realm-level roles granted to this group
|
||||
description: An array of the realm-level roles granted to this group.
|
||||
type: list
|
||||
returned: always
|
||||
sample: []
|
||||
@@ -196,7 +253,7 @@ group:
|
||||
type: list
|
||||
returned: always
|
||||
clientRoles:
|
||||
description: A list of client-level roles granted to this group
|
||||
description: A list of client-level roles granted to this group.
|
||||
type: list
|
||||
returned: always
|
||||
sample: []
|
||||
@@ -208,6 +265,7 @@ group:
|
||||
manage: true
|
||||
manageMembership: true
|
||||
view: true
|
||||
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
@@ -222,6 +280,7 @@ def main():
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
realm=dict(default='master'),
|
||||
@@ -254,16 +313,6 @@ def main():
|
||||
name = module.params.get('name')
|
||||
attributes = module.params.get('attributes')
|
||||
|
||||
before_group = None # current state of the group, for merging.
|
||||
|
||||
# does the group already exist?
|
||||
if gid is None:
|
||||
before_group = kc.get_group_by_name(name, realm=realm)
|
||||
else:
|
||||
before_group = kc.get_group_by_groupid(gid, realm=realm)
|
||||
|
||||
before_group = {} if before_group is None else before_group
|
||||
|
||||
# attributes in Keycloak have their values returned as lists
|
||||
# via the API. attributes is a dict, so we'll transparently convert
|
||||
# the values to lists.
|
||||
@@ -271,81 +320,103 @@ def main():
|
||||
for key, val in module.params['attributes'].items():
|
||||
module.params['attributes'][key] = [val] if not isinstance(val, list) else val
|
||||
|
||||
# Filter and map the parameters names that apply to the group
|
||||
group_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm'] and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# build a changeset
|
||||
# See if it already exists in Keycloak
|
||||
if gid is None:
|
||||
before_group = kc.get_group_by_name(name, realm=realm)
|
||||
else:
|
||||
before_group = kc.get_group_by_groupid(gid, realm=realm)
|
||||
|
||||
if before_group is None:
|
||||
before_group = {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = {}
|
||||
|
||||
for param in group_params:
|
||||
new_param_value = module.params.get(param)
|
||||
old_value = before_group[param] if param in before_group else None
|
||||
if new_param_value != old_value:
|
||||
changeset[camel(param)] = new_param_value
|
||||
|
||||
# prepare the new group
|
||||
updated_group = before_group.copy()
|
||||
updated_group.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_group = before_group.copy()
|
||||
desired_group.update(changeset)
|
||||
|
||||
# if before_group is none, the group doesn't exist.
|
||||
if before_group == {}:
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_group:
|
||||
if state == 'absent':
|
||||
# nothing to do.
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['group'] = result['end_state']
|
||||
result['msg'] = 'Group does not exist; doing nothing.'
|
||||
result['group'] = dict()
|
||||
module.exit_json(**result)
|
||||
|
||||
# for 'present', create a new group.
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if name is None:
|
||||
module.fail_json(msg='name must be specified when creating a new group')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=updated_group)
|
||||
result['diff'] = dict(before='', after=desired_group)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do it for real!
|
||||
kc.create_group(updated_group, realm=realm)
|
||||
# create it
|
||||
kc.create_group(desired_group, realm=realm)
|
||||
after_group = kc.get_group_by_name(name, realm)
|
||||
|
||||
result['group'] = after_group
|
||||
result['end_state'] = after_group
|
||||
result['group'] = result['end_state']
|
||||
|
||||
result['msg'] = 'Group {name} has been created with ID {id}'.format(name=after_group['name'],
|
||||
id=after_group['id'])
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
# no changes
|
||||
if updated_group == before_group:
|
||||
if desired_group == before_group:
|
||||
result['changed'] = False
|
||||
result['group'] = updated_group
|
||||
result['end_state'] = desired_group
|
||||
result['group'] = result['end_state']
|
||||
result['msg'] = "No changes required to group {name}.".format(name=before_group['name'])
|
||||
module.exit_json(**result)
|
||||
|
||||
# update the existing group
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_group, after=updated_group)
|
||||
result['diff'] = dict(before=before_group, after=desired_group)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the update
|
||||
kc.update_group(updated_group, realm=realm)
|
||||
kc.update_group(desired_group, realm=realm)
|
||||
|
||||
after_group = kc.get_group_by_groupid(updated_group['id'], realm=realm)
|
||||
after_group = kc.get_group_by_groupid(desired_group['id'], realm=realm)
|
||||
|
||||
result['end_state'] = after_group
|
||||
result['group'] = result['end_state']
|
||||
|
||||
result['group'] = after_group
|
||||
result['msg'] = "Group {id} has been updated".format(id=after_group['id'])
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'absent':
|
||||
result['group'] = dict()
|
||||
else:
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_group, after='')
|
||||
@@ -353,14 +424,14 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete for real
|
||||
# delete it
|
||||
gid = before_group['id']
|
||||
kc.delete_group(groupid=gid, realm=realm)
|
||||
|
||||
result['changed'] = True
|
||||
result['msg'] = "Group {name} has been deleted".format(name=before_group['name'])
|
||||
result['end_state'] = {}
|
||||
result['group'] = result['end_state']
|
||||
|
||||
module.exit_json(**result)
|
||||
result['msg'] = "Group {name} has been deleted".format(name=before_group['name'])
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -339,13 +339,13 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Identity provider my-idp has been created"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Identity provider my-idp has been created"
|
||||
|
||||
proposed:
|
||||
description: Representation of proposed changes to identity provider
|
||||
description: Representation of proposed identity provider.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -363,7 +363,7 @@ proposed:
|
||||
}
|
||||
|
||||
existing:
|
||||
description: Representation of existing identity provider
|
||||
description: Representation of existing identity provider.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -391,8 +391,8 @@ existing:
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: Representation of identity provider after module execution
|
||||
returned: always
|
||||
description: Representation of identity provider after module execution.
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"addReadTokenRoleOnCreate": false,
|
||||
@@ -416,7 +416,6 @@ end_state:
|
||||
"storeToken": false,
|
||||
"trustEmail": false,
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
@@ -438,7 +437,7 @@ def get_identity_provider_with_mappers(kc, alias, realm):
|
||||
if idp is not None:
|
||||
idp['mappers'] = sorted(kc.get_identity_provider_mappers(alias, realm), key=lambda x: x.get('name'))
|
||||
if idp is None:
|
||||
idp = dict()
|
||||
idp = {}
|
||||
return idp
|
||||
|
||||
|
||||
@@ -497,16 +496,16 @@ def main():
|
||||
alias = module.params.get('alias')
|
||||
state = module.params.get('state')
|
||||
|
||||
# convert module parameters to client representation parameters (if they belong in there)
|
||||
# Filter and map the parameters names that apply to the identity provider.
|
||||
idp_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'mappers'] and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# does the identity provider already exist?
|
||||
# See if it already exists in Keycloak
|
||||
before_idp = get_identity_provider_with_mappers(kc, alias, realm)
|
||||
|
||||
# build a changeset
|
||||
changeset = dict()
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = {}
|
||||
|
||||
for param in idp_params:
|
||||
new_param_value = module.params.get(param)
|
||||
@@ -539,37 +538,37 @@ def main():
|
||||
changeset['mappers'] = list()
|
||||
changeset['mappers'].append(new_mapper)
|
||||
|
||||
# prepare the new representation
|
||||
updated_idp = before_idp.copy()
|
||||
updated_idp.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_idp = before_idp.copy()
|
||||
desired_idp.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize(changeset)
|
||||
result['existing'] = sanitize(before_idp)
|
||||
|
||||
# if before_idp is none, the identity provider doesn't exist.
|
||||
if before_idp == dict():
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_idp:
|
||||
if state == 'absent':
|
||||
# nothing to do.
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = dict()
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Identity provider does not exist; doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# for 'present', create a new identity provider.
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize(updated_idp))
|
||||
result['diff'] = dict(before='', after=sanitize(desired_idp))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do it for real!
|
||||
updated_idp = updated_idp.copy()
|
||||
mappers = updated_idp.pop('mappers', [])
|
||||
kc.create_identity_provider(updated_idp, realm)
|
||||
# create it
|
||||
desired_idp = desired_idp.copy()
|
||||
mappers = desired_idp.pop('mappers', [])
|
||||
kc.create_identity_provider(desired_idp, realm)
|
||||
for mapper in mappers:
|
||||
if mapper.get('identityProviderAlias') is None:
|
||||
mapper['identityProviderAlias'] = alias
|
||||
@@ -583,26 +582,28 @@ def main():
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
# no changes
|
||||
if updated_idp == before_idp:
|
||||
if desired_idp == before_idp:
|
||||
result['changed'] = False
|
||||
result['end_state'] = sanitize(updated_idp)
|
||||
result['end_state'] = sanitize(desired_idp)
|
||||
result['msg'] = "No changes required to identity provider {alias}.".format(alias=alias)
|
||||
module.exit_json(**result)
|
||||
|
||||
# update the existing role
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize(before_idp), after=sanitize(updated_idp))
|
||||
result['diff'] = dict(before=sanitize(before_idp), after=sanitize(desired_idp))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the update
|
||||
updated_idp = updated_idp.copy()
|
||||
updated_mappers = updated_idp.pop('mappers', [])
|
||||
kc.update_identity_provider(updated_idp, realm)
|
||||
desired_idp = desired_idp.copy()
|
||||
updated_mappers = desired_idp.pop('mappers', [])
|
||||
kc.update_identity_provider(desired_idp, realm)
|
||||
for mapper in updated_mappers:
|
||||
if mapper.get('id') is not None:
|
||||
kc.update_identity_provider_mapper(mapper, alias, realm)
|
||||
@@ -622,6 +623,7 @@ def main():
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'absent':
|
||||
# Process a deletion
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
@@ -630,13 +632,12 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete for real
|
||||
# delete it
|
||||
kc.delete_identity_provider(alias, realm)
|
||||
|
||||
result['end_state'] = dict()
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = "Identity provider {alias} has been deleted".format(alias=alias)
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ DOCUMENTATION = '''
|
||||
module: keycloak_realm
|
||||
|
||||
short_description: Allows administration of Keycloak realm via Keycloak API
|
||||
|
||||
version_added: 3.0.0
|
||||
|
||||
|
||||
@@ -533,20 +534,21 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Realm testrealm has been updated"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Realm testrealm has been updated"
|
||||
|
||||
proposed:
|
||||
description: realm representation of proposed changes to realm
|
||||
description: Representation of proposed realm.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
id: "test"
|
||||
}
|
||||
|
||||
existing:
|
||||
description: realm representation of existing realm (sample is truncated)
|
||||
description: Representation of existing realm (sample is truncated).
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -555,9 +557,10 @@ existing:
|
||||
"request.object.signature.alg": "RS256",
|
||||
}
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: realm representation of realm after module execution (sample is truncated)
|
||||
returned: always
|
||||
description: Representation of realm after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"adminUrl": "http://www.example.com/admin_url",
|
||||
@@ -573,7 +576,7 @@ from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def sanitize_cr(realmrep):
|
||||
""" Removes probably sensitive details from a realm representation
|
||||
""" Removes probably sensitive details from a realm representation.
|
||||
|
||||
:param realmrep: the realmrep dict to be sanitized
|
||||
:return: sanitized realmrep dict
|
||||
@@ -676,6 +679,7 @@ def main():
|
||||
verify_email=dict(type='bool', aliases=['verifyEmail']),
|
||||
wait_increment_seconds=dict(type='int', aliases=['waitIncrementSeconds']),
|
||||
)
|
||||
|
||||
argument_spec.update(meta_args)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
@@ -699,95 +703,114 @@ def main():
|
||||
|
||||
# convert module parameters to realm representation parameters (if they belong in there)
|
||||
params_to_ignore = list(keycloak_argument_spec().keys()) + ['state']
|
||||
|
||||
# Filter and map the parameters names that apply to the role
|
||||
realm_params = [x for x in module.params
|
||||
if x not in params_to_ignore and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# See whether the realm already exists in Keycloak
|
||||
before_realm = kc.get_realm_by_id(realm=realm) or {}
|
||||
before_realm = kc.get_realm_by_id(realm=realm)
|
||||
|
||||
if before_realm is None:
|
||||
before_realm = {}
|
||||
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = dict()
|
||||
changeset = {}
|
||||
|
||||
for realm_param in realm_params:
|
||||
new_param_value = module.params.get(realm_param)
|
||||
changeset[camel(realm_param)] = new_param_value
|
||||
|
||||
# Whether creating or updating a realm, take the before-state and merge the changeset into it
|
||||
updated_realm = before_realm.copy()
|
||||
updated_realm.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_realm = before_realm.copy()
|
||||
desired_realm.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize_cr(changeset)
|
||||
before_realm_sanitized = sanitize_cr(before_realm)
|
||||
result['existing'] = before_realm_sanitized
|
||||
|
||||
# If the realm does not exist yet, before_realm is still empty
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_realm:
|
||||
if state == 'absent':
|
||||
# do nothing and exit
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Realm does not exist, doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# create new realm
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
if 'id' not in updated_realm:
|
||||
|
||||
if 'id' not in desired_realm:
|
||||
module.fail_json(msg='id needs to be specified when creating a new realm')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize_cr(updated_realm))
|
||||
result['diff'] = dict(before='', after=sanitize_cr(desired_realm))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.create_realm(updated_realm)
|
||||
after_realm = kc.get_realm_by_id(updated_realm['id'])
|
||||
# create it
|
||||
kc.create_realm(desired_realm)
|
||||
after_realm = kc.get_realm_by_id(desired_realm['id'])
|
||||
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been created.' % updated_realm['id']
|
||||
result['msg'] = 'Realm %s has been created.' % desired_realm['id']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# update existing realm
|
||||
# Process an update
|
||||
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
if module.check_mode:
|
||||
# We can only compare the current realm with the proposed updates we have
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(updated_realm))
|
||||
result['changed'] = (before_realm != updated_realm)
|
||||
after=sanitize_cr(desired_realm))
|
||||
result['changed'] = (before_realm != desired_realm)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
kc.update_realm(updated_realm, realm=realm)
|
||||
# do the update
|
||||
kc.update_realm(desired_realm, realm=realm)
|
||||
|
||||
after_realm = kc.get_realm_by_id(realm=realm)
|
||||
|
||||
if before_realm == after_realm:
|
||||
result['changed'] = False
|
||||
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_realm_sanitized,
|
||||
after=sanitize_cr(after_realm))
|
||||
result['end_state'] = sanitize_cr(after_realm)
|
||||
|
||||
result['msg'] = 'Realm %s has been updated.' % updated_realm['id']
|
||||
result['msg'] = 'Realm %s has been updated.' % desired_realm['id']
|
||||
module.exit_json(**result)
|
||||
|
||||
else:
|
||||
# Delete existing realm
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff']['before'] = before_realm_sanitized
|
||||
result['diff']['after'] = ''
|
||||
result['diff'] = dict(before=before_realm_sanitized, after='')
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete it
|
||||
kc.delete_realm(realm=realm)
|
||||
result['proposed'] = dict()
|
||||
result['end_state'] = dict()
|
||||
|
||||
result['proposed'] = {}
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = 'Realm %s has been deleted.' % before_realm['id']
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -149,20 +149,21 @@ EXAMPLES = '''
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: Message as to what action was taken
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Role myrole has been updated"
|
||||
description: Message as to what action was taken.
|
||||
returned: always
|
||||
type: str
|
||||
sample: "Role myrole has been updated"
|
||||
|
||||
proposed:
|
||||
description: Role representation of proposed changes to role
|
||||
description: Representation of proposed role.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
"description": "My updated test description"
|
||||
}
|
||||
|
||||
existing:
|
||||
description: Role representation of existing role
|
||||
description: Representation of existing role.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -174,9 +175,10 @@ existing:
|
||||
"id": "561703dd-0f38-45ff-9a5a-0c978f794547",
|
||||
"name": "myrole"
|
||||
}
|
||||
|
||||
end_state:
|
||||
description: Role representation of role after module execution (sample is truncated)
|
||||
returned: always
|
||||
description: Representation of role after module execution (sample is truncated).
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"attributes": {},
|
||||
@@ -201,6 +203,7 @@ def main():
|
||||
:return:
|
||||
"""
|
||||
argument_spec = keycloak_argument_spec()
|
||||
|
||||
meta_args = dict(
|
||||
state=dict(type='str', default='present', choices=['present', 'absent']),
|
||||
name=dict(type='str', required=True),
|
||||
@@ -239,22 +242,22 @@ def main():
|
||||
for key, val in module.params['attributes'].items():
|
||||
module.params['attributes'][key] = [val] if not isinstance(val, list) else val
|
||||
|
||||
# convert module parameters to client representation parameters (if they belong in there)
|
||||
# Filter and map the parameters names that apply to the role
|
||||
role_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'client_id', 'composites'] and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# does the role already exist?
|
||||
# See if it already exists in Keycloak
|
||||
if clientid is None:
|
||||
before_role = kc.get_realm_role(name, realm)
|
||||
else:
|
||||
before_role = kc.get_client_role(name, clientid, realm)
|
||||
|
||||
if before_role is None:
|
||||
before_role = dict()
|
||||
before_role = {}
|
||||
|
||||
# build a changeset
|
||||
changeset = dict()
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = {}
|
||||
|
||||
for param in role_params:
|
||||
new_param_value = module.params.get(param)
|
||||
@@ -262,42 +265,42 @@ def main():
|
||||
if new_param_value != old_value:
|
||||
changeset[camel(param)] = new_param_value
|
||||
|
||||
# prepare the new role
|
||||
updated_role = before_role.copy()
|
||||
updated_role.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_role = before_role.copy()
|
||||
desired_role.update(changeset)
|
||||
|
||||
result['proposed'] = changeset
|
||||
result['existing'] = before_role
|
||||
|
||||
# if before_role is none, the role doesn't exist.
|
||||
if before_role == dict():
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_role:
|
||||
if state == 'absent':
|
||||
# nothing to do.
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = dict()
|
||||
result['msg'] = 'Role does not exist; doing nothing.'
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'Role does not exist, doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# for 'present', create a new role.
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if name is None:
|
||||
module.fail_json(msg='name must be specified when creating a new role')
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=updated_role)
|
||||
result['diff'] = dict(before='', after=desired_role)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do it for real!
|
||||
# create it
|
||||
if clientid is None:
|
||||
kc.create_realm_role(updated_role, realm)
|
||||
kc.create_realm_role(desired_role, realm)
|
||||
after_role = kc.get_realm_role(name, realm)
|
||||
else:
|
||||
kc.create_client_role(updated_role, clientid, realm)
|
||||
kc.create_client_role(desired_role, clientid, realm)
|
||||
after_role = kc.get_client_role(name, clientid, realm)
|
||||
|
||||
result['end_state'] = after_role
|
||||
@@ -307,28 +310,30 @@ def main():
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
# no changes
|
||||
if updated_role == before_role:
|
||||
if desired_role == before_role:
|
||||
result['changed'] = False
|
||||
result['end_state'] = updated_role
|
||||
result['end_state'] = desired_role
|
||||
result['msg'] = "No changes required to role {name}.".format(name=name)
|
||||
module.exit_json(**result)
|
||||
|
||||
# update the existing role
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=before_role, after=updated_role)
|
||||
result['diff'] = dict(before=before_role, after=desired_role)
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the update
|
||||
if clientid is None:
|
||||
kc.update_realm_role(updated_role, realm)
|
||||
kc.update_realm_role(desired_role, realm)
|
||||
after_role = kc.get_realm_role(name, realm)
|
||||
else:
|
||||
kc.update_client_role(updated_role, clientid, realm)
|
||||
kc.update_client_role(desired_role, clientid, realm)
|
||||
after_role = kc.get_client_role(name, clientid, realm)
|
||||
|
||||
result['end_state'] = after_role
|
||||
@@ -336,7 +341,8 @@ def main():
|
||||
result['msg'] = "Role {name} has been updated".format(name=name)
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'absent':
|
||||
else:
|
||||
# Process a deletion (because state was not 'present')
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
@@ -345,16 +351,15 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete for real
|
||||
# delete it
|
||||
if clientid is None:
|
||||
kc.delete_realm_role(name, realm)
|
||||
else:
|
||||
kc.delete_client_role(name, clientid, realm)
|
||||
|
||||
result['end_state'] = dict()
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = "Role {name} has been deleted".format(name=name)
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ options:
|
||||
description:
|
||||
- For one level, the search applies only for users in the DNs specified by User DNs.
|
||||
For subtree, the search applies to the whole subtree. See LDAP documentation for
|
||||
more details
|
||||
more details.
|
||||
default: '1'
|
||||
type: str
|
||||
choices:
|
||||
@@ -551,7 +551,7 @@ msg:
|
||||
sample: "No changes required to user federation 164bb483-c613-482e-80fe-7f1431308799."
|
||||
|
||||
proposed:
|
||||
description: Representation of proposed changes to user federation.
|
||||
description: Representation of proposed user federation.
|
||||
returned: always
|
||||
type: dict
|
||||
sample: {
|
||||
@@ -648,7 +648,7 @@ existing:
|
||||
|
||||
end_state:
|
||||
description: Representation of user federation after module execution.
|
||||
returned: always
|
||||
returned: on success
|
||||
type: dict
|
||||
sample: {
|
||||
"config": {
|
||||
@@ -668,7 +668,6 @@ end_state:
|
||||
"providerId": "kerberos",
|
||||
"providerType": "org.keycloak.storage.UserStorageProvider"
|
||||
}
|
||||
|
||||
'''
|
||||
|
||||
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
|
||||
@@ -808,12 +807,12 @@ def main():
|
||||
mapper['config'] = dict((k, [str(v).lower() if not isinstance(v, str) else v])
|
||||
for k, v in mapper['config'].items() if mapper['config'][k] is not None)
|
||||
|
||||
# convert module parameters to client representation parameters (if they belong in there)
|
||||
# Filter and map the parameters names that apply
|
||||
comp_params = [x for x in module.params
|
||||
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'mappers'] and
|
||||
module.params.get(x) is not None]
|
||||
|
||||
# does the user federation already exist?
|
||||
# See if it already exists in Keycloak
|
||||
if cid is None:
|
||||
found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', parent=realm, name=name)), realm)
|
||||
if len(found) > 1:
|
||||
@@ -825,14 +824,14 @@ def main():
|
||||
before_comp = kc.get_component(cid, realm)
|
||||
|
||||
if before_comp is None:
|
||||
before_comp = dict()
|
||||
before_comp = {}
|
||||
|
||||
# if user federation exists, get associated mappers
|
||||
if cid is not None:
|
||||
before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name'))
|
||||
|
||||
# build a changeset
|
||||
changeset = dict()
|
||||
# Build a proposed changeset from parameters given to this module
|
||||
changeset = {}
|
||||
|
||||
for param in comp_params:
|
||||
new_param_value = module.params.get(param)
|
||||
@@ -851,11 +850,11 @@ def main():
|
||||
if change.get('id') is None and change.get('name') is None:
|
||||
module.fail_json(msg='Either `name` or `id` has to be specified on each mapper.')
|
||||
if cid is None:
|
||||
old_mapper = dict()
|
||||
old_mapper = {}
|
||||
elif change.get('id') is not None:
|
||||
old_mapper = kc.get_component(change['id'], realm)
|
||||
if old_mapper is None:
|
||||
old_mapper = dict()
|
||||
old_mapper = {}
|
||||
else:
|
||||
found = kc.get_components(urlencode(dict(parent=cid, name=change['name'])), realm)
|
||||
if len(found) > 1:
|
||||
@@ -863,7 +862,7 @@ def main():
|
||||
if len(found) == 1:
|
||||
old_mapper = found[0]
|
||||
else:
|
||||
old_mapper = dict()
|
||||
old_mapper = {}
|
||||
new_mapper = old_mapper.copy()
|
||||
new_mapper.update(change)
|
||||
if new_mapper != old_mapper:
|
||||
@@ -871,37 +870,37 @@ def main():
|
||||
changeset['mappers'] = list()
|
||||
changeset['mappers'].append(new_mapper)
|
||||
|
||||
# prepare the new representation
|
||||
updated_comp = before_comp.copy()
|
||||
updated_comp.update(changeset)
|
||||
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
|
||||
desired_comp = before_comp.copy()
|
||||
desired_comp.update(changeset)
|
||||
|
||||
result['proposed'] = sanitize(changeset)
|
||||
result['existing'] = sanitize(before_comp)
|
||||
|
||||
# if before_comp is none, the user federation doesn't exist.
|
||||
if before_comp == dict():
|
||||
# Cater for when it doesn't exist (an empty dict)
|
||||
if not before_comp:
|
||||
if state == 'absent':
|
||||
# nothing to do.
|
||||
# Do nothing and exit
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after='')
|
||||
result['changed'] = False
|
||||
result['end_state'] = dict()
|
||||
result['end_state'] = {}
|
||||
result['msg'] = 'User federation does not exist; doing nothing.'
|
||||
module.exit_json(**result)
|
||||
|
||||
# for 'present', create a new user federation.
|
||||
# Process a creation
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before='', after=sanitize(updated_comp))
|
||||
result['diff'] = dict(before='', after=sanitize(desired_comp))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do it for real!
|
||||
updated_comp = updated_comp.copy()
|
||||
updated_mappers = updated_comp.pop('mappers', [])
|
||||
after_comp = kc.create_component(updated_comp, realm)
|
||||
# create it
|
||||
desired_comp = desired_comp.copy()
|
||||
updated_mappers = desired_comp.pop('mappers', [])
|
||||
after_comp = kc.create_component(desired_comp, realm)
|
||||
|
||||
for mapper in updated_mappers:
|
||||
if mapper.get('id') is not None:
|
||||
@@ -919,26 +918,28 @@ def main():
|
||||
|
||||
else:
|
||||
if state == 'present':
|
||||
# Process an update
|
||||
|
||||
# no changes
|
||||
if updated_comp == before_comp:
|
||||
if desired_comp == before_comp:
|
||||
result['changed'] = False
|
||||
result['end_state'] = sanitize(updated_comp)
|
||||
result['end_state'] = sanitize(desired_comp)
|
||||
result['msg'] = "No changes required to user federation {id}.".format(id=cid)
|
||||
module.exit_json(**result)
|
||||
|
||||
# update the existing role
|
||||
# doing an update
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
result['diff'] = dict(before=sanitize(before_comp), after=sanitize(updated_comp))
|
||||
result['diff'] = dict(before=sanitize(before_comp), after=sanitize(desired_comp))
|
||||
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# do the update
|
||||
updated_comp = updated_comp.copy()
|
||||
updated_mappers = updated_comp.pop('mappers', [])
|
||||
kc.update_component(updated_comp, realm)
|
||||
desired_comp = desired_comp.copy()
|
||||
updated_mappers = desired_comp.pop('mappers', [])
|
||||
kc.update_component(desired_comp, realm)
|
||||
after_comp = kc.get_component(cid, realm)
|
||||
|
||||
for mapper in updated_mappers:
|
||||
@@ -946,7 +947,7 @@ def main():
|
||||
kc.update_component(mapper, realm)
|
||||
else:
|
||||
if mapper.get('parentId') is None:
|
||||
mapper['parentId'] = updated_comp['id']
|
||||
mapper['parentId'] = desired_comp['id']
|
||||
mapper = kc.create_component(mapper, realm)
|
||||
|
||||
after_comp['mappers'] = updated_mappers
|
||||
@@ -956,6 +957,7 @@ def main():
|
||||
module.exit_json(**result)
|
||||
|
||||
elif state == 'absent':
|
||||
# Process a deletion
|
||||
result['changed'] = True
|
||||
|
||||
if module._diff:
|
||||
@@ -964,13 +966,12 @@ def main():
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# delete for real
|
||||
# delete it
|
||||
kc.delete_component(cid, realm)
|
||||
|
||||
result['end_state'] = dict()
|
||||
result['end_state'] = {}
|
||||
|
||||
result['msg'] = "User federation {id} has been deleted".format(id=cid)
|
||||
module.exit_json(**result)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
1
plugins/modules/mssql_script.py
Symbolic link
1
plugins/modules/mssql_script.py
Symbolic link
@@ -0,0 +1 @@
|
||||
./database/mssql/mssql_script.py
|
||||
@@ -82,6 +82,8 @@ options:
|
||||
version_added: 3.5.0
|
||||
requirements:
|
||||
- "dnsimple >= 1.0.0"
|
||||
notes:
|
||||
- "Support for C(dnsimple < 2) is deprecated and will be removed in community.general 5.0.0."
|
||||
author: "Alex Coomans (@drcapulet)"
|
||||
'''
|
||||
|
||||
@@ -92,13 +94,6 @@ EXAMPLES = '''
|
||||
account_api_token: dummyapitoken
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Fetch my.com domain records
|
||||
community.general.dnsimple:
|
||||
domain: my.com
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
register: records
|
||||
|
||||
- name: Delete a domain
|
||||
community.general.dnsimple:
|
||||
domain: my.com
|
||||
@@ -402,6 +397,11 @@ def main():
|
||||
if DNSIMPLE_MAJOR_VERSION > 1:
|
||||
ds = DNSimpleV2(account_email, account_api_token, sandbox, module)
|
||||
else:
|
||||
module.deprecate(
|
||||
'Support for python-dnsimple < 2 is deprecated. '
|
||||
'Update python-dnsimple to version >= 2.0.0',
|
||||
version='5.0.0', collection_name='community.general'
|
||||
)
|
||||
ds = DNSimpleV1(account_email, account_api_token, sandbox, module)
|
||||
# Let's figure out what operation we want to do
|
||||
# No domain, return a list
|
||||
|
||||
@@ -106,11 +106,10 @@ def main():
|
||||
module.fail_json(msg=missing_required_lib('python-ldap'),
|
||||
exception=LDAP_IMP_ERR)
|
||||
|
||||
if not module.check_mode:
|
||||
try:
|
||||
LdapSearch(module).main()
|
||||
except Exception as exception:
|
||||
module.fail_json(msg="Attribute action failed.", details=to_native(exception))
|
||||
try:
|
||||
LdapSearch(module).main()
|
||||
except Exception as exception:
|
||||
module.fail_json(msg="Attribute action failed.", details=to_native(exception))
|
||||
|
||||
module.exit_json(changed=False)
|
||||
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_a_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS A records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_a_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of A record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:a) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this A record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
ipv4addr:
|
||||
description:
|
||||
- Configures the IPv4 address for this A record. Users can dynamically
|
||||
allocate ipv4 address to A record by passing dictionary containing,
|
||||
I(nios_next_ip) and I(CIDR network range). See example
|
||||
aliases:
|
||||
- ipv4
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this A record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure an A record
|
||||
community.general.nios_a_record:
|
||||
name: a.ansible.com
|
||||
ipv4: 192.168.10.1
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing A record
|
||||
community.general.nios_a_record:
|
||||
name: a.ansible.com
|
||||
ipv4: 192.168.10.1
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove an A record from the system
|
||||
community.general.nios_a_record:
|
||||
name: a.ansible.com
|
||||
ipv4: 192.168.10.1
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Update an A record name
|
||||
community.general.nios_a_record:
|
||||
name: {new_name: a_new.ansible.com, old_name: a.ansible.com}
|
||||
ipv4: 192.168.10.1
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Dynamically add a record to next available ip
|
||||
community.general.nios_a_record:
|
||||
name: a.ansible.com
|
||||
ipv4: {nios_next_ip: 192.168.10.0/24}
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_A_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
ipv4addr=dict(aliases=['ipv4'], ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_A_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,166 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_aaaa_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS AAAA records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_aaaa_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of AAAA record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:aaaa) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this AAAA record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
ipv6addr:
|
||||
description:
|
||||
- Configures the IPv6 address for this AAAA record.
|
||||
aliases:
|
||||
- ipv6
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this AAAA record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure an AAAA record
|
||||
community.general.nios_aaaa_record:
|
||||
name: aaaa.ansible.com
|
||||
ipv6: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing AAAA record
|
||||
community.general.nios_aaaa_record:
|
||||
name: aaaa.ansible.com
|
||||
ipv6: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove an AAAA record from the system
|
||||
community.general.nios_aaaa_record:
|
||||
name: aaaa.ansible.com
|
||||
ipv6: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Update an AAAA record name
|
||||
community.general.nios_aaaa_record:
|
||||
name: {new_name: aaaa_new.ansible.com, old_name: aaaa.ansible.com}
|
||||
ipv6: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_AAAA_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
ipv6addr=dict(aliases=['ipv6'], ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_AAAA_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,155 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_cname_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS CNAME records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_cname_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of CNAME record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:cname) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this CNAME record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
canonical:
|
||||
description:
|
||||
- Configures the canonical name for this CNAME record.
|
||||
aliases:
|
||||
- cname
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this CNAME record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a CNAME record
|
||||
community.general.nios_cname_record:
|
||||
name: cname.ansible.com
|
||||
canonical: realhost.ansible.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing CNAME record
|
||||
community.general.nios_cname_record:
|
||||
name: cname.ansible.com
|
||||
canonical: realhost.ansible.com
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove a CNAME record from the system
|
||||
community.general.nios_cname_record:
|
||||
name: cname.ansible.com
|
||||
canonical: realhost.ansible.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_CNAME_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
canonical=dict(aliases=['cname'], ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_CNAME_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,150 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_dns_view
|
||||
author: "Peter Sprygada (@privateip)"
|
||||
short_description: Configure Infoblox NIOS DNS views
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_dns_view
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of DNS view objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(view) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
- Updates instances of DNS view object from Infoblox NIOS servers.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system. User can also update the hostname as it is possible
|
||||
to pass a dict containing I(new_name), I(old_name). See examples.
|
||||
required: true
|
||||
aliases:
|
||||
- view
|
||||
type: str
|
||||
network_view:
|
||||
description:
|
||||
- Specifies the name of the network view to assign the configured
|
||||
DNS view to. The network view must already be configured on the
|
||||
target system.
|
||||
default: default
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
required: false
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
required: false
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
required: false
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a new dns view instance
|
||||
community.general.nios_dns_view:
|
||||
name: ansible-dns
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update the comment for dns view
|
||||
community.general.nios_dns_view:
|
||||
name: ansible-dns
|
||||
comment: this is an example comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove the dns view instance
|
||||
community.general.nios_dns_view:
|
||||
name: ansible-dns
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update the dns view instance
|
||||
community.general.nios_dns_view:
|
||||
name: {new_name: ansible-dns-new, old_name: ansible-dns}
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_DNS_VIEW
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, aliases=['view'], ib_req=True),
|
||||
network_view=dict(default='default', ib_req=True),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict()
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_DNS_VIEW, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,301 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_fixed_address
|
||||
author: "Sumit Jaiswal (@sjaiswal)"
|
||||
short_description: Configure Infoblox NIOS DHCP Fixed Address
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_fixed_address
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- A fixed address is a specific IP address that a DHCP server
|
||||
always assigns when a lease request comes from a particular
|
||||
MAC address of the client.
|
||||
- Supports both IPV4 and IPV6 internet protocols
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the hostname with which fixed DHCP ip-address is stored
|
||||
for respective mac.
|
||||
required: true
|
||||
type: str
|
||||
ipaddr:
|
||||
description:
|
||||
- IPV4/V6 address of the fixed address.
|
||||
required: true
|
||||
type: str
|
||||
mac:
|
||||
description:
|
||||
- The MAC address of the interface.
|
||||
required: true
|
||||
type: str
|
||||
network:
|
||||
description:
|
||||
- Specifies the network range in which ipaddr exists.
|
||||
required: true
|
||||
type: str
|
||||
network_view:
|
||||
description:
|
||||
- Configures the name of the network view to associate with this
|
||||
configured instance.
|
||||
required: false
|
||||
default: default
|
||||
type: str
|
||||
options:
|
||||
description:
|
||||
- Configures the set of DHCP options to be included as part of
|
||||
the configured network instance. This argument accepts a list
|
||||
of values (see suboptions). When configuring suboptions at
|
||||
least one of C(name) or C(num) must be specified.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- The name of the DHCP option to configure
|
||||
type: str
|
||||
num:
|
||||
description:
|
||||
- The number of the DHCP option to configure
|
||||
type: int
|
||||
value:
|
||||
description:
|
||||
- The value of the DHCP option specified by C(name)
|
||||
required: true
|
||||
type: str
|
||||
use_option:
|
||||
description:
|
||||
- Only applies to a subset of options (see NIOS API documentation)
|
||||
type: bool
|
||||
default: 'yes'
|
||||
vendor_class:
|
||||
description:
|
||||
- The name of the space this DHCP option is associated to
|
||||
default: DHCP
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure ipv4 dhcp fixed address
|
||||
community.general.nios_fixed_address:
|
||||
name: ipv4_fixed
|
||||
ipaddr: 192.168.10.1
|
||||
mac: 08:6d:41:e8:fd:e8
|
||||
network: 192.168.10.0/24
|
||||
network_view: default
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a ipv6 dhcp fixed address
|
||||
community.general.nios_fixed_address:
|
||||
name: ipv6_fixed
|
||||
ipaddr: fe80::1/10
|
||||
mac: 08:6d:41:e8:fd:e8
|
||||
network: fe80::/64
|
||||
network_view: default
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Set dhcp options for a ipv4 fixed address
|
||||
community.general.nios_fixed_address:
|
||||
name: ipv4_fixed
|
||||
ipaddr: 192.168.10.1
|
||||
mac: 08:6d:41:e8:fd:e8
|
||||
network: 192.168.10.0/24
|
||||
network_view: default
|
||||
comment: this is a test comment
|
||||
options:
|
||||
- name: domain-name
|
||||
value: ansible.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove a ipv4 dhcp fixed address
|
||||
community.general.nios_fixed_address:
|
||||
name: ipv4_fixed
|
||||
ipaddr: 192.168.10.1
|
||||
mac: 08:6d:41:e8:fd:e8
|
||||
network: 192.168.10.0/24
|
||||
network_view: default
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
import socket
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_IPV4_FIXED_ADDRESS, NIOS_IPV6_FIXED_ADDRESS
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def validate_ip_address(address):
|
||||
try:
|
||||
socket.inet_aton(address)
|
||||
except socket.error:
|
||||
return False
|
||||
return address.count(".") == 3
|
||||
|
||||
|
||||
def validate_ip_v6_address(address):
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET6, address)
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def options(module):
|
||||
''' Transforms the module argument into a valid WAPI struct
|
||||
This function will transform the options argument into a structure that
|
||||
is a valid WAPI structure in the format of:
|
||||
{
|
||||
name: <value>,
|
||||
num: <value>,
|
||||
value: <value>,
|
||||
use_option: <value>,
|
||||
vendor_class: <value>
|
||||
}
|
||||
It will remove any options that are set to None since WAPI will error on
|
||||
that condition. The use_option field only applies
|
||||
to special options that are displayed separately from other options and
|
||||
have a use flag. This function removes the use_option flag from all
|
||||
other options. It will also verify that either `name` or `num` is
|
||||
set in the structure but does not validate the values are equal.
|
||||
The remainder of the value validation is performed by WAPI
|
||||
'''
|
||||
special_options = ['routers', 'router-templates', 'domain-name-servers',
|
||||
'domain-name', 'broadcast-address', 'broadcast-address-offset',
|
||||
'dhcp-lease-time', 'dhcp6.name-servers']
|
||||
options = list()
|
||||
for item in module.params['options']:
|
||||
opt = dict([(k, v) for k, v in iteritems(item) if v is not None])
|
||||
if 'name' not in opt and 'num' not in opt:
|
||||
module.fail_json(msg='one of `name` or `num` is required for option value')
|
||||
if opt['name'] not in special_options:
|
||||
del opt['use_option']
|
||||
options.append(opt)
|
||||
return options
|
||||
|
||||
|
||||
def validate_ip_addr_type(ip, arg_spec, module):
|
||||
'''This function will check if the argument ip is type v4/v6 and return appropriate infoblox network type
|
||||
'''
|
||||
check_ip = ip.split('/')
|
||||
|
||||
if validate_ip_address(check_ip[0]) and 'ipaddr' in arg_spec:
|
||||
arg_spec['ipv4addr'] = arg_spec.pop('ipaddr')
|
||||
module.params['ipv4addr'] = module.params.pop('ipaddr')
|
||||
return NIOS_IPV4_FIXED_ADDRESS, arg_spec, module
|
||||
elif validate_ip_v6_address(check_ip[0]) and 'ipaddr' in arg_spec:
|
||||
arg_spec['ipv6addr'] = arg_spec.pop('ipaddr')
|
||||
module.params['ipv6addr'] = module.params.pop('ipaddr')
|
||||
return NIOS_IPV6_FIXED_ADDRESS, arg_spec, module
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
option_spec = dict(
|
||||
# one of name or num is required; enforced by the function options()
|
||||
name=dict(),
|
||||
num=dict(type='int'),
|
||||
|
||||
value=dict(required=True),
|
||||
|
||||
use_option=dict(type='bool', default=True),
|
||||
vendor_class=dict(default='DHCP')
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True),
|
||||
ipaddr=dict(required=True, ib_req=True),
|
||||
mac=dict(required=True, ib_req=True),
|
||||
network=dict(required=True),
|
||||
network_view=dict(default='default'),
|
||||
|
||||
options=dict(type='list', elements='dict', options=option_spec, transform=options),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict()
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
# to get the argument ipaddr
|
||||
obj_filter = dict([(k, module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')])
|
||||
# to modify argument based on ipaddr type i.e. IPV4/IPV6
|
||||
fixed_address_ip_type, ib_spec, module = validate_ip_addr_type(obj_filter['ipaddr'], ib_spec, module)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
|
||||
result = wapi.run(fixed_address_ip_type, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,361 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_host_record
|
||||
author: "Peter Sprygada (@privateip)"
|
||||
short_description: Configure Infoblox NIOS host records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_host_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of host record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:host) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
- Updates instances of host record object from Infoblox NIOS servers.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system. User can also update the hostname as it is possible
|
||||
to pass a dict containing I(new_name), I(old_name). See examples.
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this host record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
configure_for_dns:
|
||||
description:
|
||||
- Sets the DNS to particular parent. If user needs to bypass DNS
|
||||
user can make the value to false.
|
||||
type: bool
|
||||
required: false
|
||||
default: true
|
||||
aliases:
|
||||
- dns
|
||||
ipv4addrs:
|
||||
description:
|
||||
- Configures the IPv4 addresses for this host record. This argument
|
||||
accepts a list of values (see suboptions)
|
||||
aliases:
|
||||
- ipv4
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
ipv4addr:
|
||||
description:
|
||||
- Configures the IPv4 address for the host record. Users can dynamically
|
||||
allocate ipv4 address to host record by passing dictionary containing,
|
||||
I(nios_next_ip) and I(CIDR network range). If user wants to add or
|
||||
remove the ipv4 address from existing record, I(add/remove)
|
||||
params need to be used. See examples
|
||||
required: true
|
||||
aliases:
|
||||
- address
|
||||
type: str
|
||||
configure_for_dhcp:
|
||||
description:
|
||||
- Configure the host_record over DHCP instead of DNS, if user
|
||||
changes it to true, user need to mention MAC address to configure
|
||||
required: false
|
||||
aliases:
|
||||
- dhcp
|
||||
type: bool
|
||||
mac:
|
||||
description:
|
||||
- Configures the hardware MAC address for the host record. If user makes
|
||||
DHCP to true, user need to mention MAC address.
|
||||
required: false
|
||||
type: str
|
||||
add:
|
||||
description:
|
||||
- If user wants to add the ipv4 address to an existing host record.
|
||||
Note that with I(add) user will have to keep the I(state) as I(present),
|
||||
as new IP address is allocated to existing host record. See examples.
|
||||
type: bool
|
||||
required: false
|
||||
version_added: '0.2.0'
|
||||
remove:
|
||||
description:
|
||||
- If user wants to remove the ipv4 address from an existing host record.
|
||||
Note that with I(remove) user will have to change the I(state) to I(absent),
|
||||
as IP address is de-allocated from an existing host record. See examples.
|
||||
type: bool
|
||||
required: false
|
||||
version_added: '0.2.0'
|
||||
ipv6addrs:
|
||||
description:
|
||||
- Configures the IPv6 addresses for the host record. This argument
|
||||
accepts a list of values (see options)
|
||||
aliases:
|
||||
- ipv6
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
ipv6addr:
|
||||
description:
|
||||
- Configures the IPv6 address for the host record
|
||||
required: true
|
||||
aliases:
|
||||
- address
|
||||
type: str
|
||||
configure_for_dhcp:
|
||||
description:
|
||||
- Configure the host_record over DHCP instead of DNS, if user
|
||||
changes it to true, user need to mention MAC address to configure
|
||||
required: false
|
||||
type: bool
|
||||
mac:
|
||||
description:
|
||||
- Configures the hardware MAC address for the host record. If user makes
|
||||
DHCP to true, user need to mention MAC address.
|
||||
required: false
|
||||
type: str
|
||||
aliases:
|
||||
description:
|
||||
- Configures an optional list of additional aliases to add to the host
|
||||
record. These are equivalent to CNAMEs but held within a host
|
||||
record. Must be in list format.
|
||||
type: list
|
||||
elements: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this host record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure an ipv4 host record
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
aliases:
|
||||
- cname.ansible.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Add a comment to an existing host record
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove a host record from the system
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update an ipv4 host record
|
||||
community.general.nios_host_record:
|
||||
name: {new_name: host-new.ansible.com, old_name: host.ansible.com}
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Create an ipv4 host record bypassing DNS
|
||||
community.general.nios_host_record:
|
||||
name: new_host
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
dns: false
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Create an ipv4 host record over DHCP
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
dhcp: true
|
||||
mac: 00-80-C8-E3-4C-BD
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Dynamically add host record to next available ip
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: {nios_next_ip: 192.168.10.0/24}
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Add ip to host record
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: 192.168.10.2
|
||||
add: true
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove ip to host record
|
||||
community.general.nios_host_record:
|
||||
name: host.ansible.com
|
||||
ipv4:
|
||||
- address: 192.168.10.1
|
||||
remove: true
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_HOST_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def ipaddr(module, key, filtered_keys=None):
|
||||
''' Transforms the input value into a struct supported by WAPI
|
||||
This function will transform the input from the playbook into a struct
|
||||
that is valid for WAPI in the form of:
|
||||
{
|
||||
ipv4addr: <value>,
|
||||
mac: <value>
|
||||
}
|
||||
This function does not validate the values are properly formatted or in
|
||||
the acceptable range, that is left to WAPI.
|
||||
'''
|
||||
filtered_keys = filtered_keys or list()
|
||||
objects = list()
|
||||
for item in module.params[key]:
|
||||
objects.append(dict([(k, v) for k, v in iteritems(item) if v is not None and k not in filtered_keys]))
|
||||
return objects
|
||||
|
||||
|
||||
def ipv4addrs(module):
|
||||
return ipaddr(module, 'ipv4addrs', filtered_keys=['address', 'dhcp'])
|
||||
|
||||
|
||||
def ipv6addrs(module):
|
||||
return ipaddr(module, 'ipv6addrs', filtered_keys=['address', 'dhcp'])
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
ipv4addr_spec = dict(
|
||||
ipv4addr=dict(required=True, aliases=['address']),
|
||||
configure_for_dhcp=dict(type='bool', required=False, aliases=['dhcp']),
|
||||
mac=dict(required=False),
|
||||
add=dict(type='bool', required=False),
|
||||
remove=dict(type='bool', required=False)
|
||||
)
|
||||
|
||||
ipv6addr_spec = dict(
|
||||
ipv6addr=dict(required=True, aliases=['address']),
|
||||
configure_for_dhcp=dict(type='bool', required=False),
|
||||
mac=dict(required=False)
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
ipv4addrs=dict(type='list', aliases=['ipv4'], elements='dict', options=ipv4addr_spec, transform=ipv4addrs),
|
||||
ipv6addrs=dict(type='list', aliases=['ipv6'], elements='dict', options=ipv6addr_spec, transform=ipv6addrs),
|
||||
configure_for_dns=dict(type='bool', default=True, required=False, aliases=['dns'], ib_req=True),
|
||||
aliases=dict(type='list', elements='str'),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_HOST_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,574 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_member
|
||||
author: "Krishna Vasudevan (@krisvasudevan)"
|
||||
short_description: Configure Infoblox NIOS members
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_member
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes Infoblox NIOS servers. This module manages NIOS C(member) objects using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
host_name:
|
||||
description:
|
||||
- Specifies the host name of the member to either add or remove from
|
||||
the NIOS instance.
|
||||
required: true
|
||||
aliases:
|
||||
- name
|
||||
type: str
|
||||
vip_setting:
|
||||
description:
|
||||
- Configures the network settings for the grid member.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- The IPv4 Address of the Grid Member
|
||||
type: str
|
||||
subnet_mask:
|
||||
description:
|
||||
- The subnet mask for the Grid Member
|
||||
type: str
|
||||
gateway:
|
||||
description:
|
||||
- The default gateway for the Grid Member
|
||||
type: str
|
||||
ipv6_setting:
|
||||
description:
|
||||
- Configures the IPv6 settings for the grid member.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
virtual_ip:
|
||||
description:
|
||||
- The IPv6 Address of the Grid Member
|
||||
type: str
|
||||
cidr_prefix:
|
||||
description:
|
||||
- The IPv6 CIDR prefix for the Grid Member
|
||||
type: int
|
||||
gateway:
|
||||
description:
|
||||
- The gateway address for the Grid Member
|
||||
type: str
|
||||
config_addr_type:
|
||||
description:
|
||||
- Address configuration type (IPV4/IPV6/BOTH)
|
||||
default: IPV4
|
||||
type: str
|
||||
comment:
|
||||
description:
|
||||
- A descriptive comment of the Grid member.
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Extensible attributes associated with the object.
|
||||
type: dict
|
||||
enable_ha:
|
||||
description:
|
||||
- If set to True, the member has two physical nodes (HA pair).
|
||||
type: bool
|
||||
default: false
|
||||
router_id:
|
||||
description:
|
||||
- Virtual router identifier. Provide this ID if "ha_enabled" is set to "true". This is a unique VRID number (from 1 to 255) for the local subnet.
|
||||
type: int
|
||||
lan2_enabled:
|
||||
description:
|
||||
- When set to "true", the LAN2 port is enabled as an independent port or as a port for failover purposes.
|
||||
type: bool
|
||||
default: false
|
||||
lan2_port_setting:
|
||||
description:
|
||||
- Settings for the Grid member LAN2 port if 'lan2_enabled' is set to "true".
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
enabled:
|
||||
description:
|
||||
- If set to True, then it has its own IP settings.
|
||||
type: bool
|
||||
network_setting:
|
||||
description:
|
||||
- If the 'enable' field is set to True, this defines IPv4 network settings for LAN2.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- The IPv4 Address of LAN2
|
||||
type: str
|
||||
subnet_mask:
|
||||
description:
|
||||
- The subnet mask of LAN2
|
||||
type: str
|
||||
gateway:
|
||||
description:
|
||||
- The default gateway of LAN2
|
||||
type: str
|
||||
v6_network_setting:
|
||||
description:
|
||||
- If the 'enable' field is set to True, this defines IPv6 network settings for LAN2.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
virtual_ip:
|
||||
description:
|
||||
- The IPv6 Address of LAN2
|
||||
type: str
|
||||
cidr_prefix:
|
||||
description:
|
||||
- The IPv6 CIDR prefix of LAN2
|
||||
type: int
|
||||
gateway:
|
||||
description:
|
||||
- The gateway address of LAN2
|
||||
type: str
|
||||
platform:
|
||||
description:
|
||||
- Configures the Hardware Platform.
|
||||
default: INFOBLOX
|
||||
type: str
|
||||
node_info:
|
||||
description:
|
||||
- Configures the node information list with detailed status report on the operations of the Grid Member.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
lan2_physical_setting:
|
||||
description:
|
||||
- Physical port settings for the LAN2 interface.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
auto_port_setting_enabled:
|
||||
description:
|
||||
- Enable or disalbe the auto port setting.
|
||||
type: bool
|
||||
duplex:
|
||||
description:
|
||||
- The port duplex; if speed is 1000, duplex must be FULL.
|
||||
type: str
|
||||
speed:
|
||||
description:
|
||||
- The port speed; if speed is 1000, duplex is FULL.
|
||||
type: str
|
||||
lan_ha_port_setting:
|
||||
description:
|
||||
- LAN/HA port settings for the node.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
ha_ip_address:
|
||||
description:
|
||||
- HA IP address.
|
||||
type: str
|
||||
ha_port_setting:
|
||||
description:
|
||||
- Physical port settings for the HA interface.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
auto_port_setting_enabled:
|
||||
description:
|
||||
- Enable or disalbe the auto port setting.
|
||||
type: bool
|
||||
duplex:
|
||||
description:
|
||||
- The port duplex; if speed is 1000, duplex must be FULL.
|
||||
type: str
|
||||
speed:
|
||||
description:
|
||||
- The port speed; if speed is 1000, duplex is FULL.
|
||||
type: str
|
||||
lan_port_setting:
|
||||
description:
|
||||
- Physical port settings for the LAN interface.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
auto_port_setting_enabled:
|
||||
description:
|
||||
- Enable or disalbe the auto port setting.
|
||||
type: bool
|
||||
duplex:
|
||||
description:
|
||||
- The port duplex; if speed is 1000, duplex must be FULL.
|
||||
type: str
|
||||
speed:
|
||||
description:
|
||||
- The port speed; if speed is 1000, duplex is FULL.
|
||||
type: str
|
||||
mgmt_ipv6addr:
|
||||
description:
|
||||
- Public IPv6 address for the LAN1 interface.
|
||||
type: str
|
||||
mgmt_lan:
|
||||
description:
|
||||
- Public IPv4 address for the LAN1 interface.
|
||||
type: str
|
||||
mgmt_network_setting:
|
||||
description:
|
||||
- Network settings for the MGMT port of the node.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- The IPv4 Address of MGMT
|
||||
type: str
|
||||
subnet_mask:
|
||||
description:
|
||||
- The subnet mask of MGMT
|
||||
type: str
|
||||
gateway:
|
||||
description:
|
||||
- The default gateway of MGMT
|
||||
type: str
|
||||
v6_mgmt_network_setting:
|
||||
description:
|
||||
- The network settings for the IPv6 MGMT port of the node.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
virtual_ip:
|
||||
description:
|
||||
- The IPv6 Address of MGMT
|
||||
type: str
|
||||
cidr_prefix:
|
||||
description:
|
||||
- The IPv6 CIDR prefix of MGMT
|
||||
type: int
|
||||
gateway:
|
||||
description:
|
||||
- The gateway address of MGMT
|
||||
type: str
|
||||
mgmt_port_setting:
|
||||
description:
|
||||
- Settings for the member MGMT port.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
enabled:
|
||||
description:
|
||||
- Determines if MGMT port settings should be enabled.
|
||||
type: bool
|
||||
security_access_enabled:
|
||||
description:
|
||||
- Determines if security access on the MGMT port is enabled or not.
|
||||
type: bool
|
||||
vpn_enabled:
|
||||
description:
|
||||
- Determines if VPN on the MGMT port is enabled or not.
|
||||
type: bool
|
||||
upgrade_group:
|
||||
description:
|
||||
- The name of the upgrade group to which this Grid member belongs.
|
||||
default: Default
|
||||
type: str
|
||||
use_syslog_proxy_setting:
|
||||
description:
|
||||
- Use flag for external_syslog_server_enable , syslog_servers, syslog_proxy_setting, syslog_size
|
||||
type: bool
|
||||
external_syslog_server_enable:
|
||||
description:
|
||||
- Determines if external syslog servers should be enabled
|
||||
type: bool
|
||||
syslog_servers:
|
||||
description:
|
||||
- The list of external syslog servers.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- The server address.
|
||||
type: str
|
||||
category_list:
|
||||
description:
|
||||
- The list of all syslog logging categories.
|
||||
type: list
|
||||
elements: str
|
||||
connection_type:
|
||||
description:
|
||||
- The connection type for communicating with this server.(STCP/TCP?UDP)
|
||||
default: UDP
|
||||
type: str
|
||||
local_interface:
|
||||
description:
|
||||
- The local interface through which the appliance sends syslog messages to the syslog server.(ANY/LAN/MGMT)
|
||||
default: ANY
|
||||
type: str
|
||||
message_node_id:
|
||||
description:
|
||||
- Identify the node in the syslog message. (HOSTNAME/IP_HOSTNAME/LAN/MGMT)
|
||||
default: LAN
|
||||
type: str
|
||||
message_source:
|
||||
description:
|
||||
- The source of syslog messages to be sent to the external syslog server.
|
||||
default: ANY
|
||||
type: str
|
||||
only_category_list:
|
||||
description:
|
||||
- The list of selected syslog logging categories. The appliance forwards syslog messages that belong to the selected categories.
|
||||
type: bool
|
||||
port:
|
||||
description:
|
||||
- The port this server listens on.
|
||||
default: 514
|
||||
type: int
|
||||
severity:
|
||||
description:
|
||||
- The severity filter. The appliance sends log messages of the specified severity and above to the external syslog server.
|
||||
default: DEBUG
|
||||
type: str
|
||||
pre_provisioning:
|
||||
description:
|
||||
- Pre-provisioning information.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
hardware_info:
|
||||
description:
|
||||
- An array of structures that describe the hardware being pre-provisioned.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
hwmodel:
|
||||
description:
|
||||
- Hardware model
|
||||
type: str
|
||||
hwtype:
|
||||
description:
|
||||
- Hardware type.
|
||||
type: str
|
||||
licenses:
|
||||
description:
|
||||
- An array of license types.
|
||||
type: list
|
||||
elements: str
|
||||
create_token:
|
||||
description:
|
||||
- Flag for initiating a create token request for pre-provisioned members.
|
||||
type: bool
|
||||
default: False
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Add a member to the grid with IPv4 address
|
||||
community.general.nios_member:
|
||||
host_name: member01.localdomain
|
||||
vip_setting:
|
||||
- address: 192.168.1.100
|
||||
subnet_mask: 255.255.255.0
|
||||
gateway: 192.168.1.1
|
||||
config_addr_type: IPV4
|
||||
platform: VNIOS
|
||||
comment: "Created by Ansible"
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Add a HA member to the grid
|
||||
community.general.nios_member:
|
||||
host_name: memberha.localdomain
|
||||
vip_setting:
|
||||
- address: 192.168.1.100
|
||||
subnet_mask: 255.255.255.0
|
||||
gateway: 192.168.1.1
|
||||
config_addr_type: IPV4
|
||||
platform: VNIOS
|
||||
enable_ha: true
|
||||
router_id: 150
|
||||
node_info:
|
||||
- lan_ha_port_setting:
|
||||
- ha_ip_address: 192.168.1.70
|
||||
mgmt_lan: 192.168.1.80
|
||||
- lan_ha_port_setting:
|
||||
- ha_ip_address: 192.168.1.71
|
||||
mgmt_lan: 192.168.1.81
|
||||
comment: "Created by Ansible"
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update the member with pre-provisioning details specified
|
||||
community.general.nios_member:
|
||||
name: member01.localdomain
|
||||
pre_provisioning:
|
||||
- hardware_info:
|
||||
- hwmodel: IB-VM-820
|
||||
hwtype: IB-VNIOS
|
||||
licenses:
|
||||
- dns
|
||||
- dhcp
|
||||
- enterprise
|
||||
- vnios
|
||||
comment: "Updated by Ansible"
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove the member
|
||||
community.general.nios_member:
|
||||
name: member01.localdomain
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_MEMBER
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
ipv4_spec = dict(
|
||||
address=dict(),
|
||||
subnet_mask=dict(),
|
||||
gateway=dict(),
|
||||
)
|
||||
|
||||
ipv6_spec = dict(
|
||||
virtual_ip=dict(),
|
||||
cidr_prefix=dict(type='int'),
|
||||
gateway=dict(),
|
||||
)
|
||||
|
||||
port_spec = dict(
|
||||
auto_port_setting_enabled=dict(type='bool'),
|
||||
duplex=dict(),
|
||||
speed=dict(),
|
||||
)
|
||||
|
||||
lan2_port_spec = dict(
|
||||
enabled=dict(type='bool'),
|
||||
network_setting=dict(type='list', elements='dict', options=ipv4_spec),
|
||||
v6_network_setting=dict(type='list', elements='dict', options=ipv6_spec),
|
||||
)
|
||||
|
||||
ha_port_spec = dict(
|
||||
ha_ip_address=dict(),
|
||||
ha_port_setting=dict(type='list', elements='dict', options=port_spec),
|
||||
lan_port_setting=dict(type='list', elements='dict', options=port_spec),
|
||||
mgmt_lan=dict(),
|
||||
mgmt_ipv6addr=dict(),
|
||||
)
|
||||
|
||||
node_spec = dict(
|
||||
lan2_physical_setting=dict(type='list', elements='dict', options=port_spec),
|
||||
lan_ha_port_setting=dict(type='list', elements='dict', options=ha_port_spec),
|
||||
mgmt_network_setting=dict(type='list', elements='dict', options=ipv4_spec),
|
||||
v6_mgmt_network_setting=dict(type='list', elements='dict', options=ipv6_spec),
|
||||
)
|
||||
|
||||
mgmt_port_spec = dict(
|
||||
enabled=dict(type='bool'),
|
||||
security_access_enabled=dict(type='bool'),
|
||||
vpn_enabled=dict(type='bool'),
|
||||
)
|
||||
|
||||
syslog_spec = dict(
|
||||
address=dict(),
|
||||
category_list=dict(type='list', elements='str'),
|
||||
connection_type=dict(default='UDP'),
|
||||
local_interface=dict(default='ANY'),
|
||||
message_node_id=dict(default='LAN'),
|
||||
message_source=dict(default='ANY'),
|
||||
only_category_list=dict(type='bool'),
|
||||
port=dict(type='int', default=514),
|
||||
severity=dict(default='DEBUG'),
|
||||
)
|
||||
|
||||
hw_spec = dict(
|
||||
hwmodel=dict(),
|
||||
hwtype=dict(),
|
||||
)
|
||||
|
||||
pre_prov_spec = dict(
|
||||
hardware_info=dict(type='list', elements='dict', options=hw_spec),
|
||||
licenses=dict(type='list', elements='str'),
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
host_name=dict(required=True, aliases=['name'], ib_req=True),
|
||||
vip_setting=dict(type='list', elements='dict', options=ipv4_spec),
|
||||
ipv6_setting=dict(type='list', elements='dict', options=ipv6_spec),
|
||||
config_addr_type=dict(default='IPV4'),
|
||||
comment=dict(),
|
||||
enable_ha=dict(type='bool', default=False),
|
||||
router_id=dict(type='int'),
|
||||
lan2_enabled=dict(type='bool', default=False),
|
||||
lan2_port_setting=dict(type='list', elements='dict', options=lan2_port_spec),
|
||||
platform=dict(default='INFOBLOX'),
|
||||
node_info=dict(type='list', elements='dict', options=node_spec),
|
||||
mgmt_port_setting=dict(type='list', elements='dict', options=mgmt_port_spec),
|
||||
upgrade_group=dict(default='Default'),
|
||||
use_syslog_proxy_setting=dict(type='bool'),
|
||||
external_syslog_server_enable=dict(type='bool'),
|
||||
syslog_servers=dict(type='list', elements='dict', options=syslog_spec),
|
||||
pre_provisioning=dict(type='list', elements='dict', options=pre_prov_spec),
|
||||
extattrs=dict(type='dict'),
|
||||
create_token=dict(type='bool', default=False),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_MEMBER, ib_spec)
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,163 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_mx_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS MX records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_mx_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of MX record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:mx) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this a record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
mail_exchanger:
|
||||
description:
|
||||
- Configures the mail exchanger FQDN for this MX record.
|
||||
aliases:
|
||||
- mx
|
||||
type: str
|
||||
preference:
|
||||
description:
|
||||
- Configures the preference (0-65535) for this MX record.
|
||||
type: int
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this host record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure an MX record
|
||||
community.general.nios_mx_record:
|
||||
name: ansible.com
|
||||
mx: mailhost.ansible.com
|
||||
preference: 0
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing MX record
|
||||
community.general.nios_mx_record:
|
||||
name: ansible.com
|
||||
mx: mailhost.ansible.com
|
||||
preference: 0
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove an MX record from the system
|
||||
community.general.nios_mx_record:
|
||||
name: ansible.com
|
||||
mx: mailhost.ansible.com
|
||||
preference: 0
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_MX_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
mail_exchanger=dict(aliases=['mx'], ib_req=True),
|
||||
preference=dict(type='int', ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_MX_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,200 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_naptr_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS NAPTR records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_naptr_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of NAPTR record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:naptr) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox_client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this a record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
order:
|
||||
description:
|
||||
- Configures the order (0-65535) for this NAPTR record. This parameter
|
||||
specifies the order in which the NAPTR rules are applied when
|
||||
multiple rules are present.
|
||||
type: int
|
||||
preference:
|
||||
description:
|
||||
- Configures the preference (0-65535) for this NAPTR record. The
|
||||
preference field determines the order NAPTR records are processed
|
||||
when multiple records with the same order parameter are present.
|
||||
type: int
|
||||
replacement:
|
||||
description:
|
||||
- Configures the replacement field for this NAPTR record.
|
||||
For nonterminal NAPTR records, this field specifies the
|
||||
next domain name to look up.
|
||||
type: str
|
||||
services:
|
||||
description:
|
||||
- Configures the services field (128 characters maximum) for this
|
||||
NAPTR record. The services field contains protocol and service
|
||||
identifiers, such as "http+E2U" or "SIPS+D2T".
|
||||
required: false
|
||||
type: str
|
||||
flags:
|
||||
description:
|
||||
- Configures the flags field for this NAPTR record. These control the
|
||||
interpretation of the fields for an NAPTR record object. Supported
|
||||
values for the flags field are "U", "S", "P" and "A".
|
||||
required: false
|
||||
type: str
|
||||
regexp:
|
||||
description:
|
||||
- Configures the regexp field for this NAPTR record. This is the
|
||||
regular expression-based rewriting rule of the NAPTR record. This
|
||||
should be a POSIX compliant regular expression, including the
|
||||
substitution rule and flags. Refer to RFC 2915 for the field syntax
|
||||
details.
|
||||
required: false
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this NAPTR record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a NAPTR record
|
||||
community.general.nios_naptr_record:
|
||||
name: '*.subscriber-100.ansiblezone.com'
|
||||
order: 1000
|
||||
preference: 10
|
||||
replacement: replacement1.network.ansiblezone.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing NAPTR record
|
||||
community.general.nios_naptr_record:
|
||||
name: '*.subscriber-100.ansiblezone.com'
|
||||
order: 1000
|
||||
preference: 10
|
||||
replacement: replacement1.network.ansiblezone.com
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove a NAPTR record from the system
|
||||
community.general.nios_naptr_record:
|
||||
name: '*.subscriber-100.ansiblezone.com'
|
||||
order: 1000
|
||||
preference: 10
|
||||
replacement: replacement1.network.ansiblezone.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
order=dict(type='int', ib_req=True),
|
||||
preference=dict(type='int', ib_req=True),
|
||||
replacement=dict(ib_req=True),
|
||||
services=dict(),
|
||||
flags=dict(),
|
||||
regexp=dict(),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run('record:naptr', ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,334 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_network
|
||||
author: "Peter Sprygada (@privateip)"
|
||||
short_description: Configure Infoblox NIOS network object
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_network
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of network objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(network) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
- Supports both IPV4 and IPV6 internet protocols
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
network:
|
||||
description:
|
||||
- Specifies the network to add or remove from the system. The value
|
||||
should use CIDR notation.
|
||||
required: true
|
||||
aliases:
|
||||
- name
|
||||
- cidr
|
||||
type: str
|
||||
network_view:
|
||||
description:
|
||||
- Configures the name of the network view to associate with this
|
||||
configured instance.
|
||||
default: default
|
||||
type: str
|
||||
options:
|
||||
description:
|
||||
- Configures the set of DHCP options to be included as part of
|
||||
the configured network instance. This argument accepts a list
|
||||
of values (see suboptions). When configuring suboptions at
|
||||
least one of C(name) or C(num) must be specified.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- The name of the DHCP option to configure. The standard options are
|
||||
C(router), C(router-templates), C(domain-name-servers), C(domain-name),
|
||||
C(broadcast-address), C(broadcast-address-offset), C(dhcp-lease-time),
|
||||
and C(dhcp6.name-servers).
|
||||
type: str
|
||||
num:
|
||||
description:
|
||||
- The number of the DHCP option to configure
|
||||
type: int
|
||||
value:
|
||||
description:
|
||||
- The value of the DHCP option specified by C(name)
|
||||
required: true
|
||||
type: str
|
||||
use_option:
|
||||
description:
|
||||
- Only applies to a subset of options (see NIOS API documentation)
|
||||
type: bool
|
||||
default: 'yes'
|
||||
vendor_class:
|
||||
description:
|
||||
- The name of the space this DHCP option is associated to
|
||||
default: DHCP
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
container:
|
||||
description:
|
||||
- If set to true it'll create the network container to be added or removed
|
||||
from the system.
|
||||
type: bool
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a network ipv4
|
||||
community.general.nios_network:
|
||||
network: 192.168.10.0/24
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a network ipv6
|
||||
community.general.nios_network:
|
||||
network: fe80::/64
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Set dhcp options for a network ipv4
|
||||
community.general.nios_network:
|
||||
network: 192.168.10.0/24
|
||||
comment: this is a test comment
|
||||
options:
|
||||
- name: domain-name
|
||||
value: ansible.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove a network ipv4
|
||||
community.general.nios_network:
|
||||
network: 192.168.10.0/24
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a ipv4 network container
|
||||
community.general.nios_network:
|
||||
network: 192.168.10.0/24
|
||||
container: true
|
||||
comment: test network container
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a ipv6 network container
|
||||
community.general.nios_network:
|
||||
network: fe80::/64
|
||||
container: true
|
||||
comment: test network container
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove a ipv4 network container
|
||||
community.general.nios_network:
|
||||
networkr: 192.168.10.0/24
|
||||
container: true
|
||||
comment: test network container
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
import socket
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_IPV4_NETWORK, NIOS_IPV6_NETWORK
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_IPV4_NETWORK_CONTAINER, NIOS_IPV6_NETWORK_CONTAINER
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
# The following function validate_ip_address has been taken from
|
||||
# https://github.com/ansible-collections/ansible.netcommon/blob/20124ecbb420daa0f5bb9cdaa865a952657aa0e7/plugins/module_utils/network/common/utils.py#L496
|
||||
# The code there is licensed under BSD 2-clause.
|
||||
# Copyright (c) 2016 Red Hat Inc.
|
||||
def validate_ip_address(address):
|
||||
try:
|
||||
socket.inet_aton(address)
|
||||
except socket.error:
|
||||
return False
|
||||
return address.count(".") == 3
|
||||
|
||||
|
||||
# The following function validate_ip_v6_address has been taken from
|
||||
# https://github.com/ansible-collections/ansible.netcommon/blob/20124ecbb420daa0f5bb9cdaa865a952657aa0e7/plugins/module_utils/network/common/utils.py#L504
|
||||
# The code there is licensed under BSD 2-clause.
|
||||
# Copyright (c) 2016 Red Hat Inc.
|
||||
def validate_ip_v6_address(address):
|
||||
try:
|
||||
socket.inet_pton(socket.AF_INET6, address)
|
||||
except socket.error:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def options(module):
|
||||
''' Transforms the module argument into a valid WAPI struct
|
||||
This function will transform the options argument into a structure that
|
||||
is a valid WAPI structure in the format of:
|
||||
{
|
||||
name: <value>,
|
||||
num: <value>,
|
||||
value: <value>,
|
||||
use_option: <value>,
|
||||
vendor_class: <value>
|
||||
}
|
||||
It will remove any options that are set to None since WAPI will error on
|
||||
that condition. It will also verify that either `name` or `num` is
|
||||
set in the structure but does not validate the values are equal.
|
||||
The remainder of the value validation is performed by WAPI
|
||||
'''
|
||||
options = list()
|
||||
for item in module.params['options']:
|
||||
opt = dict([(k, v) for k, v in iteritems(item) if v is not None])
|
||||
if 'name' not in opt and 'num' not in opt:
|
||||
module.fail_json(msg='one of `name` or `num` is required for option value')
|
||||
options.append(opt)
|
||||
return options
|
||||
|
||||
|
||||
def check_ip_addr_type(obj_filter, ib_spec):
|
||||
'''This function will check if the argument ip is type v4/v6 and return appropriate infoblox
|
||||
network/networkcontainer type
|
||||
'''
|
||||
|
||||
ip = obj_filter['network']
|
||||
if 'container' in obj_filter and obj_filter['container']:
|
||||
check_ip = ip.split('/')
|
||||
del ib_spec['container'] # removing the container key from post arguments
|
||||
del ib_spec['options'] # removing option argument as for network container it's not supported
|
||||
if validate_ip_address(check_ip[0]):
|
||||
return NIOS_IPV4_NETWORK_CONTAINER, ib_spec
|
||||
elif validate_ip_v6_address(check_ip[0]):
|
||||
return NIOS_IPV6_NETWORK_CONTAINER, ib_spec
|
||||
else:
|
||||
check_ip = ip.split('/')
|
||||
del ib_spec['container'] # removing the container key from post arguments
|
||||
if validate_ip_address(check_ip[0]):
|
||||
return NIOS_IPV4_NETWORK, ib_spec
|
||||
elif validate_ip_v6_address(check_ip[0]):
|
||||
return NIOS_IPV6_NETWORK, ib_spec
|
||||
|
||||
|
||||
def check_vendor_specific_dhcp_option(module, ib_spec):
|
||||
'''This function will check if the argument dhcp option belongs to vendor-specific and if yes then will remove
|
||||
use_options flag which is not supported with vendor-specific dhcp options.
|
||||
'''
|
||||
for key, value in iteritems(ib_spec):
|
||||
if isinstance(module.params[key], list):
|
||||
temp_dict = module.params[key][0]
|
||||
if 'num' in temp_dict:
|
||||
if temp_dict['num'] in (43, 124, 125):
|
||||
del module.params[key][0]['use_option']
|
||||
return ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
option_spec = dict(
|
||||
# one of name or num is required; enforced by the function options()
|
||||
name=dict(),
|
||||
num=dict(type='int'),
|
||||
|
||||
value=dict(required=True),
|
||||
|
||||
use_option=dict(type='bool', default=True),
|
||||
vendor_class=dict(default='DHCP')
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
network=dict(required=True, aliases=['name', 'cidr'], ib_req=True),
|
||||
network_view=dict(default='default', ib_req=True),
|
||||
|
||||
options=dict(type='list', elements='dict', options=option_spec, transform=options),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
container=dict(type='bool', ib_req=True)
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
# to get the argument ipaddr
|
||||
obj_filter = dict([(k, module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')])
|
||||
network_type, ib_spec = check_ip_addr_type(obj_filter, ib_spec)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
# to check for vendor specific dhcp option
|
||||
ib_spec = check_vendor_specific_dhcp_option(module, ib_spec)
|
||||
|
||||
result = wapi.run(network_type, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,138 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_network_view
|
||||
author: "Peter Sprygada (@privateip)"
|
||||
short_description: Configure Infoblox NIOS network views
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_network_view
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of network view objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(networkview) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
- Updates instances of network view object from Infoblox NIOS servers.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system. User can also update the hostname as it is possible
|
||||
to pass a dict containing I(new_name), I(old_name). See examples.
|
||||
required: true
|
||||
aliases:
|
||||
- network_view
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a new network view
|
||||
community.general.nios_network_view:
|
||||
name: ansible
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update the comment for network view
|
||||
community.general.nios_network_view:
|
||||
name: ansible
|
||||
comment: this is an example comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove the network view
|
||||
community.general.nios_network_view:
|
||||
name: ansible
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update a existing network view
|
||||
community.general.nios_network_view:
|
||||
name: {new_name: ansible-new, old_name: ansible}
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_NETWORK_VIEW
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, aliases=['network_view'], ib_req=True),
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_NETWORK_VIEW, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,446 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: nios_nsgroup
|
||||
short_description: Configure InfoBlox DNS Nameserver Groups
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_nsgroup
|
||||
removed_in: 5.0.0
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
author:
|
||||
- Erich Birngruber (@ebirn)
|
||||
- Sumit Jaiswal (@sjaiswal)
|
||||
description:
|
||||
- Adds and/or removes nameserver groups form Infoblox NIOS servers.
|
||||
This module manages NIOS C(nsgroup) objects using the Infoblox. WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox_client
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the name of the NIOS nameserver group to be managed.
|
||||
required: true
|
||||
type: str
|
||||
grid_primary:
|
||||
description:
|
||||
- This host is to be used as primary server in this nameserver group. It must be a grid member.
|
||||
This option is required when setting I(use_external_primaries) to C(false).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- Provide the name of the grid member to identify the host.
|
||||
required: true
|
||||
type: str
|
||||
enable_preferred_primaries:
|
||||
description:
|
||||
- This flag represents whether the preferred_primaries field values of this member are used (see Infoblox WAPI docs).
|
||||
default: false
|
||||
type: bool
|
||||
grid_replicate:
|
||||
description:
|
||||
- Use DNS zone transfers if set to C(True) or ID Grid Replication if set to C(False).
|
||||
type: bool
|
||||
default: false
|
||||
lead:
|
||||
description:
|
||||
- This flag controls if the grid lead secondary nameserver performs zone transfers to non lead secondaries.
|
||||
type: bool
|
||||
default: false
|
||||
stealth:
|
||||
description:
|
||||
- Configure the external nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
preferred_primaries:
|
||||
description:
|
||||
- Provide a list of elements like in I(external_primaries) to set the precedence of preferred primary nameservers.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- Configures the IP address of the preferred primary nameserver.
|
||||
required: true
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Set a label for the preferred primary nameserver.
|
||||
required: true
|
||||
type: str
|
||||
stealth:
|
||||
description:
|
||||
- Configure the preferred primary nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
tsig_key_name:
|
||||
description:
|
||||
- Sets a label for the I(tsig_key) value.
|
||||
required: true
|
||||
type: str
|
||||
tsig_key_alg:
|
||||
description:
|
||||
- Provides the algorithm used for the I(tsig_key) in use.
|
||||
choices: ['HMAC-MD5', 'HMAC-SHA256']
|
||||
default: 'HMAC-MD5'
|
||||
type: str
|
||||
tsig_key:
|
||||
description:
|
||||
- Set a DNS TSIG key for the nameserver to secure zone transfers (AFXRs).
|
||||
type: str
|
||||
grid_secondaries:
|
||||
description:
|
||||
- Configures the list of grid member hosts that act as secondary nameservers.
|
||||
This option is required when setting I(use_external_primaries) to C(true).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- Provide the name of the grid member to identify the host.
|
||||
required: true
|
||||
type: str
|
||||
enable_preferred_primaries:
|
||||
description:
|
||||
- This flag represents whether the preferred_primaries field values of this member are used (see Infoblox WAPI docs).
|
||||
default: false
|
||||
type: bool
|
||||
grid_replicate:
|
||||
description:
|
||||
- Use DNS zone transfers if set to C(True) or ID Grid Replication if set to C(False)
|
||||
type: bool
|
||||
default: false
|
||||
lead:
|
||||
description:
|
||||
- This flag controls if the grid lead secondary nameserver performs zone transfers to non lead secondaries.
|
||||
type: bool
|
||||
default: false
|
||||
stealth:
|
||||
description:
|
||||
- Configure the external nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
preferred_primaries:
|
||||
description:
|
||||
- Provide a list of elements like in I(external_primaries) to set the precedence of preferred primary nameservers.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- Configures the IP address of the preferred primary nameserver.
|
||||
required: true
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Set a label for the preferred primary nameserver.
|
||||
required: true
|
||||
type: str
|
||||
stealth:
|
||||
description:
|
||||
- Configure the preferred primary nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
tsig_key_name:
|
||||
description:
|
||||
- Sets a label for the I(tsig_key) value.
|
||||
type: str
|
||||
required: true
|
||||
tsig_key_alg:
|
||||
description:
|
||||
- Provides the algorithm used for the I(tsig_key) in use.
|
||||
choices: ['HMAC-MD5', 'HMAC-SHA256']
|
||||
default: 'HMAC-MD5'
|
||||
type: str
|
||||
tsig_key:
|
||||
description:
|
||||
- Set a DNS TSIG key for the nameserver to secure zone transfers (AFXRs).
|
||||
type: str
|
||||
is_grid_default:
|
||||
description:
|
||||
- If set to C(True) this nsgroup will become the default nameserver group for new zones.
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
use_external_primary:
|
||||
description:
|
||||
- This flag controls whether the group is using an external primary nameserver.
|
||||
Note that modification of this field requires passing values for I(grid_secondaries) and I(external_primaries).
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
external_primaries:
|
||||
description:
|
||||
- Configures a list of external nameservers (non-members of the grid).
|
||||
This option is required when setting I(use_external_primaries) to C(true).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- Configures the IP address of the external nameserver
|
||||
required: true
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Set a label for the external nameserver
|
||||
required: true
|
||||
type: str
|
||||
stealth:
|
||||
description:
|
||||
- Configure the external nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
tsig_key_name:
|
||||
description:
|
||||
- Sets a label for the I(tsig_key) value
|
||||
type: str
|
||||
required: true
|
||||
tsig_key_alg:
|
||||
description:
|
||||
- Provides the algorithm used for the I(tsig_key) in use.
|
||||
choices: ['HMAC-MD5', 'HMAC-SHA256']
|
||||
default: 'HMAC-MD5'
|
||||
type: str
|
||||
tsig_key:
|
||||
description:
|
||||
- Set a DNS TSIG key for the nameserver to secure zone transfers (AFXRs).
|
||||
type: str
|
||||
required: false
|
||||
external_secondaries:
|
||||
description:
|
||||
- Allows to provide a list of external secondary nameservers, that are not members of the grid.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
address:
|
||||
description:
|
||||
- Configures the IP address of the external nameserver
|
||||
required: true
|
||||
type: str
|
||||
name:
|
||||
description:
|
||||
- Set a label for the external nameserver
|
||||
required: true
|
||||
type: str
|
||||
stealth:
|
||||
description:
|
||||
- Configure the external nameserver as stealth server (without NS record) in the zones.
|
||||
type: bool
|
||||
default: false
|
||||
tsig_key_name:
|
||||
description:
|
||||
- Sets a label for the I(tsig_key) value
|
||||
type: str
|
||||
required: true
|
||||
tsig_key_alg:
|
||||
description:
|
||||
- Provides the algorithm used for the I(tsig_key) in use.
|
||||
choices: ['HMAC-MD5', 'HMAC-SHA256']
|
||||
default: 'HMAC-MD5'
|
||||
type: str
|
||||
tsig_key:
|
||||
description:
|
||||
- Set a DNS TSIG key for the nameserver to secure zone transfers (AFXRs).
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
required: false
|
||||
type: str
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
required: false
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
choices: [present, absent]
|
||||
default: present
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create simple infoblox nameserver group
|
||||
community.general.nios_nsgroup:
|
||||
name: my-simple-group
|
||||
comment: "this is a simple nameserver group"
|
||||
grid_primary:
|
||||
- name: infoblox-test.example.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Create infoblox nameserver group with external primaries
|
||||
community.general.nios_nsgroup:
|
||||
name: my-example-group
|
||||
use_external_primary: true
|
||||
comment: "this is my example nameserver group"
|
||||
external_primaries: "{{ ext_nameservers }}"
|
||||
grid_secondaries:
|
||||
- name: infoblox-test.example.com
|
||||
lead: True
|
||||
preferred_primaries: "{{ ext_nameservers }}"
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Delete infoblox nameserver group
|
||||
community.general.nios_nsgroup:
|
||||
name: my-simple-group
|
||||
comment: "this is a simple nameserver group"
|
||||
grid_primary:
|
||||
- name: infoblox-test.example.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_NSGROUP
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
# from infoblox documentation
|
||||
# Fields List
|
||||
# Field Type Req R/O Base Search
|
||||
# comment String N N Y : = ~
|
||||
# extattrs Extattr N N N ext
|
||||
# external_primaries [struct] N N N N/A
|
||||
# external_secondaries [struct] N N N N/A
|
||||
# grid_primary [struct] N N N N/A
|
||||
# grid_secondaries [struct] N N N N/A
|
||||
# is_grid_default Bool N N N N/A
|
||||
# is_multimaster Bool N Y N N/A
|
||||
# name String Y N Y : = ~
|
||||
# use_external_primary Bool N N N N/A
|
||||
|
||||
|
||||
def main():
|
||||
'''entrypoint for module execution.'''
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent']),
|
||||
)
|
||||
|
||||
# cleanup tsig fields
|
||||
def clean_tsig(ext):
|
||||
if 'tsig_key' in ext and not ext['tsig_key']:
|
||||
del ext['tsig_key']
|
||||
if 'tsig_key' not in ext and 'tsig_key_name' in ext and not ext['tsig_key_name']:
|
||||
del ext['tsig_key_name']
|
||||
if 'tsig_key' not in ext and 'tsig_key_alg' in ext:
|
||||
del ext['tsig_key_alg']
|
||||
|
||||
def clean_grid_member(member):
|
||||
if member['preferred_primaries']:
|
||||
for ext in member['preferred_primaries']:
|
||||
clean_tsig(ext)
|
||||
if member['enable_preferred_primaries'] is False:
|
||||
del member['enable_preferred_primaries']
|
||||
del member['preferred_primaries']
|
||||
if member['lead'] is False:
|
||||
del member['lead']
|
||||
if member['grid_replicate'] is False:
|
||||
del member['grid_replicate']
|
||||
|
||||
def ext_primaries_transform(module):
|
||||
if module.params['external_primaries']:
|
||||
for ext in module.params['external_primaries']:
|
||||
clean_tsig(ext)
|
||||
return module.params['external_primaries']
|
||||
|
||||
def ext_secondaries_transform(module):
|
||||
if module.params['external_secondaries']:
|
||||
for ext in module.params['external_secondaries']:
|
||||
clean_tsig(ext)
|
||||
return module.params['external_secondaries']
|
||||
|
||||
def grid_primary_preferred_transform(module):
|
||||
for member in module.params['grid_primary']:
|
||||
clean_grid_member(member)
|
||||
return module.params['grid_primary']
|
||||
|
||||
def grid_secondaries_preferred_primaries_transform(module):
|
||||
for member in module.params['grid_secondaries']:
|
||||
clean_grid_member(member)
|
||||
return module.params['grid_secondaries']
|
||||
|
||||
extserver_spec = dict(
|
||||
address=dict(required=True),
|
||||
name=dict(required=True),
|
||||
stealth=dict(type='bool', default=False),
|
||||
tsig_key=dict(no_log=True),
|
||||
tsig_key_alg=dict(choices=['HMAC-MD5', 'HMAC-SHA256'], default='HMAC-MD5'),
|
||||
tsig_key_name=dict(required=True)
|
||||
)
|
||||
|
||||
memberserver_spec = dict(
|
||||
name=dict(required=True, ),
|
||||
enable_preferred_primaries=dict(type='bool', default=False),
|
||||
grid_replicate=dict(type='bool', default=False),
|
||||
lead=dict(type='bool', default=False),
|
||||
preferred_primaries=dict(type='list', elements='dict', options=extserver_spec, default=[]),
|
||||
stealth=dict(type='bool', default=False),
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
grid_primary=dict(type='list', elements='dict', options=memberserver_spec,
|
||||
transform=grid_primary_preferred_transform),
|
||||
grid_secondaries=dict(type='list', elements='dict', options=memberserver_spec,
|
||||
transform=grid_secondaries_preferred_primaries_transform),
|
||||
external_primaries=dict(type='list', elements='dict', options=extserver_spec, transform=ext_primaries_transform),
|
||||
external_secondaries=dict(type='list', elements='dict', options=extserver_spec,
|
||||
transform=ext_secondaries_transform),
|
||||
is_grid_default=dict(type='bool', default=False),
|
||||
use_external_primary=dict(type='bool', default=False),
|
||||
extattrs=dict(),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_NSGROUP, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,168 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_ptr_record
|
||||
author: "Trebuchet Clement (@clementtrebuchet)"
|
||||
short_description: Configure Infoblox NIOS PTR records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_ptr_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of PTR record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:ptr) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox_client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The name of the DNS PTR record in FQDN format to add or remove from
|
||||
the system.
|
||||
The field is required only for an PTR object in Forward Mapping Zone.
|
||||
required: false
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this a record with. The DNS
|
||||
view must already be configured on the system
|
||||
required: false
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
ipv4addr:
|
||||
description:
|
||||
- The IPv4 Address of the record. Mutually exclusive with the ipv6addr.
|
||||
aliases:
|
||||
- ipv4
|
||||
type: str
|
||||
ipv6addr:
|
||||
description:
|
||||
- The IPv6 Address of the record. Mutually exclusive with the ipv4addr.
|
||||
aliases:
|
||||
- ipv6
|
||||
type: str
|
||||
ptrdname:
|
||||
description:
|
||||
- The domain name of the DNS PTR record in FQDN format.
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Time To Live (TTL) value for the record.
|
||||
A 32-bit unsigned integer that represents the duration, in seconds, that the record is valid (cached).
|
||||
Zero indicates that the record should not be cached.
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance. Maximum 256 characters.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create a PTR Record
|
||||
community.general.nios_ptr_record:
|
||||
ipv4: 192.168.10.1
|
||||
ptrdname: host.ansible.com
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Delete a PTR Record
|
||||
community.general.nios_ptr_record:
|
||||
ipv4: 192.168.10.1
|
||||
ptrdname: host.ansible.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_PTR_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
# Module entry point
|
||||
ib_spec = dict(
|
||||
name=dict(required=False),
|
||||
view=dict(aliases=['dns_view'], ib_req=True),
|
||||
ipv4addr=dict(aliases=['ipv4'], ib_req=True),
|
||||
ipv6addr=dict(aliases=['ipv6'], ib_req=True),
|
||||
ptrdname=dict(ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
mutually_exclusive = [('ipv4addr', 'ipv6addr')]
|
||||
required_one_of = [
|
||||
['ipv4addr', 'ipv6addr']
|
||||
]
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
mutually_exclusive=mutually_exclusive,
|
||||
supports_check_mode=True,
|
||||
required_one_of=required_one_of)
|
||||
|
||||
if module.params['ipv4addr']:
|
||||
del ib_spec['ipv6addr']
|
||||
elif module.params['ipv6addr']:
|
||||
del ib_spec['ipv4addr']
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_PTR_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,177 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_srv_record
|
||||
author: "Blair Rampling (@brampling)"
|
||||
short_description: Configure Infoblox NIOS SRV records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_srv_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of SRV record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:srv) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this a record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
port:
|
||||
description:
|
||||
- Configures the port (0-65535) of this SRV record.
|
||||
type: int
|
||||
priority:
|
||||
description:
|
||||
- Configures the priority (0-65535) for this SRV record.
|
||||
type: int
|
||||
target:
|
||||
description:
|
||||
- Configures the target FQDN for this SRV record.
|
||||
type: str
|
||||
weight:
|
||||
description:
|
||||
- Configures the weight (0-65535) for this SRV record.
|
||||
type: int
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this host record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure an SRV record
|
||||
community.general.nios_srv_record:
|
||||
name: _sip._tcp.service.ansible.com
|
||||
port: 5080
|
||||
priority: 10
|
||||
target: service1.ansible.com
|
||||
weight: 10
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Add a comment to an existing SRV record
|
||||
community.general.nios_srv_record:
|
||||
name: _sip._tcp.service.ansible.com
|
||||
port: 5080
|
||||
priority: 10
|
||||
target: service1.ansible.com
|
||||
weight: 10
|
||||
comment: this is a test comment
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
|
||||
- name: Remove an SRV record from the system
|
||||
community.general.nios_srv_record:
|
||||
name: _sip._tcp.service.ansible.com
|
||||
port: 5080
|
||||
priority: 10
|
||||
target: service1.ansible.com
|
||||
weight: 10
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_SRV_RECORD
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
port=dict(type='int', ib_req=True),
|
||||
priority=dict(type='int', ib_req=True),
|
||||
target=dict(ib_req=True),
|
||||
weight=dict(type='int', ib_req=True),
|
||||
|
||||
ttl=dict(type='int'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_SRV_RECORD, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,140 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_txt_record
|
||||
author: "Corey Wanless (@coreywan)"
|
||||
short_description: Configure Infoblox NIOS txt records
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_txt_record
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of txt record objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(record:txt) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox_client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Specifies the fully qualified hostname to add or remove from
|
||||
the system
|
||||
required: true
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Sets the DNS view to associate this tst record with. The DNS
|
||||
view must already be configured on the system
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
text:
|
||||
description:
|
||||
- Text associated with the record. It can contain up to 255 bytes
|
||||
per substring, up to a total of 512 bytes. To enter leading,
|
||||
trailing, or embedded spaces in the text, add quotes around the
|
||||
text to preserve the spaces.
|
||||
type: str
|
||||
ttl:
|
||||
description:
|
||||
- Configures the TTL to be associated with this tst record
|
||||
type: int
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Ensure a text Record Exists
|
||||
community.general.nios_txt_record:
|
||||
name: fqdn.txt.record.com
|
||||
text: mytext
|
||||
state: present
|
||||
view: External
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
|
||||
- name: Ensure a text Record does not exist
|
||||
community.general.nios_txt_record:
|
||||
name: fqdn.txt.record.com
|
||||
text: mytext
|
||||
state: absent
|
||||
view: External
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
|
||||
ib_spec = dict(
|
||||
name=dict(required=True, ib_req=True),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
text=dict(ib_req=True),
|
||||
ttl=dict(type='int'),
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict(),
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run('record:txt', ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,241 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018 Red Hat, Inc.
|
||||
# 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: nios_zone
|
||||
author: "Peter Sprygada (@privateip)"
|
||||
short_description: Configure Infoblox NIOS DNS zones
|
||||
deprecated:
|
||||
why: Please install the infoblox.nios_modules collection and use the corresponding module from it.
|
||||
alternative: infoblox.nios_modules.nios_zone
|
||||
removed_in: 5.0.0
|
||||
description:
|
||||
- Adds and/or removes instances of DNS zone objects from
|
||||
Infoblox NIOS servers. This module manages NIOS C(zone_auth) objects
|
||||
using the Infoblox WAPI interface over REST.
|
||||
requirements:
|
||||
- infoblox-client
|
||||
extends_documentation_fragment:
|
||||
- community.general.nios
|
||||
|
||||
options:
|
||||
fqdn:
|
||||
description:
|
||||
- Specifies the qualified domain name to either add or remove from
|
||||
the NIOS instance based on the configured C(state) value.
|
||||
required: true
|
||||
aliases:
|
||||
- name
|
||||
type: str
|
||||
view:
|
||||
description:
|
||||
- Configures the DNS view name for the configured resource. The
|
||||
specified DNS zone must already exist on the running NIOS instance
|
||||
prior to configuring zones.
|
||||
default: default
|
||||
aliases:
|
||||
- dns_view
|
||||
type: str
|
||||
grid_primary:
|
||||
description:
|
||||
- Configures the grid primary servers for this zone.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- The name of the grid primary server
|
||||
required: true
|
||||
type: str
|
||||
grid_secondaries:
|
||||
description:
|
||||
- Configures the grid secondary servers for this zone.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description:
|
||||
- The name of the grid secondary server
|
||||
required: true
|
||||
type: str
|
||||
ns_group:
|
||||
description:
|
||||
- Configures the name server group for this zone. Name server group is
|
||||
mutually exclusive with grid primary and grid secondaries.
|
||||
type: str
|
||||
restart_if_needed:
|
||||
description:
|
||||
- If set to true, causes the NIOS DNS service to restart and load the
|
||||
new zone configuration
|
||||
type: bool
|
||||
zone_format:
|
||||
description:
|
||||
- Create an authorative Reverse-Mapping Zone which is an area of network
|
||||
space for which one or more name servers-primary and secondary-have the
|
||||
responsibility to respond to address-to-name queries. It supports
|
||||
reverse-mapping zones for both IPv4 and IPv6 addresses.
|
||||
default: FORWARD
|
||||
type: str
|
||||
extattrs:
|
||||
description:
|
||||
- Allows for the configuration of Extensible Attributes on the
|
||||
instance of the object. This argument accepts a set of key / value
|
||||
pairs for configuration.
|
||||
type: dict
|
||||
comment:
|
||||
description:
|
||||
- Configures a text string comment to be associated with the instance
|
||||
of this object. The provided text string will be configured on the
|
||||
object instance.
|
||||
type: str
|
||||
state:
|
||||
description:
|
||||
- Configures the intended state of the instance of the object on
|
||||
the NIOS server. When this value is set to C(present), the object
|
||||
is configured on the device and when this value is set to C(absent)
|
||||
the value is removed (if necessary) from the device.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
type: str
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Configure a zone on the system using grid primary and secondaries
|
||||
community.general.nios_zone:
|
||||
name: ansible.com
|
||||
grid_primary:
|
||||
- name: gridprimary.grid.com
|
||||
grid_secondaries:
|
||||
- name: gridsecondary1.grid.com
|
||||
- name: gridsecondary2.grid.com
|
||||
restart_if_needed: true
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a zone on the system using a name server group
|
||||
community.general.nios_zone:
|
||||
name: ansible.com
|
||||
ns_group: examplensg
|
||||
restart_if_needed: true
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a reverse mapping zone on the system using IPV4 zone format
|
||||
community.general.nios_zone:
|
||||
name: 10.10.10.0/24
|
||||
zone_format: IPV4
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Configure a reverse mapping zone on the system using IPV6 zone format
|
||||
community.general.nios_zone:
|
||||
name: 100::1/128
|
||||
zone_format: IPV6
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Update the comment and ext attributes for an existing zone
|
||||
community.general.nios_zone:
|
||||
name: ansible.com
|
||||
comment: this is an example comment
|
||||
extattrs:
|
||||
Site: west-dc
|
||||
state: present
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove the dns zone
|
||||
community.general.nios_zone:
|
||||
name: ansible.com
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
- name: Remove the reverse mapping dns zone from the system with IPV4 zone format
|
||||
community.general.nios_zone:
|
||||
name: 10.10.10.0/24
|
||||
zone_format: IPV4
|
||||
state: absent
|
||||
provider:
|
||||
host: "{{ inventory_hostname_short }}"
|
||||
username: admin
|
||||
password: admin
|
||||
connection: local
|
||||
'''
|
||||
|
||||
RETURN = ''' # '''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_ZONE
|
||||
from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec
|
||||
|
||||
|
||||
def main():
|
||||
''' Main entry point for module execution
|
||||
'''
|
||||
grid_spec = dict(
|
||||
name=dict(required=True),
|
||||
)
|
||||
|
||||
ib_spec = dict(
|
||||
fqdn=dict(required=True, aliases=['name'], ib_req=True, update=False),
|
||||
zone_format=dict(default='FORWARD', ib_req=False),
|
||||
view=dict(default='default', aliases=['dns_view'], ib_req=True),
|
||||
|
||||
grid_primary=dict(type='list', elements='dict', options=grid_spec),
|
||||
grid_secondaries=dict(type='list', elements='dict', options=grid_spec),
|
||||
ns_group=dict(),
|
||||
restart_if_needed=dict(type='bool'),
|
||||
|
||||
extattrs=dict(type='dict'),
|
||||
comment=dict()
|
||||
)
|
||||
|
||||
argument_spec = dict(
|
||||
provider=dict(required=True),
|
||||
state=dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
|
||||
argument_spec.update(normalize_ib_spec(ib_spec))
|
||||
argument_spec.update(WapiModule.provider_spec)
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=[
|
||||
['ns_group', 'grid_primary'],
|
||||
['ns_group', 'grid_secondaries']
|
||||
])
|
||||
|
||||
wapi = WapiModule(module)
|
||||
result = wapi.run(NIOS_ZONE, ib_spec)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1472,7 +1472,6 @@ class Nmcli(object):
|
||||
'ipv4.dns-search',
|
||||
'ipv4.routes',
|
||||
'ipv4.routing-rules',
|
||||
'ipv4.route-metric'
|
||||
'ipv6.dns',
|
||||
'ipv6.dns-search',
|
||||
'802-11-wireless-security.group',
|
||||
@@ -1696,6 +1695,8 @@ class Nmcli(object):
|
||||
# Depending on version nmcli adds double-qoutes to gsm.apn
|
||||
# Need to strip them in order to compare both
|
||||
current_value = current_value.strip('"')
|
||||
if key == self.mtu_setting and self.mtu is None:
|
||||
self.mtu = 0
|
||||
else:
|
||||
# parameter does not exist
|
||||
current_value = None
|
||||
@@ -1704,6 +1705,8 @@ class Nmcli(object):
|
||||
# compare values between two lists
|
||||
if sorted(current_value) != sorted(value):
|
||||
changed = True
|
||||
elif all([key == self.mtu_setting, self.type == 'dummy', current_value is None, value == 'auto', self.mtu is None]):
|
||||
value = None
|
||||
else:
|
||||
if current_value != to_text(value):
|
||||
changed = True
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_a_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_aaaa_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_cname_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_dns_view.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_fixed_address.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_host_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_member.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_mx_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_naptr_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_network.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_network_view.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_nsgroup.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_ptr_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_srv_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_txt_record.py
|
||||
@@ -1 +0,0 @@
|
||||
./net_tools/nios/nios_zone.py
|
||||
@@ -33,8 +33,6 @@ options:
|
||||
- Message content.
|
||||
- The alias I(message) is deprecated and will be removed in community.general 4.0.0.
|
||||
required: true
|
||||
aliases:
|
||||
- message
|
||||
url:
|
||||
type: str
|
||||
description:
|
||||
@@ -95,9 +93,7 @@ def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
channel_token=dict(type='str', required=True, no_log=True),
|
||||
message_content=dict(type='str', required=True, aliases=['message'],
|
||||
deprecated_aliases=[dict(name='message', version='4.0.0',
|
||||
collection_name='community.general')]),
|
||||
message_content=dict(type='str', required=True),
|
||||
service=dict(type='str', default='ansible'),
|
||||
url=dict(type='str', default=None),
|
||||
icon_url=dict(type='str', default=None),
|
||||
|
||||
@@ -22,8 +22,6 @@ description:
|
||||
- Also, the user may try to use any other telegram bot API method, if you specify I(api_method) argument.
|
||||
notes:
|
||||
- You will require a telegram account and create telegram bot to use this module.
|
||||
- The options I(msg), I(msg_format) and I(chat_id) have been deprecated and will be removed in community.general
|
||||
4.0.0. Use the corresponding variables in I(api_args) instead. See the examples for how that works.
|
||||
options:
|
||||
token:
|
||||
type: str
|
||||
@@ -43,22 +41,6 @@ options:
|
||||
- Any parameters for the method.
|
||||
- For reference to default method, C(SendMessage), see U(https://core.telegram.org/bots/api#sendmessage).
|
||||
version_added: 2.0.0
|
||||
msg:
|
||||
type: str
|
||||
description:
|
||||
- (Deprecated) What message you wish to send.
|
||||
msg_format:
|
||||
type: str
|
||||
description:
|
||||
- (Deprecated) Message format. Formatting options C(markdown), C(MarkdownV2), and C(html) described in
|
||||
Telegram API docs (https://core.telegram.org/bots/api#formatting-options).
|
||||
If option C(plain) set, message will not be formatted.
|
||||
default: plain
|
||||
choices: [ "plain", "markdown", "MarkdownV2", "html" ]
|
||||
chat_id:
|
||||
type: str
|
||||
description:
|
||||
- (Deprecated) Telegram group or user chat_id.
|
||||
|
||||
'''
|
||||
|
||||
@@ -83,12 +65,6 @@ EXAMPLES = """
|
||||
from_chat_id: 111111
|
||||
disable_notification: True
|
||||
message_id: '{{ saved_msg_id }}'
|
||||
|
||||
- name: Send a message to chat in playbook (deprecated old style)
|
||||
community.general.telegram:
|
||||
token: '9999999:XXXXXXXXXXXXXXXXXXXXXXX'
|
||||
chat_id: 000000
|
||||
msg: Ansible task finished
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
@@ -119,11 +95,6 @@ def main():
|
||||
token=dict(type='str', required=True, no_log=True),
|
||||
api_args=dict(type='dict'),
|
||||
api_method=dict(type="str", default="SendMessage"),
|
||||
chat_id=dict(type='str', no_log=True, removed_in_version='4.0.0',
|
||||
removed_from_collection='community.general'),
|
||||
msg=dict(type='str', removed_in_version='4.0.0', removed_from_collection='community.general'),
|
||||
msg_format=dict(type='str', choices=['plain', 'markdown', 'html', 'MarkdownV2'], default='plain',
|
||||
removed_in_version='4.0.0', removed_from_collection='community.general'),
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
@@ -132,9 +103,9 @@ def main():
|
||||
api_args = module.params.get('api_args') or {}
|
||||
api_method = module.params.get('api_method')
|
||||
# filling backward compatibility args
|
||||
api_args['chat_id'] = api_args.get('chat_id') or module.params.get('chat_id')
|
||||
api_args['parse_mode'] = api_args.get('parse_mode') or module.params.get('msg_format')
|
||||
api_args['text'] = api_args.get('text') or module.params.get('msg')
|
||||
api_args['chat_id'] = api_args.get('chat_id')
|
||||
api_args['parse_mode'] = api_args.get('parse_mode')
|
||||
api_args['text'] = api_args.get('text')
|
||||
|
||||
if api_args['parse_mode'] == 'plain':
|
||||
del api_args['parse_mode']
|
||||
|
||||
@@ -238,7 +238,7 @@ class AnsibleGalaxyInstall(CmdModuleHelper):
|
||||
def _list_element(self, _type, path_re, elem_re):
|
||||
params = ({'type': _type}, {'galaxy_cmd': 'list'}, 'dest')
|
||||
elems = self.run_command(params=params,
|
||||
publish_rc=False, publish_out=False, publish_err=False,
|
||||
publish_rc=False, publish_out=False, publish_err=False, publish_cmd=False,
|
||||
process_output=self._process_output_list,
|
||||
check_rc=False)
|
||||
elems_dict = {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user