mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-27 05:43:05 +00:00
Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba3fe74b60 | ||
|
|
b9151f3069 | ||
|
|
6085fbf77d | ||
|
|
603bd61845 | ||
|
|
1a31f62a6f | ||
|
|
23e07a9a17 | ||
|
|
bd084ad37b | ||
|
|
099eb96b58 | ||
|
|
1276e38895 | ||
|
|
2fa9ed9127 | ||
|
|
766cf5a285 | ||
|
|
3ea452ef6f | ||
|
|
50b16cb33f | ||
|
|
9b0558a953 | ||
|
|
6124dc0cf1 | ||
|
|
423a6b0e12 | ||
|
|
a83bab9425 | ||
|
|
70f4b7d646 | ||
|
|
f2865efb1a | ||
|
|
ce143bad52 | ||
|
|
928fdf4b2d | ||
|
|
0d95b8ebcb | ||
|
|
0efe2c30d2 | ||
|
|
10e9c30af6 | ||
|
|
f770b5d581 | ||
|
|
9b020a56f3 | ||
|
|
09a0077b77 | ||
|
|
3779698e0a | ||
|
|
65adc7860e | ||
|
|
df87ff464a | ||
|
|
4b8358b897 | ||
|
|
68661d6922 | ||
|
|
461bd8b15b | ||
|
|
ef0e368741 | ||
|
|
f0a71eda84 | ||
|
|
d0402d7905 | ||
|
|
eebfdbca7a | ||
|
|
e30bcfd876 | ||
|
|
abf0cc3251 | ||
|
|
9decad4e4f | ||
|
|
03098c218d | ||
|
|
d05ad6b1f2 | ||
|
|
9981e5f84b | ||
|
|
4df2cab42a | ||
|
|
5d6324e2da | ||
|
|
8772379dcc | ||
|
|
29badaecca | ||
|
|
e88aaaf95a | ||
|
|
b54333358d | ||
|
|
c16ceac892 | ||
|
|
d303a81e4c | ||
|
|
d561d8f372 | ||
|
|
33c571ebb6 | ||
|
|
81d1896f0f | ||
|
|
75f5082ad0 | ||
|
|
a05eed6a4b | ||
|
|
cddb861fd9 | ||
|
|
15d3123ed3 | ||
|
|
7a1bf986a8 | ||
|
|
c89f6624b5 | ||
|
|
998a141482 | ||
|
|
d111f0d92b | ||
|
|
5ab9ae21ad | ||
|
|
3c130795e3 | ||
|
|
954c911a85 | ||
|
|
e681f25e5c | ||
|
|
8010d19be9 | ||
|
|
892cb037eb | ||
|
|
40d4150590 | ||
|
|
bc72bbd92e | ||
|
|
ae9c81139b | ||
|
|
d5fdaaf444 | ||
|
|
fdd4b19b18 | ||
|
|
dc62744f6a | ||
|
|
2af7602a8c | ||
|
|
1b74cf1692 | ||
|
|
19fc21cd1b | ||
|
|
804e633f13 | ||
|
|
ad37bed37b | ||
|
|
b00dc5daa5 | ||
|
|
2c278ab39d | ||
|
|
ef2adf54b4 | ||
|
|
a61c046abe | ||
|
|
1fee891aa4 | ||
|
|
1aca0c1304 | ||
|
|
60fd87c567 | ||
|
|
4aab1599bd | ||
|
|
0c36194038 | ||
|
|
680cd4c6ee | ||
|
|
401b911171 | ||
|
|
7f61e72a2c | ||
|
|
3c3396a7b8 | ||
|
|
45f583b1ed | ||
|
|
2de1dccbf5 | ||
|
|
a44515c701 | ||
|
|
8cf2e7ef7b | ||
|
|
ec198d0e09 | ||
|
|
b162122630 | ||
|
|
b89d2b1316 | ||
|
|
1d3eab804d | ||
|
|
d3b8f54d7d | ||
|
|
b7d1a2789b | ||
|
|
6bfcfcdc81 | ||
|
|
ebe5671dff | ||
|
|
2266756968 | ||
|
|
3a0a1a7529 | ||
|
|
65015e63e9 | ||
|
|
dead467982 | ||
|
|
ae286f5226 | ||
|
|
ea53e34537 | ||
|
|
48b0a13a54 | ||
|
|
04a8299be6 | ||
|
|
b0252fb57a | ||
|
|
78091e2238 | ||
|
|
25afcc3491 |
@@ -14,6 +14,8 @@ exclude_paths:
|
||||
kinds:
|
||||
- playbook: '**/tests/**/test_*.yml'
|
||||
- playbook: '**/playbooks/**/*.yml'
|
||||
- tasks: '**/tasks_*.yml'
|
||||
- tasks: '**/env_*.yml'
|
||||
|
||||
parseable: true
|
||||
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
python-version: "3.x"
|
||||
- name: Run pylint
|
||||
run: |
|
||||
pip install pylint==2.10.2
|
||||
pip install pylint==2.12.2
|
||||
pylint plugins roles --disable=import-error
|
||||
|
||||
shellcheck:
|
||||
|
||||
16
.github/workflows/readme.yml
vendored
Normal file
16
.github/workflows/readme.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: readme test
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
jobs:
|
||||
ansible_test:
|
||||
name: Verify readme
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run readme test
|
||||
run: |
|
||||
error=0
|
||||
for i in roles/ipa*/README.md README-*.md; do grep -q $i README.md && echo "OK: $i" || { echo -e "\033[31;1mERROR: ${i} missing\033[0m"; error=1; } done
|
||||
exit $error
|
||||
@@ -24,7 +24,7 @@ repos:
|
||||
hooks:
|
||||
- id: pydocstyle
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v2.10.2
|
||||
rev: v2.12.2
|
||||
hooks:
|
||||
- id: pylint
|
||||
args:
|
||||
|
||||
@@ -71,6 +71,7 @@ Example playbook to ensure a global forwarder, with a custom port, is absent:
|
||||
forwarders:
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
action: member
|
||||
state: absent
|
||||
```
|
||||
|
||||
@@ -128,9 +129,10 @@ Variable | Description | Required
|
||||
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
|
||||
| `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
|
||||
| `port` - The custom port that should be used on this server. | no
|
||||
`forward_policy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
|
||||
`forward_policy` \| `forwardpolicy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
|
||||
`allow_sync_ptr` | Allow synchronization of forward (A, AAAA) and reverse (PTR) records (bool). | yes
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
|
||||
`action` | Work on dnsconfig or member level. It can be one of `member` or `dnsconfig` and defaults to `dnsconfig`. Only `forwarders` can be managed with `action: member`. | no
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. `absent` can only be used with `action: member` and `forwarders`. | yes
|
||||
|
||||
|
||||
Authors
|
||||
|
||||
@@ -110,7 +110,7 @@ Variable | Description | Required
|
||||
`forwarders` \| `idnsforwarders` | Per-zone forwarders. A custom port can be specified for each forwarder. Options | no
|
||||
| `ip_address`: The forwarder IP address. | yes
|
||||
| `port`: The forwarder IP port. | no
|
||||
`forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no
|
||||
`forwardpolicy` \| `idnsforwardpolicy` \| `forward_policy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no
|
||||
`skip_overlap_check` | Force DNS zone creation even if it will overlap with an existing zone. Defaults to False. | no
|
||||
`permission` | Allow DNS Forward Zone to be managed. (bool) | no
|
||||
`action` | Work on group or member level. It can be on of `member` or `dnsforwardzone` and defaults to `dnsforwardzone`. | no
|
||||
|
||||
@@ -100,7 +100,7 @@ Example playbook to add group members to a group:
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Add group members sysops and appops to group sysops
|
||||
# Add group members sysops and appops to group ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ops
|
||||
@@ -166,6 +166,7 @@ Variable | Description | Required
|
||||
`membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no
|
||||
`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up.| no
|
||||
`action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
|
||||
|
||||
|
||||
196
README-idrange.md
Normal file
196
README-idrange.md
Normal file
@@ -0,0 +1,196 @@
|
||||
Idrange module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The idrange module allows the management of ID ranges.
|
||||
|
||||
In general it is not necessary to modify or delete ID ranges. If there is no other way to achieve a certain configuration than to modify or delete an ID range it should be done with great care. Because UIDs are stored in the file system and are used for access control it might be possible that users are allowed to access files of other users if an ID range got deleted and reused for a different domain.
|
||||
|
||||
|
||||
Use cases
|
||||
---------
|
||||
|
||||
* Add an ID range from a transitively trusted domain
|
||||
|
||||
If the trusted domain (A) trusts another domain (B) as well and this trust is transitive 'ipa trust-add domain-A' will only create a range for domain A. The ID range for domain B must be added manually.
|
||||
|
||||
* Add an additional ID range for the local domain
|
||||
|
||||
If the ID range of the local domain is exhausted, i.e. no new IDs can be assigned to Posix users or groups by the DNA plugin, a new range has to be created to allow new users and groups to be added. (Currently there is no connection between this range CLI and the DNA plugin, but a future version might be able to modify the configuration of the DNS plugin as well).
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* ID Range management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaidrange module.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
Example playbook to ensure a local domain idrange is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure an ID Range for the local domain is present.
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: local_domain_id_range
|
||||
base_id: 150000
|
||||
range_size: 200000
|
||||
```
|
||||
|
||||
Example playbook to ensure a local domain idrange is present, with RID and secondary RID base values:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure local idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: local_domain_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad' and using domain SID:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad-posix' and using domain SID:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
name: ad_posix_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange has auto creation of groups set to 'hybrid':
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Modify AD-trust idrange 'auto_private_groups'
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: ad_id_range
|
||||
auto_private_groups: "hybrid"
|
||||
```
|
||||
|
||||
Example playbook to make sure an idrange is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure ID range 'ad_id_range' is absent.
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of idrange name strings. | yes
|
||||
`base_id` \| `ipabaseid` | First Posix ID of the range. (int) | yes, if `state: present`
|
||||
`range_size` \| `ipaidrangesize` | Number of IDs in the range. (int) | yes, if `state: present`
|
||||
`rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | no
|
||||
`secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | no
|
||||
`dom_sid` \| `ipanttrusteddomainsid` | Domain SID of the trusted domain. | no
|
||||
`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. | no
|
||||
`idrange_type` \| `iparangetype` | ID range type, one of `ipa-ad-trust`, `ipa-ad-trust-posix`, `ipa-local`. Only valid if idrange does not exist. | no
|
||||
`auto_private_groups` \| `ipaautoprivategroups` | Auto creation of private groups, one of `true`, `false`, `hybrid`. | no
|
||||
`delete_continue` \| `continue` | Continuous mode: don't stop on errors. Valid only if `state` is `absent`. Default: `no` (bool) | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands.
|
||||
|
||||
Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range.
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Rafael Guterres Jeffman
|
||||
@@ -293,8 +293,8 @@ Variable | Description | Required
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `service` | The list of service name strings. | yes
|
||||
`certificate` \| `usercertificate` | Base-64 encoded service certificate. | no
|
||||
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, or `hardened`. | no
|
||||
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. Use empty string to reset pac_type to the initial value. | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit` or `hardened`. Use empty string to reset auth_ind to the initial value. | no
|
||||
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service. Default to true. (bool) | no
|
||||
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service. Default to false. (bool) | no
|
||||
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client. Default to false. (bool) | no
|
||||
|
||||
172
README-servicedelegationrule.md
Normal file
172
README-servicedelegationrule.md
Normal file
@@ -0,0 +1,172 @@
|
||||
Servicedelegationrule module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The servicedelegationrule module allows to ensure presence and absence of servicedelegationrules and servicedelegationrule members.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Servicedelegationrule management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationrule module.
|
||||
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of servicedelegationrule name strings. | yes
|
||||
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
|
||||
`target` \| `servicedelegationtarget` | The list of service delegation targets. | no
|
||||
`action` | Work on servicedelegationrule or member level. It can be on of `member` or `servicedelegationrule` and defaults to `servicedelegationrule`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
133
README-servicedelegationtarget.md
Normal file
133
README-servicedelegationtarget.md
Normal file
@@ -0,0 +1,133 @@
|
||||
Servicedelegationtarget module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The servicedelegationtarget module allows to ensure presence and absence of servicedelegationtargets and servicedelegationtarget members.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Servicedelegationtarget management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationtarget module.
|
||||
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of servicedelegationtarget name strings. | yes
|
||||
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
|
||||
`action` | Work on servicedelegationtarget or member level. It can be on of `member` or `servicedelegationtarget` and defaults to `servicedelegationtarget`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
@@ -105,6 +105,7 @@ Variable | Description | Required
|
||||
`password` | Active Directory domain administrator's password string. | no
|
||||
`server` | Domain controller for the Active Directory domain string. | no
|
||||
`trust_secret` | Shared secret for the trust string. | no
|
||||
`trust_type` | Trust type. Currently, only 'ad' for Active Directory is supported. | no
|
||||
`base_id` | First posix id for the trusted domain integer. | no
|
||||
`range_size` | Size of the ID range reserved for the trusted domain integer. | no
|
||||
`range_type` | Type of trusted domain ID range, It can be one of `ipa-ad-trust` or `ipa-ad-trust-posix`and defaults to `ipa-ad-trust`. | no
|
||||
|
||||
16
README.md
16
README.md
@@ -13,7 +13,9 @@ Features
|
||||
* Repair mode for clients
|
||||
* Backup and restore, also to and from controller
|
||||
* Modules for automembership rule management
|
||||
* Modules for automount key management
|
||||
* Modules for automount location management
|
||||
* Modules for automount map management
|
||||
* Modules for config management
|
||||
* Modules for delegation management
|
||||
* Modules for dns config management
|
||||
@@ -26,6 +28,7 @@ Features
|
||||
* Modules for hbacsvcgroup management
|
||||
* Modules for host management
|
||||
* Modules for hostgroup management
|
||||
* Modules for idrange management
|
||||
* Modules for location management
|
||||
* Modules for permission management
|
||||
* Modules for privilege management
|
||||
@@ -34,6 +37,8 @@ Features
|
||||
* Modules for self service management
|
||||
* Modules for server management
|
||||
* Modules for service management
|
||||
* Modules for service delegation rule management
|
||||
* Modules for service delegation target management
|
||||
* Modules for sudocmd management
|
||||
* Modules for sudocmdgroup management
|
||||
* Modules for sudorule management
|
||||
@@ -63,7 +68,6 @@ Requirements
|
||||
**Controller**
|
||||
* Ansible version: 2.8+ (ansible-freeipa is an Ansible Collection)
|
||||
* /usr/bin/kinit is required on the controller if a one time password (OTP) is used
|
||||
* python3-gssapi is required on the controller if a one time password (OTP) is used with keytab to install the client.
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
@@ -283,7 +287,8 @@ ipaserver_domain=test.local
|
||||
ipaserver_realm=TEST.LOCAL
|
||||
```
|
||||
|
||||
For enhanced security it is possible to use a auto-generated one-time-password (OTP). This will be generated on the controller using the (first) server. It is needed to have the python-gssapi bindings installed on the controller for this.
|
||||
For enhanced security it is possible to use a auto-generated one-time-password (OTP). This will be generated on the controller using the (first) server.
|
||||
|
||||
To enable the generation of the one-time-password:
|
||||
```yaml
|
||||
[ipaclients:vars]
|
||||
@@ -425,7 +430,9 @@ Modules in plugin/modules
|
||||
=========================
|
||||
|
||||
* [ipaautomember](README-automember.md)
|
||||
* [ipaautomountkey](README-automountkey.md)
|
||||
* [ipaautomountlocation](README-automountlocation.md)
|
||||
* [ipaautomountmap](README-automountmap.md)
|
||||
* [ipaconfig](README-config.md)
|
||||
* [ipadelegation](README-delegation.md)
|
||||
* [ipadnsconfig](README-dnsconfig.md)
|
||||
@@ -435,9 +442,10 @@ Modules in plugin/modules
|
||||
* [ipagroup](README-group.md)
|
||||
* [ipahbacrule](README-hbacrule.md)
|
||||
* [ipahbacsvc](README-hbacsvc.md)
|
||||
* [ipahbacsvcgroup](README-hbacsvc.md)
|
||||
* [ipahbacsvcgroup](README-hbacsvcgroup.md)
|
||||
* [ipahost](README-host.md)
|
||||
* [ipahostgroup](README-hostgroup.md)
|
||||
* [idrange](README-idrange.md)
|
||||
* [ipalocation](README-location.md)
|
||||
* [ipapermission](README-permission.md)
|
||||
* [ipaprivilege](README-privilege.md)
|
||||
@@ -446,6 +454,8 @@ Modules in plugin/modules
|
||||
* [ipaselfservice](README-selfservice.md)
|
||||
* [ipaserver](README-server.md)
|
||||
* [ipaservice](README-service.md)
|
||||
* [ipaservicedelegationrule](README-servicedelegationrule.md)
|
||||
* [ipaservicedelegationtarget](README-servicedelegationtarget.md)
|
||||
* [ipasudocmd](README-sudocmd.md)
|
||||
* [ipasudocmdgroup](README-sudocmdgroup.md)
|
||||
* [ipasudorule](README-sudorule.md)
|
||||
|
||||
30
molecule/c8s-build/Dockerfile
Normal file
30
molecule/c8s-build/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
FROM quay.io/centos/centos:stream8
|
||||
ENV container=docker
|
||||
|
||||
RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
dnf makecache; \
|
||||
dnf --assumeyes install \
|
||||
/usr/bin/python3 \
|
||||
/usr/bin/python3-config \
|
||||
/usr/bin/dnf-3 \
|
||||
sudo \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
iproute && \
|
||||
dnf clean all; \
|
||||
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/*;\
|
||||
rm -f /etc/systemd/system/*.wants/*;\
|
||||
rm -f /lib/systemd/system/local-fs.target.wants/*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
|
||||
rm -f /lib/systemd/system/basic.target.wants/*;\
|
||||
rm -f /lib/systemd/system/anaconda.target.wants/*; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
VOLUME ["/sys/fs/cgroup"]
|
||||
|
||||
CMD ["/usr/sbin/init"]
|
||||
19
molecule/c8s-build/molecule.yml
Normal file
19
molecule/c8s-build/molecule.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: c8s-build
|
||||
image: "quay.io/centos/centos:stream8"
|
||||
dockerfile: Dockerfile
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /usr/sbin/init
|
||||
privileged: true
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
@@ -2,8 +2,8 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-9
|
||||
image: quay.io/ansible-freeipa/upstream-tests:centos-9
|
||||
- name: c8s
|
||||
image: quay.io/ansible-freeipa/upstream-tests:c8s
|
||||
pre_build_image: true
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
@@ -5,7 +5,6 @@ RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
dnf makecache; \
|
||||
dnf --assumeyes install \
|
||||
/usr/bin/python3 \
|
||||
/usr/bin/python3-config \
|
||||
/usr/bin/dnf-3 \
|
||||
sudo \
|
||||
bash \
|
||||
@@ -2,7 +2,7 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-9-build
|
||||
- name: c9s-build
|
||||
image: "quay.io/centos/centos:stream9"
|
||||
dockerfile: Dockerfile
|
||||
hostname: ipaserver.test.local
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
19
molecule/c9s/molecule.yml
Normal file
19
molecule/c9s/molecule.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: c9s
|
||||
image: quay.io/ansible-freeipa/upstream-tests:c9s
|
||||
pre_build_image: true
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
- 127.0.0.1
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /usr/sbin/init
|
||||
privileged: true
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
|
||||
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
tasks:
|
||||
- name: Ensure aumount key TestKey is renamed to NewKeyName
|
||||
ipaautomountkey:
|
||||
ipaadmin_password: password01
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
automountlocationcn: TestLocation
|
||||
automountmapname: TestMap
|
||||
automountkey: TestKey
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
tasks:
|
||||
- name: Disable global forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forward_policy: none
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
tasks:
|
||||
- name: Disallow reverse record synchronization.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
allow_sync_ptr: no
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Set dnsconfig.
|
||||
- name: Set dnsconfig forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
14
playbooks/dnsconfig/forwarders-present.yml
Normal file
14
playbooks/dnsconfig/forwarders-present.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Playbook to handle global DNS configuration
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Set dnsconfig forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
action: member
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: Set dnsconfig.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
tasks:
|
||||
- name: Ensure that 'host04' has CNAME, with cname_hostname, is absent
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
zone_name: example.com
|
||||
name: host04
|
||||
cname_hostname: host04.example.com
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
tasks:
|
||||
- name: Ensure that 'host04' has CNAME, with cname_hostname, is present
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
zone_name: example.com
|
||||
name: host04
|
||||
cname_hostname: host04.example.com
|
||||
|
||||
11
playbooks/idrange/idrange-absent.yml
Normal file
11
playbooks/idrange/idrange-absent.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Idrange absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure idrange is absent
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
state: absent
|
||||
15
playbooks/idrange/idrange-ad-posix-present.yml
Normal file
15
playbooks/idrange/idrange-ad-posix-present.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
auto_private_groups: "false"
|
||||
16
playbooks/idrange/idrange-ad-present.yml
Normal file
16
playbooks/idrange/idrange-ad-present.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
auto_private_groups: "true"
|
||||
14
playbooks/idrange/idrange-present.yml
Normal file
14
playbooks/idrange/idrange-present.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure local idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
@@ -6,5 +6,6 @@
|
||||
tasks:
|
||||
- name: Ensure privilege "Broad Privilege" is absent
|
||||
ipaprivilege:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: Broad Privilege
|
||||
state: absent
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Servicedelegationrule absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule test-delegation-rule is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
state: absent
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Servicedelegationrule present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule test-delegation-rule is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationrule principal member absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure principal member test/example.com is absent in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationrule principal member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure principal member test/example.com is present in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationrule absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is absent in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationrule member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is present in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Servicedelegationtarget absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget test-delegation-target is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
state: absent
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationtarget absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is absent in servicedelegationtarget test-delegation-target
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationtarget member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is present in servicedelegationtarget test-delegation-target
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Servicedelegationtarget present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget test-delegation-target is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
@@ -6,7 +6,7 @@
|
||||
tasks:
|
||||
- name: Ensure sudocmdgroup is absent
|
||||
ipasudocmdgroup:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: network
|
||||
state: absent
|
||||
action: sudocmdgroup
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
tasks:
|
||||
- name: Ensure sudocmdgroup sudocmds are present
|
||||
ipasudocmdgroup:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: network
|
||||
description: Group of important commands.
|
||||
sudocmd:
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
tasks:
|
||||
- name: Ensure sudorule command is absent
|
||||
ipasudorule:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testrule1
|
||||
state: absent
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: ensure the trust is present
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
admin: Administrator
|
||||
password: secret_password
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
tasks:
|
||||
- name: ensure the trust is absent
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
state: absent
|
||||
|
||||
@@ -45,3 +45,13 @@ options:
|
||||
type: bool
|
||||
default: true
|
||||
"""
|
||||
|
||||
DELETE_CONTINUE = r"""
|
||||
options:
|
||||
delete_continue:
|
||||
description: |
|
||||
Continuous mode. Don't stop on errors. Valid only if `state` is `absent`.
|
||||
aliases: ["continue"]
|
||||
type: bool
|
||||
default: True
|
||||
"""
|
||||
|
||||
@@ -86,6 +86,7 @@ else:
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib.krb_utils import get_credentials_if_valid
|
||||
from ipapython.dnsutil import DNSName
|
||||
from ipapython import kerberos
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.common.text.converters import jsonify
|
||||
@@ -309,15 +310,49 @@ else:
|
||||
raise ValueError("Invalid date '%s'" % value)
|
||||
|
||||
def compare_args_ipa(module, args, ipa, ignore=None): # noqa
|
||||
"""Compare IPA obj attrs with the command args.
|
||||
"""Compare IPA object attributes against command arguments.
|
||||
|
||||
This function compares IPA objects attributes with the args the
|
||||
module is intending to use to call a command. ignore can be a list
|
||||
of attributes, that should be ignored in the comparison.
|
||||
This is useful to know if a call to IPA server will be needed or not.
|
||||
In order to compare we have to perform slight changes in data formats.
|
||||
This function compares 'ipa' attributes with the 'args' the module
|
||||
is intending to use as parameters to an IPA API command. A list of
|
||||
attribute names that should be ignored during comparison may be
|
||||
provided.
|
||||
|
||||
Returns True if they are the same and False otherwise.
|
||||
The comparison will be performed on every attribute provided in
|
||||
'args'. If the attribute in 'args' or 'ipa' is not a scalar value
|
||||
(including strings) the comparison will be performed as if the
|
||||
attribute is a set of values, so duplicate values will count as a
|
||||
single one. If both values are scalar values, then a direct
|
||||
comparison is performed.
|
||||
|
||||
If an attribute is not available in 'ipa', its value is considered
|
||||
to be a list with an empty string (['']), possibly forcing the
|
||||
conversion of the 'args' attribute to a list for comparison. This
|
||||
allows, for example, the usage of empty strings which should compare
|
||||
as equals to inexistent attributes (None), as is done in IPA API.
|
||||
|
||||
This function is mostly useful to evaluate the need of a call to
|
||||
IPA server when provided arguments are equivalent to the existing
|
||||
values for a given IPA object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
module: AnsibleModule
|
||||
The AnsibleModule used to log debug messages.
|
||||
|
||||
args: dict
|
||||
The set of attributes provided by the playbook task.
|
||||
|
||||
ipa: dict
|
||||
The set of attributes from the IPA object retrieved.
|
||||
|
||||
ignore: list
|
||||
An optional list of attribute names that should be ignored and
|
||||
not evaluated.
|
||||
|
||||
Return
|
||||
------
|
||||
True is returned if all attribute values in 'args' are
|
||||
equivalent to the corresponding attribute value in 'ipa'.
|
||||
"""
|
||||
base_debug_msg = "Ansible arguments and IPA commands differed. "
|
||||
|
||||
@@ -337,52 +372,45 @@ else:
|
||||
filtered_args = [key for key in args if key not in ignore]
|
||||
|
||||
for key in filtered_args:
|
||||
if key not in ipa: # pylint: disable=no-else-return
|
||||
module.debug(
|
||||
base_debug_msg + "Command key not present in IPA: %s" % key
|
||||
)
|
||||
return False
|
||||
arg = args[key]
|
||||
ipa_arg = ipa.get(key, [""])
|
||||
# If ipa_arg is a list and arg is not, replace arg
|
||||
# with list containing arg. Most args in a find result
|
||||
# are lists, but not all.
|
||||
if isinstance(ipa_arg, (list, tuple)):
|
||||
if not isinstance(arg, list):
|
||||
arg = [arg]
|
||||
if len(ipa_arg) != len(arg):
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "List length doesn't match for key %s: %d %d"
|
||||
% (key, len(arg), len(ipa_arg),)
|
||||
)
|
||||
return False
|
||||
# ensure list elements types are the same.
|
||||
if not (
|
||||
isinstance(ipa_arg[0], type(arg[0]))
|
||||
or isinstance(arg[0], type(ipa_arg[0]))
|
||||
):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
try:
|
||||
arg_set = set(arg)
|
||||
ipa_arg_set = set(ipa_arg)
|
||||
except TypeError:
|
||||
if arg != ipa_arg:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different values: %s %s" % (arg, ipa_arg)
|
||||
)
|
||||
return False
|
||||
else:
|
||||
arg = args[key]
|
||||
ipa_arg = ipa[key]
|
||||
# If ipa_arg is a list and arg is not, replace arg
|
||||
# with list containing arg. Most args in a find result
|
||||
# are lists, but not all.
|
||||
if isinstance(ipa_arg, tuple):
|
||||
ipa_arg = list(ipa_arg)
|
||||
if isinstance(ipa_arg, list):
|
||||
if not isinstance(arg, list):
|
||||
arg = [arg]
|
||||
if len(ipa_arg) != len(arg):
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "List length doesn't match for key %s: %d %d"
|
||||
% (key, len(arg), len(ipa_arg),)
|
||||
)
|
||||
return False
|
||||
if isinstance(ipa_arg[0], str) and isinstance(arg[0], int):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
if isinstance(ipa_arg[0], unicode) \
|
||||
and isinstance(arg[0], int):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
try:
|
||||
arg_set = set(arg)
|
||||
ipa_arg_set = set(ipa_arg)
|
||||
except TypeError:
|
||||
if arg != ipa_arg:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different values: %s %s" % (arg, ipa_arg)
|
||||
)
|
||||
return False
|
||||
else:
|
||||
if arg_set != ipa_arg_set:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different set content: %s %s"
|
||||
% (arg_set, ipa_arg_set,)
|
||||
)
|
||||
return False
|
||||
if arg_set != ipa_arg_set:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different set content: %s %s"
|
||||
% (arg_set, ipa_arg_set,)
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _afm_convert(value):
|
||||
@@ -397,11 +425,32 @@ else:
|
||||
|
||||
return value
|
||||
|
||||
def module_params_get(module, name):
|
||||
return _afm_convert(module.params.get(name))
|
||||
|
||||
def module_params_get_lowercase(module, name):
|
||||
def module_params_get(module, name, allow_empty_string=False):
|
||||
value = _afm_convert(module.params.get(name))
|
||||
|
||||
# Fail on empty strings in the list or if allow_empty_string is True
|
||||
# if there is another entry in the list together with the empty
|
||||
# string.
|
||||
# Due to an issue in Ansible it is possible to use the empty string
|
||||
# "" for lists with choices, even if the empty list is not part of
|
||||
# the choices.
|
||||
# Ansible issue https://github.com/ansible/ansible/issues/77108
|
||||
if isinstance(value, list):
|
||||
for val in value:
|
||||
if isinstance(val, (str, unicode)) and not val:
|
||||
if not allow_empty_string:
|
||||
module.fail_json(
|
||||
msg="Parameter '%s' contains an empty string" %
|
||||
name)
|
||||
elif len(value) > 1:
|
||||
module.fail_json(
|
||||
msg="Parameter '%s' may not contain another "
|
||||
"entry together with an empty string" % name)
|
||||
|
||||
return value
|
||||
|
||||
def module_params_get_lowercase(module, name, allow_empty_string=False):
|
||||
value = module_params_get(module, name, allow_empty_string)
|
||||
if isinstance(value, list):
|
||||
value = [v.lower() for v in value]
|
||||
if isinstance(value, (str, unicode)):
|
||||
@@ -550,6 +599,89 @@ else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def servicedelegation_normalize_principals(module, principal,
|
||||
check_exists=False):
|
||||
"""
|
||||
Normalize servicedelegation principals.
|
||||
|
||||
The principals can be service and with IPA 4.9.0+ also host principals.
|
||||
"""
|
||||
|
||||
def _normalize_principal_name(name, realm):
|
||||
# Normalize principal name
|
||||
# Copied from ipaserver/plugins/servicedelegation.py
|
||||
try:
|
||||
princ = kerberos.Principal(name, realm=realm)
|
||||
except ValueError as _err:
|
||||
raise ipalib_errors.ValidationError(
|
||||
name='principal',
|
||||
reason="Malformed principal: %s" % str(_err))
|
||||
|
||||
if len(princ.components) == 1 and \
|
||||
not princ.components[0].endswith('$'):
|
||||
nprinc = 'host/' + unicode(princ)
|
||||
else:
|
||||
nprinc = unicode(princ)
|
||||
return nprinc
|
||||
|
||||
def _check_exists(module, _type, name):
|
||||
# Check if item of type _type exists using the show command
|
||||
try:
|
||||
module.ipa_command("%s_show" % _type, name, {})
|
||||
except ipalib_errors.NotFound as e:
|
||||
msg = str(e)
|
||||
if "%s not found" % _type in msg:
|
||||
return False
|
||||
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
|
||||
return True
|
||||
|
||||
ipa_realm = module.ipa_get_realm()
|
||||
_principal = []
|
||||
for _princ in principal:
|
||||
princ = _princ
|
||||
realm = ipa_realm
|
||||
|
||||
# Get principal and realm from _princ if there is a realm
|
||||
if '@' in _princ:
|
||||
princ, realm = _princ.rsplit('@', 1)
|
||||
|
||||
# Lowercase principal
|
||||
princ = princ.lower()
|
||||
|
||||
# Normalize principal
|
||||
try:
|
||||
nprinc = _normalize_principal_name(princ, realm)
|
||||
except ipalib_errors.ValidationError as err:
|
||||
module.fail_json(msg="%s: %s" % (_princ, str(err)))
|
||||
princ = unicode(nprinc)
|
||||
|
||||
# Check that host principal exists
|
||||
if princ.startswith("host/"):
|
||||
if module.ipa_check_version("<", "4.9.0"):
|
||||
module.fail_json(
|
||||
msg="The use of host principals is not supported "
|
||||
"by your IPA version")
|
||||
|
||||
# Get host FQDN (no leading 'host/' and no trailing realm)
|
||||
# (There is no removeprefix and removesuffix in Python2)
|
||||
_host = princ[5:]
|
||||
if _host.endswith("@%s" % realm):
|
||||
_host = _host[:-len(realm) - 1]
|
||||
|
||||
# Seach for host
|
||||
if check_exists and not _check_exists(module, "host", _host):
|
||||
module.fail_json(msg="Host '%s' does not exist" % _host)
|
||||
|
||||
# Check the service principal exists
|
||||
else:
|
||||
if check_exists and \
|
||||
not _check_exists(module, "service", princ):
|
||||
module.fail_json(msg="Service %s does not exist" % princ)
|
||||
|
||||
_principal.append(princ)
|
||||
|
||||
return _principal
|
||||
|
||||
def exit_raw_json(module, **kwargs):
|
||||
"""
|
||||
Print the raw parameters in JSON format, without masking.
|
||||
@@ -742,6 +874,12 @@ else:
|
||||
ipaapi_ldap_cache=dict(type="bool", default="True"),
|
||||
)
|
||||
|
||||
ipa_module_options_spec = dict(
|
||||
delete_continue=dict(
|
||||
type="bool", default=True, aliases=["continue"]
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Extend argument_spec with ipa_module_base_spec
|
||||
if "argument_spec" in kwargs:
|
||||
@@ -749,6 +887,16 @@ else:
|
||||
_spec.update(self.ipa_module_base_spec)
|
||||
kwargs["argument_spec"] = _spec
|
||||
|
||||
if "ipa_module_options" in kwargs:
|
||||
_update = {
|
||||
k: self.ipa_module_options_spec[k]
|
||||
for k in kwargs["ipa_module_options"]
|
||||
}
|
||||
_spec = kwargs.get("argument_spec", {})
|
||||
_spec.update(_update)
|
||||
kwargs["argument_spec"] = _spec
|
||||
del kwargs["ipa_module_options"]
|
||||
|
||||
# pylint: disable=super-with-arguments
|
||||
super(IPAAnsibleModule, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -797,7 +945,7 @@ else:
|
||||
finally:
|
||||
temp_kdestroy(ccache_dir, ccache_name)
|
||||
|
||||
def params_get(self, name):
|
||||
def params_get(self, name, allow_empty_string=False):
|
||||
"""
|
||||
Retrieve value set for module parameter.
|
||||
|
||||
@@ -805,11 +953,13 @@ else:
|
||||
----------
|
||||
name: string
|
||||
The name of the parameter to retrieve.
|
||||
allow_empty_string: bool
|
||||
The parameter allowes to have empty strings in a list
|
||||
|
||||
"""
|
||||
return module_params_get(self, name)
|
||||
return module_params_get(self, name, allow_empty_string)
|
||||
|
||||
def params_get_lowercase(self, name):
|
||||
def params_get_lowercase(self, name, allow_empty_string=False):
|
||||
"""
|
||||
Retrieve value set for module parameter as lowercase, if not None.
|
||||
|
||||
@@ -817,9 +967,11 @@ else:
|
||||
----------
|
||||
name: string
|
||||
The name of the parameter to retrieve.
|
||||
allow_empty_string: bool
|
||||
The parameter allowes to have empty strings in a list
|
||||
|
||||
"""
|
||||
return module_params_get_lowercase(self, name)
|
||||
return module_params_get_lowercase(self, name, allow_empty_string)
|
||||
|
||||
def params_fail_used_invalid(self, invalid_params, state, action=None):
|
||||
"""
|
||||
|
||||
@@ -587,7 +587,6 @@ def main():
|
||||
commands.append([None,
|
||||
'automember_default_group_remove',
|
||||
{'type': automember_type}])
|
||||
ansible_module.warn("commands: %s" % repr(commands))
|
||||
|
||||
else:
|
||||
dn_default_group = [DN(('cn', default_group),
|
||||
|
||||
@@ -112,21 +112,23 @@ class AutomountMap(IPAAnsibleModule):
|
||||
state = self.params_get("state")
|
||||
if state == "present":
|
||||
if len(name) != 1:
|
||||
self.fail_json(msg="Exactly one name must be provided \
|
||||
for state=present.")
|
||||
self.fail_json(msg="Exactly one name must be provided for"
|
||||
" 'state: present'.")
|
||||
if state == "absent":
|
||||
if len(name) == 0:
|
||||
self.fail_json(msg="Argument 'map_type' can not be used with "
|
||||
"state 'absent'")
|
||||
self.fail_json(msg="At least one 'name' must be provided for"
|
||||
" 'state: absent'")
|
||||
invalid = ["desc"]
|
||||
|
||||
self.params_fail_used_invalid(invalid, state)
|
||||
|
||||
def get_args(self, mapname, desc): # pylint: disable=no-self-use
|
||||
_args = {}
|
||||
if mapname:
|
||||
_args["automountmapname"] = mapname
|
||||
if desc:
|
||||
# automountmapname is required for all automountmap operations.
|
||||
if not mapname:
|
||||
self.fail_json(msg="automountmapname cannot be None or empty.")
|
||||
_args = {"automountmapname": mapname}
|
||||
# An empty string is valid and will clear the attribute.
|
||||
if desc is not None:
|
||||
_args["description"] = desc
|
||||
return _args
|
||||
|
||||
|
||||
@@ -346,11 +346,13 @@ def main():
|
||||
"ca_renewal_master_server": "ca_renewal_master_server",
|
||||
"domain_resolution_order": "ipadomainresolutionorder"
|
||||
}
|
||||
allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
|
||||
reverse_field_map = {v: k for k, v in field_map.items()}
|
||||
|
||||
params = {}
|
||||
for x in field_map:
|
||||
val = ansible_module.params_get(x)
|
||||
val = ansible_module.params_get(
|
||||
x, allow_empty_string=(x in allow_empty_string))
|
||||
|
||||
if val is not None:
|
||||
params[field_map.get(x, x)] = val
|
||||
@@ -401,6 +403,10 @@ def main():
|
||||
k: v for k, v in params.items()
|
||||
if k not in result or result[k] != v
|
||||
}
|
||||
# Remove empty string args from params if result arg is not set
|
||||
for k in ["ipakrbauthzdata", "ipauserauthtype", "ipaconfigstring"]:
|
||||
if k not in result and k in params and params[k] == [""]:
|
||||
del params[k]
|
||||
if params \
|
||||
and not compare_args_ipa(ansible_module, params, result):
|
||||
changed = True
|
||||
@@ -441,6 +447,13 @@ def main():
|
||||
raise ValueError(
|
||||
"Unexpected attribute type: %s" % arg_type)
|
||||
exit_args[k] = type_map[arg_type](value)
|
||||
# Add empty pac_type and user_auth_type if they are not set
|
||||
for key in ["pac_type", "user_auth_type"]:
|
||||
if key not in exit_args:
|
||||
exit_args[key] = ""
|
||||
# Add empty domain_resolution_order if it is not set
|
||||
if "domain_resolution_order" not in exit_args:
|
||||
exit_args["domain_resolution_order"] = []
|
||||
|
||||
# Done
|
||||
ansible_module.exit_json(changed=changed, config=exit_args)
|
||||
|
||||
@@ -54,13 +54,22 @@ options:
|
||||
global forwarders.
|
||||
required: false
|
||||
choices: ['only', 'first', 'none']
|
||||
alias: ["forwardpolicy"]
|
||||
allow_sync_ptr:
|
||||
description:
|
||||
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
|
||||
required: false
|
||||
type: bool
|
||||
action:
|
||||
description: |
|
||||
Work on dnsconfig or member level. It can be one of `member` or
|
||||
`dnsconfig`. Only `forwarders` can be managed with `action: member`.
|
||||
default: "dnsconfig"
|
||||
choices: ["member", "dnsconfig"]
|
||||
state:
|
||||
description: State to ensure
|
||||
description: |
|
||||
The state to ensure. It can be one of `present` or `absent`.
|
||||
`absent` can only be used with `action: member` and `forwarders`.
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
"""
|
||||
@@ -83,6 +92,7 @@ EXAMPLES = """
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
state: absent
|
||||
action: member
|
||||
|
||||
# Disable PTR record synchronization.
|
||||
- ipadnsconfig:
|
||||
@@ -118,7 +128,7 @@ def find_dnsconfig(module):
|
||||
return None
|
||||
|
||||
|
||||
def gen_args(module, state, dnsconfig, forwarders, forward_policy,
|
||||
def gen_args(module, state, action, dnsconfig, forwarders, forward_policy,
|
||||
allow_sync_ptr):
|
||||
_args = {}
|
||||
|
||||
@@ -137,15 +147,20 @@ def gen_args(module, state, dnsconfig, forwarders, forward_policy,
|
||||
|
||||
global_forwarders = dnsconfig.get('idnsforwarders', [])
|
||||
if state == 'absent':
|
||||
_args['idnsforwarders'] = [
|
||||
fwd for fwd in global_forwarders if fwd not in _forwarders]
|
||||
# When all forwarders should be excluded, use an empty string ('').
|
||||
if not _args['idnsforwarders']:
|
||||
_args['idnsforwarders'] = ['']
|
||||
if action == "member":
|
||||
_args['idnsforwarders'] = [
|
||||
fwd for fwd in global_forwarders if fwd not in _forwarders]
|
||||
# When all forwarders should be excluded,
|
||||
# use an empty string ('').
|
||||
if not _args['idnsforwarders']:
|
||||
_args['idnsforwarders'] = ['']
|
||||
|
||||
elif state == 'present':
|
||||
_args['idnsforwarders'] = [
|
||||
fwd for fwd in _forwarders if fwd not in global_forwarders]
|
||||
if action == "member":
|
||||
_args['idnsforwarders'] = \
|
||||
list(set(list(_forwarders) + list(global_forwarders)))
|
||||
else:
|
||||
_args['idnsforwarders'] = _forwarders
|
||||
# If no forwarders should be added, remove argument.
|
||||
if not _args['idnsforwarders']:
|
||||
del _args['idnsforwarders']
|
||||
@@ -175,10 +190,13 @@ def main():
|
||||
forwarders=dict(type='list', default=None, required=False,
|
||||
options=dict(**forwarder_spec)),
|
||||
forward_policy=dict(type='str', required=False, default=None,
|
||||
choices=['only', 'first', 'none']),
|
||||
choices=['only', 'first', 'none'],
|
||||
aliases=["forwardpolicy"]),
|
||||
allow_sync_ptr=dict(type='bool', required=False, default=None),
|
||||
|
||||
# general
|
||||
action=dict(type="str", default="dnsconfig",
|
||||
choices=["member", "dnsconfig"]),
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
)
|
||||
@@ -191,11 +209,17 @@ def main():
|
||||
forward_policy = ansible_module.params_get('forward_policy')
|
||||
allow_sync_ptr = ansible_module.params_get('allow_sync_ptr')
|
||||
|
||||
action = ansible_module.params_get('action')
|
||||
state = ansible_module.params_get('state')
|
||||
|
||||
# Check parameters.
|
||||
invalid = []
|
||||
if state == "present" and action == "member":
|
||||
invalid = ['forward_policy', 'allow_sync_ptr']
|
||||
if state == 'absent':
|
||||
if action != "member":
|
||||
ansible_module.fail_json(
|
||||
msg="State 'absent' is only valid with action 'member'.")
|
||||
invalid = ['forward_policy', 'allow_sync_ptr']
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
@@ -208,7 +232,7 @@ def main():
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
res_find = find_dnsconfig(ansible_module)
|
||||
args = gen_args(ansible_module, state, res_find, forwarders,
|
||||
args = gen_args(ansible_module, state, action, res_find, forwarders,
|
||||
forward_policy, allow_sync_ptr)
|
||||
|
||||
# Execute command only if configuration changes.
|
||||
|
||||
@@ -68,7 +68,7 @@ options:
|
||||
required: false
|
||||
default: only
|
||||
choices: ["only", "first", "none"]
|
||||
aliases: ["idnsforwarders"]
|
||||
aliases: ["idnsforwarders", "forward_policy"]
|
||||
skip_overlap_check:
|
||||
description:
|
||||
- Force DNS zone creation even if it will overlap with an existing zone.
|
||||
@@ -189,7 +189,8 @@ def main():
|
||||
port=dict(type='int', required=False,
|
||||
default=None),
|
||||
)),
|
||||
forwardpolicy=dict(type='str', aliases=["idnsforwardpolicy"],
|
||||
forwardpolicy=dict(type='str',
|
||||
aliases=["idnsforwardpolicy", "forward_policy"],
|
||||
required=False,
|
||||
choices=['only', 'first', 'none']),
|
||||
skip_overlap_check=dict(type='bool', required=False),
|
||||
|
||||
@@ -97,6 +97,11 @@ options:
|
||||
required: false
|
||||
type: list
|
||||
ailases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
required: false
|
||||
type: list
|
||||
action:
|
||||
description: Work on group or member level
|
||||
default: group
|
||||
@@ -181,9 +186,10 @@ EXAMPLES = """
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
||||
gen_add_list, gen_intersection_list
|
||||
gen_add_list, gen_intersection_list, api_check_param
|
||||
|
||||
|
||||
def find_group(module, name):
|
||||
@@ -198,7 +204,14 @@ def find_group(module, name):
|
||||
module.fail_json(
|
||||
msg="There is more than one group '%s'" % (name))
|
||||
elif len(_result["result"]) == 1:
|
||||
return _result["result"][0]
|
||||
_res = _result["result"][0]
|
||||
# The returned services are of type ipapython.kerberos.Principal,
|
||||
# also services are not case sensitive. Therefore services are
|
||||
# converted to lowercase strings to be able to do the comparison.
|
||||
if "member_service" in _res:
|
||||
_res["member_service"] = \
|
||||
[to_text(svc).lower() for svc in _res["member_service"]]
|
||||
return _res
|
||||
|
||||
return None
|
||||
|
||||
@@ -215,7 +228,7 @@ def gen_args(description, gid, nomembers):
|
||||
return _args
|
||||
|
||||
|
||||
def gen_member_args(user, group, service, externalmember):
|
||||
def gen_member_args(user, group, service, externalmember, idoverrideuser):
|
||||
_args = {}
|
||||
if user is not None:
|
||||
_args["member_user"] = user
|
||||
@@ -225,6 +238,8 @@ def gen_member_args(user, group, service, externalmember):
|
||||
_args["member_service"] = service
|
||||
if externalmember is not None:
|
||||
_args["member_external"] = externalmember
|
||||
if idoverrideuser is not None:
|
||||
_args["member_idoverrideuser"] = idoverrideuser
|
||||
|
||||
return _args
|
||||
|
||||
@@ -272,6 +287,7 @@ def main():
|
||||
user=dict(required=False, type='list', default=None),
|
||||
group=dict(required=False, type='list', default=None),
|
||||
service=dict(required=False, type='list', default=None),
|
||||
idoverrideuser=dict(required=False, type='list', default=None),
|
||||
membermanager_user=dict(required=False, type='list', default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
default=None),
|
||||
@@ -304,11 +320,13 @@ def main():
|
||||
gid = ansible_module.params_get("gid")
|
||||
nonposix = ansible_module.params_get("nonposix")
|
||||
external = ansible_module.params_get("external")
|
||||
idoverrideuser = ansible_module.params_get("idoverrideuser")
|
||||
posix = ansible_module.params_get("posix")
|
||||
nomembers = ansible_module.params_get("nomembers")
|
||||
user = ansible_module.params_get("user")
|
||||
group = ansible_module.params_get("group")
|
||||
service = ansible_module.params_get("service")
|
||||
# Services are not case sensitive
|
||||
service = ansible_module.params_get_lowercase("service")
|
||||
membermanager_user = ansible_module.params_get("membermanager_user")
|
||||
membermanager_group = ansible_module.params_get("membermanager_group")
|
||||
externalmember = ansible_module.params_get("externalmember")
|
||||
@@ -370,6 +388,13 @@ def main():
|
||||
"by your IPA version"
|
||||
)
|
||||
|
||||
has_idoverrideuser = api_check_param(
|
||||
"group_add_member", "idoverrideuser")
|
||||
if idoverrideuser is not None and not has_idoverrideuser:
|
||||
ansible_module.fail_json(
|
||||
msg="Managing a idoverrideuser as part of a group is not "
|
||||
"supported by your IPA version")
|
||||
|
||||
commands = []
|
||||
|
||||
for name in names:
|
||||
@@ -380,6 +405,7 @@ def main():
|
||||
group_add, group_del = [], []
|
||||
service_add, service_del = [], []
|
||||
externalmember_add, externalmember_del = [], []
|
||||
idoverrides_add, idoverrides_del = [], []
|
||||
membermanager_user_add, membermanager_user_del = [], []
|
||||
membermanager_group_add, membermanager_group_del = [], []
|
||||
|
||||
@@ -429,7 +455,7 @@ def main():
|
||||
res_find["objectclass"].append("posixgroup")
|
||||
|
||||
member_args = gen_member_args(
|
||||
user, group, service, externalmember
|
||||
user, group, service, externalmember, idoverrideuser
|
||||
)
|
||||
if not compare_args_ipa(ansible_module, member_args,
|
||||
res_find):
|
||||
@@ -447,6 +473,12 @@ def main():
|
||||
externalmember_del) = gen_add_del_lists(
|
||||
externalmember, res_find.get("member_external"))
|
||||
|
||||
(idoverrides_add,
|
||||
idoverrides_del) = gen_add_del_lists(
|
||||
idoverrideuser,
|
||||
res_find.get("member_idoverrideuser")
|
||||
)
|
||||
|
||||
membermanager_user_add, membermanager_user_del = \
|
||||
gen_add_del_lists(
|
||||
membermanager_user,
|
||||
@@ -474,6 +506,8 @@ def main():
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_add = gen_add_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
idoverrides_add = gen_add_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
|
||||
membermanager_user_add = gen_add_list(
|
||||
membermanager_user,
|
||||
@@ -507,6 +541,8 @@ def main():
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_del = gen_intersection_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
idoverrides_del = gen_intersection_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
|
||||
membermanager_user_del = gen_intersection_list(
|
||||
membermanager_user, res_find.get("membermanager_user"))
|
||||
@@ -523,10 +559,16 @@ def main():
|
||||
"user": user_add,
|
||||
"group": group_add,
|
||||
}
|
||||
|
||||
del_member_args = {
|
||||
"user": user_del,
|
||||
"group": group_del,
|
||||
}
|
||||
|
||||
if has_idoverrideuser:
|
||||
add_member_args["idoverrideuser"] = idoverrides_add
|
||||
del_member_args["idoverrideuser"] = idoverrides_del
|
||||
|
||||
if has_add_member_service:
|
||||
add_member_args["service"] = service_add
|
||||
del_member_args["service"] = service_del
|
||||
@@ -541,15 +583,16 @@ def main():
|
||||
msg="Cannot add external members to a "
|
||||
"non-external group."
|
||||
)
|
||||
|
||||
# Add members
|
||||
add_members = any([user_add, group_add,
|
||||
add_members = any([user_add, group_add, idoverrides_add,
|
||||
service_add, externalmember_add])
|
||||
if add_members:
|
||||
commands.append(
|
||||
[name, "group_add_member", add_member_args]
|
||||
)
|
||||
# Remove members
|
||||
remove_members = any([user_del, group_del,
|
||||
remove_members = any([user_del, group_del, idoverrides_del,
|
||||
service_del, externalmember_del])
|
||||
if remove_members:
|
||||
commands.append(
|
||||
|
||||
@@ -360,28 +360,28 @@ def main():
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists
|
||||
if host:
|
||||
if host is not None:
|
||||
host_add, host_del = gen_add_del_lists(
|
||||
host, res_find.get("memberhost_host"))
|
||||
|
||||
if hostgroup:
|
||||
if hostgroup is not None:
|
||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
if hbacsvc:
|
||||
if hbacsvc is not None:
|
||||
hbacsvc_add, hbacsvc_del = gen_add_del_lists(
|
||||
hbacsvc, res_find.get("memberservice_hbacsvc"))
|
||||
|
||||
if hbacsvcgroup:
|
||||
if hbacsvcgroup is not None:
|
||||
hbacsvcgroup_add, hbacsvcgroup_del = gen_add_del_lists(
|
||||
hbacsvcgroup,
|
||||
res_find.get("memberservice_hbacsvcgroup"))
|
||||
|
||||
if user:
|
||||
if user is not None:
|
||||
user_add, user_del = gen_add_del_lists(
|
||||
user, res_find.get("memberuser_user"))
|
||||
|
||||
if group:
|
||||
if group is not None:
|
||||
group_add, group_del = gen_add_del_lists(
|
||||
group, res_find.get("memberuser_group"))
|
||||
|
||||
@@ -395,7 +395,7 @@ def main():
|
||||
if host:
|
||||
host_add = gen_add_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
if hostgroup is not None:
|
||||
if hostgroup:
|
||||
hostgroup_add = gen_add_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
|
||||
@@ -709,7 +709,7 @@ def main():
|
||||
elements='dict', required=False),
|
||||
|
||||
# mod
|
||||
update_password=dict(type='str', default=None,
|
||||
update_password=dict(type='str', default=None, no_log=False,
|
||||
choices=['always', 'on_create']),
|
||||
|
||||
# general
|
||||
@@ -764,7 +764,7 @@ def main():
|
||||
mac_address = ansible_module.params_get("mac_address")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey")
|
||||
userclass = ansible_module.params_get("userclass")
|
||||
auth_ind = ansible_module.params_get("auth_ind")
|
||||
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
|
||||
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
||||
ok_as_delegate = ansible_module.params_get("ok_as_delegate")
|
||||
ok_to_auth_as_delegate = ansible_module.params_get(
|
||||
|
||||
@@ -139,7 +139,7 @@ RETURN = """
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
||||
gen_intersection_list
|
||||
gen_intersection_list, ensure_fqdn
|
||||
|
||||
|
||||
def find_hostgroup(module, name):
|
||||
@@ -281,6 +281,15 @@ def main():
|
||||
ansible_module.fail_json(
|
||||
msg="Renaming hostgroups is not supported by your IPA version")
|
||||
|
||||
# If hosts are given, ensure that the hosts are FQDN and also
|
||||
# lowercase to be able to do a proper comparison to exising hosts
|
||||
# in the hostgroup.
|
||||
# Fixes #666 (ipahostgroup not idempotent and with error)
|
||||
if host is not None:
|
||||
default_domain = ansible_module.ipa_get_domain()
|
||||
host = [ensure_fqdn(_host, default_domain).lower()
|
||||
for _host in host]
|
||||
|
||||
commands = []
|
||||
|
||||
for name in names:
|
||||
|
||||
332
plugins/modules/ipaidrange.py
Normal file
332
plugins/modules/ipaidrange.py
Normal file
@@ -0,0 +1,332 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaidrange
|
||||
short description: Manage FreeIPA idrange
|
||||
description: Manage FreeIPA idrange
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
- ipamodule_base_docs.delete_continue
|
||||
options:
|
||||
name:
|
||||
description: The list of idrange name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
base_id:
|
||||
description: First Posix ID of the range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipabaseid"]
|
||||
range_size:
|
||||
description: Number of IDs in the range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipaidrangesize"]
|
||||
rid_base:
|
||||
description: First RID of the corresponding RID range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipabaserid"]
|
||||
secondary_rid_base:
|
||||
description: First RID of the secondary RID range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipasecondarybaserid"]
|
||||
idrange_type:
|
||||
description: ID range type.
|
||||
type: string
|
||||
required: false
|
||||
choices: ["ipa-ad-trust", "ipa-ad-trust-posix", "ipa-local"]
|
||||
aliases: ["iparangetype"]
|
||||
dom_sid:
|
||||
description: Domain SID of the trusted domain.
|
||||
type: string
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainsid"]
|
||||
dom_name:
|
||||
description: Domain name of the trusted domain.
|
||||
type: string
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainname"]
|
||||
auto_private_groups:
|
||||
description: Auto creation of private groups.
|
||||
type: string
|
||||
required: false
|
||||
choices: ["true", "false", "hybrid"]
|
||||
aliases: ["ipaautoprivategroups"]
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure local domain idrange is present
|
||||
- ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
|
||||
# Ensure local domain idrange is absent
|
||||
- ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
state: absent
|
||||
|
||||
# Ensure AD-trust idrange is present
|
||||
- ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
auto_private_groups: "false"
|
||||
|
||||
# Ensure AD-trust idrange is present, with range type ad-trust-posix,
|
||||
# and using domain name
|
||||
- ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
auto_private_groups: "hybrid"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_idrange(module, name):
|
||||
"""Find if a idrange with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("idrange_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if idrange name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def gen_args(
|
||||
base_id, range_size, rid_base, secondary_rid_base, idrange_type, dom_sid,
|
||||
auto_private_groups
|
||||
):
|
||||
_args = {}
|
||||
# Integer parameters are stored as strings.
|
||||
# Converting them here allows the proper use of compare_args_ipa.
|
||||
if base_id is not None:
|
||||
_args["ipabaseid"] = base_id
|
||||
if range_size is not None:
|
||||
_args["ipaidrangesize"] = range_size
|
||||
if rid_base is not None:
|
||||
_args["ipabaserid"] = rid_base
|
||||
if secondary_rid_base is not None:
|
||||
_args["ipasecondarybaserid"] = secondary_rid_base
|
||||
if idrange_type is not None:
|
||||
_args["iparangetype"] = idrange_type
|
||||
if dom_sid is not None:
|
||||
_args["ipanttrusteddomainsid"] = dom_sid
|
||||
if auto_private_groups is not None:
|
||||
_args["ipaautoprivategroups"] = auto_private_groups
|
||||
return _args
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
# present
|
||||
base_id=dict(required=False, type='int',
|
||||
aliases=["ipabaseid"], default=None),
|
||||
range_size=dict(required=False, type='int',
|
||||
aliases=["ipaidrangesize"], default=None),
|
||||
rid_base=dict(required=False, type='int',
|
||||
aliases=["ipabaserid"], default=None),
|
||||
secondary_rid_base=dict(required=False, type='int', default=None,
|
||||
aliases=["ipasecondarybaserid"]),
|
||||
idrange_type=dict(required=False, aliases=["iparangetype"],
|
||||
type="str", default=None,
|
||||
choices=["ipa-ad-trust", "ipa-ad-trust-posix",
|
||||
"ipa-local"]),
|
||||
dom_sid=dict(required=False, type='str', default=None,
|
||||
aliases=["ipanttrusteddomainsid"]),
|
||||
dom_name=dict(required=False, type='str', default=None,
|
||||
aliases=["ipanttrusteddomainname"]),
|
||||
auto_private_groups=dict(required=False, type='str', default=None,
|
||||
aliases=["ipaautoprivategroups"],
|
||||
choices=['true', 'false', 'hybrid']),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
mutually_exclusive=[
|
||||
["dom_sid", "secondary_rid_base"],
|
||||
["dom_name", "secondary_rid_base"],
|
||||
["dom_sid", "dom_name"],
|
||||
],
|
||||
supports_check_mode=True,
|
||||
ipa_module_options=["delete_continue"],
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
delete_continue = ansible_module.params_get("delete_continue")
|
||||
|
||||
# present
|
||||
base_id = ansible_module.params_get("base_id")
|
||||
range_size = ansible_module.params_get("range_size")
|
||||
rid_base = ansible_module.params_get("rid_base")
|
||||
secondary_rid_base = ansible_module.params_get("secondary_rid_base")
|
||||
idrange_type = ansible_module.params_get("idrange_type")
|
||||
dom_sid = ansible_module.params_get("dom_sid")
|
||||
auto_private_groups = \
|
||||
ansible_module.params_get_lowercase("auto_private_groups")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one idrange can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
invalid = ["base_id", "range_size", "idrange_type", "dom_sid"]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
range_types = {
|
||||
"Active Directory domain range": "ipa-ad-trust",
|
||||
"Active Directory trust range with POSIX attributes":
|
||||
"ipa-ad-trust-posix",
|
||||
"local domain range": "ipa-local",
|
||||
}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
commands = []
|
||||
for name in names:
|
||||
# Make sure idrange exists
|
||||
res_find = find_idrange(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
# Generate args
|
||||
args = gen_args(
|
||||
base_id, range_size, rid_base, secondary_rid_base,
|
||||
idrange_type, dom_sid, auto_private_groups
|
||||
)
|
||||
|
||||
# Found the idrange
|
||||
if res_find is not None:
|
||||
# For all settings is args, check if there are
|
||||
# different settings in the find result.
|
||||
# If yes: modify
|
||||
if not compare_args_ipa(
|
||||
ansible_module, args, res_find, ignore=["iparangetype"]
|
||||
):
|
||||
res_type = range_types.get(
|
||||
res_find.get("iparangetype")[0]
|
||||
)
|
||||
if res_type == "local_id_range":
|
||||
ansible_module.fail_json(
|
||||
"Cannot modify local IPA domain idrange."
|
||||
)
|
||||
|
||||
arg_type = args.get("iparangetype")
|
||||
if arg_type:
|
||||
if arg_type != res_type:
|
||||
ansible_module.fail_json(
|
||||
"Cannot modify idrange type."
|
||||
)
|
||||
del args["iparangetype"]
|
||||
commands.append([name, "idrange_mod", args])
|
||||
else:
|
||||
commands.append([name, "idrange_add", args])
|
||||
|
||||
elif state == "absent":
|
||||
if res_find is not None:
|
||||
commands.append([
|
||||
name,
|
||||
"idrange_del",
|
||||
{"continue": delete_continue or False}
|
||||
])
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(commands)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -50,13 +50,13 @@ options:
|
||||
pac_type:
|
||||
description: Supported PAC type.
|
||||
required: false
|
||||
choices: ["MS-PAC", "PAD", "NONE"]
|
||||
choices: ["MS-PAC", "PAD", "NONE", ""]
|
||||
type: list
|
||||
aliases: ["pac_type", "ipakrbauthzdata"]
|
||||
auth_ind:
|
||||
description: Defines a whitelist for Authentication Indicators.
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened"]
|
||||
choices: ["otp", "radius", "pkinit", "hardened", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
@@ -356,7 +356,7 @@ def init_ansible_module():
|
||||
smb=dict(type="bool", required=False),
|
||||
netbiosname=dict(type="str", required=False),
|
||||
pac_type=dict(type="list", aliases=["ipakrbauthzdata"],
|
||||
choices=["MS-PAC", "PAD", "NONE"]),
|
||||
choices=["MS-PAC", "PAD", "NONE", ""]),
|
||||
auth_ind=dict(type="list",
|
||||
aliases=["krbprincipalauthind"],
|
||||
choices=["otp", "radius", "pkinit", "hardened", ""]),
|
||||
@@ -420,8 +420,8 @@ def main():
|
||||
# service attributes
|
||||
principal = ansible_module.params_get("principal")
|
||||
certificate = ansible_module.params_get("certificate")
|
||||
pac_type = ansible_module.params_get("pac_type")
|
||||
auth_ind = ansible_module.params_get("auth_ind")
|
||||
pac_type = ansible_module.params_get("pac_type", allow_empty_string=True)
|
||||
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
|
||||
skip_host_check = ansible_module.params_get("skip_host_check")
|
||||
force = ansible_module.params_get("force")
|
||||
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
||||
@@ -537,6 +537,15 @@ def main():
|
||||
if remove in args:
|
||||
del args[remove]
|
||||
|
||||
if (
|
||||
"ipakrbauthzdata" in args
|
||||
and (
|
||||
args.get("ipakrbauthzdata", [""]) ==
|
||||
res_find.get("ipakrbauthzdata", [""])
|
||||
)
|
||||
):
|
||||
del args["ipakrbauthzdata"]
|
||||
|
||||
if (
|
||||
"krbprincipalauthind" in args
|
||||
and (
|
||||
|
||||
352
plugins/modules/ipaservicedelegationrule.py
Normal file
352
plugins/modules/ipaservicedelegationrule.py
Normal file
@@ -0,0 +1,352 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationrule
|
||||
short description: Manage FreeIPA servicedelegationrule
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationrule and servicedelegationrule members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationrule name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
description: |
|
||||
The list of principals. A principal can be of the format:
|
||||
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
|
||||
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
|
||||
are host principals and the same as host/fqdn and host/fqd
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
required: false
|
||||
target:
|
||||
description: |
|
||||
The list of service delegation targets.
|
||||
required: false
|
||||
aliases: ["servicedelegationtarget"]
|
||||
action:
|
||||
description: Work on servicedelegationrule or member level.
|
||||
choices: ["servicedelegationrule", "member"]
|
||||
default: servicedelegationrule
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure servicedelegationrule delegation-rule is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member principal
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member principal
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member target
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member target
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
|
||||
servicedelegation_normalize_principals, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_servicedelegationrule(module, name):
|
||||
"""Find if a servicedelegationrule with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationrule_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if servicedelegationrule name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def check_targets(module, targets):
|
||||
def _check_exists(module, _type, name):
|
||||
# Check if item of type _type exists using the show command
|
||||
try:
|
||||
module.ipa_command("%s_show" % _type, name, {})
|
||||
except ipalib_errors.NotFound as e:
|
||||
msg = str(e)
|
||||
if "%s not found" % _type in msg:
|
||||
return False
|
||||
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
|
||||
return True
|
||||
|
||||
for _target in targets:
|
||||
if not _check_exists(module, "servicedelegationtarget", _target):
|
||||
module.fail_json(
|
||||
msg="Service delegation target '%s' does not exist" % _target)
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
target=dict(required=False, type='list',
|
||||
aliases=["servicedelegationtarget"], default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationrule",
|
||||
choices=["member", "servicedelegationrule"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
principal = ansible_module.params_get("principal")
|
||||
target = ansible_module.params_get("target")
|
||||
|
||||
action = ansible_module.params_get("action")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one servicedelegationrule can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
if action == "servicedelegationrule":
|
||||
invalid = ["principal", "target"]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
# Init
|
||||
|
||||
membertarget = "ipaallowedtarget_servicedelegationtarget"
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
# Normalize principals
|
||||
if principal:
|
||||
principal = servicedelegation_normalize_principals(
|
||||
ansible_module, principal, state == "present")
|
||||
if target and state == "present":
|
||||
check_targets(ansible_module, target)
|
||||
|
||||
commands = []
|
||||
principal_add = principal_del = []
|
||||
target_add = target_del = []
|
||||
for name in names:
|
||||
# Make sure servicedelegationrule exists
|
||||
res_find = find_servicedelegationrule(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
if action == "servicedelegationrule":
|
||||
# A servicedelegationrule does not have normal options.
|
||||
# There is no servicedelegationtarget-mod command.
|
||||
# Principal members are handled with the _add_member and
|
||||
# _remove_member commands further down.
|
||||
if res_find is None:
|
||||
commands.append([name, "servicedelegationrule_add",
|
||||
{}])
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists for principal
|
||||
principal_add, principal_del = gen_add_del_lists(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
|
||||
# Generate addition and removal lists for target
|
||||
target_add, target_del = gen_add_del_lists(
|
||||
target, res_find.get(membertarget))
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationrule '%s'" % name)
|
||||
|
||||
# Reduce add lists for principal
|
||||
# to new entries only that are not in res_find.
|
||||
if principal is not None and \
|
||||
"memberprincipal" in res_find:
|
||||
principal_add = gen_add_list(
|
||||
principal, res_find["memberprincipal"])
|
||||
else:
|
||||
principal_add = principal
|
||||
|
||||
# Reduce add lists for target
|
||||
# to new entries only that are not in res_find.
|
||||
if target is not None and membertarget in res_find:
|
||||
target_add = gen_add_list(
|
||||
target, res_find[membertarget])
|
||||
else:
|
||||
target_add = target
|
||||
|
||||
elif state == "absent":
|
||||
if action == "servicedelegationrule":
|
||||
if res_find is not None:
|
||||
commands.append([name, "servicedelegationrule_del",
|
||||
{}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationrule '%s'" % name)
|
||||
|
||||
# Reduce del lists of principals to the entries only
|
||||
# that are in res_find.
|
||||
if principal is not None:
|
||||
principal_del = gen_intersection_list(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
else:
|
||||
principal_del = principal
|
||||
|
||||
# Reduce del lists of targets to the entries only
|
||||
# that are in res_find.
|
||||
if target is not None:
|
||||
target_del = gen_intersection_list(
|
||||
target, res_find.get(membertarget))
|
||||
else:
|
||||
target_del = target
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Handle members
|
||||
|
||||
# Add principal members
|
||||
if principal_add is not None and len(principal_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_add_member",
|
||||
{
|
||||
"principal": principal_add,
|
||||
}])
|
||||
# Remove principal members
|
||||
if principal_del is not None and len(principal_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_remove_member",
|
||||
{
|
||||
"principal": principal_del,
|
||||
}])
|
||||
|
||||
# Add target members
|
||||
if target_add is not None and len(target_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationrule_add_target",
|
||||
{
|
||||
"servicedelegationtarget": target_add,
|
||||
}])
|
||||
# Remove target members
|
||||
if target_del is not None and len(target_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationrule_remove_target",
|
||||
{
|
||||
"servicedelegationtarget": target_del,
|
||||
}])
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, fail_on_member_errors=True)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
270
plugins/modules/ipaservicedelegationtarget.py
Normal file
270
plugins/modules/ipaservicedelegationtarget.py
Normal file
@@ -0,0 +1,270 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationtarget
|
||||
short description: Manage FreeIPA servicedelegationtarget
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationtarget and servicedelegationtarget members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationtarget name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
description: |
|
||||
The list of principals. A principal can be of the format:
|
||||
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
|
||||
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
|
||||
are host principals and the same as host/fqdn and host/fqdn@REALM.
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
required: false
|
||||
action:
|
||||
description: Work on servicedelegationtarget or member level.
|
||||
choices: ["servicedelegationtarget", "member"]
|
||||
default: servicedelegationtarget
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure servicedelegationtarget delegation-target is present
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target member principal
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target member principal
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target is absent
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
|
||||
servicedelegation_normalize_principals
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_servicedelegationtarget(module, name):
|
||||
"""Find if a servicedelegationtarget with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationtarget_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if servicedelegationtarget name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationtarget",
|
||||
choices=["member", "servicedelegationtarget"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
principal = ansible_module.params_get("principal")
|
||||
|
||||
action = ansible_module.params_get("action")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one servicedelegationtarget can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
if action == "servicedelegationtarget":
|
||||
invalid.append("principal")
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
# Normalize principals
|
||||
if principal:
|
||||
principal = servicedelegation_normalize_principals(
|
||||
ansible_module, principal, state == "present")
|
||||
|
||||
commands = []
|
||||
principal_add = principal_del = []
|
||||
for name in names:
|
||||
# Make sure servicedelegationtarget exists
|
||||
res_find = find_servicedelegationtarget(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
if action == "servicedelegationtarget":
|
||||
# A servicedelegationtarget does not have normal options.
|
||||
# There is no servicedelegationtarget-mod command.
|
||||
# Principal members are handled with the _add_member and
|
||||
# _remove_member commands further down.
|
||||
if res_find is None:
|
||||
commands.append([name, "servicedelegationtarget_add",
|
||||
{}])
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists
|
||||
principal_add, principal_del = gen_add_del_lists(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationtarget '%s'" % name)
|
||||
|
||||
# Reduce add lists for principal
|
||||
# to new entries only that are not in res_find.
|
||||
if principal is not None and \
|
||||
"memberprincipal" in res_find:
|
||||
principal_add = gen_add_list(
|
||||
principal, res_find["memberprincipal"])
|
||||
else:
|
||||
principal_add = principal
|
||||
|
||||
elif state == "absent":
|
||||
if action == "servicedelegationtarget":
|
||||
if res_find is not None:
|
||||
commands.append([name, "servicedelegationtarget_del",
|
||||
{}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationtarget '%s'" % name)
|
||||
|
||||
# Reduce del lists of principal
|
||||
# to the entries only that are in res_find.
|
||||
if principal is not None:
|
||||
principal_del = gen_intersection_list(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
else:
|
||||
principal_del = principal
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Handle members
|
||||
|
||||
# Add principal members
|
||||
if principal_add is not None and len(principal_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_add_member",
|
||||
{
|
||||
"principal": principal_add,
|
||||
}])
|
||||
# Remove principal members
|
||||
if principal_del is not None and len(principal_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_remove_member",
|
||||
{
|
||||
"principal": principal_del,
|
||||
}])
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, fail_on_member_errors=True)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -297,17 +297,19 @@ def main():
|
||||
hostcategory = ansible_module.params_get("hostcategory") # noqa
|
||||
nomembers = ansible_module.params_get("nomembers") # noqa
|
||||
host = ansible_module.params_get("host")
|
||||
hostgroup = ansible_module.params_get("hostgroup")
|
||||
user = ansible_module.params_get("user")
|
||||
group = ansible_module.params_get("group")
|
||||
hostgroup = ansible_module.params_get_lowercase("hostgroup")
|
||||
user = ansible_module.params_get_lowercase("user")
|
||||
group = ansible_module.params_get_lowercase("group")
|
||||
allow_sudocmd = ansible_module.params_get('allow_sudocmd')
|
||||
allow_sudocmdgroup = ansible_module.params_get('allow_sudocmdgroup')
|
||||
allow_sudocmdgroup = \
|
||||
ansible_module.params_get_lowercase('allow_sudocmdgroup')
|
||||
deny_sudocmd = ansible_module.params_get('deny_sudocmd')
|
||||
deny_sudocmdgroup = ansible_module.params_get('deny_sudocmdgroup')
|
||||
deny_sudocmdgroup = \
|
||||
ansible_module.params_get_lowercase('deny_sudocmdgroup')
|
||||
sudooption = ansible_module.params_get("sudooption")
|
||||
order = ansible_module.params_get("order")
|
||||
runasuser = ansible_module.params_get("runasuser")
|
||||
runasgroup = ansible_module.params_get("runasgroup")
|
||||
runasuser = ansible_module.params_get_lowercase("runasuser")
|
||||
runasgroup = ansible_module.params_get_lowercase("runasgroup")
|
||||
action = ansible_module.params_get("action")
|
||||
|
||||
# state
|
||||
@@ -383,6 +385,17 @@ def main():
|
||||
)
|
||||
|
||||
commands = []
|
||||
host_add, host_del = [], []
|
||||
user_add, user_del = [], []
|
||||
group_add, group_del = [], []
|
||||
hostgroup_add, hostgroup_del = [], []
|
||||
allow_cmd_add, allow_cmd_del = [], []
|
||||
allow_cmdgroup_add, allow_cmdgroup_del = [], []
|
||||
deny_cmd_add, deny_cmd_del = [], []
|
||||
deny_cmdgroup_add, deny_cmdgroup_del = [], []
|
||||
sudooption_add, sudooption_del = [], []
|
||||
runasuser_add, runasuser_del = [], []
|
||||
runasgroup_add, runasgroup_del = [], []
|
||||
|
||||
for name in names:
|
||||
# Make sure sudorule exists
|
||||
@@ -487,95 +500,11 @@ def main():
|
||||
runasgroup_add, runasgroup_del = gen_add_del_lists(
|
||||
runasgroup,
|
||||
(
|
||||
res_find.get('ipasudorunas_group', [])
|
||||
res_find.get('ipasudorunasgroup_group', [])
|
||||
+ res_find.get('ipasudorunasextgroup', [])
|
||||
)
|
||||
)
|
||||
|
||||
# Add hosts and hostgroups
|
||||
if len(host_add) > 0 or len(hostgroup_add) > 0:
|
||||
commands.append([name, "sudorule_add_host",
|
||||
{
|
||||
"host": host_add,
|
||||
"hostgroup": hostgroup_add,
|
||||
}])
|
||||
# Remove hosts and hostgroups
|
||||
if len(host_del) > 0 or len(hostgroup_del) > 0:
|
||||
commands.append([name, "sudorule_remove_host",
|
||||
{
|
||||
"host": host_del,
|
||||
"hostgroup": hostgroup_del,
|
||||
}])
|
||||
|
||||
# Add users and groups
|
||||
if len(user_add) > 0 or len(group_add) > 0:
|
||||
commands.append([name, "sudorule_add_user",
|
||||
{
|
||||
"user": user_add,
|
||||
"group": group_add,
|
||||
}])
|
||||
# Remove users and groups
|
||||
if len(user_del) > 0 or len(group_del) > 0:
|
||||
commands.append([name, "sudorule_remove_user",
|
||||
{
|
||||
"user": user_del,
|
||||
"group": group_del,
|
||||
}])
|
||||
|
||||
# Add commands allowed
|
||||
if len(allow_cmd_add) > 0 or len(allow_cmdgroup_add) > 0:
|
||||
commands.append([name, "sudorule_add_allow_command",
|
||||
{"sudocmd": allow_cmd_add,
|
||||
"sudocmdgroup": allow_cmdgroup_add,
|
||||
}])
|
||||
|
||||
if len(allow_cmd_del) > 0 or len(allow_cmdgroup_del) > 0:
|
||||
commands.append([name, "sudorule_remove_allow_command",
|
||||
{"sudocmd": allow_cmd_del,
|
||||
"sudocmdgroup": allow_cmdgroup_del
|
||||
}])
|
||||
|
||||
# Add commands denied
|
||||
if len(deny_cmd_add) > 0 or len(deny_cmdgroup_add) > 0:
|
||||
commands.append([name, "sudorule_add_deny_command",
|
||||
{"sudocmd": deny_cmd_add,
|
||||
"sudocmdgroup": deny_cmdgroup_add,
|
||||
}])
|
||||
|
||||
if len(deny_cmd_del) > 0 or len(deny_cmdgroup_del) > 0:
|
||||
commands.append([name, "sudorule_remove_deny_command",
|
||||
{"sudocmd": deny_cmd_del,
|
||||
"sudocmdgroup": deny_cmdgroup_del
|
||||
}])
|
||||
|
||||
# Add RunAS Users
|
||||
if len(runasuser_add) > 0:
|
||||
commands.append([name, "sudorule_add_runasuser",
|
||||
{"user": runasuser_add}])
|
||||
# Remove RunAS Users
|
||||
if len(runasuser_del) > 0:
|
||||
commands.append([name, "sudorule_remove_runasuser",
|
||||
{"user": runasuser_del}])
|
||||
|
||||
# Add RunAS Groups
|
||||
if len(runasgroup_add) > 0:
|
||||
commands.append([name, "sudorule_add_runasgroup",
|
||||
{"group": runasgroup_add}])
|
||||
# Remove RunAS Groups
|
||||
if len(runasgroup_del) > 0:
|
||||
commands.append([name, "sudorule_remove_runasgroup",
|
||||
{"group": runasgroup_del}])
|
||||
|
||||
# Add sudo options
|
||||
for sudoopt in sudooption_add:
|
||||
commands.append([name, "sudorule_add_option",
|
||||
{"ipasudoopt": sudoopt}])
|
||||
|
||||
# Remove sudo options
|
||||
for sudoopt in sudooption_del:
|
||||
commands.append([name, "sudorule_remove_option",
|
||||
{"ipasudoopt": sudoopt}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(msg="No sudorule '%s'" % name)
|
||||
@@ -585,56 +514,47 @@ def main():
|
||||
# deny_sudocmdgroup, sudooption, runasuser, runasgroup
|
||||
# and res_find to only try to add the items that not in
|
||||
# the sudorule already
|
||||
if host is not None and \
|
||||
"memberhost_host" in res_find:
|
||||
host = gen_add_list(
|
||||
host, res_find["memberhost_host"])
|
||||
if hostgroup is not None and \
|
||||
"memberhost_hostgroup" in res_find:
|
||||
hostgroup = gen_add_list(
|
||||
hostgroup, res_find["memberhost_hostgroup"])
|
||||
if user is not None and \
|
||||
"memberuser_user" in res_find:
|
||||
user = gen_add_list(
|
||||
user, res_find["memberuser_user"])
|
||||
if group is not None and \
|
||||
"memberuser_group" in res_find:
|
||||
group = gen_add_list(
|
||||
group, res_find["memberuser_group"])
|
||||
if allow_sudocmd is not None and \
|
||||
"memberallowcmd_sudocmd" in res_find:
|
||||
allow_sudocmd = gen_add_list(
|
||||
allow_sudocmd, res_find["memberallowcmd_sudocmd"])
|
||||
if allow_sudocmdgroup is not None and \
|
||||
"memberallowcmd_sudocmdgroup" in res_find:
|
||||
allow_sudocmdgroup = gen_add_list(
|
||||
if host is not None:
|
||||
host_add = gen_add_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
if hostgroup is not None:
|
||||
hostgroup_add = gen_add_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
if user is not None:
|
||||
user_add = gen_add_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
if group is not None:
|
||||
group_add = gen_add_list(
|
||||
group, res_find.get("memberuser_group"))
|
||||
if allow_sudocmd is not None:
|
||||
allow_cmd_add = gen_add_list(
|
||||
allow_sudocmd,
|
||||
res_find.get("memberallowcmd_sudocmd")
|
||||
)
|
||||
if allow_sudocmdgroup is not None:
|
||||
allow_cmdgroup_add = gen_add_list(
|
||||
allow_sudocmdgroup,
|
||||
res_find["memberallowcmd_sudocmdgroup"])
|
||||
if deny_sudocmd is not None and \
|
||||
"memberdenycmd_sudocmd" in res_find:
|
||||
deny_sudocmd = gen_add_list(
|
||||
deny_sudocmd, res_find["memberdenycmd_sudocmd"])
|
||||
if deny_sudocmdgroup is not None and \
|
||||
"memberdenycmd_sudocmdgroup" in res_find:
|
||||
deny_sudocmdgroup = gen_add_list(
|
||||
res_find.get("memberallowcmd_sudocmdgroup")
|
||||
)
|
||||
if deny_sudocmd is not None:
|
||||
deny_cmd_add = gen_add_list(
|
||||
deny_sudocmd,
|
||||
res_find.get("memberdenycmd_sudocmd")
|
||||
)
|
||||
if deny_sudocmdgroup is not None:
|
||||
deny_cmdgroup_add = gen_add_list(
|
||||
deny_sudocmdgroup,
|
||||
res_find["memberdenycmd_sudocmdgroup"])
|
||||
if sudooption is not None and \
|
||||
"ipasudoopt" in res_find:
|
||||
sudooption = gen_add_list(
|
||||
sudooption, res_find["ipasudoopt"])
|
||||
res_find.get("memberdenycmd_sudocmdgroup")
|
||||
)
|
||||
if sudooption is not None:
|
||||
sudooption_add = gen_add_list(
|
||||
sudooption, res_find.get("ipasudoopt"))
|
||||
# runasuser attribute can be used with both IPA and
|
||||
# non-IPA (external) users, so we need to compare
|
||||
# the provided list against both users and external
|
||||
# users list.
|
||||
if (
|
||||
runasuser is not None
|
||||
and (
|
||||
"ipasudorunas_user" in res_find
|
||||
or "ipasudorunasextuser" in res_find
|
||||
)
|
||||
):
|
||||
runasuser = gen_add_list(
|
||||
if runasuser is not None:
|
||||
runasuser_add = gen_add_list(
|
||||
runasuser,
|
||||
(list(res_find.get('ipasudorunas_user', []))
|
||||
+ list(res_find.get('ipasudorunasextuser', [])))
|
||||
@@ -643,69 +563,13 @@ def main():
|
||||
# non-IPA (external) groups, so we need to compare
|
||||
# the provided list against both users and external
|
||||
# groups list.
|
||||
if (
|
||||
runasgroup is not None
|
||||
and (
|
||||
"ipasudorunasgroup_group" in res_find
|
||||
or "ipasudorunasextgroup" in res_find
|
||||
)
|
||||
):
|
||||
runasgroup = gen_add_list(
|
||||
if runasgroup is not None:
|
||||
runasgroup_add = gen_add_list(
|
||||
runasgroup,
|
||||
(list(res_find.get("ipasudorunasgroup_group", []))
|
||||
+ list(res_find.get("ipasudorunasextgroup", [])))
|
||||
)
|
||||
|
||||
# Add hosts and hostgroups
|
||||
if host is not None or hostgroup is not None:
|
||||
commands.append([name, "sudorule_add_host",
|
||||
{
|
||||
"host": host,
|
||||
"hostgroup": hostgroup,
|
||||
}])
|
||||
|
||||
# Add users and groups
|
||||
if user is not None or group is not None:
|
||||
commands.append([name, "sudorule_add_user",
|
||||
{
|
||||
"user": user,
|
||||
"group": group,
|
||||
}])
|
||||
|
||||
# Add commands
|
||||
if allow_sudocmd is not None \
|
||||
or allow_sudocmdgroup is not None:
|
||||
commands.append([name, "sudorule_add_allow_command",
|
||||
{"sudocmd": allow_sudocmd,
|
||||
"sudocmdgroup": allow_sudocmdgroup,
|
||||
}])
|
||||
|
||||
# Add commands
|
||||
if deny_sudocmd is not None \
|
||||
or deny_sudocmdgroup is not None:
|
||||
commands.append([name, "sudorule_add_deny_command",
|
||||
{"sudocmd": deny_sudocmd,
|
||||
"sudocmdgroup": deny_sudocmdgroup,
|
||||
}])
|
||||
|
||||
# Add RunAS Users
|
||||
if runasuser is not None and len(runasuser) > 0:
|
||||
commands.append([name, "sudorule_add_runasuser",
|
||||
{"user": runasuser}])
|
||||
|
||||
# Add RunAS Groups
|
||||
if runasgroup is not None and len(runasgroup) > 0:
|
||||
commands.append([name, "sudorule_add_runasgroup",
|
||||
{"group": runasgroup}])
|
||||
|
||||
# Add options
|
||||
if sudooption is not None:
|
||||
existing_opts = res_find.get('ipasudoopt', [])
|
||||
for sudoopt in sudooption:
|
||||
if sudoopt not in existing_opts:
|
||||
commands.append([name, "sudorule_add_option",
|
||||
{"ipasudoopt": sudoopt}])
|
||||
|
||||
elif state == "absent":
|
||||
if action == "sudorule":
|
||||
if res_find is not None:
|
||||
@@ -721,153 +585,70 @@ def main():
|
||||
# and res_find to only try to remove the items that are
|
||||
# in sudorule
|
||||
if host is not None:
|
||||
if "memberhost_host" in res_find:
|
||||
host = gen_intersection_list(
|
||||
host, res_find["memberhost_host"])
|
||||
else:
|
||||
host = None
|
||||
host_del = gen_intersection_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
|
||||
if hostgroup is not None:
|
||||
if "memberhost_hostgroup" in res_find:
|
||||
hostgroup = gen_intersection_list(
|
||||
hostgroup, res_find["memberhost_hostgroup"])
|
||||
else:
|
||||
hostgroup = None
|
||||
hostgroup_del = gen_intersection_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
if user is not None:
|
||||
if "memberuser_user" in res_find:
|
||||
user = gen_intersection_list(
|
||||
user, res_find["memberuser_user"])
|
||||
else:
|
||||
user = None
|
||||
user_del = gen_intersection_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
|
||||
if group is not None:
|
||||
if "memberuser_group" in res_find:
|
||||
group = gen_intersection_list(
|
||||
group, res_find["memberuser_group"])
|
||||
else:
|
||||
group = None
|
||||
group_del = gen_intersection_list(
|
||||
group, res_find.get("memberuser_group"))
|
||||
|
||||
if allow_sudocmd is not None:
|
||||
if "memberallowcmd_sudocmd" in res_find:
|
||||
allow_sudocmd = gen_intersection_list(
|
||||
allow_sudocmd,
|
||||
res_find["memberallowcmd_sudocmd"])
|
||||
else:
|
||||
allow_sudocmd = None
|
||||
allow_cmd_del = gen_intersection_list(
|
||||
allow_sudocmd,
|
||||
res_find.get("memberallowcmd_sudocmd")
|
||||
)
|
||||
if allow_sudocmdgroup is not None:
|
||||
if "memberallowcmd_sudocmdgroup" in res_find:
|
||||
allow_sudocmdgroup = gen_intersection_list(
|
||||
allow_sudocmdgroup,
|
||||
res_find["memberallowcmd_sudocmdgroup"])
|
||||
else:
|
||||
allow_sudocmdgroup = None
|
||||
allow_cmdgroup_del = gen_intersection_list(
|
||||
allow_sudocmdgroup,
|
||||
res_find.get("memberallowcmd_sudocmdgroup")
|
||||
)
|
||||
if deny_sudocmd is not None:
|
||||
if "memberdenycmd_sudocmd" in res_find:
|
||||
deny_sudocmd = gen_intersection_list(
|
||||
deny_sudocmd,
|
||||
res_find["memberdenycmd_sudocmd"])
|
||||
else:
|
||||
deny_sudocmd = None
|
||||
deny_cmd_del = gen_intersection_list(
|
||||
deny_sudocmd,
|
||||
res_find.get("memberdenycmd_sudocmd")
|
||||
)
|
||||
if deny_sudocmdgroup is not None:
|
||||
if "memberdenycmd_sudocmdgroup" in res_find:
|
||||
deny_sudocmdgroup = gen_intersection_list(
|
||||
deny_sudocmdgroup,
|
||||
res_find["memberdenycmd_sudocmdgroup"])
|
||||
else:
|
||||
deny_sudocmdgroup = None
|
||||
deny_cmdgroup_del = gen_intersection_list(
|
||||
deny_sudocmdgroup,
|
||||
res_find.get("memberdenycmd_sudocmdgroup")
|
||||
)
|
||||
if sudooption is not None:
|
||||
if "ipasudoopt" in res_find:
|
||||
sudooption = gen_intersection_list(
|
||||
sudooption, res_find["ipasudoopt"])
|
||||
else:
|
||||
sudooption = None
|
||||
sudooption_del = gen_intersection_list(
|
||||
sudooption, res_find.get("ipasudoopt"))
|
||||
# runasuser attribute can be used with both IPA and
|
||||
# non-IPA (external) users, so we need to compare
|
||||
# the provided list against both users and external
|
||||
# users list.
|
||||
if runasuser is not None:
|
||||
if (
|
||||
"ipasudorunas_user" in res_find
|
||||
or "ipasudorunasextuser" in res_find
|
||||
):
|
||||
runasuser = gen_intersection_list(
|
||||
runasuser,
|
||||
(
|
||||
list(res_find.get('ipasudorunas_user', []))
|
||||
+ list(res_find.get(
|
||||
'ipasudorunasextuser', []))
|
||||
)
|
||||
runasuser_del = gen_intersection_list(
|
||||
runasuser,
|
||||
(
|
||||
list(res_find.get('ipasudorunas_user', []))
|
||||
+ list(res_find.get('ipasudorunasextuser', []))
|
||||
)
|
||||
else:
|
||||
runasuser = None
|
||||
)
|
||||
# runasgroup attribute can be used with both IPA and
|
||||
# non-IPA (external) groups, so we need to compare
|
||||
# the provided list against both groups and external
|
||||
# groups list.
|
||||
if runasgroup is not None:
|
||||
if (
|
||||
"ipasudorunasgroup_group" in res_find
|
||||
or "ipasudorunasextgroup" in res_find
|
||||
):
|
||||
runasgroup = gen_intersection_list(
|
||||
runasgroup,
|
||||
(
|
||||
list(res_find.get(
|
||||
"ipasudorunasgroup_group", []))
|
||||
+ list(res_find.get(
|
||||
"ipasudorunasextgroup", []))
|
||||
)
|
||||
runasgroup_del = gen_intersection_list(
|
||||
runasgroup,
|
||||
(
|
||||
list(res_find.get(
|
||||
"ipasudorunasgroup_group", []))
|
||||
+ list(res_find.get(
|
||||
"ipasudorunasextgroup", []))
|
||||
)
|
||||
else:
|
||||
runasgroup = None
|
||||
|
||||
# Remove hosts and hostgroups
|
||||
if host is not None or hostgroup is not None:
|
||||
commands.append([name, "sudorule_remove_host",
|
||||
{
|
||||
"host": host,
|
||||
"hostgroup": hostgroup,
|
||||
}])
|
||||
|
||||
# Remove users and groups
|
||||
if user is not None or group is not None:
|
||||
commands.append([name, "sudorule_remove_user",
|
||||
{
|
||||
"user": user,
|
||||
"group": group,
|
||||
}])
|
||||
|
||||
# Remove allow commands
|
||||
if allow_sudocmd is not None \
|
||||
or allow_sudocmdgroup is not None:
|
||||
commands.append([name, "sudorule_remove_allow_command",
|
||||
{"sudocmd": allow_sudocmd,
|
||||
"sudocmdgroup": allow_sudocmdgroup
|
||||
}])
|
||||
|
||||
# Remove deny commands
|
||||
if deny_sudocmd is not None \
|
||||
or deny_sudocmdgroup is not None:
|
||||
commands.append([name, "sudorule_remove_deny_command",
|
||||
{"sudocmd": deny_sudocmd,
|
||||
"sudocmdgroup": deny_sudocmdgroup
|
||||
}])
|
||||
|
||||
# Remove RunAS Users
|
||||
if runasuser is not None:
|
||||
commands.append([name, "sudorule_remove_runasuser",
|
||||
{"user": runasuser}])
|
||||
|
||||
# Remove RunAS Groups
|
||||
if runasgroup is not None:
|
||||
commands.append([name, "sudorule_remove_runasgroup",
|
||||
{"group": runasgroup}])
|
||||
|
||||
# Remove options
|
||||
if sudooption is not None:
|
||||
existing_opts = res_find.get('ipasudoopt', [])
|
||||
for sudoopt in sudooption:
|
||||
if sudoopt in existing_opts:
|
||||
commands.append([name,
|
||||
"sudorule_remove_option",
|
||||
{"ipasudoopt": sudoopt}])
|
||||
)
|
||||
|
||||
elif state == "enabled":
|
||||
if res_find is None:
|
||||
@@ -892,6 +673,99 @@ def main():
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Manage members.
|
||||
# Manage hosts and hostgroups
|
||||
if host_add or hostgroup_add:
|
||||
commands.append([name, "sudorule_add_host",
|
||||
{
|
||||
"host": host_add,
|
||||
"hostgroup": hostgroup_add,
|
||||
}])
|
||||
if host_del or hostgroup_del:
|
||||
commands.append([name, "sudorule_remove_host",
|
||||
{
|
||||
"host": host_del,
|
||||
"hostgroup": hostgroup_del,
|
||||
}])
|
||||
|
||||
# Manage users and groups
|
||||
if user_add or group_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_user",
|
||||
{"user": user_add, "group": group_add}
|
||||
])
|
||||
if user_del or group_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_user",
|
||||
{"user": user_del, "group": group_del}
|
||||
])
|
||||
|
||||
# Manage commands allowed
|
||||
if allow_cmd_add or allow_cmdgroup_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_allow_command",
|
||||
{
|
||||
"sudocmd": allow_cmd_add,
|
||||
"sudocmdgroup": allow_cmdgroup_add,
|
||||
}
|
||||
])
|
||||
if allow_cmd_del or allow_cmdgroup_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_allow_command",
|
||||
{
|
||||
"sudocmd": allow_cmd_del,
|
||||
"sudocmdgroup": allow_cmdgroup_del
|
||||
}
|
||||
])
|
||||
# Manage commands denied
|
||||
if deny_cmd_add or deny_cmdgroup_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_deny_command",
|
||||
{
|
||||
"sudocmd": deny_cmd_add,
|
||||
"sudocmdgroup": deny_cmdgroup_add,
|
||||
}
|
||||
])
|
||||
if deny_cmd_del or deny_cmdgroup_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_deny_command",
|
||||
{
|
||||
"sudocmd": deny_cmd_del,
|
||||
"sudocmdgroup": deny_cmdgroup_del
|
||||
}
|
||||
])
|
||||
# Manage RunAS users
|
||||
if runasuser_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_runasuser", {"user": runasuser_add}
|
||||
])
|
||||
if runasuser_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_runasuser", {"user": runasuser_del}
|
||||
])
|
||||
|
||||
# Manage RunAS Groups
|
||||
if runasgroup_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_runasgroup", {"group": runasgroup_add}
|
||||
])
|
||||
if runasgroup_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_runasgroup",
|
||||
{"group": runasgroup_del}
|
||||
])
|
||||
# Manage sudo options
|
||||
if sudooption_add:
|
||||
for option in sudooption_add:
|
||||
commands.append([
|
||||
name, "sudorule_add_option", {"ipasudoopt": option}
|
||||
])
|
||||
if sudooption_del:
|
||||
for option in sudooption_del:
|
||||
commands.append([
|
||||
name, "sudorule_remove_option", {"ipasudoopt": option}
|
||||
])
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
|
||||
@@ -44,7 +44,8 @@ options:
|
||||
description:
|
||||
- Trust type (ad for Active Directory, default)
|
||||
default: ad
|
||||
required: true
|
||||
required: false
|
||||
choices: ["ad"]
|
||||
admin:
|
||||
description:
|
||||
- Active Directory domain administrator
|
||||
@@ -103,7 +104,7 @@ EXAMPLES = """
|
||||
realm: ad.example.test
|
||||
trust_type: ad
|
||||
admin: Administrator
|
||||
password: Welcome2020!
|
||||
password: SomeW1Npassword
|
||||
state: present
|
||||
|
||||
# delete ad-trust
|
||||
@@ -157,7 +158,7 @@ def add_trust(module, realm, args):
|
||||
|
||||
|
||||
def gen_args(trust_type, admin, password, server, trust_secret, base_id,
|
||||
range_size, _range_type, two_way, external):
|
||||
range_size, range_type, two_way, external):
|
||||
_args = {}
|
||||
if trust_type is not None:
|
||||
_args["trust_type"] = trust_type
|
||||
@@ -173,6 +174,8 @@ def gen_args(trust_type, admin, password, server, trust_secret, base_id,
|
||||
_args["base_id"] = base_id
|
||||
if range_size is not None:
|
||||
_args["range_size"] = range_size
|
||||
if range_type is not None:
|
||||
_args["range_type"] = range_type
|
||||
if two_way is not None:
|
||||
_args["bidirectional"] = two_way
|
||||
if external is not None:
|
||||
@@ -190,7 +193,8 @@ def main():
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
# present
|
||||
trust_type=dict(type="str", default="ad", required=False),
|
||||
trust_type=dict(type="str", default="ad", required=False,
|
||||
choices=["ad"]),
|
||||
admin=dict(type="str", default=None, required=False),
|
||||
password=dict(type="str", default=None,
|
||||
required=False, no_log=True),
|
||||
|
||||
@@ -474,41 +474,31 @@ user:
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, date_format, \
|
||||
encode_certificate, load_cert_from_str, DN_x500_text, to_text
|
||||
encode_certificate, load_cert_from_str, DN_x500_text, to_text, \
|
||||
ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_user(module, name, preserved=False):
|
||||
def find_user(module, name):
|
||||
_args = {
|
||||
"all": True,
|
||||
"uid": name,
|
||||
}
|
||||
if preserved:
|
||||
_args["preserved"] = preserved
|
||||
|
||||
_result = module.ipa_command("user_find", name, _args)
|
||||
try:
|
||||
_result = module.ipa_command("user_show", name, _args).get("result")
|
||||
except ipalib_errors.NotFound:
|
||||
return None
|
||||
|
||||
if len(_result["result"]) > 1:
|
||||
module.fail_json(
|
||||
msg="There is more than one user '%s'" % (name))
|
||||
elif len(_result["result"]) == 1:
|
||||
# Transform each principal to a string
|
||||
_result = _result["result"][0]
|
||||
if "krbprincipalname" in _result \
|
||||
and _result["krbprincipalname"] is not None:
|
||||
_list = []
|
||||
for x in _result["krbprincipalname"]:
|
||||
_list.append(str(x))
|
||||
_result["krbprincipalname"] = _list
|
||||
certs = _result.get("usercertificate")
|
||||
if certs is not None:
|
||||
_result["usercertificate"] = [encode_certificate(x)
|
||||
for x in certs]
|
||||
return _result
|
||||
|
||||
return None
|
||||
# Transform each principal to a string
|
||||
_result["krbprincipalname"] = [
|
||||
to_text(x) for x in (_result.get("krbprincipalname") or [])
|
||||
]
|
||||
_result["usercertificate"] = [
|
||||
encode_certificate(x) for x in (_result.get("usercertificate") or [])
|
||||
]
|
||||
return _result
|
||||
|
||||
|
||||
def gen_args(first, last, fullname, displayname, initials, homedir, shell,
|
||||
@@ -902,8 +892,10 @@ def main():
|
||||
title = ansible_module.params_get("title")
|
||||
manager = ansible_module.params_get("manager")
|
||||
carlicense = ansible_module.params_get("carlicense")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey")
|
||||
userauthtype = ansible_module.params_get("userauthtype")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey",
|
||||
allow_empty_string=True)
|
||||
userauthtype = ansible_module.params_get("userauthtype",
|
||||
allow_empty_string=True)
|
||||
userclass = ansible_module.params_get("userclass")
|
||||
radius = ansible_module.params_get("radius")
|
||||
radiususer = ansible_module.params_get("radiususer")
|
||||
@@ -1085,12 +1077,6 @@ def main():
|
||||
|
||||
# Make sure user exists
|
||||
res_find = find_user(ansible_module, name)
|
||||
# Also search for preserved user if the user could not be found
|
||||
if res_find is None:
|
||||
res_find_preserved = find_user(ansible_module, name,
|
||||
preserved=True)
|
||||
else:
|
||||
res_find_preserved = None
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
@@ -1104,10 +1090,6 @@ def main():
|
||||
departmentnumber, employeenumber, employeetype,
|
||||
preferredlanguage, noprivate, nomembers)
|
||||
|
||||
# Also check preserved users
|
||||
if res_find is None and res_find_preserved is not None:
|
||||
res_find = res_find_preserved
|
||||
|
||||
if action == "user":
|
||||
# Found the user
|
||||
if res_find is not None:
|
||||
@@ -1121,13 +1103,6 @@ def main():
|
||||
if "noprivate" in args:
|
||||
del args["noprivate"]
|
||||
|
||||
# Ignore userauthtype if it is empty (for resetting)
|
||||
# and not set in for the user
|
||||
if "ipauserauthtype" not in res_find and \
|
||||
"ipauserauthtype" in args and \
|
||||
args["ipauserauthtype"] == ['']:
|
||||
del args["ipauserauthtype"]
|
||||
|
||||
# For all settings is args, check if there are
|
||||
# different settings in the find result.
|
||||
# If yes: modify
|
||||
@@ -1310,16 +1285,16 @@ def main():
|
||||
gen_certmapdata_args(_data)])
|
||||
|
||||
elif state == "absent":
|
||||
# Also check preserved users
|
||||
if res_find is None and res_find_preserved is not None:
|
||||
res_find = res_find_preserved
|
||||
|
||||
if action == "user":
|
||||
if res_find is not None:
|
||||
args = {}
|
||||
if preserve is not None:
|
||||
args["preserve"] = preserve
|
||||
commands.append([name, "user_del", args])
|
||||
if (
|
||||
not res_find.get("preserved", False)
|
||||
or not args.get("preserve", False)
|
||||
):
|
||||
commands.append([name, "user_del", args])
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
@@ -1370,17 +1345,18 @@ def main():
|
||||
commands.append([name, "user_remove_certmapdata",
|
||||
gen_certmapdata_args(_data)])
|
||||
elif state == "undeleted":
|
||||
if res_find_preserved is not None:
|
||||
commands.append([name, "user_undel", {}])
|
||||
if res_find is not None:
|
||||
if res_find.get("preserved", False):
|
||||
commands.append([name, "user_undel", {}])
|
||||
else:
|
||||
raise ValueError("No preserved user '%s'" % name)
|
||||
raise ValueError("No user '%s'" % name)
|
||||
|
||||
elif state == "enabled":
|
||||
if res_find is not None:
|
||||
if res_find["nsaccountlock"]:
|
||||
commands.append([name, "user_enable", {}])
|
||||
else:
|
||||
raise ValueError("No disabled user '%s'" % name)
|
||||
raise ValueError("No user '%s'" % name)
|
||||
|
||||
elif state == "disabled":
|
||||
if res_find is not None:
|
||||
@@ -1392,6 +1368,8 @@ def main():
|
||||
elif state == "unlocked":
|
||||
if res_find is not None:
|
||||
commands.append([name, "user_unlock", {}])
|
||||
else:
|
||||
raise ValueError("No user '%s'" % name)
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
ipdb
|
||||
pre-commit
|
||||
flake8-bugbear
|
||||
pylint==2.10.2
|
||||
pylint==2.12.2
|
||||
|
||||
@@ -33,7 +33,6 @@ Requirements
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
* /usr/bin/kinit is required on the controller if a one time password (OTP) is used
|
||||
* python3-gssapi is required on the controller if a one time password (OTP) is used with keytab
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
@@ -21,10 +21,6 @@ from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
try:
|
||||
import gssapi
|
||||
except ImportError:
|
||||
gssapi = None
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -82,22 +78,17 @@ def kinit_keytab(principal, keytab, ccache_name, config):
|
||||
It uses the specified config file to kinit and stores the TGT
|
||||
in ccache_name.
|
||||
"""
|
||||
if gssapi is None:
|
||||
raise ImportError("gssapi is not available")
|
||||
|
||||
args = ["/usr/bin/kinit", "-kt", keytab, "-c", ccache_name, principal]
|
||||
old_config = os.environ.get('KRB5_CONFIG')
|
||||
os.environ['KRB5_CONFIG'] = config
|
||||
os.environ["KRB5_CONFIG"] = config
|
||||
|
||||
try:
|
||||
name = gssapi.Name(principal, gssapi.NameType.kerberos_principal)
|
||||
store = {'ccache': ccache_name,
|
||||
'client_keytab': keytab}
|
||||
cred = gssapi.Credentials(name=name, store=store, usage='initiate')
|
||||
return cred
|
||||
return run_cmd(args)
|
||||
finally:
|
||||
if old_config is not None:
|
||||
os.environ['KRB5_CONFIG'] = old_config
|
||||
os.environ["KRB5_CONFIG"] = old_config
|
||||
else:
|
||||
os.environ.pop('KRB5_CONFIG', None)
|
||||
os.environ.pop("KRB5_CONFIG", None)
|
||||
|
||||
|
||||
KRB5CONF_TEMPLATE = """
|
||||
|
||||
@@ -207,7 +207,7 @@ else:
|
||||
cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
|
||||
filename, client_domain, client_hostname, force=False,
|
||||
configure_sssd=True):
|
||||
# pylint: disable=global-statement
|
||||
# pylint: disable=global-variable-not-assigned
|
||||
global options
|
||||
options.force = force
|
||||
options.sssd = configure_sssd
|
||||
|
||||
@@ -216,15 +216,18 @@
|
||||
ipaclient_force_join)
|
||||
|
||||
- block:
|
||||
- fail:
|
||||
- name: krb5 configuration not correct
|
||||
fail:
|
||||
msg: >
|
||||
The krb5 configuration is not correct, please enable allow_repair
|
||||
to fix this.
|
||||
when: not result_ipaclient_test_keytab.krb5_conf_ok
|
||||
- fail:
|
||||
- name: IPA test failed
|
||||
fail:
|
||||
msg: "The IPA test failed, please enable allow_repair to fix this."
|
||||
when: not result_ipaclient_test_keytab.ping_test_ok
|
||||
- fail:
|
||||
- name: ca.crt file is missing
|
||||
fail:
|
||||
msg: >
|
||||
The ca.crt file is missing, please enable allow_repair to fix this.
|
||||
when: not result_ipaclient_test_keytab.ca_crt_exists
|
||||
|
||||
@@ -34,6 +34,7 @@ ignore = D1,D212,D203
|
||||
|
||||
[pylint.MASTER]
|
||||
disable =
|
||||
consider-using-f-string, # f-string is not supported on Python2
|
||||
unspecified-encoding, # open() does not provide `encoding` in Python2
|
||||
use-maxsplit-arg,
|
||||
redundant-u-string-prefix,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
- name: Test automountmap
|
||||
hosts: ipaserver
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
@@ -71,6 +71,24 @@
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: ensure map TestMap has an empty description
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
location: TestLocation
|
||||
desc: ""
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: ensure map TestMap has an empty description, again
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
location: TestLocation
|
||||
desc: ""
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: ensure map TestMap is removed
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
40
tests/automount/test_automountmap_client_context.yml
Normal file
40
tests/automount/test_automountmap_client_context.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
- name: Test automountmap
|
||||
hosts: ipaclients, ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Include FreeIPA facts.
|
||||
include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# Test will only be executed if host is not a server.
|
||||
- name: Execute with server context in the client.
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: server
|
||||
location: default
|
||||
name: ThisShouldNotWork
|
||||
register: result
|
||||
failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*"))
|
||||
when: ipa_host_is_client
|
||||
|
||||
# Import basic module tests, and execute with ipa_context set to 'client'.
|
||||
# If ipaclients is set, it will be executed using the client, if not,
|
||||
# ipaserver will be used.
|
||||
#
|
||||
# With this setup, tests can be executed against an IPA client, against
|
||||
# an IPA server using "client" context, and ensure that tests are executed
|
||||
# in upstream CI.
|
||||
|
||||
- name: Test automountmap using client context, in client host.
|
||||
import_playbook: test_automountmap.yml
|
||||
when: groups['ipaclients']
|
||||
vars:
|
||||
ipa_test_host: ipaclients
|
||||
|
||||
- name: Test automountmap using client context, in server host.
|
||||
import_playbook: test_automountmap.yml
|
||||
when: groups['ipaclients'] is not defined or not groups['ipaclients']
|
||||
vars:
|
||||
ipa_context: client
|
||||
@@ -18,28 +18,39 @@ stages:
|
||||
scenario: fedora-latest
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
# CentOS 9
|
||||
# CentOS 9 Stream
|
||||
|
||||
- stage: CentOS9_Ansible_2_9
|
||||
- stage: c9s_Ansible_2_9
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-9
|
||||
scenario: c9s
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
# CentOS 8
|
||||
# CentOS 8 Stream
|
||||
|
||||
- stage: CentOS8_Ansible_2_9
|
||||
- stage: c8s_Ansible_2_9
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-8
|
||||
scenario: c8s
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
# # CentOS 8
|
||||
#
|
||||
# - stage: CentOS8_Ansible_2_9
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/group_tests.yml
|
||||
# parameters:
|
||||
# build_number: $(Build.BuildNumber)
|
||||
# scenario: centos-8
|
||||
# ansible_version: ">=2.9,<2.10"
|
||||
|
||||
# CentOS 7
|
||||
|
||||
- stage: CentOS7_Ansible_2_9
|
||||
|
||||
@@ -21,17 +21,23 @@ jobs:
|
||||
container_name: centos-7
|
||||
build_scenario_name: centos-7-build
|
||||
|
||||
- template: templates/build_container.yml
|
||||
parameters:
|
||||
job_name_suffix: Centos8
|
||||
container_name: centos-8
|
||||
build_scenario_name: centos-8-build
|
||||
# - template: templates/build_container.yml
|
||||
# parameters:
|
||||
# job_name_suffix: Centos8
|
||||
# container_name: centos-8
|
||||
# build_scenario_name: centos-8-build
|
||||
|
||||
- template: templates/build_container.yml
|
||||
parameters:
|
||||
job_name_suffix: Centos9
|
||||
container_name: centos-9
|
||||
build_scenario_name: centos-9-build
|
||||
job_name_suffix: C8S
|
||||
container_name: c8s
|
||||
build_scenario_name: c8s-build
|
||||
|
||||
- template: templates/build_container.yml
|
||||
parameters:
|
||||
job_name_suffix: C9S
|
||||
container_name: c9s
|
||||
build_scenario_name: c9s-build
|
||||
|
||||
- template: templates/build_container.yml
|
||||
parameters:
|
||||
|
||||
@@ -52,73 +52,120 @@ stages:
|
||||
scenario: fedora-latest
|
||||
ansible_version: ""
|
||||
|
||||
# CentoOS 9
|
||||
# CentoOS 9 Stream
|
||||
|
||||
- stage: CentOS9_Ansible_2_9
|
||||
- stage: c9s_Ansible_2_9
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-9
|
||||
scenario: c9s
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
- stage: CentOS9_Ansible_Core_2_11
|
||||
- stage: c9s_Ansible_Core_2_11
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-9
|
||||
scenario: c9s
|
||||
ansible_version: "-core >=2.11,<2.12"
|
||||
|
||||
- stage: CentOS9_Ansible_latest
|
||||
- stage: c9s_Ansible_Core_2_12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-9
|
||||
ansible_version: ""
|
||||
|
||||
# CentOS 8
|
||||
|
||||
- stage: CentOS8_Ansible_2_9
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-8
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
- stage: CentOS8_Ansible_Core_2_11
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-8
|
||||
ansible_version: "-core >=2.11,<2.12"
|
||||
|
||||
- stage: CentOS8_Ansible_Core_2_12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-8
|
||||
scenario: c9s
|
||||
ansible_version: "-core >=2.12,<2.13"
|
||||
|
||||
- stage: CentOS8_Ansible_latest
|
||||
- stage: c9s_Ansible_latest
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: centos-8
|
||||
scenario: c9s
|
||||
ansible_version: ""
|
||||
|
||||
# CentOS 8 Stream
|
||||
|
||||
- stage: c8s_Ansible_2_9
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: c8s
|
||||
ansible_version: ">=2.9,<2.10"
|
||||
|
||||
- stage: c8s_Ansible_Core_2_11
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: c8s
|
||||
ansible_version: "-core >=2.11,<2.12"
|
||||
|
||||
- stage: c8s_Ansible_Core_2_12
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: c8s
|
||||
ansible_version: "-core >=2.12,<2.13"
|
||||
|
||||
- stage: c8s_Ansible_latest
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/group_tests.yml
|
||||
parameters:
|
||||
build_number: $(Build.BuildNumber)
|
||||
scenario: c8s
|
||||
ansible_version: ""
|
||||
|
||||
# # CentOS 8
|
||||
#
|
||||
# - stage: CentOS8_Ansible_2_9
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/group_tests.yml
|
||||
# parameters:
|
||||
# build_number: $(Build.BuildNumber)
|
||||
# scenario: centos-8
|
||||
# ansible_version: ">=2.9,<2.10"
|
||||
#
|
||||
# - stage: CentOS8_Ansible_Core_2_11
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/group_tests.yml
|
||||
# parameters:
|
||||
# build_number: $(Build.BuildNumber)
|
||||
# scenario: centos-8
|
||||
# ansible_version: "-core >=2.11,<2.12"
|
||||
#
|
||||
# - stage: CentOS8_Ansible_Core_2_12
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/group_tests.yml
|
||||
# parameters:
|
||||
# build_number: $(Build.BuildNumber)
|
||||
# scenario: centos-8
|
||||
# ansible_version: "-core >=2.12,<2.13"
|
||||
#
|
||||
# - stage: CentOS8_Ansible_latest
|
||||
# dependsOn: []
|
||||
# jobs:
|
||||
# - template: templates/group_tests.yml
|
||||
# parameters:
|
||||
# build_number: $(Build.BuildNumber)
|
||||
# scenario: centos-8
|
||||
# ansible_version: ""
|
||||
|
||||
# CentOS 7
|
||||
|
||||
- stage: CentOS7_Ansible_2_9
|
||||
|
||||
@@ -6,6 +6,9 @@ parameters:
|
||||
type: string
|
||||
- name: build_scenario_name
|
||||
type: string
|
||||
- name: python_version
|
||||
type: string
|
||||
default: 3.x
|
||||
|
||||
jobs:
|
||||
- job: BuildTestImage${{ parameters.job_name_suffix }}
|
||||
@@ -13,7 +16,7 @@ jobs:
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '3.6'
|
||||
versionSpec: '${{ parameters.python_version }}'
|
||||
|
||||
- script: python -m pip install --upgrade pip setuptools wheel ansible
|
||||
displayName: Install tools
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
parameters:
|
||||
- name: scenario
|
||||
type: string
|
||||
default: centos-8
|
||||
default: fedora-latest
|
||||
- name: build_number
|
||||
type: string
|
||||
- name: ansible_version
|
||||
|
||||
@@ -8,7 +8,7 @@ parameters:
|
||||
default: 1
|
||||
- name: scenario
|
||||
type: string
|
||||
default: centos-8
|
||||
default: fedora-latest
|
||||
- name: ansible_version
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
@@ -4,6 +4,7 @@ parameters:
|
||||
type: string
|
||||
- name: scenario
|
||||
type: string
|
||||
default: fedora-latest
|
||||
- name: ansible_version
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type: ""
|
||||
|
||||
- name: set maxhostname to 255
|
||||
block:
|
||||
- ipaconfig:
|
||||
- block:
|
||||
- name: set maxhostname to 255
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
maxhostname: 255
|
||||
@@ -221,16 +221,17 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: set maxhostname to 77
|
||||
block:
|
||||
- ipaconfig:
|
||||
- block:
|
||||
- name: set maxhostname to 77
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
maxhostname: 77
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- ipaconfig:
|
||||
- name: set maxhostname to 77, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
maxhostname: 77
|
||||
@@ -409,9 +410,9 @@
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: reset maxhostname
|
||||
block:
|
||||
- ipaconfig:
|
||||
- block:
|
||||
- name: reset maxhostname
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
maxhostname: '{{ previousconfig.config.maxhostname | default(omit) }}'
|
||||
@@ -444,9 +445,9 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: reset maxhostname
|
||||
block:
|
||||
- ipaconfig:
|
||||
- block:
|
||||
- name: reset maxhostname
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
maxhostname: '{{ previousconfig.config.maxhostname | default(omit) }}'
|
||||
|
||||
143
tests/config/test_config_empty_string_params.yml
Normal file
143
tests/config/test_config_empty_string_params.yml
Normal file
@@ -0,0 +1,143 @@
|
||||
---
|
||||
- name: Test config
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
become: yes
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
|
||||
# GET CURRENT CONFIG
|
||||
|
||||
- name: Return current values of the global configuration options
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
register: previousconfig
|
||||
|
||||
- name: Ensure config with empty pac_type, user_auth_type and configstring
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type: ""
|
||||
user_auth_type: ""
|
||||
configstring: ""
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Ensure config with pac_type "nfs:NONE" and PAD
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type:
|
||||
- "nfs:NONE"
|
||||
- PAD
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with pac_type "nfs:NONE" and PAD, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type:
|
||||
- "nfs:NONE"
|
||||
- PAD
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty pac_type
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type: ""
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty pac_type, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type: ""
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with user_auth_type otp and radius
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type:
|
||||
- otp
|
||||
- radius
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with user_auth_type otp and radius, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type:
|
||||
- otp
|
||||
- radius
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty user_auth_type
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type: ""
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty user_auth_type, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
user_auth_type: ""
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout"
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
configstring:
|
||||
- AllowNThash
|
||||
- "KDC:Disable Lockout"
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with configstring AllowNThash and "KDC:Disable Lockout", again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
configstring:
|
||||
- AllowNThash
|
||||
- "KDC:Disable Lockout"
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty configstring
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
configstring: ""
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure config with empty configstring, again
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
configstring: ""
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# REVERT TO PREVIOUS CONFIG
|
||||
|
||||
- name: Reset to previous pac_type and user_auth_type
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
pac_type: '{{ previousconfig.config.pac_type }}'
|
||||
user_auth_type: '{{ previousconfig.config.user_auth_type }}'
|
||||
configstring: '{{ previousconfig.config.configstring }}'
|
||||
@@ -17,6 +17,7 @@
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
state: absent
|
||||
action: member
|
||||
|
||||
# Tests.
|
||||
- name: Set config to invalid IPv4.
|
||||
@@ -74,23 +75,72 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder is absent.
|
||||
- name: Ensure forwarder 8.8.8.8 is absent.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.8.8
|
||||
state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder is absent, again.
|
||||
- name: Ensure forwarder 8.8.8.8 is absent, again.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.8.8
|
||||
state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder 8.8.4.4 is present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder 8.8.8.8 is present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.8.8
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder 8.8.4.4 is present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders are absent.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 8.8.8.8
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders are absent, again.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 8.8.8.8
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
@@ -168,10 +218,10 @@
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
|
||||
- name: Ensure all forwarders are absent, again.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -182,6 +232,69 @@
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarder is present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.8.8
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders is not present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
check_mode: yes
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders are present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 8.8.8.8
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders are present, again.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 8.8.8.8
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure another forwarder is present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure forwarders are present.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 8.8.8.8
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
@@ -197,3 +310,4 @@
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
port: 53
|
||||
state: absent
|
||||
action: member
|
||||
|
||||
@@ -31,4 +31,3 @@
|
||||
dnssec: yes
|
||||
skip_nameserver_check: yes
|
||||
skip_overlap_check: yes
|
||||
ignore_errors: yes
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
- name: Verify if host is an IPA server or client.
|
||||
shell:
|
||||
cmd: |
|
||||
echo SomeADMINpassword | kinit -c {{ KRB5CCNAME }} admin
|
||||
RESULT=$(KRB5CCNAME={{ KRB5CCNAME }} ipa server-show `hostname` && echo SERVER || echo CLIENT)
|
||||
kdestroy -A -c {{ KRB5CCNAME }}
|
||||
echo SomeADMINpassword | kinit -c {{ krb5ccname }} admin
|
||||
RESULT=$(KRB5CCNAME={{ krb5ccname }} ipa server-show `hostname` && echo SERVER || echo CLIENT)
|
||||
kdestroy -A -c {{ krb5ccname }}
|
||||
echo $RESULT
|
||||
vars:
|
||||
KRB5CCNAME: "__check_ipa_host_is_client_or_server__"
|
||||
krb5ccname: "__check_ipa_host_is_client_or_server__"
|
||||
register: output
|
||||
|
||||
- name: Set FreeIPA facts.
|
||||
|
||||
@@ -2,9 +2,20 @@
|
||||
- name: Test group
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
become: true
|
||||
gather_facts: false
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
# setup
|
||||
- include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
# GET FQDN_AT_DOMAIN
|
||||
|
||||
- name: Get fqdn_at_domain
|
||||
set_fact:
|
||||
fqdn_at_domain: "{{ ansible_facts['fqdn'] + '@' + ipaserver_realm }}"
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure users user1, user2 and user3 are absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -19,6 +30,8 @@
|
||||
name: group3,group2,group1
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
- name: Ensure users user1..user3 are present
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -36,6 +49,8 @@
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Ensure group1 is present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -119,6 +134,156 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# service
|
||||
|
||||
- block:
|
||||
|
||||
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is present in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is present in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'HTTP/' + fqdn_at_domain }}" is absent in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure service "{{ 'ldap/' + fqdn_at_domain }}" is absent in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure services are present in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure services are present in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'http/' + fqdn_at_domain }}"
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure services are absent in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
- "{{ 'LDAP/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure services are absent in group group1, again
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: group1
|
||||
service:
|
||||
- "{{ 'HTTP/' + fqdn_at_domain }}"
|
||||
- "{{ 'ldap/' + fqdn_at_domain }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
when: ipa_version is version('4.7.0', '>=')
|
||||
|
||||
# user
|
||||
|
||||
- name: Ensure users user1, user2 and user3 are present in group group1
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -297,6 +462,8 @@
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure group group3, group2 and group1 are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
104
tests/group/test_group_idoverrideuser.yml
Normal file
104
tests/group/test_group_idoverrideuser.yml
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
- name: Test group
|
||||
hosts: ipaserver
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
vars:
|
||||
ad_user: "{{ test_ad_user | default('AD\\aduser') }}"
|
||||
ad_domain: "{{ test_ad_domain | default('ad.ipa.test') }}"
|
||||
|
||||
tasks:
|
||||
- include_tasks: ../env_freeipa_facts.yml
|
||||
|
||||
- block:
|
||||
- name: Create idoverrideuser.
|
||||
shell: |
|
||||
kinit -c idoverride_cache admin <<< SomeADMINpassword
|
||||
ipa idoverrideuser-add "Default Trust View" {{ ad_user }}
|
||||
kdestroy -A -q -c idoverride_cache
|
||||
|
||||
- name: Remove testing groups.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- idovergroup
|
||||
state: absent
|
||||
|
||||
- name: Add group with idoverrideuser.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Add group with idoverrideuser, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Remove idoverrideuser member.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Remove idoverrideuser member, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
action: member
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Add idoverrideuser member.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.failed or not result.changed
|
||||
|
||||
- name: Add idoverrideuser member, again.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.failed or result.changed
|
||||
|
||||
- name: Cleanup idoverrideuser member.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idovergroup
|
||||
idoverrideuser: "{{ ad_user }}"
|
||||
state: absent
|
||||
|
||||
- name: Remove testing groups.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- idovergroup
|
||||
state: absent
|
||||
|
||||
always:
|
||||
- name: Remove idoverrideuser.
|
||||
shell: |
|
||||
kinit -c idoverride_cache admin <<< SomeADMINpassword
|
||||
ipa idoverrideuser-del "Default Trust View" {{ ad_user }}
|
||||
kdestroy -A -q -c idoverride_cache
|
||||
when:
|
||||
|
||||
when: ipa_version is version("4.8.7", ">=") and trust_test_is_supported | default(false)
|
||||
296
tests/hbacrule/test_hbacrule_member_empty.yml
Normal file
296
tests/hbacrule/test_hbacrule_member_empty.yml
Normal file
@@ -0,0 +1,296 @@
|
||||
---
|
||||
- name: Test hbacrule
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Get Domain from server name
|
||||
set_fact:
|
||||
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
|
||||
when: ipaserver_domain is not defined
|
||||
|
||||
- block:
|
||||
# SETUP:
|
||||
- name: Ensure test HBAC rule is absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
state: absent
|
||||
|
||||
- name: Ensure test hosts are present
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
hosts:
|
||||
- name: "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
force: yes
|
||||
- name: "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
force: yes
|
||||
|
||||
- name: Ensure test hostgroups are present
|
||||
ipahostgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- testhostgroup03
|
||||
- testhostgroup04
|
||||
|
||||
- name: Ensure test users are present
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
users:
|
||||
- name: testuser03
|
||||
first: test
|
||||
last: user03
|
||||
- name: testuser04
|
||||
first: test
|
||||
last: user04
|
||||
|
||||
- name: Ensure test groups are present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- testgroup03
|
||||
- testgroup04
|
||||
|
||||
- name: Ensure test HBAC Services are present
|
||||
ipahbacsvc:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- testhbacsvc03
|
||||
- testhbacsvc04
|
||||
|
||||
- name: Ensure test HBAC Service Groups are present
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ item }}"
|
||||
with_items:
|
||||
- testhbacsvcgroup03
|
||||
- testhbacsvcgroup04
|
||||
|
||||
- name: Ensure test HBAC rule hbacrule01 is absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
state: absent
|
||||
|
||||
# Ensure members are empty.
|
||||
- name: Ensure HBAC rule is present with known members
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
host:
|
||||
- "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
- "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
hostgroup: testhostgroup03,testhostgroup04
|
||||
user: testuser03,testuser04
|
||||
group: testgroup03,testgroup04
|
||||
hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule host is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
host: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule host is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
host: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hostgroup is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hostgroup: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hostgroup is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hostgroup: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule user is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
user: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule user is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
user: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule group is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
group: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule group is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
group: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hbacsvc is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hbacsvc: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hbacsvc is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hbacsvc: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hbacsvcgroup is empty
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hbacsvcgroup: []
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure test HBAC rule hbacsvcgroup is empty, again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
hbacsvcgroup: []
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Verify HBAC rule is present with only members would not require changes.
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
host: []
|
||||
hostgroup: []
|
||||
user: []
|
||||
group: []
|
||||
hbacsvc: []
|
||||
hbacsvcgroup: []
|
||||
check_mode: yes
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Verify HBAC rule is present with known members would require changes.
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
host:
|
||||
- "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
- "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
hostgroup: testhostgroup03,testhostgroup04
|
||||
user: testuser03,testuser04
|
||||
group: testgroup03,testgroup04
|
||||
hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
check_mode: yes
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
always:
|
||||
# CLEANUP
|
||||
- name: Ensure test HBAC rule is absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: hbacrule01
|
||||
state: absent
|
||||
|
||||
- name: Ensure test HBAC Service Groups are absent
|
||||
ipahbacsvcgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: testhbacsvcgroup01,testhbacsvcgroup02,testhbacsvcgroup03,testhbacsvcgroup04
|
||||
state: absent
|
||||
|
||||
- name: Ensure test HBAC Services are absent
|
||||
ipahbacsvc:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: testhbacsvc01,testhbacsvc02,testhbacsvc03,testhbacsvc04
|
||||
state: absent
|
||||
|
||||
- name: Ensure test hostgroups are absent
|
||||
ipahostgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: testhostgroup01,testhostgroup02,testhostgroup03,testhostgroup04
|
||||
state: absent
|
||||
|
||||
- name: Ensure test hosts are absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name:
|
||||
- "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
- "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
- "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
- "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
state: absent
|
||||
|
||||
- name: Ensure test user groups are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: testgroup01,testgroup02,testgroup03,testgroup04
|
||||
state: absent
|
||||
|
||||
- name: Ensure test users are absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: testuser01,testuser02,testuser03,testuser04
|
||||
state: absent
|
||||
86
tests/host/test_host_empty_string_params.yml
Normal file
86
tests/host/test_host_empty_string_params.yml
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
- name: Test host
|
||||
hosts: "{{ ipa_test_host | default('ipaserver') }}"
|
||||
become: yes
|
||||
gather_facts: yes
|
||||
|
||||
tasks:
|
||||
- name: Get Domain from server name
|
||||
set_fact:
|
||||
ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
|
||||
when: ipaserver_domain is not defined
|
||||
|
||||
- name: Set host1_fqdn .. host6_fqdn
|
||||
set_fact:
|
||||
host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
state: absent
|
||||
|
||||
# CREATE TEST ITEMS
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
force: yes
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
# TESTS
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind:
|
||||
- otp
|
||||
- radius
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with auth_ind otp and radius, again
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind:
|
||||
- otp
|
||||
- radius
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind: ""
|
||||
register: result
|
||||
failed_when: not result.changed or result.failed
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" present with empty auth_ind, again
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
auth_ind: ""
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
# CLEANUP TEST ITEMS
|
||||
|
||||
- name: Ensure host "{{ host1_fqdn }}" absent
|
||||
ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: "{{ host1_fqdn }}"
|
||||
state: absent
|
||||
@@ -133,6 +133,19 @@
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure hosts db1 and db2 (no FQDN) are member of host-group databases again
|
||||
ipahostgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: databases
|
||||
state: present
|
||||
host:
|
||||
- db1
|
||||
- db2
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed or result.failed
|
||||
|
||||
- name: Ensure host-group mysql-server is member of host-group databases
|
||||
ipahostgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user