Compare commits

..

1 Commits

Author SHA1 Message Date
Thomas Woerner
d01848d820 Fix README-role.md title
Change title of README-role to "Role module"
2020-07-29 10:16:05 +02:00
208 changed files with 9603 additions and 8101 deletions

View File

@@ -1,23 +0,0 @@
exclude_paths:
- roles
- .tox
- .venv
parseable: true
quiet: false
skip_list:
- '201' # Trailing whitespace
- '204' # Lines should be no longer than 160 chars
- '206' # Variables should have spaces before and after: {{ var_name }}'
- '208' # File permissions not mentioned
- '301' # Commands should not change things if nothing needs doing'
- '305' # Use shell only when shell functionality is required'
- '306' # Shells that use pipes should set the pipefail option'
- '502' # All tasks should be named
- '505' # Referenced missing file
use_default_rules: true
verbosity: 1

View File

@@ -1,9 +0,0 @@
srpm:
# Setup development environment
echo "Installing base development environment"
dnf install -y dnf-plugins-core git-all
echo "Call SRPM build Script"
./utils/build-srpm.sh
if [[ "${outdir}" != "" ]]; then \
mv /builddir/build/SRPMS/* ${outdir}; \
fi

View File

@@ -1,33 +0,0 @@
---
name: Run Linters
on:
- push
- pull_request
jobs:
linters:
name: Run Linters
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.6"
- name: Run ansible-lint
uses: ansible/ansible-lint-action@master
with:
targets: |
tests/*.yml
tests/*/*.yml
tests/*/*/*.yml
playbooks/*.yml
playbooks/*/*.yml
env:
ANSIBLE_MODULE_UTILS: plugins/module_utils
ANSIBLE_LIBRARY: plugins/modules
- name: Run yaml-lint
uses: ibiqlik/action-yamllint@v1
- name: Run Python linters
uses: rjeffman/python-lint-action@master

6
.gitignore vendored
View File

@@ -1,8 +1,2 @@
*.pyc
*.retry
# ignore virtual environments
/.tox/
/.venv/
tests/logs/

View File

@@ -1,28 +0,0 @@
---
ignore: |
/.tox/
/.venv/
/.github/
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
truthy:
allowed-values: ["yes", "no", "true", "false", "True", "False"]
level: error
# Disabled rules
document-start: disable
indentation: disable
line-length: disable
colons: disable
empty-lines: disable
comments: disable
comments-indentation: disable
trailing-spaces: disable
new-line-at-end-of-file: disable

View File

@@ -19,7 +19,6 @@ Supported FreeIPA Versions
FreeIPA versions 4.4.0 and up are supported by the ipaconfig module.
Some variables are only supported on newer versions of FreeIPA. Check `Variables` section for details.
Requirements
------------
@@ -92,7 +91,7 @@ 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
`maxusername` \| `ipamaxusernamelength` | Set the maximum username length (1 to 255) | no
`maxhostname` \| `ipamaxhostnamelength` | Set the maximum hostname length between 64-255. Only usable with IPA versions 4.8.0 and up. | no
`maxhostname` \| `ipamaxhostnamelength` | Set the maximum hostname length between 64-255 | no
`homedirectory` \| `ipahomesrootdir` | Set the default location of home directories | no
`defaultshell` \| `ipadefaultloginshell` | Set the default shell for new users | no
`defaultgroup` \| `ipadefaultprimarygroup` | Set the default group for new users | no

View File

@@ -1,157 +0,0 @@
Delegation module
=================
Description
-----------
The delegation module allows to ensure presence, absence of delegations and delegation attributes.
Features
--------
* Delegation management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipadelegation 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 make sure delegation "basic manager attributes" is present:
```yaml
---
- name: Playbook to manage IPA delegation.
hosts: ipaserver
become: yes
tasks:
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
permission: read
attribute:
- businesscategory
- employeetype
group: managers
membergroup: employees
```
Example playbook to make sure delegation "basic manager attributes" is absent:
```yaml
---
- name: Playbook to manage IPA delegation.
hosts: ipaserver
become: yes
tasks:
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
state: absent
```
Example playbook to make sure "basic manager attributes" member attributes employeetype and employeenumber are present:
```yaml
---
- name: Playbook to manage IPA delegation.
hosts: ipaserver
become: yes
tasks:
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- employeenumber
- employeetype
action: member
```
Example playbook to make sure "basic manager attributes" member attributes employeetype and employeenumber are absent:
```yaml
---
- name: Playbook to manage IPA delegation.
hosts: ipaserver
become: yes
tasks:
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- employeenumber
- employeetype
action: member
state: absent
```
Example playbook to make sure delegation "basic manager attributes" is absent:
```yaml
---
- name: Playbook to manage IPA delegation.
hosts: ipaserver
become: yes
tasks:
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
state: absent
```
Variables
---------
ipadelegation
-------
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
`name` \| `aciname` | The list of delegation name strings. | yes
`permission` \| `permissions` | The permission to grant `read`, `read,write`, `write`]. Default is `write`. | no
`attribute` \| `attrs` | The attribute list to which the delegation applies. | no
`membergroup` \| `memberof` | The user group to apply delegation to. | no
`group` | User group ACI grants access to. | no
`action` | Work on delegation or member level. It can be on of `member` or `delegation` and defaults to `delegation`. | no
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Authors
=======
Thomas Woerner

View File

@@ -152,46 +152,6 @@ Example playbook to remove a zone:
```
Example playbook to create a zone for reverse DNS lookup, from an IP address:
```yaml
---
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone for reverse DNS lookup is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name_from_ip: 192.168.1.2
state: present
```
Note that, on the previous example the zone created with `name_from_ip` might be "1.168.192.in-addr.arpa.", "168.192.in-addr.arpa.", or "192.in-addr.arpa.", depending on the DNS response the system get while querying for zones, and for this reason, when creating a zone using `name_from_ip`, the inferred zone name is returned to the controller, in the attribute `dnszone.name`. Since the zone inferred might not be what a user expects, `name_from_ip` can only be used with `state: present`. To have more control over the zone name, the prefix length for the IP address can be provided.
Example playbook to create a zone for reverse DNS lookup, from an IP address, given the prefix length and displaying the resulting zone name:
```yaml
---
- name: dnszone present
hosts: ipaserver
become: true
tasks:
- name: Ensure zone for reverse DNS lookup is present.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name_from_ip: 192.168.1.2/24
state: present
register: result
- name: Display inferred zone name.
debug:
msg: "Zone name: {{ result.dnszone.name }}"
```
Variables
=========
@@ -203,8 +163,7 @@ 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
`name` \| `zone_name` | The zone name string or list of strings. | no
`name_from_ip` | Derive zone name from reverse of IP (PTR). Can only be used with `state: present`. | no
`name` \| `zone_name` | The zone name string. | yes
`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
@@ -230,17 +189,6 @@ Variable | Description | Required
`skip_nameserver_check` | Force DNS zone creation even if nameserver is not resolvable | no
Return Values
=============
ipadnszone
----------
Variable | Description | Returned When
-------- | ----------- | -------------
`dnszone` | DNS Zone dict with zone name infered from `name_from_ip`. <br>Options: | If `state` is `present`, `name_from_ip` is used, and a zone was created.
&nbsp; | `name` - The name of the zone created, inferred from `name_from_ip`. | Always
Authors
=======

View File

@@ -19,8 +19,6 @@ Supported FreeIPA Versions
FreeIPA versions 4.4.0 and up are supported by the ipagroup module.
Some variables are only supported on newer versions of FreeIPA. Check `Variables` section for details.
Requirements
------------

View File

@@ -19,8 +19,6 @@ Supported FreeIPA Versions
FreeIPA versions 4.4.0 and up are supported by the ipahostgroup module.
Some variables are only supported on newer versions of FreeIPA. Check `Variables` section for details.
Requirements
------------
@@ -107,23 +105,6 @@ Example playbook to make sure hosts and hostgroups are absent in databases hostg
state: absent
```
Example playbook to rename an existing playbook:
```yaml
---
- name: Playbook to handle hostgroups
hosts: ipaserver
become: true
tasks:
# Ensure host-group databases is absent
- ipahostgroup:
ipaadmin_password: SomeADMINpassword
name: databases
rename: datalake
state: renamed
```
Example playbook to make sure host-group databases is absent:
```yaml
@@ -140,6 +121,7 @@ Example playbook to make sure host-group databases is absent:
state: absent
```
Variables
=========
@@ -157,9 +139,8 @@ Variable | Description | Required
`hostgroup` | List of hostgroup name strings assigned to this hostgroup. | no
`membermanager_user` | List of member manager users assigned to this hostgroup. Only usable with IPA versions 4.8.4 and up. | no
`membermanager_group` | List of member manager groups assigned to this hostgroup. Only usable with IPA versions 4.8.4 and up. | no
`rename` \| `new_name` | Rename hostgroup to the provided name. Only usable with IPA versions 4.8.7 and up. | no
`action` | Work on hostgroup or member level. It can be on of `member` or `hostgroup` and defaults to `hostgroup`. | no
`state` | The state to ensure. It can be one of `present`, `absent` or `renamed`, default: `present`. | no
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | no
Authors

View File

@@ -1,92 +0,0 @@
Location module
===============
Description
-----------
The location module allows to ensure presence and absence of locations.
Features
--------
* Location management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipalocation 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 make sure location "my_location1" is present:
```yaml
---
- name: Playbook to manage IPA location.
hosts: ipaserver
become: yes
tasks:
- ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1
description: My Location 1
```
Example playbook to make sure location "my_location1" is absent:
```yaml
---
- name: Playbook to manage IPA location.
hosts: ipaserver
become: yes
tasks:
- ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1
state: absent
```
Variables
---------
ipalocation
-------
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
`name` \| `idnsname` | The list of location name strings. | yes
`description` | The IPA location string | false
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Authors
=======
Thomas Woerner

View File

@@ -1,147 +0,0 @@
Privilege module
================
Description
-----------
The privilege module allows to ensure presence and absence of privileges and privilege members.
Features
--------
* Privilege management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipaprivilege 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 make sure privilege "Broad Privilege" is present:
```yaml
---
- name: Playbook to manage IPA privilege.
hosts: ipaserver
become: yes
tasks:
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
description: Broad Privilege
```
Example playbook to make sure privilege "Broad Privilege" member permission has multiple values:
```yaml
---
- name: Playbook to manage IPA privilege permission member.
hosts: ipaserver
become: yes
tasks:
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "Write IPA Configuration"
- "System: Write DNS Configuration"
- "System: Update DNS Entries"
action: member
```
Example playbook to make sure privilege "Broad Privilege" member permission 'Write IPA Configuration' is absent:
```yaml
---
- name: Playbook to manage IPA privilege permission member.
hosts: ipaserver
become: yes
tasks:
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "Write IPA Configuration"
action: member
state: absent
```
Example playbook to rename privilege "Broad Privilege" to "DNS Special Privilege":
```yaml
---
- name: Playbook to manage IPA privilege.
hosts: ipaserver
become: yes
tasks:
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
rename: DNS Special Privilege
state: renamed
```
Example playbook to make sure privilege "DNS Special Privilege" is absent:
```yaml
---
- name: Playbook to manage IPA privilege.
hosts: ipaserver
become: yes
- name: Ensure privilege Broad Privilege is absent
ipaadmin_password: SomeADMINpassword
name: DNS Special Privilege
state: absent
```
Variables
---------
ipaprivilege
------------
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
`name` \| `cn` | The list of privilege name strings. | yes
`description` | Privilege description. | no
`rename` \| `new_name` | Rename the privilege object. | no
`permission` | Permissions to be added to the privilege. | no
`action` | Work on privilege or member level. It can be one of `member` or `privilege` and defaults to `privilege`. | no
`state` | The state to ensure. It can be one of `present`, `absent` or `renamed`, default: `present`. | no
Authors
=======
Rafael Guterres Jeffman

View File

@@ -1,4 +1,4 @@
Role module
"
===========
Description

View File

@@ -1,151 +0,0 @@
Selfservice module
=================
Description
-----------
The selfservice module allows to ensure presence, absence of selfservices and selfservice attributes.
Features
--------
* Selfservice management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipaselfservice 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 make sure selfservice "Users can manage their own name details" is present:
```yaml
---
- name: Playbook to manage IPA selfservice.
hosts: ipaserver
become: yes
tasks:
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
permission: read
attribute:
- title
- initials
```
Example playbook to make sure selfservice "Users can manage their own name details" is absent:
```yaml
---
- name: Playbook to manage IPA selfservice.
hosts: ipaserver
become: yes
tasks:
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
state: absent
```
Example playbook to make sure "Users can manage their own name details" member attribute initials is present:
```yaml
---
- name: Playbook to manage IPA selfservice.
hosts: ipaserver
become: yes
tasks:
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
attribute:
- initials
action: member
```
Example playbook to make sure "Users can manage their own name details" member attribute initials is absent:
```yaml
---
- name: Playbook to manage IPA selfservice.
hosts: ipaserver
become: yes
tasks:
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
attribute:
- initials
action: member
state: absent
```
Example playbook to make sure selfservice "Users can manage their own name details" is absent:
```yaml
---
- name: Playbook to manage IPA selfservice.
hosts: ipaserver
become: yes
tasks:
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
state: absent
```
Variables
---------
ipaselfservice
-------
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
`name` \| `aciname` | The list of selfservice name strings. | yes
`permission` \| `permissions` | The permission to grant `read`, `read,write`, `write`]. Default is `write`. | no
`attribute` \| `attrs` | The attribute list to which the selfservice applies. | no
`action` | Work on selfservice or member level. It can be on of `member` or `selfservice` and defaults to `selfservice`. | no
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
Authors
=======
Thomas Woerner

View File

@@ -18,7 +18,7 @@ Supported FreeIPA Versions
FreeIPA versions 4.4.0 and up are supported by the ipaservice module.
Some variables are only supported on newer versions of FreeIPA. Check `Variables` section for details.
Option `skip_host_check` requires FreeIPA version 4.7.0 or later.
Requirements
@@ -56,7 +56,7 @@ Example playbook to make sure service is present:
- ipaservice:
ipaadmin_password: SomeADMINpassword
name: HTTP/www.example.com
certificate: |
certificate:
- MIIC/zCCAeegAwIBAgIUMNHIbn+hhrOVew/2WbkteisV29QwDQYJKoZIhvcNAQELBQAw
DzENMAsGA1UEAwwEdGVzdDAeFw0yMDAyMDQxNDQxMDhaFw0zMDAyMDExNDQxMDhaMA8xDT
ALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+XVVGFYpH
@@ -77,7 +77,7 @@ Example playbook to make sure service is present:
requires_pre_auth: false
ok_as_delegate: false
ok_to_auth_as_delegate: false
skip_host_check: true
skip-host-check: true
force: true
```
@@ -167,7 +167,7 @@ Example playbook to ensure service has a certificate:
- ipaservice:
ipaadmin_password: SomeADMINpassword
name: HTTP/www.example.com
certificate: |
certificate:
- MIIC/zCCAeegAwIBAgIUMNHIbn+hhrOVew/2WbkteisV29QwDQYJKoZIhvcNAQELBQAw
DzENMAsGA1UEAwwEdGVzdDAeFw0yMDAyMDQxNDQxMDhaFw0zMDAyMDExNDQxMDhaMA8xDT
ALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+XVVGFYpH
@@ -298,7 +298,7 @@ Variable | Description | Required
`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
`skip_host_check` | Force service to be created even when host object does not exist to manage it. Only usable with IPA versions 4.7.0 and up. Default to false. (bool)| no
`skip_host_check` | Force service to be created even when host object does not exist to manage it. Default to false. (bool)| no
`force` | Force principal name even if host not in DNS. Default to false. (bool) | no
`host` \| `managedby_host`| Hosts that can manage the service. | no
`principal` \| `krbprincipalname` | List of principal aliases for the service. | no

View File

@@ -1,119 +0,0 @@
Trust module
============
Description
-----------
The trust module allows to ensure presence and absence of a domain trust.
Features
--------
* Trust management
Supported FreeIPA Versions
--------------------------
FreeIPA versions 4.4.0 and up are supported by the ipatrust module.
Requirements
------------
**Controller**
* Ansible version: 2.8+
**Node**
* Supported FreeIPA version (see above)
* samba-4
* ipa-server-trust-ad
Usage
=====
Example inventory file
```ini
[ipaserver]
ipaserver.test.local
```
Example playbook to ensure a one-way trust is present:
Omitting the two_way option implies the default of one-way
```yaml
---
- name: Playbook to ensure a one-way trust is present
hosts: ipaserver
become: true
tasks:
- name: ensure the one-way trust present
ipatrust:
realm: ad.example.test
admin: Administrator
password: secret_password
state: present
```
Example playbook to ensure a two-way trust is present using a shared-secret:
```yaml
---
- name: Playbook to ensure a two-way trust is present
hosts: ipaserver
become: true
tasks:
- name: ensure the two-way trust is present
ipatrust:
realm: ad.example.test
trust_secret: my_share_Secret
two_way: True
state: present
```
Example playbook to ensure a trust is absent:
```yaml
---
- name: Playbook to ensure a trust is absent
hosts: ipaserver
become: true
tasks:
- name: ensure the trust is absent
ipatrust:
realm: ad.example.test
state: absent
```
This will only delete the ipa-side of the trust and it does NOT delete the id-range that matches the trust,
Variables
=========
ipatrust
-------
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
`realm` | The realm name string. | yes
`admin` | Active Directory domain administrator string. | no
`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
`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
`two_way` | Establish bi-directional trust. By default trust is inbound one-way only. (bool) | no
`external` | Establish external trust to a domain in another forest. The trust is not transitive beyond the domain. (bool) | no
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
Authors
=======
Rob Verduijn

View File

@@ -437,7 +437,7 @@ There are only return values if one or more random passwords have been generated
Variable | Description | Returned When
-------- | ----------- | -------------
`user` | User dict with random password. (dict) <br>Options: | If random is yes and user did not exist or update_password is yes
`host` | Host dict with random password. (dict) <br>Options: | If random is yes and user did not exist or update_password is yes
&nbsp; | `randompassword` - The generated random password | If only one user is handled by the module
&nbsp; | `name` - The user name of the user that got a new random password. (dict) <br> Options: <br> &nbsp; `randompassword` - The generated random password | If several users are handled by the module

View File

@@ -197,7 +197,7 @@ Example playbook to make sure vault is absent:
state: absent
register: result
- debug:
msg: "{{ result.vault.data }}"
msg: "{{ result.data }}"
```
Variables
@@ -246,8 +246,7 @@ There is only a return value if `state` is `retrieved`.
Variable | Description | Returned When
-------- | ----------- | -------------
`vault` | Vault dict with archived data. (dict) <br>Options: | If `state` is `retrieved` and `out` is not defined.
&nbsp; | `data` - The vault data. | Always
`data` | The data stored in the vault. | If `state` is `retrieved`.
Notes

View File

@@ -27,7 +27,6 @@ Features
* Modules for sudocmdgroup management
* Modules for sudorule management
* Modules for topology management
* Modules fot trust management
* Modules for user management
* Modules for vault management
@@ -430,7 +429,6 @@ Modules in plugin/modules
* [ipasudorule](README-sudorule.md)
* [ipatopologysegment](README-topology.md)
* [ipatopologysuffix](README-topology.md)
* [ipatrust](README-trust.md)
* [ipauser](README-user.md)
* [ipavault](README-vault.md)

22
azure-pipelines.yml Normal file
View File

@@ -0,0 +1,22 @@
trigger:
- master
pool:
vmImage: 'ubuntu-18.04'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.6'
- script: python -m pip install --upgrade pip setuptools wheel
displayName: Install tools
- script: pip install pydocstyle flake8
displayName: Install dependencies
- script: flake8 .
displayName: Run flake8 checks
- script: pydocstyle .
displayName: Verify docstings

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: centos-7-build
image: centos/systemd
pre_build_image: true
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

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: centos-7
image: quay.io/ansible-freeipa/upstream-tests:centos-7
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

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: centos-8-build
image: centos:8
pre_build_image: true
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

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: centos-8
image: quay.io/ansible-freeipa/upstream-tests:centos-8
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

View File

@@ -1 +0,0 @@
centos-8

View File

@@ -1,30 +0,0 @@
FROM fedora:latest
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"]

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: fedora-latest-build
image: fedora-latest
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

View File

@@ -1,18 +0,0 @@
---
driver:
name: docker
platforms:
- name: fedora-latest
image: quay.io/ansible-freeipa/upstream-tests:fedora-latest
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

View File

@@ -1 +0,0 @@
../../../plugins/modules/

View File

@@ -1 +0,0 @@
../../../plugins/module_utils/

View File

@@ -1,27 +0,0 @@
---
- name: Converge
hosts: all
tasks:
- include_tasks: prepare-common.yml
- name: Ensure sudo package is installed
package:
name: sudo
- name: Ensure nss package is updated
package:
name: nss
state: latest # noqa 403
- include_role:
name: ipaserver
vars:
ipaserver_setup_dns: yes
ipaserver_setup_kra: yes
ipaserver_auto_forwarders: yes
ipaserver_no_dnssec_validation: yes
ipaserver_auto_reverse: yes
ipaadmin_password: SomeADMINpassword
ipadm_password: SomeDMpassword
ipaserver_domain: test.local
ipaserver_realm: TEST.LOCAL

View File

@@ -1,33 +0,0 @@
# IPA depends on IPv6 and without it dirsrv service won't start.
- name: Ensure IPv6 is ENABLED
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
sysctl_set: yes
state: present
reload: yes
with_items :
- name: net.ipv6.conf.all.disable_ipv6
value: 0
- name: net.ipv6.conf.lo.disable_ipv6
value: 0
- name: net.ipv6.conf.eth0.disable_ipv6
value: 1
# Set fs.protected_regular to 0
# This is needed in some IPA versions in order to get KRA enabled.
# See https://pagure.io/freeipa/issue/7906 for more information.
- name: stat protected_regular
stat:
path: /proc/sys/fs/protected_regular
register: result
- name: Ensure fs.protected_regular is disabled
sysctl:
name: fs.protected_regular
value: 0
sysctl_set: yes
state: present
reload: yes
when: result.stat.exists

View File

@@ -1,26 +0,0 @@
---
- name: Converge
hosts: all
tasks:
- include_tasks: prepare-common.yml
# In some distros DS won't start up after reboot
# This is due to a problem in 389-ds. See tickets:
# * https://pagure.io/389-ds-base/issue/47429
# * https://pagure.io/389-ds-base/issue/51039
#
# To avoid this problem we create the directories before starting IPA.
- name: Ensure lock dirs for DS exists
file:
state: directory
owner: dirsrv
group: dirsrv
path: "{{ item }}"
loop:
- /var/lock/dirsrv/
- /var/lock/dirsrv/slapd-TEST-LOCAL/
- name: Ensure IPA server is up an running
service:
name: ipa
state: started

View File

@@ -1 +0,0 @@
../../../roles/

View File

@@ -1,11 +0,0 @@
---
- name: Delegation absent
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" is absent
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
state: absent

View File

@@ -1,15 +0,0 @@
---
- name: Delegation member absent
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" member attributes employeenumber and employeetype are absent
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- employeenumber
- employeetype
action: member
state: absent

View File

@@ -1,13 +0,0 @@
---
- name: Delegation member present
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" member attribute departmentnumber is present
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- departmentnumber
action: member

View File

@@ -1,15 +0,0 @@
---
- name: Delegation present
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" is present
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
permission: read
attribute:
- businesscategory
group: managers
membergroup: employees

View File

@@ -1,11 +0,0 @@
---
- name: Playbook to manage DNS forward zone
hosts: ipaserver
become: true
gather_facts: false
tasks:
# Ensure DNS zone is present
- ipadnsforwardzone:
ipaadmin_password: SomeADMINpassword
state: absent

View File

@@ -1,16 +0,0 @@
---
- name: Playbook to manage DNS forward zone
hosts: ipaserver
become: true
gather_facts: false
tasks:
# Ensure DNS zone is present
- ipadnsforwardzone:
ipaadmin_password: SomeADMINpassword
name: example.com
forwarders:
- ip_address: 8.8.8.8
forwardpolicy: first
skip_overlap_check: true
permission: yes

View File

@@ -1,14 +0,0 @@
---
- name: Playbook to manage DNS forward zone
hosts: ipaserver
become: true
gather_facts: false
tasks:
# Ensure DNS zone is present
- ipadnsforwardzone:
ipaadmin_password: SomeADMINpassword
name: example.com
forwarders:
- ip_address: 192.168.100.123
port: 8063

View File

@@ -1,15 +0,0 @@
---
- name: Playbook to ensure DNS zone exist
hosts: ipaserver
become: true
tasks:
- name: Ensure zone exist, finding zone name from IP address.
ipadnszone:
ipaadmin_password: SomeADMINpassword
name_from_ip: 10.1.2.3/24
register: result
- name: Zone name inferred from `name_from_ip`
debug:
msg: "Zone created: {{ result.dnszone.name }}"

View File

@@ -4,7 +4,7 @@
become: true
tasks:
- ipahost:
ipahost:
ipaadmin_password: SomeADMINpassword
name: host01.exmaple.com
managedby_host: server.exmaple.com

View File

@@ -4,7 +4,7 @@
become: true
tasks:
- ipahost:
ipahost:
ipaadmin_password: SomeADMINpassword
name: host01.exmaple.com
managedby_host: server.exmaple.com

View File

@@ -4,7 +4,7 @@
become: true
tasks:
- ipahost:
ipahost:
ipaadmin_password: SomeADMINpassword
name: host01.exmaple.com
managedby_host: server.exmaple.com

View File

@@ -4,7 +4,6 @@
become: true
tasks:
- name: Ensure hosts manadegby_host is absent.
ipahost:
ipaadmin_password: SomeADMINpassword
hosts:

View File

@@ -4,7 +4,6 @@
become: true
tasks:
- name: Ensure hosts manadegby_host is absent.
ipahost:
ipaadmin_password: SomeADMINpassword
hosts:

View File

@@ -4,7 +4,7 @@
become: true
tasks:
- ipahost:
ipahost:
ipaadmin_password: SomeADMINpassword
hosts:
- name: host01.exmaple.com

View File

@@ -23,3 +23,4 @@
- name: Print generated random password for host02.example.com
debug:
var: ipahost.host["host02.example.com"].randompassword

View File

@@ -1,12 +0,0 @@
---
- name: Playbook to handle hostgroups
hosts: ipaserver
become: yes
tasks:
- name : Rename host-group from `databases` to `datalake`
ipahostgroup:
ipaadmin_password: SomeADMINpassword
name: databases
rename: datalake
state: renamed

View File

@@ -1,11 +0,0 @@
---
- name: Location absent test
hosts: ipaserver
become: true
tasks:
- name: Ensure location my_location1 is absent
ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1
state: absent

View File

@@ -1,10 +0,0 @@
---
- name: Location present test
hosts: ipaserver
become: true
tasks:
- name: Ensure location my_location1 is present
ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1

View File

@@ -1,10 +0,0 @@
---
- name: Privilege absent example
hosts: ipaserver
become: true
tasks:
- name: Ensure privilege "Broad Privilege" is absent
ipaprivilege:
name: Broad Privilege
state: absent

View File

@@ -1,14 +0,0 @@
---
- name: Privilege absent example
hosts: ipaserver
become: true
tasks:
- name: Ensure privilege "Broad Privilege" permission is absent
ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "System: Write IPA Configuration"
action: member
state: absent

View File

@@ -1,15 +0,0 @@
---
- name: Privilege member present example
hosts: ipaserver
become: true
tasks:
- name: Ensure privilege "Broad Privilege" permissions are present
ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "System: Write IPA Configuration"
- "System: Write DNS Configuration"
- "System: Update DNS Entries"
action: member

View File

@@ -1,11 +0,0 @@
---
- name: Privilege present example
hosts: ipaserver
become: true
tasks:
- name: Ensure privilege Broad Privilege is present
ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
description: Broad Privilege

View File

@@ -1,11 +0,0 @@
---
- name: Delegation absent
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" is absent
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
state: absent

View File

@@ -1,15 +0,0 @@
---
- name: Delegation member absent
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" member attributes employeenumber and employeetype are absent
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- employeenumber
- employeetype
action: member
state: absent

View File

@@ -1,13 +0,0 @@
---
- name: Delegation member present
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" member attribute departmentnumber is present
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- departmentnumber
action: member

View File

@@ -1,13 +0,0 @@
---
- name: Delegation present
hosts: ipaserver
become: true
tasks:
- name: Ensure delegation "basic manager attributes" is present
ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
permission: read
attribute:
- businesscategory

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure management host is absent.
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
host: "{{ groups.ipaserver[0] }}"
action: member

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure management host is present.
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
host: "{{ groups.ipaserver[0] }}"
action: member

View File

@@ -7,6 +7,6 @@
tasks:
# Ensure service is absent
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
state: absent

View File

@@ -7,6 +7,6 @@
tasks:
# Ensure service is disabled
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
state: disabled

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure service is present
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
certificate:
- MIICBjCCAW8CFHnm32VcXaUDGfEGdDL/erPSijUAMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwHhcNMjAwMTIzMDA1NjQ2WhcNMjEwMTIyMDA1NjQ2WjBCMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYrdVmsr7iT3f67DM5bb1osSEe5/c91UUMEIcFq5wrgBhzVfs8iIMDVC1yiUGTsDLJNJc4nb1tUxeR9K5fh25E6n/eWDBP75NStotjAXRU4Ahi3FNRhWFOKesds5xNqgDk5/dY8UekJv2yUblQuZzeF8b2XFrmHuCaYuFctzPfWwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACF+5RS8Ce0HRixGPu4Xd51i+Kzblg++lx8fDJ8GW5G16/Z1AsB72Hc7etJL2PksHlue/xCq6SA9fIfHc4TBNCiWjPSP1NhHJeYyoPiSkcYsqXuxWyoyRLbnAhBVvhoiqZbUt3u3tGB0uMMA0yJvj07mP7Nea2KdBYVH8X1pM0V+

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure service is present
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/ihavenodns.info
force: yes
# state: absent

View File

@@ -7,6 +7,6 @@
tasks:
# Ensure service is present
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.ansible.com
skip_host_check: yes

View File

@@ -7,5 +7,5 @@
tasks:
# Ensure service is present
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.example.com members allow_create_keytab absent for users, groups, hosts and hostgroups
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
allow_create_keytab_user:
- user01

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.example.com members allow_create_keytab present for users, groups, hosts and hostgroups
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
allow_create_keytab_user:
- user01

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.example.com members allow_retrieve_keytab absent for users, groups, hosts and hostgroups
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
allow_retrieve_keytab_user:
- user01

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.example.com members allow_retrieve_keytab present for users, groups, hosts and hostgroups
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
allow_retrieve_keytab_user:
- user01

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure service certificate is absent
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
certificate:

View File

@@ -7,7 +7,7 @@
tasks:
# Ensure service certificate is present
- ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
certificate:
- MIICBjCCAW8CFHnm32VcXaUDGfEGdDL/erPSijUAMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQgQ29tcGFueSBMdGQwHhcNMjAwMTIzMDA1NjQ2WhcNMjEwMTIyMDA1NjQ2WjBCMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYrdVmsr7iT3f67DM5bb1osSEe5/c91UUMEIcFq5wrgBhzVfs8iIMDVC1yiUGTsDLJNJc4nb1tUxeR9K5fh25E6n/eWDBP75NStotjAXRU4Ahi3FNRhWFOKesds5xNqgDk5/dY8UekJv2yUblQuZzeF8b2XFrmHuCaYuFctzPfWwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACF+5RS8Ce0HRixGPu4Xd51i+Kzblg++lx8fDJ8GW5G16/Z1AsB72Hc7etJL2PksHlue/xCq6SA9fIfHc4TBNCiWjPSP1NhHJeYyoPiSkcYsqXuxWyoyRLbnAhBVvhoiqZbUt3u3tGB0uMMA0yJvj07mP7Nea2KdBYVH8X1pM0V+

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.exmaple.com member principals host/test.exmaple.com absent
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
principal:
- host/test.exmaple.com

View File

@@ -6,7 +6,7 @@
tasks:
- name: Service HTTP/www.exmaple.com member principals host/test.exmaple.com present
ipaservice:
ipaadmin_password: SomeADMINpassword
ipaadmin_password: MyPassword123
name: HTTP/www.example.com
principal:
- host/test.exmaple.com

View File

@@ -1,12 +0,0 @@
---
- name: Playbook to create a trust
hosts: ipaserver
become: true
tasks:
- name: ensure the trust is present
ipatrust:
realm: windows.local
admin: Administrator
password: secret_password
state: present

View File

@@ -1,10 +0,0 @@
---
- name: Playbook to delete trust
hosts: ipaserver
become: true
tasks:
- name: ensure the trust is absent
ipatrust:
realm: windows.local
state: absent

View File

@@ -14,4 +14,4 @@
state: retrieved
register: result
- debug:
msg: "Data: {{ result.vault.data }}"
msg: "Data: {{ result.data }}"

View File

@@ -14,4 +14,4 @@
state: retrieved
register: result
- debug:
msg: "{{ result.vault.data }}"
msg: "{{ result.data | b64decode }}"

View File

@@ -506,7 +506,7 @@ class FreeIPABaseModule(AnsibleModule):
# when needed.
self.ipa_params = AnsibleFreeIPAParams(self)
def get_ipa_command_args(self, **kwargs):
def get_ipa_command_args(self):
"""
Return a dict to be passed to an IPA command.
@@ -538,7 +538,7 @@ class FreeIPABaseModule(AnsibleModule):
elif hasattr(self, param_name):
method = getattr(self, param_name)
if callable(method):
value = method(**kwargs)
value = method()
# We don't have a way to guess the value so fail.
else:
@@ -610,16 +610,13 @@ class FreeIPABaseModule(AnsibleModule):
exit the module with proper arguments.
"""
# TODO: shouldn't we also disconnect from api backend?
temp_kdestroy(self.ccache_dir, self.ccache_name)
if exc_type == SystemExit:
raise
if exc_val:
self.fail_json(msg=str(exc_val))
self.exit_json(changed=self.changed, **self.exit_args)
# TODO: shouldn't we also disconnect from api backend?
temp_kdestroy(self.ccache_dir, self.ccache_name)
self.exit_json(changed=self.changed, user=self.exit_args)
def get_command_errors(self, command, result):
"""Look for erros into command results."""
@@ -658,22 +655,14 @@ class FreeIPABaseModule(AnsibleModule):
except Exception as excpt:
self.fail_json(msg="%s: %s: %s" % (command, name, str(excpt)))
else:
self.process_command_result(name, command, args, result)
if "completed" in result:
if result["completed"] > 0:
self.changed = True
else:
self.changed = True
self.get_command_errors(command, result)
def process_command_result(self, name, command, args, result):
"""
Process an API command result.
This method can be overriden in subclasses, and change self.exit_values
to return data in the result for the controller.
"""
if "completed" in result:
if result["completed"] > 0:
self.changed = True
else:
self.changed = True
def require_ipa_attrs_change(self, command_args, ipa_attrs):
"""
Compare given args with current object attributes.

View File

@@ -1,340 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2020 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/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipadelegation
short description: Manage FreeIPA delegations
description: Manage FreeIPA delegations and delegation attributes
options:
ipaadmin_principal:
description: The admin principal.
default: admin
ipaadmin_password:
description: The admin password.
required: false
name:
description: The list of delegation name strings.
required: true
aliases: ["aciname"]
permission:
description: Permissions to grant (read, write). Default is write.
required: false
aliases: ["permissions"]
attribute:
description: Attribute list to which the delegation applies
required: false
aliases: ["attrs"]
membergroup
description: User group to apply delegation to
required: false
aliases: ["memberof"]
group:
description: User group ACI grants access to
required: false
action:
description: Work on delegation or member level.
choices: ["delegation", "member"]
default: delegation
required: false
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure delegation "basic manager attributes" is present
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
permission: read
attribute:
- businesscategory
- employeetype
group: managers
membergroup: employees
# Ensure delegation "basic manager attributes" member attribute
# departmentnumber is present
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- departmentnumber
action: member
# Ensure delegation "basic manager attributes" member attributes
# employeetype and employeenumber are present
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
attribute:
- employeenumber
- employeetype
action: member
state: absent
# Ensure delegation "basic manager attributes" is absent
- ipadelegation:
ipaadmin_password: SomeADMINpassword
name: "basic manager attributes"
state: absent
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import \
temp_kinit, temp_kdestroy, valid_creds, api_connect, api_command, \
compare_args_ipa, module_params_get
import six
if six.PY3:
unicode = str
def find_delegation(module, name):
"""Find if a delegation with the given name already exist."""
try:
_result = api_command(module, "delegation_show", name, {"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if delegation name is not found.
return None
else:
return _result["result"]
def gen_args(permission, attribute, membergroup, group):
_args = {}
if permission is not None:
_args["permissions"] = permission
if attribute is not None:
_args["attrs"] = attribute
if membergroup is not None:
_args["memberof"] = membergroup
if group is not None:
_args["group"] = group
return _args
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="list", aliases=["aciname"], default=None,
required=True),
# present
permission=dict(required=False, type='list',
aliases=["permissions"], default=None),
attribute=dict(required=False, type='list', aliases=["attrs"],
default=None),
membergroup=dict(type="str", aliases=["memberof"], default=None),
group=dict(type="str", default=None),
action=dict(type="str", default="delegation",
choices=["member", "delegation"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
names = module_params_get(ansible_module, "name")
# present
permission = module_params_get(ansible_module, "permission")
attribute = module_params_get(ansible_module, "attribute")
membergroup = module_params_get(ansible_module, "membergroup")
group = module_params_get(ansible_module, "group")
action = module_params_get(ansible_module, "action")
# state
state = module_params_get(ansible_module, "state")
# Check parameters
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one delegation be added at a time.")
if action == "member":
invalid = ["permission", "membergroup", "group"]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s' and state '%s'" % (x, action, state))
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
invalid = ["permission", "membergroup", "group"]
if action == "delegation":
invalid.append("attribute")
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s' and state '%s'" % (x, action, state))
if permission is not None:
perm = [p for p in permission if p not in ("read", "write")]
if perm:
ansible_module.fail_json(msg="Invalid permission '%s'" % perm)
if len(set(permission)) != len(permission):
ansible_module.fail_json(
msg="Invalid permission '%s', items are not unique" %
repr(permission))
if attribute is not None:
if len(set(attribute)) != len(attribute):
ansible_module.fail_json(
msg="Invalid attribute '%s', items are not unique" %
repr(attribute))
# Init
changed = False
exit_args = {}
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
commands = []
for name in names:
# Make sure delegation exists
res_find = find_delegation(ansible_module, name)
# Create command
if state == "present":
# Generate args
args = gen_args(permission, attribute, membergroup, group)
if action == "delegation":
# Found the delegation
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):
commands.append([name, "delegation_mod", args])
else:
commands.append([name, "delegation_add", args])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No delegation '%s'" % name)
if attribute is None:
ansible_module.fail_json(msg="No attributes given")
# New attribute list (add given ones to find result)
# Make list with unique entries
attrs = list(set(list(res_find["attrs"]) + attribute))
if len(attrs) > len(res_find["attrs"]):
commands.append([name, "delegation_mod",
{"attrs": attrs}])
elif state == "absent":
if action == "delegation":
if res_find is not None:
commands.append([name, "delegation_del", {}])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No delegation '%s'" % name)
if attribute is None:
ansible_module.fail_json(msg="No attributes given")
# New attribute list (remove given ones from find result)
# Make list with unique entries
attrs = list(set(res_find["attrs"]) - set(attribute))
if len(attrs) < 1:
ansible_module.fail_json(
msg="At minimum one attribute is needed.")
# Entries New number of attributes is smaller
if len(attrs) < len(res_find["attrs"]):
commands.append([name, "delegation_mod",
{"attrs": attrs}])
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
for name, command, args in commands:
try:
result = api_command(ansible_module, command, name,
args)
if "completed" in result:
if result["completed"] > 0:
changed = True
else:
changed = True
except Exception as e:
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
str(e)))
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -106,7 +106,6 @@ RETURN = '''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, compare_args_ipa, \
module_params_get
@@ -151,7 +150,7 @@ def forwarder_list(forwarders):
formatter = "{ip_address} port {port}"
else:
formatter = "{ip_address}"
fwd_list.append(to_text(formatter.format(**forwarder)))
fwd_list.append(formatter.format(**forwarder))
return fwd_list

View File

@@ -41,14 +41,8 @@ options:
name:
description: The zone name string.
required: true
type: list
alises: ["zone_name"]
name_from_ip:
description: |
Derive zone name from reverse of IP (PTR).
Can only be used with `state: present`.
required: false
type: str
alises: ["zone_name"]
forwarders:
description: The list of global DNS forwarders.
required: false
@@ -194,14 +188,6 @@ EXAMPLES = """
"""
RETURN = """
dnszone:
description: DNS Zone dict with zone name infered from `name_from_ip`.
returned:
If `state` is `present`, `name_from_ip` is used, and a zone was created.
options:
name:
description: The name of the zone created, inferred from `name_from_ip`.
returned: always
"""
from ipapython.dnsutil import DNSName # noqa: E402
@@ -211,12 +197,6 @@ from ansible.module_utils.ansible_freeipa_module import (
is_ipv6_addr,
is_valid_port,
) # noqa: E402
import netaddr
import six
if six.PY3:
unicode = str
class DNSZoneModule(FreeIPABaseModule):
@@ -288,7 +268,7 @@ class DNSZoneModule(FreeIPABaseModule):
return True
def get_ipa_nsec3paramrecord(self, **kwargs):
def get_ipa_nsec3paramrecord(self):
nsec3param_rec = self.ipa_params.nsec3param_rec
if nsec3param_rec is not None:
error_msg = (
@@ -300,7 +280,7 @@ class DNSZoneModule(FreeIPABaseModule):
self.fail_json(msg=error_msg)
return nsec3param_rec
def get_ipa_idnsforwarders(self, **kwargs):
def get_ipa_idnsforwarders(self):
if self.ipa_params.forwarders is not None:
forwarders = []
for forwarder in self.ipa_params.forwarders:
@@ -324,14 +304,14 @@ class DNSZoneModule(FreeIPABaseModule):
return forwarders
def get_ipa_idnsallowtransfer(self, **kwargs):
def get_ipa_idnsallowtransfer(self):
if self.ipa_params.allow_transfer is not None:
error_msg = "Invalid ip_address for DNS allow_transfer: %s"
self.validate_ips(self.ipa_params.allow_transfer, error_msg)
return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
def get_ipa_idnsallowquery(self, **kwargs):
def get_ipa_idnsallowquery(self):
if self.ipa_params.allow_query is not None:
error_msg = "Invalid ip_address for DNS allow_query: %s"
self.validate_ips(self.ipa_params.allow_query, error_msg)
@@ -354,141 +334,81 @@ class DNSZoneModule(FreeIPABaseModule):
return ".".join((name, domain))
def get_ipa_idnssoarname(self, **kwargs):
def get_ipa_idnssoarname(self):
if self.ipa_params.admin_email is not None:
return DNSName(
self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
)
def get_ipa_idnssoamname(self, **kwargs):
def get_ipa_idnssoamname(self):
if self.ipa_params.name_server is not None:
return DNSName(self.ipa_params.name_server)
def get_ipa_skip_overlap_check(self, **kwargs):
zone = kwargs.get('zone')
if not zone and self.ipa_params.skip_overlap_check is not None:
def get_ipa_skip_overlap_check(self):
if not self.zone and self.ipa_params.skip_overlap_check is not None:
return self.ipa_params.skip_overlap_check
def get_ipa_skip_nameserver_check(self, **kwargs):
zone = kwargs.get('zone')
if not zone and self.ipa_params.skip_nameserver_check is not None:
def get_ipa_skip_nameserver_check(self):
if not self.zone and self.ipa_params.skip_nameserver_check is not None:
return self.ipa_params.skip_nameserver_check
def __reverse_zone_name(self, ipaddress):
"""
Infer reverse zone name from an ip address.
This function uses the same heuristics as FreeIPA to infer the zone
name from ip.
"""
try:
ip = netaddr.IPAddress(str(ipaddress))
except (netaddr.AddrFormatError, ValueError):
net = netaddr.IPNetwork(ipaddress)
items = net.ip.reverse_dns.split('.')
prefixlen = net.prefixlen
ip_version = net.version
else:
items = ip.reverse_dns.split('.')
prefixlen = 24 if ip.version == 4 else 64
ip_version = ip.version
if ip_version == 4:
return u'.'.join(items[4 - prefixlen // 8:])
elif ip_version == 6:
return u'.'.join(items[32 - prefixlen // 4:])
else:
self.fail_json(msg="Invalid IP version for reverse zone.")
def get_zone(self, zone_name):
get_zone_args = {"idnsname": zone_name, "all": True}
response = self.api_command("dnszone_find", args=get_zone_args)
zone = None
is_zone_active = False
if response["count"] == 1:
zone = response["result"][0]
is_zone_active = zone.get("idnszoneactive") == ["TRUE"]
self.zone = response["result"][0]
self.is_zone_active = self.zone.get("idnszoneactive") == ["TRUE"]
return self.zone
return zone, is_zone_active
# Zone doesn't exist yet
self.zone = None
self.is_zone_active = False
def get_zone_names(self):
zone_names = self.__get_zone_names_from_params()
if len(zone_names) > 1 and self.ipa_params.state != "absent":
self.fail_json(
msg=("Please provide a single name. Multiple values for 'name'"
"can only be supplied for state 'absent'.")
)
return zone_names
def __get_zone_names_from_params(self):
if not self.ipa_params.name:
return [self.__reverse_zone_name(self.ipa_params.name_from_ip)]
@property
def zone_name(self):
return self.ipa_params.name
def check_ipa_params(self):
if not self.ipa_params.name and not self.ipa_params.name_from_ip:
self.fail_json(
msg="Either `name` or `name_from_ip` must be provided."
)
if self.ipa_params.state != "present" and self.ipa_params.name_from_ip:
self.fail_json(
msg=(
"Cannot use argument `name_from_ip` with state `%s`."
% self.ipa_params.state
)
)
def define_ipa_commands(self):
for zone_name in self.get_zone_names():
# Look for existing zone in IPA
zone, is_zone_active = self.get_zone(zone_name)
args = self.get_ipa_command_args(zone=zone)
just_added = False
# Look for existing zone in IPA
self.get_zone(self.zone_name)
args = self.get_ipa_command_args()
just_added = False
if self.ipa_params.state in ["present", "enabled", "disabled"]:
if not zone:
# Since the zone doesn't exist we just create it
# with given args
self.add_ipa_command("dnszone_add", zone_name, args)
is_zone_active = True
just_added = True
if self.ipa_params.state in ["present", "enabled", "disabled"]:
if not self.zone:
# Since the zone doesn't exist we just create it
# with given args
self.add_ipa_command("dnszone_add", self.zone_name, args)
self.is_zone_active = True
just_added = True
else:
# Zone already exist so we need to verify if given args
# matches the current config. If not we updated it.
if self.require_ipa_attrs_change(args, zone):
self.add_ipa_command("dnszone_mod", zone_name, args)
else:
# Zone already exist so we need to verify if given args
# matches the current config. If not we updated it.
if self.require_ipa_attrs_change(args, self.zone):
self.add_ipa_command("dnszone_mod", self.zone_name, args)
if self.ipa_params.state == "enabled" and not is_zone_active:
self.add_ipa_command("dnszone_enable", zone_name)
if self.ipa_params.state == "enabled" and not self.is_zone_active:
self.add_ipa_command("dnszone_enable", self.zone_name)
if self.ipa_params.state == "disabled" and is_zone_active:
self.add_ipa_command("dnszone_disable", zone_name)
if self.ipa_params.state == "disabled" and self.is_zone_active:
self.add_ipa_command("dnszone_disable", self.zone_name)
if self.ipa_params.state == "absent":
if zone:
self.add_ipa_command("dnszone_del", zone_name)
if self.ipa_params.state == "absent":
if self.zone:
self.add_ipa_command("dnszone_del", self.zone_name)
# Due to a bug in FreeIPA dnszone-add won't set
# SOA Serial. The good news is that dnszone-mod does the job.
# See: https://pagure.io/freeipa/issue/8227
# Because of that, if the zone was just added with a given serial
# we run mod just after to workaround the bug
if just_added and self.ipa_params.serial is not None:
args = {
"idnssoaserial": self.ipa_params.serial,
}
self.add_ipa_command("dnszone_mod", zone_name, args)
def process_command_result(self, name, command, args, result):
super(DNSZoneModule, self).process_command_result(
name, command, args, result
)
if command == "dnszone_add" and self.ipa_params.name_from_ip:
dnszone_exit_args = self.exit_args.setdefault('dnszone', {})
dnszone_exit_args['name'] = name
# Due to a bug in FreeIPA dnszone-add won't set
# SOA Serial. The good news is that dnszone-mod does the job.
# See: https://pagure.io/freeipa/issue/8227
# Because of that, if the zone was just added with a given serial
# we run mod just after to workaround the bug
if just_added and self.ipa_params.serial is not None:
args = {
"idnssoaserial": self.ipa_params.serial,
}
self.add_ipa_command("dnszone_mod", self.zone_name, args)
def get_argument_spec():
@@ -506,9 +426,8 @@ def get_argument_spec():
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(
type="list", default=None, required=False, aliases=["zone_name"]
type="str", default=None, required=True, aliases=["zone_name"]
),
name_from_ip=dict(type="str", default=None, required=False),
forwarders=dict(
type="list",
default=None,
@@ -548,11 +467,7 @@ def get_argument_spec():
def main():
DNSZoneModule(
argument_spec=get_argument_spec(),
mutually_exclusive=[["name", "name_from_ip"]],
required_one_of=[["name", "name_from_ip"]],
).ipa_run()
DNSZoneModule(argument_spec=get_argument_spec()).ipa_run()
if __name__ == "__main__":

View File

@@ -70,12 +70,6 @@ options:
- Only usable with IPA versions 4.8.4 and up.
required: false
type: list
rename:
description:
- Rename hostgroup to the given name.
- Only usable with IPA versions 4.8.7 and up.
required: false
aliases: ["new_name"]
action:
description: Work on hostgroup or member level
default: hostgroup
@@ -83,7 +77,7 @@ options:
state:
description: State to ensure
default: present
choices: ["present", "absent", "renamed"]
choices: ["present", "absent"]
author:
- Thomas Woerner
"""
@@ -122,12 +116,6 @@ EXAMPLES = """
action: member
state: absent
# Rename hostgroup
- ipahostgroup:
ipaadmin_password: SomeADMINpassword
name: databases
rename: datalake
# Ensure host-group databases is absent
- ipahostgroup:
ipaadmin_password: SomeADMINpassword
@@ -141,7 +129,7 @@ RETURN = """
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, compare_args_ipa, \
module_params_get, gen_add_del_lists, api_check_command, api_check_param
module_params_get, gen_add_del_lists, api_check_command
def find_hostgroup(module, name):
@@ -161,14 +149,12 @@ def find_hostgroup(module, name):
return None
def gen_args(description, nomembers, rename):
def gen_args(description, nomembers):
_args = {}
if description is not None:
_args["description"] = description
if nomembers is not None:
_args["nomembers"] = nomembers
if rename is not None:
_args["rename"] = rename
return _args
@@ -200,13 +186,11 @@ def main():
membermanager_user=dict(required=False, type='list', default=None),
membermanager_group=dict(required=False, type='list',
default=None),
rename=dict(required=False, type='str', default=None,
aliases=["new_name"]),
action=dict(type="str", default="hostgroup",
choices=["member", "hostgroup"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent", "renamed"]),
choices=["present", "absent"]),
),
supports_check_mode=True,
)
@@ -231,7 +215,6 @@ def main():
"membermanager_user")
membermanager_group = module_params_get(ansible_module,
"membermanager_group")
rename = module_params_get(ansible_module, "rename")
action = module_params_get(ansible_module, "action")
# state
state = module_params_get(ansible_module, "state")
@@ -242,38 +225,19 @@ def main():
if len(names) != 1:
ansible_module.fail_json(
msg="Only one hostgroup can be added at a time.")
invalid = ["rename"]
if action == "member":
invalid.extend(["description", "nomembers"])
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s'" % (x, action))
if state == "renamed":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one hostgroup can be added at a time.")
if action == "member":
ansible_module.fail_json(
msg="Action '%s' can not be used with state '%s'" %
(action, state))
invalid = [
"description", "nomembers", "host", "hostgroup",
"membermanager_user", "membermanager_group"
]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with state '%s'" %
(x, state))
invalid = ["description", "nomembers"]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s'" % (x, action))
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(
msg="No name given.")
invalid = ["description", "nomembers", "rename"]
invalid = ["description", "nomembers"]
if action == "hostgroup":
invalid.extend(["host", "hostgroup"])
for x in invalid:
@@ -302,10 +266,6 @@ def main():
msg="Managing a membermanager user or group is not supported "
"by your IPA version"
)
has_mod_rename = api_check_param("hostgroup_mod", "rename")
if not has_mod_rename and rename is not None:
ansible_module.fail_json(
msg="Renaming hostgroups is not supported by your IPA version")
commands = []
@@ -316,7 +276,7 @@ def main():
# Create command
if state == "present":
# Generate args
args = gen_args(description, nomembers, rename)
args = gen_args(description, nomembers)
if action == "hostgroup":
# Found the hostgroup
@@ -415,22 +375,6 @@ def main():
}]
)
elif state == "renamed":
if res_find is not None:
if rename != name:
commands.append(
[name, "hostgroup_mod", {"rename": rename}]
)
else:
# If a hostgroup with the desired name exists, do nothing.
new_find = find_hostgroup(ansible_module, rename)
if new_find is None:
# Fail only if the either hostsgroups do not exist.
ansible_module.fail_json(
msg="Attribute `rename` can not be used, unless "
"hostgroup exists."
)
elif state == "absent":
if action == "hostgroup":
if res_find is not None:

View File

@@ -1,220 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2020 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/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipalocation
short description: Manage FreeIPA location
description: Manage FreeIPA location
options:
ipaadmin_principal:
description: The admin principal.
default: admin
ipaadmin_password:
description: The admin password.
required: false
name:
description: The list of location name strings.
required: true
aliases: ["idnsname"]
description:
description: The IPA location string
required: false
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure location my_location1 is present
- ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1
description: My location 1
# Ensure location my_location1 is absent
- ipalocation:
ipaadmin_password: SomeADMINpassword
name: my_location1
state: absent
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import \
temp_kinit, temp_kdestroy, valid_creds, api_connect, api_command, \
compare_args_ipa, module_params_get
import six
if six.PY3:
unicode = str
def find_location(module, name):
"""Find if a location with the given name already exist."""
try:
_result = api_command(module, "location_show", name, {"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if location name is not found.
return None
else:
return _result["result"]
def gen_args(description):
_args = {}
if description is not None:
_args["description"] = description
return _args
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="list", aliases=["idnsname"],
default=None, required=True),
# present
description=dict(required=False, type='str', default=None),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
names = module_params_get(ansible_module, "name")
# present
description = module_params_get(ansible_module, "description")
# state
state = module_params_get(ansible_module, "state")
# Check parameters
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one location be added at a time.")
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
invalid = ["description"]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with state '%s'" %
(x, state))
# Init
changed = False
exit_args = {}
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
commands = []
for name in names:
# Make sure location exists
res_find = find_location(ansible_module, name)
# Create command
if state == "present":
# Generate args
args = gen_args(description)
# Found the location
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):
commands.append([name, "location_mod", args])
else:
commands.append([name, "location_add", args])
elif state == "absent":
if res_find is not None:
commands.append([name, "location_del", {}])
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
for name, command, args in commands:
try:
result = api_command(ansible_module, command, name,
args)
if "completed" in result:
if result["completed"] > 0:
changed = True
else:
changed = True
except Exception as e:
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
str(e)))
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -1,357 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Rafael Guterres Jeffman <rjeffman@redhat.com>
#
# Copyright (C) 2020 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/>.
"""ansible-freeipa module to manage FreeIPA privileges."""
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipaprivilege
short description: Manage FreeIPA privilege
description: Manage FreeIPA privilege and privilege members
options:
ipaadmin_principal:
description: The admin principal.
default: admin
ipaadmin_password:
description: The admin password.
required: false
name:
description: The list of privilege name strings.
required: true
aliases: ["cn"]
description:
description: Privilege description
required: false
rename:
description: Rename the privilege object.
required: false
aliases: ["new_name"]
permission:
description: Permissions to be added to the privilege.
required: false
action:
description: Work on privilege or member level.
choices: ["privilege", "member"]
default: privilege
required: false
state:
description: The state to ensure.
choices: ["present", "absent", "renamed"]
default: present
required: true
"""
EXAMPLES = """
# Ensure privilege "Broad Privilege" is present
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
description: Broad Privilege
# Ensure privilege "Broad Privilege" has permissions set
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "Write IPA Configuration"
- "System: Write DNS Configuration"
- "System: Update DNS Entries"
action: member
# Ensure privilege member permission 'Write IPA Configuration' is absent
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
permission:
- "Write IPA Configuration"
action: member
state: absent
# Rename privilege "Broad Privilege" to "DNS Special Privilege"
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: Broad Privilege
rename: DNS Special Privilege
state: renamed
# Ensure privilege "DNS Special Privilege" is absent
- ipaprivilege:
ipaadmin_password: SomeADMINpassword
name: DNS Special Privilege
state: absent
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import \
temp_kinit, temp_kdestroy, valid_creds, api_connect, api_command, \
compare_args_ipa, module_params_get, gen_add_del_lists
import six
if six.PY3:
unicode = str
def find_privilege(module, name):
"""Find if a privilege with the given name already exist."""
try:
_result = api_command(module, "privilege_show", name, {"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if privilege name is not found.
return None
else:
return _result["result"]
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="list", aliases=["cn"],
default=None, required=True),
# present
description=dict(required=False, type='str', default=None),
rename=dict(required=False, type='str', default=None,
aliases=["new_name"], ),
permission=dict(required=False, type='list', default=None),
action=dict(type="str", default="privilege",
choices=["member", "privilege"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent", "renamed"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
names = module_params_get(ansible_module, "name")
# present
description = module_params_get(ansible_module, "description")
permission = module_params_get(ansible_module, "permission")
rename = module_params_get(ansible_module, "rename")
action = module_params_get(ansible_module, "action")
# state
state = module_params_get(ansible_module, "state")
# Check parameters
invalid = []
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one privilege be added at a time.")
if action == "member":
invalid = ["description"]
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
invalid = ["description", "rename"]
if action == "privilege":
invalid.append("permission")
if state == "renamed":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one privilege be added at a time.")
invalid = ["description", "permission"]
if action != "privilege":
ansible_module.fail_json(
msg="Action '%s' can not be used with state '%s'"
% (action, state))
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s' and state '%s'" % (x, action, state))
# Init
changed = False
exit_args = {}
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
commands = []
for name in names:
# Make sure privilege exists
res_find = find_privilege(ansible_module, name)
# Create command
if state == "present":
args = {}
if description:
args['description'] = description
if action == "privilege":
# Found the privilege
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):
commands.append([name, "privilege_mod", args])
else:
commands.append([name, "privilege_add", args])
member_args = {}
if permission:
member_args['permission'] = permission
if not compare_args_ipa(ansible_module, member_args,
res_find):
# Generate addition and removal lists
permission_add, permission_del = gen_add_del_lists(
permission, res_find.get("member_permission"))
# Add members
if len(permission_add) > 0:
commands.append([name, "privilege_add_permission",
{
"permission": permission_add,
}])
# Remove members
if len(permission_del) > 0:
commands.append([
name,
"privilege_remove_permission",
{"permission": permission_del}
])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No privilege '%s'" % name)
if permission is None:
ansible_module.fail_json(msg="No permission given")
commands.append([name, "privilege_add_permission",
{"permission": permission}])
elif state == "absent":
if action == "privilege":
if res_find is not None:
commands.append([name, "privilege_del", {}])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No privilege '%s'" % name)
if permission is None:
ansible_module.fail_json(msg="No permission given")
commands.append([name, "privilege_remove_permission",
{
"permission": permission,
}])
elif state == "renamed":
if not rename:
ansible_module.fail_json(msg="No rename value given.")
if res_find is None:
ansible_module.fail_json(
msg="No privilege found to be renamed: '%s'" % (name))
if name != rename:
commands.append(
[name, "privilege_mod", {"rename": rename}])
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
for name, command, args in commands:
try:
result = api_command(ansible_module, command, name,
args)
if "completed" in result:
if result["completed"] > 0:
changed = True
else:
changed = True
except Exception as e:
ansible_module.fail_json(
msg="%s: %s: %s" % (command, name, str(e)))
# Get all errors
# All "already a member" and "not a member" failures in the
# result are ignored. All others are reported.
errors = []
for failed_item in result.get("failed", []):
failed = result["failed"][failed_item]
for member_type in failed:
for member, failure in failed[member_type]:
if "already a member" in failure \
or "not a member" in failure:
continue
errors.append("%s: %s %s: %s" % (
command, member_type, member, failure))
if len(errors) > 0:
ansible_module.fail_json(msg=", ".join(errors))
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -30,9 +30,9 @@ ANSIBLE_METADATA = {
DOCUMENTATION = """
---
module: iparole
short description: Manage FreeIPA role
description: Manage FreeIPA role
module: ipaservice
short description: Manage FreeIPA service
description: Manage FreeIPA service
options:
ipaadmin_principal:
description: The admin principal.
@@ -66,7 +66,7 @@ options:
description: List of services.
required: false
action:
description: Work on role or member level.
description: Work on service or member level.
choices: ["role", "member"]
default: role
required: false

View File

@@ -1,323 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2020 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/>.
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
module: ipaselfservice
short description: Manage FreeIPA selfservices
description: Manage FreeIPA selfservices and selfservice attributes
options:
ipaadmin_principal:
description: The admin principal.
default: admin
ipaadmin_password:
description: The admin password.
required: false
name:
description: The list of selfservice name strings.
required: true
aliases: ["aciname"]
permission:
description: Permissions to grant (read, write). Default is write.
required: false
aliases: ["permissions"]
attribute:
description: Attribute list to which the selfservice applies
required: false
aliases: ["attrs"]
action:
description: Work on selfservice or member level.
choices: ["selfservice", "member"]
default: selfservice
required: false
state:
description: The state to ensure.
choices: ["present", "absent"]
default: present
required: true
"""
EXAMPLES = """
# Ensure selfservice "Users can manage their own name details" is present
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
permission: read
attribute:
- title
- initials
# Ensure selfservice "Users can manage their own name details" member
# attribute departmentnumber is present
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
attribute:
- initials
action: member
# Ensure selfservice "Users can manage their own name details" member
# attributes employeetype and employeenumber are present
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
attribute:
- title
- initials
action: member
state: absent
# Ensure selfservice "Users can manage their own name details" is absent
- ipaselfservice:
ipaadmin_password: SomeADMINpassword
name: "Users can manage their own name details"
state: absent
"""
RETURN = """
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ansible_freeipa_module import \
temp_kinit, temp_kdestroy, valid_creds, api_connect, api_command, \
compare_args_ipa, module_params_get
import six
if six.PY3:
unicode = str
def find_selfservice(module, name):
"""Find if a selfservice with the given name already exist."""
try:
_result = api_command(module, "selfservice_show", name, {"all": True})
except Exception: # pylint: disable=broad-except
# An exception is raised if selfservice name is not found.
return None
else:
return _result["result"]
def gen_args(permission, attribute):
_args = {}
if permission is not None:
_args["permissions"] = permission
if attribute is not None:
_args["attrs"] = attribute
return _args
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
name=dict(type="list", aliases=["aciname"], default=None,
required=True),
# present
permission=dict(required=False, type='list',
aliases=["permissions"], default=None),
attribute=dict(required=False, type='list', aliases=["attrs"],
default=None),
action=dict(type="str", default="selfservice",
choices=["member", "selfservice"]),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
),
supports_check_mode=True,
)
ansible_module._ansible_debug = True
# Get parameters
# general
ipaadmin_principal = module_params_get(ansible_module,
"ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
names = module_params_get(ansible_module, "name")
# present
permission = module_params_get(ansible_module, "permission")
attribute = module_params_get(ansible_module, "attribute")
action = module_params_get(ansible_module, "action")
# state
state = module_params_get(ansible_module, "state")
# Check parameters
if state == "present":
if len(names) != 1:
ansible_module.fail_json(
msg="Only one selfservice be added at a time.")
if action == "member":
invalid = ["permission"]
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s' and state '%s'" % (x, action, state))
if state == "absent":
if len(names) < 1:
ansible_module.fail_json(msg="No name given.")
invalid = ["permission"]
if action == "selfservice":
invalid.append("attribute")
for x in invalid:
if vars()[x] is not None:
ansible_module.fail_json(
msg="Argument '%s' can not be used with action "
"'%s' and state '%s'" % (x, action, state))
if permission is not None:
perm = [p for p in permission if p not in ("read", "write")]
if perm:
ansible_module.fail_json(msg="Invalid permission '%s'" % perm)
if len(set(permission)) != len(permission):
ansible_module.fail_json(
msg="Invalid permission '%s', items are not unique" %
repr(permission))
if attribute is not None:
if len(set(attribute)) != len(attribute):
ansible_module.fail_json(
msg="Invalid attribute '%s', items are not unique" %
repr(attribute))
# Init
changed = False
exit_args = {}
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
ipaadmin_password)
api_connect()
commands = []
for name in names:
# Make sure selfservice exists
res_find = find_selfservice(ansible_module, name)
# Create command
if state == "present":
# Generate args
args = gen_args(permission, attribute)
if action == "selfservice":
# Found the selfservice
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):
commands.append([name, "selfservice_mod", args])
else:
commands.append([name, "selfservice_add", args])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No selfservice '%s'" % name)
if attribute is None:
ansible_module.fail_json(msg="No attributes given")
# New attribute list (add given ones to find result)
# Make list with unique entries
attrs = list(set(list(res_find["attrs"]) + attribute))
if len(attrs) > len(res_find["attrs"]):
commands.append([name, "selfservice_mod",
{"attrs": attrs}])
elif state == "absent":
if action == "selfservice":
if res_find is not None:
commands.append([name, "selfservice_del", {}])
elif action == "member":
if res_find is None:
ansible_module.fail_json(
msg="No selfservice '%s'" % name)
if attribute is None:
ansible_module.fail_json(msg="No attributes given")
# New attribute list (remove given ones from find result)
# Make list with unique entries
attrs = list(set(res_find["attrs"]) - set(attribute))
if len(attrs) < 1:
ansible_module.fail_json(
msg="At minimum one attribute is needed.")
# Entries New number of attributes is smaller
if len(attrs) < len(res_find["attrs"]):
commands.append([name, "selfservice_mod",
{"attrs": attrs}])
else:
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
for name, command, args in commands:
try:
result = api_command(ansible_module, command, name,
args)
if "completed" in result:
if result["completed"] > 0:
changed = True
else:
changed = True
except Exception as e:
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
str(e)))
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -460,7 +460,7 @@ def main():
allow_retrieve_keytab_group = module_params_get(
ansible_module, "allow_retrieve_keytab_group")
allow_retrieve_keytab_host = module_params_get(
ansible_module, "allow_retrieve_keytab_host")
ansible_module, "allow_create_keytab_host")
allow_retrieve_keytab_hostgroup = module_params_get(
ansible_module, "allow_retrieve_keytab_hostgroup")
delete_continue = module_params_get(ansible_module, "delete_continue")
@@ -727,7 +727,7 @@ def main():
# Allow retrieve keytab
if len(allow_retrieve_keytab_user_add) > 0 or \
len(allow_retrieve_keytab_group_add) > 0 or \
len(allow_retrieve_keytab_host_add) > 0 or \
len(allow_retrieve_keytab_hostgroup_add) > 0 or \
len(allow_retrieve_keytab_hostgroup_add) > 0:
commands.append(
[name, "service_allow_retrieve_keytab",

View File

@@ -1,274 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Authors:
# Rob Verduijn <rob.verduijn@gmail.com>
#
# Copyright (C) 2019 By Rob Verduijn
# 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 ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, module_params_get
from ansible.module_utils.basic import AnsibleModule
ANSIBLE_METADATA = {'metadata_version': '1.1',
'supported_by': 'community',
'status': ['preview'],
}
DOCUMENTATION = """
---
module: ipatrust
short_description: Manage FreeIPA Domain Trusts.
description: Manage FreeIPA Domain Trusts.
options:
realm:
description:
- Realm name
required: true
trust_type:
description:
- Trust type (ad for Active Directory, default)
default: ad
required: true
admin:
description:
- Active Directory domain administrator
required: false
password:
description:
- Active Directory domain administrator's password
required: false
server:
description:
- Domain controller for the Active Directory domain (optional)
required: false
trust_secret:
description:
- Shared secret for the trust
required: false
base_id:
description:
- First Posix ID of the range reserved for the trusted domain
required: false
range_size:
description:
- Size of the ID range reserved for the trusted domain
range_type:
description:
- Type of trusted domain ID range, one of ipa-ad-trust, ipa-ad-trust-posix
default: ipa-ad-trust
required: false
two_way:
description:
- Establish bi-directional trust. By default trust is inbound one-way only.
default: false
required: false
choices: ["true", "false"]
external:
description:
- Establish external trust to a domain in another forest.
- The trust is not transitive beyond the domain.
default: false
required: false
choices: ["true", "false"]
state:
description: State to ensure
default: present
required: true
choices: ["present", "absent"]
author:
- Rob Verduijn
"""
EXAMPLES = """
# add ad-trust
- ipatrust:
realm: ad.example.test
trust_type: ad
admin: Administrator
password: Welcome2020!
state: present
# delete ad-trust
- ipatrust:
realm: ad.example.test
state: absent
"""
RETURN = """
"""
def find_trust(module, realm):
_args = {
"all": True,
"cn": realm,
}
_result = api_command(module, "trust_find", realm, _args)
if len(_result["result"]) > 1:
module.fail_json(msg="There is more than one realm '%s'" % (realm))
elif len(_result["result"]) == 1:
return _result["result"][0]
else:
return None
def del_trust(module, realm):
_args = {}
_result = api_command(module, "trust_del", realm, _args)
if len(_result["result"]["failed"]) > 0:
module.fail_json(
msg="Trust deletion has failed for '%s'" % (realm))
else:
return None
def add_trust(module, realm, args):
_args = args
_result = api_command(module, "trust_add", realm, _args)
if "cn" not in _result["result"]:
module.fail_json(
msg="Trust add has failed for '%s'" % (realm))
else:
return None
def gen_args(trust_type, admin, password, server, trust_secret, base_id,
range_size, range_type, two_way, external):
_args = {}
if trust_type is not None:
_args["trust_type"] = trust_type
if admin is not None:
_args["realm_admin"] = admin
if password is not None:
_args["realm_passwd"] = password
if server is not None:
_args["realm_server"] = server
if trust_secret is not None:
_args["trust_secret"] = trust_secret
if base_id is not None:
_args["base_id"] = base_id
if range_size is not None:
_args["range_size"] = range_size
if two_way is not None:
_args["bidirectional"] = two_way
if external is not None:
_args["external"] = external
return _args
def main():
ansible_module = AnsibleModule(
argument_spec=dict(
# general
ipaadmin_principal=dict(type="str", default="admin"),
ipaadmin_password=dict(type="str", required=False, no_log=True),
realm=dict(type="str", default=None, required=True),
# state
state=dict(type="str", default="present",
choices=["present", "absent"]),
# present
trust_type=dict(type="str", default="ad", required=False),
admin=dict(type="str", default=None, required=False),
password=dict(type="str", default=None,
required=False, no_log=True),
server=dict(type="str", default=None, required=False),
trust_secret=dict(type="str", default=None,
required=False, no_log=True),
base_id=dict(type="int", default=None, required=False),
range_size=dict(type="int", default=200000, required=False),
range_type=dict(type="str", default="ipa-ad-trust",
required=False, choices=["ipa-ad-trust-posix",
"ipa-ad-trust"]),
two_way=dict(type="bool", default=False, required=False),
external=dict(type="bool", default=False, required=False),
),
mutually_exclusive=[["trust_secret", "admin"]],
required_together=[["admin", "password"]],
supports_check_mode=True
)
ansible_module._ansible_debug = True
# general
ipaadmin_principal = module_params_get(
ansible_module, "ipaadmin_principal")
ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
realm = module_params_get(ansible_module, "realm")
# state
state = module_params_get(ansible_module, "state")
# trust
trust_type = module_params_get(ansible_module, "trust_type")
admin = module_params_get(ansible_module, "admin")
password = module_params_get(ansible_module, "password")
server = module_params_get(ansible_module, "server")
trust_secret = module_params_get(ansible_module, "trust_secret")
base_id = module_params_get(ansible_module, "base_id")
range_size = module_params_get(ansible_module, "range_size")
range_type = module_params_get(ansible_module, "range_type")
two_way = module_params_get(ansible_module, "two_way")
external = module_params_get(ansible_module, "external")
changed = False
exit_args = {}
ccache_dir = None
ccache_name = None
try:
if not valid_creds(ansible_module, ipaadmin_principal):
ccache_dir, ccache_name = temp_kinit(
ipaadmin_principal, ipaadmin_password)
api_connect()
res_find = find_trust(ansible_module, realm)
if state == "absent":
if res_find is not None:
del_trust(ansible_module, realm)
changed = True
elif res_find is None:
if admin is None and trust_secret is None:
ansible_module.fail_json(
msg="one of admin or trust_secret is required when state "
"is present")
else:
args = gen_args(trust_type, admin, password, server,
trust_secret, base_id, range_size, range_type,
two_way, external)
add_trust(ansible_module, realm, args)
changed = True
except Exception as e:
ansible_module.fail_json(msg=str(e))
finally:
temp_kdestroy(ccache_dir, ccache_name)
# Done
ansible_module.exit_json(changed=changed, **exit_args)
if __name__ == "__main__":
main()

View File

@@ -243,7 +243,7 @@ EXAMPLES = """
state: retrieved
register: result
- debug:
msg: "{{ result.vault.data }}"
msg: "{{ result.data }}"
# Change password of a symmetric vault
- ipavault:
@@ -267,7 +267,7 @@ EXAMPLES = """
username: user01
description: An asymmetric vault
vault_type: asymmetric
public_key: |
public_key:
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTR
HTkFEQ0JpUUtCZ1FDdGFudjRkK3ptSTZ0T3ova1RXdGowY3AxRAowUENoYy8vR0pJMTUzTi
9CN3UrN0h3SXlRVlZoNUlXZG1UcCtkWXYzd09yeVpPbzYvbHN5eFJaZ2pZRDRwQ3VGCjlxM
@@ -303,15 +303,10 @@ EXAMPLES = """
"""
RETURN = """
vault:
description: Vault dict with archived data.
returned: If state is `retrieved`.
type: dict
options:
data:
description: The vault data.
returned: always
type: string
user:
description: The vault data.
returned: If state is retrieved.
type: string
"""
import os
@@ -494,10 +489,8 @@ def check_encryption_params(module, state, action, vault_type, salt,
new_password, new_password_file, res_find):
vault_type_invalid = []
if vault_type is None and res_find is not None:
if res_find is not None:
vault_type = res_find['ipavaulttype']
if isinstance(vault_type, (tuple, list)):
vault_type = vault_type[0]
if vault_type == "standard":
vault_type_invalid = ['public_key', 'public_key_file', 'password',
@@ -517,16 +510,6 @@ def check_encryption_params(module, state, action, vault_type, salt,
module.fail_json(
msg="Cannot modify password of inexistent vault.")
if (
salt is not None
and not(
any([password, password_file])
and any([new_password, new_password_file])
)
):
module.fail_json(
msg="Vault `salt` can only change when changing the password.")
if vault_type == "asymmetric":
vault_type_invalid = [
'password', 'password_file', 'new_password', 'new_password_file'
@@ -756,7 +739,7 @@ def main():
res_vault_type = res_find.get('ipavaulttype')[0]
args['ipavaulttype'] = vault_type = res_vault_type
else:
args['ipavaulttype'] = vault_type = u"symmetric"
args['ipavaulttype'] = vault_type = "symmetric"
# Create command
if state == "present":
@@ -778,12 +761,7 @@ def main():
commands.append([name, "vault_mod_internal", args])
else:
if vault_type == 'symmetric' \
and 'ipavaultsalt' not in args:
args['ipavaultsalt'] = os.urandom(32)
commands.append([name, "vault_add_internal", args])
if vault_type != 'standard' and vault_data is None:
vault_data = ''
@@ -841,6 +819,14 @@ def main():
commands.append(
[name, 'vault_remove_owner', owner_del_args])
if vault_type == 'symmetric' \
and 'ipavaultsalt' not in args:
args['ipavaultsalt'] = os.urandom(32)
if vault_type == 'symmetric' \
and 'ipavaultsalt' not in args:
args['ipavaultsalt'] = os.urandom(32)
elif action in "member":
# Add users and groups
if any([users, groups, services]):
@@ -923,12 +909,12 @@ def main():
elif command == 'vault_retrieve':
if 'result' not in result:
raise Exception("No result obtained.")
if "data" in result["result"]:
data_return = exit_args.setdefault("vault", {})
data_return["data"] = result["result"]["data"]
if 'data' in result['result']:
exit_args['data'] = result['result']['data']
elif 'vault_data' in result['result']:
exit_args['data'] = result['result']['vault_data']
else:
if not datafile_out:
raise Exception("No data retrieved.")
raise Exception("No data retrieved.")
changed = False
else:
if "completed" in result:

View File

@@ -1,6 +1,2 @@
[pytest]
python_files = test_*.py
junit_family = xunit1
markers=
source_order: mark test as order bound
playbook: playbook tests

View File

@@ -1,2 +0,0 @@
-r requirements-tests.txt
ipdb

View File

@@ -1,7 +0,0 @@
-r requirements.txt
pytest>=2.7
pytest-sourceorder>=0.5
pytest-split-tests>=1.0.3
testinfra>=5.0
jmespath>=0.9 # needed for the `json_query` filter
pyyaml>=3

View File

@@ -0,0 +1,9 @@
#!/usr/bin/python3
# Test ipaclient python3 binding
from ipaclient.install.client import SECURE_PATH # noqa: F401
# Check ipapython version to be >= 4.6
from ipapython.version import NUM_VERSION, VERSION
if NUM_VERSION < 40600:
raise Exception("ipa %s not usable with python3" % VERSION)

View File

@@ -37,12 +37,12 @@ description:
options:
domain:
description: Primary DNS domain of the IPA deployment
required: yes
required: no
firefox_dir:
description:
Specify directory where Firefox is installed (for example
'/usr/lib/firefox')
required: no
required: yes
author:
- Thomas Woerner
'''

View File

@@ -107,12 +107,9 @@ if NUM_VERSION >= 40400:
from ipalib import api, errors, x509
from ipalib import constants
try:
from ipalib import sysrestore
from ipalib.install import sysrestore
except ImportError:
try:
from ipalib.install import sysrestore
except ImportError:
from ipapython import sysrestore
from ipapython import sysrestore
try:
from ipalib.install import certmonger
except ImportError:

View File

@@ -7,6 +7,9 @@
state: present
when: ipaclient_install_packages | bool
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
- name: Install - Set ipaclient_servers
set_fact:
ipaclient_servers: "{{ groups['ipaservers'] | list }}"
@@ -110,6 +113,10 @@
fail: msg="Keytab or password is required for getting otp"
when: ipaadmin_keytab is undefined and ipaadmin_password is undefined
#- name: Install - Include Python2/3 import test
# import_tasks: "{{ role_path }}/tasks/python_2_3_test.yml"
# delegate_to: "{{ result_ipaclient_test.servers[0] }}"
- name: Install - Get One-Time Password for client enrollment
no_log: yes
ipaclient_get_otp:
@@ -343,7 +350,6 @@
- name: Install - Configure firefox
ipaclient_setup_firefox:
firefox_dir: "{{ ipaclient_firefox_dir | default(omit) }}"
domain: "{{ result_ipaclient_test.domain }}"
when: ipaclient_configure_firefox | bool
- name: Install - Configure NIS

View File

@@ -0,0 +1,18 @@
---
- block:
- name: Verify Python3 import
script: py3test.py
register: result_py3test
failed_when: False
changed_when: False
check_mode: no
- name: Set python interpreter to 3
set_fact:
ansible_python_interpreter: "/usr/bin/python3"
when: result_py3test.rc == 0
- name: Set python interpreter to 2
set_fact:
ansible_python_interpreter: "/usr/bin/python2"
when: result_py3test.failed or result_py3test.rc != 0

Some files were not shown because too many files have changed in this diff Show More