diff --git a/README-host.md b/README-host.md
index 7ff7afa7..77ca098d 100644
--- a/README-host.md
+++ b/README-host.md
@@ -41,7 +41,7 @@ ipaserver.test.local
```
-Example playbook to add hosts:
+Example playbook to ensure host presence:
```yaml
---
@@ -67,7 +67,7 @@ Example playbook to add hosts:
```
-Example playbook to create host without DNS:
+Example playbook to ensure host presence without DNS:
```yaml
---
@@ -85,28 +85,118 @@ Example playbook to create host without DNS:
```
-Example playbook to initiate the generation of a random password to be used in bulk enrollment:
+Example playbook to ensure host presence with a random password:
```yaml
---
-- name: Playbook to handle hosts
+- name: Ensure host with random password
hosts: ipaserver
become: true
tasks:
- # Generate a random password for bulk enrollment
- - ipahost:
+ - name: Host host01.example.com present with random password
+ ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
- description: Example host
- ip_address: 192.168.0.123
random: yes
+ force: yes
register: ipahost
- name: Print generated random password
debug:
var: ipahost.host.randompassword
```
+Please remember that the `force` tag will also force the generation of a new random password even if the host already exists and if `update_password` is limited to `on_create`.
+
+
+Example playbook to ensure presence of several hosts with a random password:
+
+```yaml
+---
+- name: Ensure hosts with random password
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.example.com and host01.example.com present with random passwords
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.example.com
+ random: yes
+ force: yes
+ - name: host02.example.com
+ random: yes
+ force: yes
+ register: ipahost
+
+ - name: Print generated random password for host01.example.com
+ debug:
+ var: ipahost.host["host01.example.com"].randompassword
+
+ - name: Print generated random password for host02.example.com
+ debug:
+ var: ipahost.host["host02.example.com"].randompassword
+```
+Please remember that the `force` tag will also force the generation of a new random password even if the host alreay exists and if `update_password` is limited to `on_create`.
+
+
+Example playbook to ensure presence of host member principal:
+
+```yaml
+---
+- name: Host present with principal
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com present with principals host/testhost01.example.com and host/myhost01.example.com
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ principal:
+ - host/testhost01.example.com
+ - host/myhost01.example.com
+ action: member
+```
+
+
+Example playbook to ensure presence of host member certificate:
+
+```yaml
+- name: Host present with certificate
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com present with certificate
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAg...
+ action: member
+```
+
+
+Example playbook to ensure presence of member managedby_host for serveral hosts:
+
+```yaml
+---
+- name: Host present with managedby_host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ - name: host02.exmaple.com
+ managedby_host: server.exmaple.com
+ action: member
+```
Example playbook to disable a host:
@@ -155,7 +245,20 @@ 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` \| `fqdn` | The list of host name strings. | yes
+`name` \| `fqdn` | The list of host name strings. `name` with *host variables* or `hosts` containing *host variables* need to be used. | no
+**Host variables** | Only used with `name` variable in the first level. | no
+`hosts` | The list of host dicts. Each `hosts` dict entry can contain **host variables**.
There is one required option in the `hosts` dict:| no
+ | `name` \| `fqdn` - The user name string of the entry. | yes
+ | **Host variables** | no
+`update_password` | Set password for a host in present state only on creation or always. It can be one of `always` or `on_create` and defaults to `always`. | no
+`action` | Work on host or member level. It can be on of `member` or `host` and defaults to `host`. | no
+`state` | The state to ensure. It can be one of `present`, `absent` or `disabled`, default: `present`. | yes
+
+
+**Host Variables:**
+
+Variable | Description | Required
+-------- | ----------- | --------
`description` | The host description. | no
`locality` | Host locality (e.g. "Baltimore, MD"). | no
`location` \| `ns_host_location` | Host location (e.g. "Lab 2"). | no
@@ -163,13 +266,28 @@ Variable | Description | Required
`os` \| `ns_os_version` | Host operating system and version (e.g. "Fedora 9"). | no
`password` \| `user_password` \| `userpassword` | Password used in bulk enrollment. | no
`random` \| `random_password` | Initiate the generation of a random password to be used in bulk enrollment. | no
+`certificate` \| `usercertificate` | List of base-64 encoded host certificates | no
+`managedby` \| `principalname` \| `krbprincipalname` | List of hosts that can manage this host | no
+`principal` \| `principalname` \| `krbprincipalname` | List of principal aliases for this host | no
+`allow_create_keytab_user` \| `ipaallowedtoperform_write_keys_user` | Users allowed to create a keytab of this host.
Options: | no
+`allow_create_keytab_group` \| `ipaallowedtoperform_write_keys_group` | Groups allowed to create a keytab of this host.
Options: | no
+`allow_create_keytab_host` \| `ipaallowedtoperform_write_keys_host` | Hosts allowed to create a keytab of this host.
Options: | no
+`allow_create_keytab_hostgroup` \| `ipaallowedtoperform_write_keys_hostgroup` | Host groups allowed to create a keytab of this host.
Options: | no
+`allow_retrieve_keytab_user` \| `ipaallowedtoperform_read_keys_user` | Users allowed to retieve a keytab of this host.
Options: | no
+`allow_retrieve_keytab_group` \| `ipaallowedtoperform_read_keys_group` | Groups allowed to retieve a keytab of this host.
Options: | no
+`allow_retrieve_keytab_host` \| `ipaallowedtoperform_read_keys_host` | Hosts allowed to retieve a keytab of this host.
Options: | no
+`allow_retrieve_keytab_hostgroup` \| `ipaallowedtoperform_read_keys_hostgroup` | Host groups allowed to retieve a keytab of this host.
Options: | no
`mac_address` \| `macaddress` | List of hardware MAC addresses. | no
+`sshpubkey` \| `ipasshpubkey` | List of SSH public keys | no
+`userclass` \| `class` | Host category (semantics placed on this attribute are for local interpretation) | no
+`auth_ind` \| `krbprincipalauthind` | Defines a whitelist for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Other values may be used for custom configurations. choices: ["radius", "otp", "pkinit", "hardened"] | no
+`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service (bool) | no
+`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service (bool) | no
+`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client (bool) | no
`force` | Force host name even if not in DNS. | no
`reverse` | Reverse DNS detection. | no
`ip_address` \| `ipaddress` | The host IP address. | no
`update_dns` | Update DNS entries. | no
-`update_password` | Set password for a host in present state only on creation or always. It can be one of `always` or `on_create` and defaults to `always`. | no
-`state` | The state to ensure. It can be one of `present`, `absent` or `disabled`, default: `present`. | yes
Return Values
diff --git a/playbooks/host/add-host.yml b/playbooks/host/add-host.yml
deleted file mode 100644
index 61b8a958..00000000
--- a/playbooks/host/add-host.yml
+++ /dev/null
@@ -1,20 +0,0 @@
----
-- name: Playbook to handle hosts
- hosts: ipaserver
- become: true
-
- tasks:
- - name: Ensure host is present
- ipahost:
- ipaadmin_password: MyPassword123
- name: host01.example.com
- description: Example host
- ip_address: 192.168.0.123
- locality: Lab
- ns_host_location: Lab
- ns_os_version: CentOS 7
- ns_hardware_platform: Lenovo T61
- mac_address:
- - "08:00:27:E3:B1:2D"
- - "52:54:00:BD:97:1E"
- state: present
diff --git a/playbooks/host/add-host.yml b/playbooks/host/add-host.yml
new file mode 120000
index 00000000..6d5bc9a9
--- /dev/null
+++ b/playbooks/host/add-host.yml
@@ -0,0 +1 @@
+host-present.yml
\ No newline at end of file
diff --git a/playbooks/host/host-member-allow_create_keytab-absent.yml b/playbooks/host/host-member-allow_create_keytab-absent.yml
new file mode 100644
index 00000000..55e3110d
--- /dev/null
+++ b/playbooks/host/host-member-allow_create_keytab-absent.yml
@@ -0,0 +1,24 @@
+---
+- name: Host member allow_create_keytab absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com members allow_create_keytab absent for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_create_keytab_user:
+ - user01
+ - user02
+ allow_create_keytab_group:
+ - group01
+ - group02
+ allow_create_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_create_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ action: member
+ state: absent
diff --git a/playbooks/host/host-member-allow_create_keytab-present.yml b/playbooks/host/host-member-allow_create_keytab-present.yml
new file mode 100644
index 00000000..f5865497
--- /dev/null
+++ b/playbooks/host/host-member-allow_create_keytab-present.yml
@@ -0,0 +1,23 @@
+---
+- name: Host member allow_create_keytab present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com members allow_create_keytab present for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_create_keytab_user:
+ - user01
+ - user02
+ allow_create_keytab_group:
+ - group01
+ - group02
+ allow_create_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_create_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ action: member
diff --git a/playbooks/host/host-member-allow_retrieve_keytab-absent.yml b/playbooks/host/host-member-allow_retrieve_keytab-absent.yml
new file mode 100644
index 00000000..b8830f60
--- /dev/null
+++ b/playbooks/host/host-member-allow_retrieve_keytab-absent.yml
@@ -0,0 +1,24 @@
+---
+- name: Host member allow_retrieve_keytab absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com members allow_retrieve_keytab absent for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_retrieve_keytab_user:
+ - user01
+ - user02
+ allow_retrieve_keytab_group:
+ - group01
+ - group02
+ allow_retrieve_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ action: member
+ state: absent
diff --git a/playbooks/host/host-member-allow_retrieve_keytab-present.yml b/playbooks/host/host-member-allow_retrieve_keytab-present.yml
new file mode 100644
index 00000000..fde116cc
--- /dev/null
+++ b/playbooks/host/host-member-allow_retrieve_keytab-present.yml
@@ -0,0 +1,23 @@
+---
+- name: Host member allow_retrieve_keytab present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com members allow_retrieve_keytab present for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_retrieve_keytab_user:
+ - user01
+ - user02
+ allow_retrieve_keytab_group:
+ - group01
+ - group02
+ allow_retrieve_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ action: member
diff --git a/playbooks/host/host-member-certificate-absent.yml b/playbooks/host/host-member-certificate-absent.yml
new file mode 100644
index 00000000..918951f8
--- /dev/null
+++ b/playbooks/host/host-member-certificate-absent.yml
@@ -0,0 +1,13 @@
+- name: Host member certificate absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com member certificate absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ action: member
+ state: absent
diff --git a/playbooks/host/host-member-certificate-present.yml b/playbooks/host/host-member-certificate-present.yml
new file mode 100644
index 00000000..066ae0a9
--- /dev/null
+++ b/playbooks/host/host-member-certificate-present.yml
@@ -0,0 +1,12 @@
+- name: Host member certificate present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com member certificate present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ action: member
diff --git a/playbooks/host/host-member-managedby_host-absent.yml b/playbooks/host/host-member-managedby_host-absent.yml
new file mode 100644
index 00000000..f899a52f
--- /dev/null
+++ b/playbooks/host/host-member-managedby_host-absent.yml
@@ -0,0 +1,12 @@
+---
+- name: Host member managedby_host absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ action: member
+ state: absent
diff --git a/playbooks/host/host-member-managedby_host-present.yml b/playbooks/host/host-member-managedby_host-present.yml
new file mode 100644
index 00000000..073d81ad
--- /dev/null
+++ b/playbooks/host/host-member-managedby_host-present.yml
@@ -0,0 +1,11 @@
+---
+- name: Host member managedby_host present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ action: member
diff --git a/playbooks/host/host-member-principal-absent.yml b/playbooks/host/host-member-principal-absent.yml
new file mode 100644
index 00000000..b2c3a8d8
--- /dev/null
+++ b/playbooks/host/host-member-principal-absent.yml
@@ -0,0 +1,15 @@
+---
+- name: Host member principal absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com principals host/testhost01.example.com and host/myhost01.example.com absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ principal:
+ - host/testhost01.example.com
+ - host/myhost01.example.com
+ action: member
+ state: absent
diff --git a/playbooks/host/host-member-principal-present.yml b/playbooks/host/host-member-principal-present.yml
new file mode 100644
index 00000000..b56fd591
--- /dev/null
+++ b/playbooks/host/host-member-principal-present.yml
@@ -0,0 +1,14 @@
+---
+- name: Host member principal present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com principals host/testhost01.example.com and host/myhost01.example.com present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ principal:
+ - host/testhost01.example.com
+ - host/myhost01.example.com
+ action: member
diff --git a/playbooks/host/host-present-with-allow_create_keytab.yml b/playbooks/host/host-present-with-allow_create_keytab.yml
new file mode 100644
index 00000000..f7b9c6f4
--- /dev/null
+++ b/playbooks/host/host-present-with-allow_create_keytab.yml
@@ -0,0 +1,23 @@
+---
+- name: Host present with allow_create_keytab
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com present with allow_create_keytab for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_create_keytab_user:
+ - user01
+ - user02
+ allow_create_keytab_group:
+ - group01
+ - group02
+ allow_create_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_create_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ ip_address: 192.168.0.123
diff --git a/playbooks/host/host-present-with-allow_retrieve_keytab.yml b/playbooks/host/host-present-with-allow_retrieve_keytab.yml
new file mode 100644
index 00000000..5a9f3af5
--- /dev/null
+++ b/playbooks/host/host-present-with-allow_retrieve_keytab.yml
@@ -0,0 +1,23 @@
+---
+- name: Host present with allow_retrieve_keytab
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host1.example.com present with allow_retrieve_keytab for users, groups, hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ allow_retrieve_keytab_user:
+ - user01
+ - user02
+ allow_retrieve_keytab_group:
+ - group01
+ - group02
+ allow_retrieve_keytab_host:
+ - host02.exmaple.com
+ - host03.exmaple.com
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup01
+ - hostgroup02
+ ip_address: 192.168.0.123
diff --git a/playbooks/host/host-present-with-certificate.yml b/playbooks/host/host-present-with-certificate.yml
new file mode 100644
index 00000000..f5da46d7
--- /dev/null
+++ b/playbooks/host/host-present-with-certificate.yml
@@ -0,0 +1,12 @@
+- name: Host present with certificate
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com present with certificate
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ force: yes
diff --git a/playbooks/host/host-present-with-managedby_host.yml b/playbooks/host/host-present-with-managedby_host.yml
new file mode 100644
index 00000000..b85f5e60
--- /dev/null
+++ b/playbooks/host/host-present-with-managedby_host.yml
@@ -0,0 +1,11 @@
+---
+- name: Host present with managedby_host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ force: yes
diff --git a/playbooks/host/host-present-with-principal.yml b/playbooks/host/host-present-with-principal.yml
new file mode 100644
index 00000000..5b8ad4ee
--- /dev/null
+++ b/playbooks/host/host-present-with-principal.yml
@@ -0,0 +1,14 @@
+---
+- name: Host present with principal
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com present with principals host/testhost01.example.com and host/myhost01.example.com
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ principal:
+ - host/testhost01.example.com
+ - host/myhost01.example.com
+ force: yes
diff --git a/playbooks/host/host-present-with-randompassword.yml b/playbooks/host/host-present-with-randompassword.yml
new file mode 100644
index 00000000..9063c480
--- /dev/null
+++ b/playbooks/host/host-present-with-randompassword.yml
@@ -0,0 +1,17 @@
+---
+- name: Host present with random password
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Host host01.example.com present with random password
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ random: yes
+ force: yes
+ register: ipahost
+
+ - name: Print generated random password
+ debug:
+ var: ipahost.host.randompassword
diff --git a/playbooks/host/host-present.yml b/playbooks/host/host-present.yml
new file mode 100644
index 00000000..d40c1ecf
--- /dev/null
+++ b/playbooks/host/host-present.yml
@@ -0,0 +1,20 @@
+---
+- name: Host present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Ensure host is present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: host01.example.com
+ description: Example host
+ ip_address: 192.168.0.123
+ locality: Lab
+ ns_host_location: Lab
+ ns_os_version: CentOS 7
+ ns_hardware_platform: Lenovo T61
+ mac_address:
+ - "08:00:27:E3:B1:2D"
+ - "52:54:00:BD:97:1E"
+ state: present
diff --git a/playbooks/host/hosts-member-certificate-absent.yml b/playbooks/host/hosts-member-certificate-absent.yml
new file mode 100644
index 00000000..bb2d5b03
--- /dev/null
+++ b/playbooks/host/hosts-member-certificate-absent.yml
@@ -0,0 +1,18 @@
+---
+- name: Hosts member certificate absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.example.com and host01.exmaple.com member certificate absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ - name: host02.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ action: member
+ state: absent
diff --git a/playbooks/host/hosts-member-certificate-present.yml b/playbooks/host/hosts-member-certificate-present.yml
new file mode 100644
index 00000000..c402ef4a
--- /dev/null
+++ b/playbooks/host/hosts-member-certificate-present.yml
@@ -0,0 +1,17 @@
+---
+- name: Hosts member certificate present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.example.com and host01.exmaple.com member certificate present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ - name: host02.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ action: member
diff --git a/playbooks/host/hosts-member-managedby_host-absent.yml b/playbooks/host/hosts-member-managedby_host-absent.yml
new file mode 100644
index 00000000..9b584e51
--- /dev/null
+++ b/playbooks/host/hosts-member-managedby_host-absent.yml
@@ -0,0 +1,15 @@
+---
+- name: Hosts member managedby_host absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ - name: host02.exmaple.com
+ managedby_host: server.exmaple.com
+ action: member
+ state: absent
diff --git a/playbooks/host/hosts-member-managedby_host-present.yml b/playbooks/host/hosts-member-managedby_host-present.yml
new file mode 100644
index 00000000..f8d4e2b7
--- /dev/null
+++ b/playbooks/host/hosts-member-managedby_host-present.yml
@@ -0,0 +1,14 @@
+---
+- name: Hosts member managedby_host present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ - name: host02.exmaple.com
+ managedby_host: server.exmaple.com
+ action: member
diff --git a/playbooks/host/hosts-member-principal-absent.yml b/playbooks/host/hosts-member-principal-absent.yml
new file mode 100644
index 00000000..edd33521
--- /dev/null
+++ b/playbooks/host/hosts-member-principal-absent.yml
@@ -0,0 +1,18 @@
+---
+- name: Host member principal absent
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.exmaple.com and host02.exmaple.com member principals host/testhost0X.exmaple.com absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ principal:
+ - host/testhost01.exmaple.com
+ - name: host02.exmaple.com
+ principal:
+ - host/testhost02.exmaple.com
+ action: member
+ state: absent
diff --git a/playbooks/host/hosts-member-principal-present.yml b/playbooks/host/hosts-member-principal-present.yml
new file mode 100644
index 00000000..54c9a8f6
--- /dev/null
+++ b/playbooks/host/hosts-member-principal-present.yml
@@ -0,0 +1,17 @@
+---
+- name: Hosts member principal present
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.exmaple.com and host02.exmaple.com member principals host/testhost0X.exmaple.com present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ principal:
+ - host/testhost01.exmaple.com
+ - name: host02.exmaple.com
+ principal:
+ - host/testhost02.exmaple.com
+ action: member
diff --git a/playbooks/host/hosts-present-with-certificate.yml b/playbooks/host/hosts-present-with-certificate.yml
new file mode 100644
index 00000000..34e402f7
--- /dev/null
+++ b/playbooks/host/hosts-present-with-certificate.yml
@@ -0,0 +1,17 @@
+---
+- name: Hosts present with certificate
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.example.com and host01.exmaple.com present with certificate
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdxpOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsGLv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOsOblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMAvTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePKiNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyji8r3
+ - name: host02.example.com
+ certificate:
+ - MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVrID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFMHRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdotIWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbpFbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81tscJV
+ force: yes
diff --git a/playbooks/host/hosts-present-with-managedby_host.yml b/playbooks/host/hosts-present-with-managedby_host.yml
new file mode 100644
index 00000000..5f3546b6
--- /dev/null
+++ b/playbooks/host/hosts-present-with-managedby_host.yml
@@ -0,0 +1,15 @@
+---
+- name: Host present with managedby_host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.exmaple.com
+ managedby_host: server.exmaple.com
+ force: yes
+ - name: host02.exmaple.com
+ managedby_host: server.exmaple.com
+ force: yes
diff --git a/playbooks/host/hosts-present-with-randompasswords.yml b/playbooks/host/hosts-present-with-randompasswords.yml
new file mode 100644
index 00000000..f747ca31
--- /dev/null
+++ b/playbooks/host/hosts-present-with-randompasswords.yml
@@ -0,0 +1,26 @@
+---
+- name: Hosts present with random passwords
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Hosts host01.example.com and host01.example.com present with random passwords
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: host01.example.com
+ random: yes
+ force: yes
+ - name: host02.example.com
+ random: yes
+ force: yes
+ register: ipahost
+
+ - name: Print generated random password for host01.example.com
+ debug:
+ var: ipahost.host["host01.example.com"].randompassword
+
+ - name: Print generated random password for host02.example.com
+ debug:
+ var: ipahost.host["host02.example.com"].randompassword
+
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
index 7977a8ea..6a3e771e 100644
--- a/plugins/module_utils/ansible_freeipa_module.py
+++ b/plugins/module_utils/ansible_freeipa_module.py
@@ -38,6 +38,11 @@ from ipapython.ipautil import run
from ipaplatform.paths import paths
from ipalib.krb_utils import get_credentials_if_valid
from ansible.module_utils._text import to_text
+try:
+ from ipalib.x509 import Encoding
+except ImportError:
+ from cryptography.hazmat.primitives.serialization import Encoding
+import base64
import six
@@ -236,3 +241,28 @@ def module_params_get(module, name):
def api_get_realm():
return api.env.realm
+
+
+def gen_add_del_lists(user_list, res_list):
+ """
+ Generate the lists for the addition and removal of members using the
+ provided user and ipa settings
+ """
+ add_list = list(set(user_list or []) - set(res_list or []))
+ del_list = list(set(res_list or []) - set(user_list or []))
+
+ return add_list, del_list
+
+
+def encode_certificate(cert):
+ """
+ Encode a certificate using base64 with also taking FreeIPA and Python
+ versions into account
+ """
+ if isinstance(cert, str) or isinstance(cert, unicode):
+ encoded = base64.b64encode(cert)
+ else:
+ encoded = base64.b64encode(cert.public_bytes(Encoding.DER))
+ if not six.PY2:
+ encoded = encoded.decode('ascii')
+ return encoded
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
index 4a240bdb..ec5e1963 100644
--- a/plugins/modules/ipahost.py
+++ b/plugins/modules/ipahost.py
@@ -42,6 +42,145 @@ options:
description: The full qualified domain name.
aliases: ["fqdn"]
required: true
+
+ hosts:
+ description: The list of user host dicts
+ required: false
+ options:
+ name:
+ description: The host (internally uid).
+ aliases: ["fqdn"]
+ required: true
+ description:
+ description: The host description
+ required: false
+ locality:
+ description: Host locality (e.g. "Baltimore, MD")
+ required: false
+ location:
+ description: Host location (e.g. "Lab 2")
+ aliases: ["ns_host_location"]
+ required: false
+ platform:
+ description: Host hardware platform (e.g. "Lenovo T61")
+ aliases: ["ns_hardware_platform"]
+ required: false
+ os:
+ description: Host operating system and version (e.g. "Fedora 9")
+ aliases: ["ns_os_version"]
+ required: false
+ password:
+ description: Password used in bulk enrollment
+ aliases: ["user_password", "userpassword"]
+ required: false
+ random:
+ description:
+ Initiate the generation of a random password to be used in bulk
+ enrollment
+ aliases: ["random_password"]
+ required: false
+ certificate:
+ description: List of base-64 encoded host certificates
+ type: list
+ aliases: ["usercertificate"]
+ required: false
+ managedby_host:
+ description: List of hosts that can manage this host
+ type: list
+ aliases: ["principalname", "krbprincipalname"]
+ required: false
+ principal:
+ description: List of principal aliases for this host
+ type: list
+ aliases: ["principalname", "krbprincipalname"]
+ required: false
+ allow_create_keytab_user:
+ description: Users allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_user"]
+ required: false
+ allow_create_keytab_group:
+ description: Groups allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_group"]
+ required: false
+ allow_create_keytab_host:
+ description: Hosts allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_host"]
+ required: false
+ allow_create_keytab_hostgroup:
+ description: Hostgroups allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
+ required: false
+ allow_retrieve_keytab_user:
+ description: Users allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_user"]
+ required: false
+ allow_retrieve_keytab_group:
+ description: Groups allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_group"]
+ required: false
+ allow_retrieve_keytab_host:
+ description: Hosts allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_host"]
+ required: false
+ allow_retrieve_keytab_hostgroup:
+ description: Hostgroups allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
+ required: false
+ mac_address:
+ description: List of hardware MAC addresses.
+ type: list
+ aliases: ["macaddress"]
+ required: false
+ sshpubkey:
+ description: List of SSH public keys
+ type: list
+ aliases: ["ipasshpubkey"]
+ required: false
+ userclass:
+ description:
+ Host category (semantics placed on this attribute are for local
+ interpretation)
+ aliases: ["class"]
+ required: false
+ auth_ind:
+ description:
+ Defines a whitelist for Authentication Indicators. Use 'otp' to allow
+ OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA
+ authentications. Other values may be used for custom configurations.
+ type: list
+ aliases: ["krbprincipalauthind"]
+ choices: ["radius", "otp", "pkinit", "hardened"]
+ required: false
+ requires_pre_auth:
+ description: Pre-authentication is required for the service
+ type: bool
+ aliases: ["ipakrbrequirespreauth"]
+ required: false
+ ok_as_delegate:
+ description: Client credentials may be delegated to the service
+ type: bool
+ aliases: ["ipakrbokasdelegate"]
+ required: false
+ ok_to_auth_as_delegate:
+ description:
+ The service is allowed to authenticate on behalf of a client
+ type: bool
+ aliases: ["ipakrboktoauthasdelegate"]
+ required: false
+ force:
+ description: Force host name even if not in DNS
+ required: false
+ reverse:
+ description: Reverse DNS detection
+ default: true
+ required: false
+ ip_address:
+ description: The host IP address
+ aliases: ["ipaddress"]
+ required: false
+ update_dns:
+ description: Update DNS entries
+ required: false
description:
description: The host description
required: false
@@ -70,11 +209,93 @@ options:
enrollment
aliases: ["random_password"]
required: false
+ certificate:
+ description: List of base-64 encoded host certificates
+ type: list
+ aliases: ["usercertificate"]
+ required: false
+ managedby_host:
+ description: List of hosts that can manage this host
+ type: list
+ aliases: ["principalname", "krbprincipalname"]
+ required: false
+ principal:
+ description: List of principal aliases for this host
+ type: list
+ aliases: ["principalname", "krbprincipalname"]
+ required: false
+ allow_create_keytab_user:
+ description: Users allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_user"]
+ required: false
+ allow_create_keytab_group:
+ description: Groups allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_group"]
+ required: false
+ allow_create_keytab_host:
+ description: Hosts allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_host"]
+ required: false
+ allow_create_keytab_hostgroup:
+ description: Hostgroups allowed to create a keytab of this host
+ aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
+ required: false
+ allow_retrieve_keytab_user:
+ description: Users allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_user"]
+ required: false
+ allow_retrieve_keytab_group:
+ description: Groups allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_group"]
+ required: false
+ allow_retrieve_keytab_host:
+ description: Hosts allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_host"]
+ required: false
+ allow_retrieve_keytab_hostgroup:
+ description: Hostgroups allowed to retrieve a keytab of this host
+ aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
+ required: false
mac_address:
description: List of hardware MAC addresses.
type: list
aliases: ["macaddress"]
required: false
+ sshpubkey:
+ description: List of SSH public keys
+ type: list
+ aliases: ["ipasshpubkey"]
+ required: false
+ userclass:
+ description:
+ Host category (semantics placed on this attribute are for local
+ interpretation)
+ aliases: ["class"]
+ required: false
+ auth_ind:
+ description:
+ Defines a whitelist for Authentication Indicators. Use 'otp' to allow
+ OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA
+ authentications. Other values may be used for custom configurations.
+ type: list
+ aliases: ["krbprincipalauthind"]
+ choices: ["radius", "otp", "pkinit", "hardened"]
+ required: false
+ requires_pre_auth:
+ description: Pre-authentication is required for the service
+ type: bool
+ aliases: ["ipakrbrequirespreauth"]
+ required: false
+ ok_as_delegate:
+ description: Client credentials may be delegated to the service
+ type: bool
+ aliases: ["ipakrbokasdelegate"]
+ required: false
+ ok_to_auth_as_delegate:
+ description: The service is allowed to authenticate on behalf of a client
+ type: bool
+ aliases: ["ipakrboktoauthasdelegate"]
+ required: false
force:
description: Force host name even if not in DNS
required: false
@@ -94,6 +315,10 @@ options:
Set password for a host in present state only on creation or always
default: 'always'
choices: ["always", "on_create"]
+ action:
+ description: Work on host or member level
+ default: "host"
+ choices: ["member", "host"]
state:
description: State to ensure
default: present
@@ -170,7 +395,13 @@ host:
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
+ temp_kdestroy, valid_creds, api_connect, api_command, compare_args_ipa, \
+ module_params_get, gen_add_del_lists, encode_certificate, api_get_realm
+import six
+
+
+if six.PY3:
+ unicode = str
def find_host(module, name):
@@ -185,7 +416,12 @@ def find_host(module, name):
module.fail_json(
msg="There is more than one host '%s'" % (name))
elif len(_result["result"]) == 1:
- return _result["result"][0]
+ _res = _result["result"][0]
+ certs = _res.get("usercertificate")
+ if certs is not None:
+ _res["usercertificate"] = [encode_certificate(cert) for
+ cert in certs]
+ return _res
else:
return None
@@ -195,13 +431,15 @@ def show_host(module, name):
return _result["result"]
-def gen_args(description, force, locality, location, platform, os, password,
- random, mac_address, ip_address, update_dns, reverse):
+def gen_args(description, locality, location, platform, os, password, random,
+ mac_address, sshpubkey, userclass, auth_ind, requires_pre_auth,
+ ok_as_delegate, ok_to_auth_as_delegate, force, reverse,
+ ip_address, update_dns):
+ # certificate, managedby_host, principal, create_keytab_* and
+ # allow_retrieve_keytab_* are not handled here
_args = {}
if description is not None:
_args["description"] = description
- if force is not None:
- _args["force"] = force
if locality is not None:
_args["l"] = locality
if location is not None:
@@ -216,17 +454,162 @@ def gen_args(description, force, locality, location, platform, os, password,
_args["random"] = random
if mac_address is not None:
_args["macaddress"] = mac_address
+ if sshpubkey is not None:
+ _args["ipasshpubkey"] = sshpubkey
+ if userclass is not None:
+ _args["userclass"] = userclass
+ if auth_ind is not None:
+ _args["krbprincipalauthind"] = auth_ind
+ if requires_pre_auth is not None:
+ _args["ipakrbrequirespreauth"] = requires_pre_auth
+ if ok_as_delegate is not None:
+ _args["ipakrbokasdelegate"] = ok_as_delegate
+ if ok_to_auth_as_delegate is not None:
+ _args["ipakrboktoauthasdelegate"] = ok_to_auth_as_delegate
+ if force is not None:
+ _args["force"] = force
+ if reverse is not None:
+ _args["no_reverse"] = not reverse
if ip_address is not None:
_args["ip_address"] = ip_address
if update_dns is not None:
_args["updatedns"] = update_dns
- if reverse is not None:
- _args["no_reverse"] = not reverse
return _args
+def check_parameters(
+ module, state, action,
+ description, locality, location, platform, os, password, random,
+ certificate, managedby_host, principal, allow_create_keytab_user,
+ allow_create_keytab_group, allow_create_keytab_host,
+ allow_create_keytab_hostgroup, allow_retrieve_keytab_user,
+ allow_retrieve_keytab_group, allow_retrieve_keytab_host,
+ allow_retrieve_keytab_hostgroup, mac_address, sshpubkey,
+ userclass, auth_ind, requires_pre_auth, ok_as_delegate,
+ ok_to_auth_as_delegate, force, reverse, ip_address, update_dns,
+ update_password):
+ if state == "present":
+ if action == "member":
+ # certificate, managedby_host, principal,
+ # allow_create_keytab_*, allow_retrieve_keytab_*,
+ invalid = ["description", "locality", "location", "platform",
+ "os", "password", "random", "mac_address", "sshpubkey",
+ "userclass", "auth_ind", "requires_pre_auth",
+ "ok_as_delegate", "ok_to_auth_as_delegate", "force",
+ "reverse", "ip_address", "update_dns",
+ "update_password"]
+ for x in invalid:
+ if vars()[x] is not None:
+ module.fail_json(
+ msg="Argument '%s' can not be used with action "
+ "'%s'" % (x, action))
+
+ if state == "absent":
+ invalid = ["description", "locality", "location", "platform", "os",
+ "password", "random", "mac_address", "sshpubkey",
+ "userclass", "auth_ind", "requires_pre_auth",
+ "ok_as_delegate", "ok_to_auth_as_delegate", "force",
+ "reverse", "ip_address", "update_password"]
+ if action == "host":
+ invalid.extend([
+ "certificate", "managedby_host", "principal",
+ "allow_create_keytab_user", "allow_create_keytab_group",
+ "allow_create_keytab_host", "allow_create_keytab_hostgroup",
+ "allow_retrieve_keytab_user", "allow_retrieve_keytab_group",
+ "allow_retrieve_keytab_host",
+ "allow_retrieve_keytab_hostgroup"])
+ for x in invalid:
+ if vars()[x] is not None:
+ module.fail_json(
+ msg="Argument '%s' can not be used with state '%s'" %
+ (x, state))
+
+
def main():
+ host_spec = dict(
+ # present
+ description=dict(type="str", default=None),
+ locality=dict(type="str", default=None),
+ location=dict(type="str", aliases=["ns_host_location"],
+ default=None),
+ platform=dict(type="str", aliases=["ns_hardware_platform"],
+ default=None),
+ os=dict(type="str", aliases=["ns_os_version"], default=None),
+ password=dict(type="str",
+ aliases=["user_password", "userpassword"],
+ default=None, no_log=True),
+ random=dict(type="bool", aliases=["random_password"],
+ default=None),
+
+
+
+ certificate=dict(type="list", aliases=["usercertificate"],
+ default=None),
+ managedby_host=dict(type="list",
+ default=None),
+ principal=dict(type="list", aliases=["krbprincipalname"],
+ default=None),
+ allow_create_keytab_user=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_user"],
+ default=None),
+ allow_create_keytab_group=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_group"],
+ default=None),
+ allow_create_keytab_host=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_host"],
+ default=None),
+ allow_create_keytab_hostgroup=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_hostgroup"],
+ default=None),
+ allow_retrieve_keytab_user=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_user"],
+ default=None),
+ allow_retrieve_keytab_group=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_group"],
+ default=None),
+ allow_retrieve_keytab_host=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_host"],
+ default=None),
+ allow_retrieve_keytab_hostgroup=dict(
+ type="list",
+ aliases=["ipaallowedtoperform_write_keys_hostgroup"],
+ default=None),
+ mac_address=dict(type="list", aliases=["macaddress"],
+ default=None),
+ sshpubkey=dict(type="str", aliases=["ipasshpubkey"],
+ default=None),
+ userclass=dict(type="list", aliases=["class"],
+ default=None),
+ auth_ind=dict(type='list', aliases=["krbprincipalauthind"],
+ default=None,
+ choices=['password', 'radius', 'otp']),
+ requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
+ default=None),
+ ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],
+ default=None),
+ ok_to_auth_as_delegate=dict(type="bool",
+ aliases=["ipakrboktoauthasdelegate"],
+ default=None),
+ force=dict(type='bool', default=None),
+ reverse=dict(type='bool', default=None),
+ ip_address=dict(type="str", aliases=["ipaddress"],
+ default=None),
+ update_dns=dict(type="bool", aliases=["updatedns"],
+ default=None),
+ # no_members
+
+ # for update:
+ # krbprincipalname
+ )
+
ansible_module = AnsibleModule(
argument_spec=dict(
# general
@@ -234,51 +617,33 @@ def main():
ipaadmin_password=dict(type="str", no_log=True),
name=dict(type="list", aliases=["fqdn"], default=None,
- required=True),
- # present
- description=dict(type="str", default=None),
- locality=dict(type="str", default=None),
- location=dict(type="str", aliases=["ns_host_location"],
- default=None),
- platform=dict(type="str", aliases=["ns_hardware_platform"],
- default=None),
- os=dict(type="str", aliases=["ns_os_version"], default=None),
- password=dict(type="str",
- aliases=["user_password", "userpassword"],
- default=None, no_log=True),
- random=dict(type="bool", aliases=["random_password"],
- default=None),
- # certificate (usercertificate)
- mac_address=dict(type="list", aliases=["macaddress"],
- default=None),
- # sshpubkey=dict(type="str", aliases=["ipasshpubkey"],
- # default=None),
- # class
- # auth_ind
- # requires_pre_auth
- # ok_as_delegate
- # ok_to_auth_as_delegate
- force=dict(type='bool', default=None),
- reverse=dict(type='bool', default=True),
- ip_address=dict(type="str", aliases=["ipaddress"],
- default=None),
- # no_members
+ required=False),
- # for update:
- # krbprincipalname
- update_dns=dict(type="bool", aliases=["updatedns"],
- default=None),
+ hosts=dict(type="list", default=None,
+ options=dict(
+ # Here name is a simple string
+ name=dict(type="str", aliases=["fqdn"],
+ required=True),
+ # Add host specific parameters
+ **host_spec
+ ),
+ elements='dict', required=False),
+
+ # mod
update_password=dict(type='str', default=None,
choices=['always', 'on_create']),
- # absent
- # continue
- # disabled
-
- # state
+ # general
+ action=dict(type="str", default="host",
+ choices=["member", "host"]),
state=dict(type="str", default="present",
choices=["present", "absent", "disabled"]),
+
+ # Add host specific parameters for simple use case
+ **host_spec
),
+ mutually_exclusive=[["name", "hosts"]],
+ required_one_of=[["name", "hosts"]],
supports_check_mode=True,
)
@@ -287,49 +652,82 @@ def main():
# Get parameters
# general
- ipaadmin_principal = ansible_module.params.get("ipaadmin_principal")
- ipaadmin_password = ansible_module.params.get("ipaadmin_password")
- names = ansible_module.params.get("name")
+ 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")
+ hosts = module_params_get(ansible_module, "hosts")
# present
- description = ansible_module.params.get("description")
- locality = ansible_module.params.get("locality")
- location = ansible_module.params.get("location")
- platform = ansible_module.params.get("platform")
- os = ansible_module.params.get("os")
- password = ansible_module.params.get("password")
- random = ansible_module.params.get("random")
- mac_address = ansible_module.params.get("mac_address")
- force = ansible_module.params.get("force")
- reverse = ansible_module.params.get("reverse")
- ip_address = ansible_module.params.get("ip_address")
- update_dns = ansible_module.params.get("update_dns")
- update_password = ansible_module.params.get("update_password")
- # absent
- # disabled
- # state
- state = ansible_module.params.get("state")
+ description = module_params_get(ansible_module, "description")
+ locality = module_params_get(ansible_module, "locality")
+ location = module_params_get(ansible_module, "location")
+ platform = module_params_get(ansible_module, "platform")
+ os = module_params_get(ansible_module, "os")
+ password = module_params_get(ansible_module, "password")
+ random = module_params_get(ansible_module, "random")
+ certificate = module_params_get(ansible_module, "certificate")
+ managedby_host = module_params_get(ansible_module, "managedby_host")
+ principal = module_params_get(ansible_module, "principal")
+ allow_create_keytab_user = module_params_get(
+ ansible_module, "allow_create_keytab_user")
+ allow_create_keytab_group = module_params_get(
+ ansible_module, "allow_create_keytab_group")
+ allow_create_keytab_host = module_params_get(
+ ansible_module, "allow_create_keytab_host")
+ allow_create_keytab_hostgroup = module_params_get(
+ ansible_module, "allow_create_keytab_hostgroup")
+ allow_retrieve_keytab_user = module_params_get(
+ ansible_module, "allow_retrieve_keytab_user")
+ 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")
+ allow_retrieve_keytab_hostgroup = module_params_get(
+ ansible_module, "allow_retrieve_keytab_hostgroup")
+ mac_address = module_params_get(ansible_module, "mac_address")
+ sshpubkey = module_params_get(ansible_module, "sshpubkey")
+ userclass = module_params_get(ansible_module, "userclass")
+ auth_ind = module_params_get(ansible_module, "auth_ind")
+ requires_pre_auth = module_params_get(ansible_module, "requires_pre_auth")
+ ok_as_delegate = module_params_get(ansible_module, "ok_as_delegate")
+ ok_to_auth_as_delegate = module_params_get(ansible_module,
+ "ok_to_auth_as_delegate")
+ force = module_params_get(ansible_module, "force")
+ reverse = module_params_get(ansible_module, "reverse")
+ ip_address = module_params_get(ansible_module, "ip_address")
+ update_dns = module_params_get(ansible_module, "update_dns")
+ update_password = module_params_get(ansible_module, "update_password")
+ # general
+ action = module_params_get(ansible_module, "action")
+ state = module_params_get(ansible_module, "state")
# Check parameters
+ if (names is None or len(names) < 1) and \
+ (hosts is None or len(hosts) < 1):
+ ansible_module.fail_json(msg="One of name and hosts is required")
+
if state == "present":
- if len(names) != 1:
+ if names is not None and len(names) != 1:
ansible_module.fail_json(
msg="Only one host can be added at a time.")
- if state == "absent":
- if len(names) < 1:
- ansible_module.fail_json(
- msg="No name given.")
- for x in ["description", "password", "random", "mac_address",
- "force", "ip_address", "update_password"]:
- if vars()[x] is not None:
- ansible_module.fail_json(
- msg="Argument '%s' can not be used with state '%s'" %
- (x, state))
+ check_parameters(
+ ansible_module, state, action,
+ description, locality, location, platform, os, password, random,
+ certificate, managedby_host, principal, allow_create_keytab_user,
+ allow_create_keytab_group, allow_create_keytab_host,
+ allow_create_keytab_hostgroup, allow_retrieve_keytab_user,
+ allow_retrieve_keytab_group, allow_retrieve_keytab_host,
+ allow_retrieve_keytab_hostgroup, mac_address, sshpubkey, userclass,
+ auth_ind, requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
+ force, reverse, ip_address, update_dns, update_password)
- if update_password is None:
- update_password = "always"
+ # Use hosts if names is None
+ if hosts is not None:
+ names = hosts
# Init
@@ -343,9 +741,75 @@ def main():
ipaadmin_password)
api_connect()
+ # Check version specific settings
+
+ server_realm = api_get_realm()
+
commands = []
- for name in names:
+ for host in names:
+ if isinstance(host, dict):
+ name = host.get("name")
+ description = host.get("description")
+ locality = host.get("locality")
+ location = host.get("location")
+ platform = host.get("platform")
+ os = host.get("os")
+ password = host.get("password")
+ random = host.get("random")
+ certificate = host.get("certificate")
+ managedby_host = host.get("managedby_host")
+ principal = host.get("principal")
+ allow_create_keytab_user = host.get(
+ "allow_create_keytab_user")
+ allow_create_keytab_group = host.get(
+ "allow_create_keytab_group")
+ allow_create_keytab_host = host.get(
+ "allow_create_keytab_host")
+ allow_create_keytab_hostgroup = host.get(
+ "allow_create_keytab_hostgroup")
+ allow_retrieve_keytab_user = host.get(
+ "allow_retrieve_keytab_user")
+ allow_retrieve_keytab_group = host.get(
+ "allow_retrieve_keytab_group")
+ allow_retrieve_keytab_host = host.get(
+ "allow_retrieve_keytab_host")
+ allow_retrieve_keytab_hostgroup = host.get(
+ "allow_retrieve_keytab_hostgroup")
+ mac_address = host.get("mac_address")
+ sshpubkey = host.get("sshpubkey")
+ userclass = host.get("userclass")
+ auth_ind = host.get("auth_ind")
+ requires_pre_auth = host.get("requires_pre_auth")
+ ok_as_delegate = host.get("ok_as_delegate")
+ ok_to_auth_as_delegate = host.get("ok_to_auth_as_delegate")
+ force = host.get("force")
+ reverse = host.get("reverse")
+ ip_address = host.get("ip_address")
+ update_dns = host.get("update_dns")
+ # update_password is not part of hosts structure
+ # action is not part of hosts structure
+ # state is not part of hosts structure
+
+ check_parameters(
+ ansible_module, state, action,
+ description, locality, location, platform, os, password,
+ random, certificate, managedby_host, principal,
+ allow_create_keytab_user, allow_create_keytab_group,
+ allow_create_keytab_host, allow_create_keytab_hostgroup,
+ allow_retrieve_keytab_user, allow_retrieve_keytab_group,
+ allow_retrieve_keytab_host,
+ allow_retrieve_keytab_hostgroup, mac_address, sshpubkey,
+ userclass, auth_ind, requires_pre_auth, ok_as_delegate,
+ ok_to_auth_as_delegate, force, reverse, ip_address,
+ update_dns, update_password)
+
+ elif isinstance(host, str) or isinstance(host, unicode):
+ name = host
+ else:
+ ansible_module.fail_json(msg="Host '%s' is not valid" %
+ repr(host))
+
# Make sure host exists
res_find = find_host(ansible_module, name)
@@ -353,41 +817,392 @@ def main():
if state == "present":
# Generate args
args = gen_args(
- description, force, locality, location, platform, os,
- password, random, mac_address, ip_address, update_dns,
- reverse)
+ description, locality, location, platform, os, password,
+ random, mac_address, sshpubkey, userclass, auth_ind,
+ requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
+ force, reverse, ip_address, update_dns)
- # Found the host
- if res_find is not None:
- # Ignore password with update_password == on_create
- if update_password == "on_create":
- if "userpassword" in args:
+ if action == "host":
+ # Found the host
+ if res_find is not None:
+ # Ignore password with update_password == on_create
+ if update_password == "on_create" and \
+ "userpassword" in args:
del args["userpassword"]
- if "random" in args:
- del args["random"]
- # Ignore force, ip_address and no_reverse for mod
- for x in ["force", "ip_address", "no_reverse"]:
- if x in args:
- del args[x]
+ # Ignore force, ip_address and no_reverse for mod
+ for x in ["force", "ip_address", "no_reverse"]:
+ if x in args:
+ del args[x]
+
+ # 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, "host_mod", args])
+ elif random and "userpassword" in res_find:
+ # Host exists and random is set, return
+ # userpassword
+ if len(names) == 1:
+ exit_args["userpassword"] = \
+ res_find["userpassword"]
+ else:
+ exit_args.setdefault("hosts", {})[name] = {
+ "userpassword": res_find["userpassword"]
+ }
+
+ else:
+ # Remove update_dns as it is not supported by host_add
+ if "updatedns" in args:
+ del args["updatedns"]
+ commands.append([name, "host_add", args])
+
+ # Handle members: certificate, managedby_host, principal,
+ # allow_create_keytab and allow_retrieve_keytab
+ if res_find is not None:
+ certificate_add, certificate_del = gen_add_del_lists(
+ certificate, res_find.get("usercertificate"))
+ managedby_host_add, managedby_host_del = \
+ gen_add_del_lists(managedby_host,
+ res_find.get("managedby_host"))
+ principal_add, principal_del = gen_add_del_lists(
+ principal, res_find.get("principal"))
+ # Principals are not returned as utf8 for IPA using
+ # python2 using host_find, therefore we need to
+ # convert the principals that we should remove.
+ principal_del = [to_text(x) for x in principal_del]
+
+ (allow_create_keytab_user_add,
+ allow_create_keytab_user_del) = \
+ gen_add_del_lists(
+ allow_create_keytab_user,
+ res_find.get(
+ "ipaallowedtoperform_write_keys_user"))
+ (allow_create_keytab_group_add,
+ allow_create_keytab_group_del) = \
+ gen_add_del_lists(
+ allow_create_keytab_group,
+ res_find.get(
+ "ipaallowedtoperform_write_keys_group"))
+ (allow_create_keytab_host_add,
+ allow_create_keytab_host_del) = \
+ gen_add_del_lists(
+ allow_create_keytab_host,
+ res_find.get(
+ "ipaallowedtoperform_write_keys_host"))
+ (allow_create_keytab_hostgroup_add,
+ allow_create_keytab_hostgroup_del) = \
+ gen_add_del_lists(
+ allow_create_keytab_hostgroup,
+ res_find.get(
+ "ipaallowedtoperform_write_keys_"
+ "hostgroup"))
+ (allow_retrieve_keytab_user_add,
+ allow_retrieve_keytab_user_del) = \
+ gen_add_del_lists(
+ allow_retrieve_keytab_user,
+ res_find.get(
+ "ipaallowedtoperform_read_keys_user"))
+ (allow_retrieve_keytab_group_add,
+ allow_retrieve_keytab_group_del) = \
+ gen_add_del_lists(
+ allow_retrieve_keytab_group,
+ res_find.get(
+ "ipaallowedtoperform_read_keys_group"))
+ (allow_retrieve_keytab_host_add,
+ allow_retrieve_keytab_host_del) = \
+ gen_add_del_lists(
+ allow_retrieve_keytab_host,
+ res_find.get(
+ "ipaallowedtoperform_read_keys_host"))
+ (allow_retrieve_keytab_hostgroup_add,
+ allow_retrieve_keytab_hostgroup_del) = \
+ gen_add_del_lists(
+ allow_retrieve_keytab_hostgroup,
+ res_find.get(
+ "ipaallowedtoperform_read_keys_hostgroup"))
+
+ else:
+ certificate_add = certificate or []
+ certificate_del = []
+ managedby_host_add = managedby_host or []
+ managedby_host_del = []
+ principal_add = principal or []
+ principal_del = []
+ allow_create_keytab_user_add = \
+ allow_create_keytab_user or []
+ allow_create_keytab_user_del = []
+ allow_create_keytab_group_add = \
+ allow_create_keytab_group or []
+ allow_create_keytab_group_del = []
+ allow_create_keytab_host_add = \
+ allow_create_keytab_host or []
+ allow_create_keytab_host_del = []
+ allow_create_keytab_hostgroup_add = \
+ allow_create_keytab_hostgroup or []
+ allow_create_keytab_hostgroup_del = []
+ allow_retrieve_keytab_user_add = \
+ allow_retrieve_keytab_user or []
+ allow_retrieve_keytab_user_del = []
+ allow_retrieve_keytab_group_add = \
+ allow_retrieve_keytab_group or []
+ allow_retrieve_keytab_group_del = []
+ allow_retrieve_keytab_host_add = \
+ allow_retrieve_keytab_host or []
+ allow_retrieve_keytab_host_del = []
+ allow_retrieve_keytab_hostgroup_add = \
+ allow_retrieve_keytab_hostgroup or []
+ allow_retrieve_keytab_hostgroup_del = []
- # 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, "host_mod", args])
else:
- commands.append([name, "host_add", args])
+ certificate_add = certificate or []
+ certificate_del = []
+ managedby_host_add = managedby_host or []
+ managedby_host_del = []
+ principal_add = principal or []
+ principal_del = []
+ allow_create_keytab_user_add = \
+ allow_create_keytab_user or []
+ allow_create_keytab_user_del = []
+ allow_create_keytab_group_add = \
+ allow_create_keytab_group or []
+ allow_create_keytab_group_del = []
+ allow_create_keytab_host_add = \
+ allow_create_keytab_host or []
+ allow_create_keytab_host_del = []
+ allow_create_keytab_hostgroup_add = \
+ allow_create_keytab_hostgroup or []
+ allow_create_keytab_hostgroup_del = []
+ allow_retrieve_keytab_user_add = \
+ allow_retrieve_keytab_user or []
+ allow_retrieve_keytab_user_del = []
+ allow_retrieve_keytab_group_add = \
+ allow_retrieve_keytab_group or []
+ allow_retrieve_keytab_group_del = []
+ allow_retrieve_keytab_host_add = \
+ allow_retrieve_keytab_host or []
+ allow_retrieve_keytab_host_del = []
+ allow_retrieve_keytab_hostgroup_add = \
+ allow_retrieve_keytab_hostgroup or []
+ allow_retrieve_keytab_hostgroup_del = []
+
+ # Remove canonical principal from principal_del
+ canonical_principal = "host/" + name + "@" + server_realm
+ if canonical_principal in principal_del and \
+ action == "host" and (principal is not None or
+ canonical_principal not in principal):
+ principal_del.remove(canonical_principal)
+
+ # Remove canonical managedby managedby_host_del for
+ # action host if managedby_host is set and the canonical
+ # managedby host is not in the managedby_host list.
+ canonical_managedby_host = name
+ if canonical_managedby_host in managedby_host_del and \
+ action == "host" and (managedby_host is None or
+ canonical_managedby_host not in
+ managedby_host):
+ managedby_host_del.remove(canonical_managedby_host)
+
+ # Certificates need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Add certificates
+ for _certificate in certificate_add:
+ commands.append([name, "host_add_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+ # Remove certificates
+ for _certificate in certificate_del:
+ commands.append([name, "host_remove_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+
+ # Managedby_Hosts need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Add managedby_hosts
+ for _managedby_host in managedby_host_add:
+ commands.append([name, "host_add_managedby",
+ {
+ "host":
+ _managedby_host,
+ }])
+ # Remove managedby_hosts
+ for _managedby_host in managedby_host_del:
+ commands.append([name, "host_remove_managedby",
+ {
+ "host":
+ _managedby_host,
+ }])
+
+ # Principals need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Add principals
+ for _principal in principal_add:
+ commands.append([name, "host_add_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+ # Remove principals
+ for _principal in principal_del:
+ commands.append([name, "host_remove_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+
+ # Allow create keytab
+ if len(allow_create_keytab_user_add) > 0 or \
+ len(allow_create_keytab_group_add) > 0 or \
+ len(allow_create_keytab_host_add) > 0 or \
+ len(allow_create_keytab_hostgroup_add) > 0:
+ commands.append(
+ [name, "host_allow_create_keytab",
+ {
+ "user": allow_create_keytab_user_add,
+ "group": allow_create_keytab_group_add,
+ "host": allow_create_keytab_host_add,
+ "hostgroup": allow_create_keytab_hostgroup_add,
+ }])
+
+ # Disallow create keytab
+ if len(allow_create_keytab_user_del) > 0 or \
+ len(allow_create_keytab_group_del) > 0 or \
+ len(allow_create_keytab_host_del) > 0 or \
+ len(allow_create_keytab_hostgroup_del) > 0:
+ commands.append(
+ [name, "host_disallow_create_keytab",
+ {
+ "user": allow_create_keytab_user_del,
+ "group": allow_create_keytab_group_del,
+ "host": allow_create_keytab_host_del,
+ "hostgroup": allow_create_keytab_hostgroup_del,
+ }])
+
+ # 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:
+ commands.append(
+ [name, "host_allow_retrieve_keytab",
+ {
+ "user": allow_retrieve_keytab_user_add,
+ "group": allow_retrieve_keytab_group_add,
+ "host": allow_retrieve_keytab_host_add,
+ "hostgroup": allow_retrieve_keytab_hostgroup_add,
+ }])
+
+ # Disallow retrieve keytab
+ if len(allow_retrieve_keytab_user_del) > 0 or \
+ len(allow_retrieve_keytab_group_del) > 0 or \
+ len(allow_retrieve_keytab_host_del) > 0 or \
+ len(allow_retrieve_keytab_hostgroup_del) > 0:
+ commands.append(
+ [name, "host_disallow_retrieve_keytab",
+ {
+ "user": allow_retrieve_keytab_user_del,
+ "group": allow_retrieve_keytab_group_del,
+ "host": allow_retrieve_keytab_host_del,
+ "hostgroup": allow_retrieve_keytab_hostgroup_del,
+ }])
elif state == "absent":
- if res_find is not None:
- commands.append([name, "host_del", {}])
+ if action == "host":
+
+ if res_find is not None:
+ args = {}
+ if update_dns is not None:
+ args["updatedns"] = update_dns
+ commands.append([name, "host_del", args])
+ else:
+
+ # Certificates need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Remove certificates
+ if certificate is not None:
+ for _certificate in certificate:
+ commands.append([name, "host_remove_cert",
+ {
+ "usercertificate":
+ _certificate,
+ }])
+
+ # Managedby_Hosts need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Remove managedby_hosts
+ if managedby_host is not None:
+ for _managedby_host in managedby_host:
+ commands.append([name, "host_remove_managedby",
+ {
+ "host":
+ _managedby_host,
+ }])
+
+ # Principals need to be added and removed one by one,
+ # because if entry already exists, the processing of
+ # the remaining enries is stopped. The same applies to
+ # the removal of non-existing entries.
+
+ # Remove principals
+ if principal is not None:
+ for _principal in principal:
+ commands.append([name, "host_remove_principal",
+ {
+ "krbprincipalname":
+ _principal,
+ }])
+
+ # Disallow create keytab
+ if allow_create_keytab_user is not None or \
+ allow_create_keytab_group is not None or \
+ allow_create_keytab_host is not None or \
+ allow_create_keytab_hostgroup is not None:
+ commands.append(
+ [name, "host_disallow_create_keytab",
+ {
+ "user": allow_create_keytab_user,
+ "group": allow_create_keytab_group,
+ "host": allow_create_keytab_host,
+ "hostgroup": allow_create_keytab_hostgroup,
+ }])
+
+ # Disallow retrieve keytab
+ if allow_retrieve_keytab_user is not None or \
+ allow_retrieve_keytab_group is not None or \
+ allow_retrieve_keytab_host is not None or \
+ allow_retrieve_keytab_hostgroup is not None:
+ commands.append(
+ [name, "host_disallow_retrieve_keytab",
+ {
+ "user": allow_retrieve_keytab_user,
+ "group": allow_retrieve_keytab_group,
+ "host": allow_retrieve_keytab_host,
+ "hostgroup": allow_retrieve_keytab_hostgroup,
+ }])
elif state == "disabled":
if res_find is not None:
- res_show = show_host(ansible_module, name)
- if res_show["has_keytab"]:
- commands.append([name, "host_disable", {}])
+ commands.append([name, "host_disable", {}])
else:
raise ValueError("No host '%s'" % name)
@@ -395,11 +1210,17 @@ def main():
ansible_module.fail_json(msg="Unkown state '%s'" % state)
# Execute commands
+
+ errors = []
for name, command, args in commands:
try:
result = api_command(ansible_module, command, to_text(name),
args)
- changed = True
+ if "completed" in result:
+ if result["completed"] > 0:
+ changed = True
+ else:
+ changed = True
if "random" in args and command in ["host_add", "host_mod"] \
and "randompassword" in result["result"]:
@@ -411,8 +1232,37 @@ def main():
result["result"]["randompassword"]
except Exception as e:
+ msg = str(e)
+ if "already contains" in msg \
+ or "does not contain" in msg:
+ continue
+
+ # The canonical principal name may not be removed
+ if "equal to the canonical principal name must" in msg:
+ continue
+
+ # Host is already disabled, ignore error
+ if "This entry is already disabled" in msg:
+ continue
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
- str(e)))
+ msg))
+
+ # Get all errors
+ # All "already a member" and "not a member" failures in the
+ # result are ignored. All others are reported.
+ if "failed" in result and len(result["failed"]) > 0:
+ for item in result["failed"]:
+ failed_item = result["failed"][item]
+ for member_type in failed_item:
+ for member, failure in failed_item[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))
diff --git a/tests/host/certificate/cert1.der b/tests/host/certificate/cert1.der
new file mode 100644
index 00000000..334511ff
Binary files /dev/null and b/tests/host/certificate/cert1.der differ
diff --git a/tests/host/certificate/cert1.pem b/tests/host/certificate/cert1.pem
new file mode 100644
index 00000000..6fb9d2e9
--- /dev/null
+++ b/tests/host/certificate/cert1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUZGHLaSYg1myp6EI4VGWSC27vOrswDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4MzVaFw0yMDEwMTMxNjI4
+MzVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDER/lB8wUAmPTSwSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJm
+OVpOUo4K2fGRZ0yAH9fkGv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQb
+CYkV+wmq8Puzw/+xA9EJrrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmsp
+sir1tccmf4x1PP+yHJWdcXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzY
+Z2FmNtjES6ZhCsYL31fQbF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15
+RcgYTckY+7QZ2nYqplRBoDlQl6DnAgMBAAGjUzBRMB0GA1UdDgQWBBTPG99XVRdx
+pOXMZo3Nhy+ldnf13TAfBgNVHSMEGDAWgBTPG99XVRdxpOXMZo3Nhy+ldnf13TAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAjWTcnIl2mpNbfHAN8
+DB4Kk+RNRmhsH0y+r/47MXVTMMMToCfofeNY3Jeohu+2lIXMPQfTvXUbDTkNAGsG
+Lv6LtQEUfSREqgk1eY7bT9BFfpH1uV2ZFhCO9jBA+E4bf55Kx7bgUNG31ykBshOs
+OblOJM1lS/0q4TWHAxrsU2PNwPi8X0ten+eGeB8aRshxS17Ij2cH0fdAMmSA+jMA
+vTIZl853Bxe0HuozauKwOFWL4qHm61c4O/j1mQCLqJKYfJ9mBDWFQLszd/tF+ePK
+iNhZCQly60F8Lumn2CDZj5UIkl8wk9Wls5n1BIQs+M8AN65NAdv7+js8jKUKCuyj
+i8r3
+-----END CERTIFICATE-----
diff --git a/tests/host/certificate/cert2.der b/tests/host/certificate/cert2.der
new file mode 100644
index 00000000..a3ba5a57
Binary files /dev/null and b/tests/host/certificate/cert2.der differ
diff --git a/tests/host/certificate/cert2.pem b/tests/host/certificate/cert2.pem
new file mode 100644
index 00000000..4a243b25
--- /dev/null
+++ b/tests/host/certificate/cert2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUAWE1vaA+mZd3nwZqwWH64EbHvR0wDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NDVaFw0yMDEwMTMxNjI4
+NDVaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCWzJibKtN8Zf7LgandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3V
+fJNYmCbA1baLVJ0YZJijJ7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSY
+OKmdHHRClplysL8OyyEG7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv
+1wNw1rqWKF1ZzagWRlG4QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCk
+VOZIhxu77OmNrFsXmM4rZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0
+KgE57zCDVr9Ix+p/dA5R1mG4RJ2XAgMBAAGjUzBRMB0GA1UdDgQWBBSbuiH2lNVr
+ID3yt1SsFwtOFKOnpTAfBgNVHSMEGDAWgBSbuiH2lNVrID3yt1SsFwtOFKOnpTAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBCVWd293wWyohFqMFM
+HRBBg97T2Uc1yeT0dMH4BpuOaCqQp4q5ep+uLcXEI6+3mEwm8pa/ULQCD8yLLdot
+IWlG3+h/4boFpdiPFcBDgT8kGe+0KOzB8Nt7E13QYOu12MNi10qwGrjKhdhu1xBe
+4fpY5VCetVU1OLyuTsUyucQsFrtZI0SR83h+blbyoMZ7IhMngCfGUe1bnYeWnLbp
+FbigKfPuVDWsMH2kgj05EAd5EgHkWbX8QA8hmcmDKfNT3YZM8kiGQwmFrnQdq8bN
+0uHR8Nz+24cbmdbHcD65wlDW6GmYxi8mW+V6bAqn9pir/J14r4YFnqMGgjmdt81t
+scJV
+-----END CERTIFICATE-----
diff --git a/tests/host/certificate/cert3.der b/tests/host/certificate/cert3.der
new file mode 100644
index 00000000..783830ee
Binary files /dev/null and b/tests/host/certificate/cert3.der differ
diff --git a/tests/host/certificate/cert3.pem b/tests/host/certificate/cert3.pem
new file mode 100644
index 00000000..b2a6a99c
--- /dev/null
+++ b/tests/host/certificate/cert3.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgIUTC33WUoYGFoIVGMwgjbc5J6xCyowDQYJKoZIhvcNAQEL
+BQAwDzENMAsGA1UEAwwEdGVzdDAeFw0xOTEwMTQxNjI4NTJaFw0yMDEwMTMxNjI4
+NTJaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDCA+6P2eieXHaVJivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN
+0mse/POWXdC+zXRMC2X/c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2
+tECSUEnSCz9n1ofHnyqDyT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+
+IP77+ou4fhkBLI1MX5nkWa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7
+c4DYMJQF/51bi2ByZWERNjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu
+4summWgH0QYDmbkdhGwYvup0EmEfAgMBAAGjUzBRMB0GA1UdDgQWBBSJCQ8ho0Pp
+e0khVhgiMqsvlgxIjzAfBgNVHSMEGDAWgBSJCQ8ho0Ppe0khVhgiMqsvlgxIjzAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAILLPnau32r/YoOVCV
+WQotGtySy36aFlHa3T8IkSpatNCPIf3U0FWS6TVYBwY0PBfdqWBkvCuJTupLh0OE
+P4TCsDa5pJGOK7blyfiAfcHajqyouACSVNlG63EPvB63h4H4F4HJnhDd4z7pVC/W
+PB8w5GTBJNjELmeWfH7nj7lu8UkOdLhzTKL40RPs0k4l09yYBmZqqExxGsSfvRBQ
+crwlAsvQ0E/cTNGbyzOKs3SbOM2WEHye6xNEsey01icYcjfjqvEd6mw3+WOUeJAu
+DH9/EOloFM2iz5Xp31Ig3WT0RVy+lMriG9GesPpFBs2xp9wQCXLNIkpbHKyYs3vo
+MyBH
+-----END CERTIFICATE-----
diff --git a/tests/host/certificate/private1.key b/tests/host/certificate/private1.key
new file mode 100644
index 00000000..cb76298b
--- /dev/null
+++ b/tests/host/certificate/private1.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDER/lB8wUAmPTS
+wSc/NOXNlzdpPOQDSwrhKH6XsqZF4KpQoSY/nmCjAhJmOVpOUo4K2fGRZ0yAH9fk
+Gv6yJP6c7IAFjLeec7GPHVwN4bZrP1DXfTAmfmXhcRQbCYkV+wmq8Puzw/+xA9EJ
+rrodnJPPsE6E8HnSVLF6Ys9+cJMJ7HuwOI+wYt3gkmspsir1tccmf4x1PP+yHJWd
+cXyetlFRcmZ8gspjqOR2jb89xSQsh8gcyDW6rPNlSTzYZ2FmNtjES6ZhCsYL31fQ
+bF2QglidlLGpAlvHUUS+xCigW73cvhFPMWXcfO51Mr15RcgYTckY+7QZ2nYqplRB
+oDlQl6DnAgMBAAECggEBALtKTj6urHxId3xPEKsQR6Noglgp4Qx/Y687W6hWsLAG
+051CV+PmtSF2DaZ7XX9U6PLTydzL68RqHjArzhKgmE+WoAYrot5QWQJNqpQYZ19o
+uDQW4YYpn/+BTgUKkUNnGm+BqTt8b5QyJxoNHsy4ppZMDnBtomCfrgYxGPr2YmfZ
+Ee7oEEf1xIU2maE5Nxv97lNR2Xvm2R4F8lzRcHmvejLYNiqZ2Ag4ijnKVTpoEMUy
+afl5LNSzGJETXsv+LtaJGEr6x8/IesVSCdyX2LZeAyQPLKwb3YQDkQree54vwS7p
+cVmQdx6fLTYV1tOSXUEC2ibInO188kGA198HSqSgHJkCgYEA7zhL+6tYZdXoMzTH
+hXHLYGHmQsQXxleH5uciz4q+en7do6BFB2DqIgLTpcD/H8XMDlg9WO7756H1zqvb
+6IOkqwsrro/fsgb6FrmjXl8zlkwT3pTNJfmBydRf7Qk2woCRPUoLZBRAumNL8RSx
+Xm1/DbPbTR3jjVNH9dPb3Efd0qUCgYEA0gyesMgwDzjsXpPUsuWTMBMziy0KRFNT
+lCMCI5DVpy/XnptyLdkY93jvmq+VWbily4KlOYbfYJ/16xeNZ7aNOMnC6z4z9p9+
+w3E9q5xKJcAJP5kN/WnjBwErveDK9r1YSj8RJpvapJFqjxA5WVTwADtyBhgNS4Og
+mXPPBleMC5sCgYEA0Yw/AvXVOV9nR3O0UvCbdpJLYbDkIpoKMfnGRIcE08jN3cdG
+sG/0qFZRj6C/2tUpKmehVYYCo6T77U4eFE88r5fZa9Ab45a4+68hrEk4py99ODyg
+d+NYDbQ7Uyf/D+IPV+DEmaYkDSFuJIA73ruL0DT8pVDJQ8LwBibPMObDKQECgYBa
+aUYxD6noE3diaj1GV5zYN5ubD2L47+jsvXjhOClOkkA8K+qko2qksrBno6YkfV8X
+zv8xWMVzgMbIT1X1S1VUGTxGJ3sUb6iPlYGXCWm9AAC7GDU2W8p1rGJYk5apR+zl
+4GmQdctRxKnaNICK3A2F/BBjYRzv4RNSmc+Fik9kewKBgHsCF3uEP7ONvmEjYLQ4
+7+6fZ+m4BXKeU/kKQoEXSjSFn0dBIHo+2yuafSUz04VJCVXUic3c47kHwVtgX5lu
+jEUL1jgK4aBbl9cvywupHBf3spAP89aocgFiC9uUJzp3u39U0LpgXY7Z+1lUsCL+
+VG2oGh0KVgazjUzmbTf9ZcLp
+-----END PRIVATE KEY-----
diff --git a/tests/host/certificate/private2.key b/tests/host/certificate/private2.key
new file mode 100644
index 00000000..59d83b9f
--- /dev/null
+++ b/tests/host/certificate/private2.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWzJibKtN8Zf7L
+gandINhFonx99AKi44iaZkrlMKEObE6Faf8NTUbUgK3VfJNYmCbA1baLVJ0YZJij
+J7S/4o7h7eeqcJVXJkEhWNTimWXNW/YCzTHe3SSapnSYOKmdHHRClplysL8OyyEG
+7pbX/aB9iAfFb/+vUFCX5sMwFFrYxOimKJ9Pc/NRFtdv1wNw1rqWKF1ZzagWRlG4
+QgzRGwQ4quc7yO98TKikj2OPiIt7Zd46hbqQxmgGBtCkVOZIhxu77OmNrFsXmM4r
+ZZpmqh0UdqcpwkRojVnGXmNqeMCd6dNTnLhr9wukUYw0KgE57zCDVr9Ix+p/dA5R
+1mG4RJ2XAgMBAAECggEAS5nXCDO4Qy1/R9eBqXLF+mMztpGWoMMhwQZ3ld+DXw+9
+bfVuAOU1FWRNwjHqTQg6pYJ/Oer5tzj3rRRC8dBLgckb078Nn9t125oFYHU3LHVm
+KJFm5yxHJaE94vLFVhbl0lxeIbmqj2gW7rq+tRpaU5TXEIzNyr6hKQZv5LLPuMx6
+MiBrSpkCwfPf9psv6k2GIGqE1JuY99dNqdEUi8UQryNMzV4pthUmVybO8NPxUY8M
+s/VAbG1Hy9tgInR3wRgTjEc2ejUJrTziiqiZarZtCp+JSZufYakDU9yZbu9v4Oz9
+ityPdApkW8CuZnJcUDAtdgtKMhWyBPnWcrUgkbV0AQKBgQDGY1saiI9M7VlleyDc
+QNVXpPCmOpDLso5X3hZrrHDgDIGkvXa026Q5ufkdxkybRYJeOCdYzIM/iXSJlgNe
+R2a+aoAsePfEVFAe96ZgzrLrBq7lGvcPXGpT6GTVl0d0CwN/vG1Tzk89Hq3xIBbh
+NTlM+j2ot66xgekIsE0v5Pi41wKBgQDCl14mgaui4DqYFYlI/ckI00r/X0/0HIhf
+kf/Ck/pkF89IeOAK+O4GOfVoMk3vi1gDYgiz6G7h+sUsFTOYKuP9io/vX0pIFNOA
+NPgaVtRKitiepNo4vwc+/PRmxvf2XXFXFRSiYf0jDzruvE3yDzWwX9P1nQFBQoPj
+r8g/6+7pQQKBgDXHnVzWBDLQbNmLxV6v3KXDutD1M2dk4h2DwQQzXO3/te1YxyNE
+H4LenV+q7/1vnGW6R0BVQIcq1gKuPf+Cz6Fy8Ygcyt3YFVgvvlSj8/CugR7ubmcl
+oFVavGsCdYZJrgsko2aCmQxykqi5EDrA2OW7OJfSI3NPSkLmuCXxplNFAoGBALHD
+D5pDqOTAzCY0vlY0qNrsEr4ZdvO8wQP1XtyEzB919MDy01CSuPZtKfeGxNWIyN1G
+SEb5lZnQuSCdOaXPwLjURMralQQmKlQbj26YVZTHJD5AwK1ILTloYWgmaUzhbfGs
+a04wD8xgVGjVEquHI3e9AueEBypztgJgiaGDSZxBAoGADpxUn3L6lJrPyOd3IJrj
+ypU/EfvY7Qd5pRTrJd9tObbi8zF1sWi/FcQNgoZP7oz/aklFfq8WWwJbe0fL1Wk/
+MeVHj8JEc/dh1ISgbHYdBgegvS6L30RcNRUJWANYcifEQPlSHTzYXviQ8tEOCq+S
+/TPqxnd2CkT6w3bSCJbxKVM=
+-----END PRIVATE KEY-----
diff --git a/tests/host/certificate/private3.key b/tests/host/certificate/private3.key
new file mode 100644
index 00000000..f4261623
--- /dev/null
+++ b/tests/host/certificate/private3.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCA+6P2eieXHaV
+JivtWif7SntjjkJm0juRKRRGsT3wt+zCZqoDe8zylTBN0mse/POWXdC+zXRMC2X/
+c4V10kgrvWbnNdFdUFfBUphiXSoqnUYHZ6Ta+b4UTzC2tECSUEnSCz9n1ofHnyqD
+yT9FELzVkRkQqexD+BFgZTF39R4q8BA4bWKQy94Kgvb+IP77+ou4fhkBLI1MX5nk
+Wa3Oyu4TMzT/tqgPE70hk8wQzUU2aiwJ7IsmnWE6Ysk7c4DYMJQF/51bi2ByZWER
+NjyBY6L+ZV90aL4UFR9O+Pw9HatfHVBRdmzSkKJOr9iu4summWgH0QYDmbkdhGwY
+vup0EmEfAgMBAAECggEAdEgFAGSbHebPD79sDnq9gcf3QgjuVU/lcbAMPf5W4GJr
+3WvItAPMJwwxgkL9/vmeSN37kY/0BuvB+yPStnYM2WJQPX0s+V+A6RZGzJWIAzh1
+01RUIwYR3XxE9wv7s3W5eNFS9DpI8OS9h3TjndJVSy8Gtc0SFP6l839S8dGQfiyN
+eMqV16M+TM0LwyEogvGa79l4HjMIcorypCXg8NVcDaxNJYnAcegoRwdhGsb4jKG6
+kB+Z4dfAKLu7OFT6/20Q0QUdA/PrdBRAFt8KPhrrweKaAApVtrU0OHNs9ULFHXnu
+kSVKZ+UTCUGWxMd4lJw5XZQ4FqUdb8Sxt8TUuvRioQKBgQDy6zY1EiqsDZE+sJbd
+/jnUWn+I4/xR5y4KmbEx76dWL39TooyiHYKABJQ9BgvBIXi95AXaRodwn12DhaW7
+VW0m4RgJH/FNZoxc9xOE2+EPr2pQGn6bvJK9IjsITDoAmDbguzMZ+TCDGZqIYiIE
+GTcgeW7NOBYM2Qy8Ufqe9zfV0QKBgQDMdo426TPxdU6Gb8AVOFFuXlL6Py0Sxk0q
+pEAhyEzCKV9HM1eX8aDrJ5++lFiMwlhkYRrWVBENPyhPgWo9sMATJM0AIsBKTSyg
+rVuqlaU8e+Pqyl8ZMOZ6uMq3zLts/Vp1sX5yU8vw5FqMddMas6SMpIoPEIAiJlse
+CujyJ29T7wKBgQCiQnry+C+IvYdHWK1tm2MFdW27Ao6IJuOaMQ8rS+l6qD9kni9S
+GmQRHv3lxSQU3UbJkIZYRsQxdkIAmEUb3PQMBE8JyUxlZxpa/q8LD9RFpeZdm1T2
+sf9SVosX/9K+ku4VLvXzY4AEEhYnA2W1VyJ7jqF0cwJHkrPvFtNRW9DwAQKBgCRi
+6NYu1DahSLM2Cfn8xskccinkulHABpWTG3KnoblgAXu7UFhTAO84Yv5YihWqtG5Q
+taT02v//gF39yvlljhkaEH14sb3HVCzYDRsjfH9yENKE5z2lbS7j2fexsJ0pzUJq
+rvULopyhFtguU75Jv/vjgEpEBnmNV+PVzzTg/bfzAoGAGz11E33qpZjVw6becf9w
+U8qnPfncIqSCg0fWNnsYwD56vI9L2ExCZG//SOUZ54b8GW+RaTFDHOlIE8dRAhrF
+M5QnEjm2S+wVPJz7gKQ3cVART8EPi/Q6BT7YIgNIhemq+AwW5xMhZcBiA3vRI/Eu
+vi807exD569efFLa9uspI8o=
+-----END PRIVATE KEY-----
diff --git a/tests/host/certificate/test_host_certificate.yml b/tests/host/certificate/test_host_certificate.yml
new file mode 100644
index 00000000..7607006f
--- /dev/null
+++ b/tests/host/certificate/test_host_certificate.yml
@@ -0,0 +1,110 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test host certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Host test absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ state: absent
+
+ - name: Host test present
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test cert members present
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test cert members present again
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host test cert members absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test cert members absent again
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host test absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test absent again
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ name: "{{ 'test.' + ipaserver_domain }}"
+ state: absent
+ register: result
+ failed_when: result.changed
diff --git a/tests/host/certificate/test_hosts_certificate.yml b/tests/host/certificate/test_hosts_certificate.yml
new file mode 100644
index 00000000..853762c6
--- /dev/null
+++ b/tests/host/certificate/test_hosts_certificate.yml
@@ -0,0 +1,109 @@
+#
+# Generate self-signed certificates using openssl:
+#
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private1.key -out cert1.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private2.key -out cert2.pem -subj '/CN=test'
+# openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout private3.key -out cert3.pem -subj '/CN=test'
+#
+# Convert the certificate do DER for easier handling through CLI
+#
+# openssl x509 -outform der -in cert1.pem -out cert1.der
+# openssl x509 -outform der -in cert2.pem -out cert2.der
+# openssl x509 -outform der -in cert3.pem -out cert3.der
+#
+# Use base64:
+#
+# base64 cert1.der -w5000
+# base64 cert2.der -w5000
+# base64 cert3.der -w5000
+#
+---
+- name: Test host certificates
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Host test absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ state: absent
+
+ - name: Host test present
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test cert members present
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host test cert members present again
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host test cert members absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ state: absent
+ action: member
+ #register: result
+ #failed_when: not result.changed
+
+ - name: Host test cert members absent again
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ certificate:
+ - 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
+ state: absent
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host test absent
+ ipahost:
+ ipaadmin_password: SomeADMINpassword
+ hosts:
+ - name: "{{ 'test.' + ipaserver_domain }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/host/test_host.yml b/tests/host/test_host.yml
new file mode 100644
index 00000000..1a555a13
--- /dev/null
+++ b/tests/host/test_host.yml
@@ -0,0 +1,218 @@
+---
+- name: Test host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Set host1_fqdn .. host6_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+ host3_fqdn: "{{ 'host3.' + ipaserver_domain }}"
+ host4_fqdn: "{{ 'host4.' + ipaserver_domain }}"
+ host5_fqdn: "{{ 'host5.' + ipaserver_domain }}"
+ host6_fqdn: "{{ 'host6.' + ipaserver_domain }}"
+
+ - name: Host absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ - "{{ host4_fqdn }}"
+ - "{{ host5_fqdn }}"
+ - "{{ host6_fqdn }}"
+ update_dns: yes
+ state: absent
+
+ - name: Get IPv4 address prefix from server node
+ set_fact:
+ ipv4_prefix: "{{ ansible_default_ipv4.address.split('.')[:-1] |
+ join('.') }}"
+
+ - name: Host "{{ host1_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.201' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.201' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host2_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host2_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.202' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host2_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host2_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.202' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host3_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host3_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.203' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host3_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host3_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.203' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host4_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host4_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.204' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host4_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host4_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.204' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host5_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host5_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.205' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host5_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.205' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host6_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host6_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.206' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host6_fqdn }}" present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host6_fqdn }}"
+ ip_address: "{{ ipv4_prefix + '.206' }}"
+ update_dns: yes
+ reverse: no
+ register: result
+ failed_when: result.changed
+
+ # disabled can only be checked with enabled hosts, all hosts above are
+ # not enabled.
+ #- name: Hosts host1..host6 disabled
+ # ipahost:
+ # ipaadmin_password: MyPassword123
+ # name:
+ # - "{{ host1_fqdn }}"
+ # - "{{ host2_fqdn }}"
+ # - "{{ host3_fqdn }}"
+ # - "{{ host4_fqdn }}"
+ # - "{{ host5_fqdn }}"
+ # - "{{ host6_fqdn }}"
+ # state: disabled
+ # register: result
+ # failed_when: not result.changed
+ #
+ #- name: Hosts host1..host6 disabled again
+ # ipahost:
+ # ipaadmin_password: MyPassword123
+ # name:
+ # - "{{ host1_fqdn }}"
+ # - "{{ host2_fqdn }}"
+ # - "{{ host3_fqdn }}"
+ # - "{{ host4_fqdn }}"
+ # - "{{ host5_fqdn }}"
+ # - "{{ host6_fqdn }}"
+ # state: disabled
+ # register: result
+ # failed_when: result.changed
+
+ - name: Hosts host1..host6 absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ - "{{ host4_fqdn }}"
+ - "{{ host5_fqdn }}"
+ - "{{ host6_fqdn }}"
+ update_dns: yes
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts host1..host6 absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ - "{{ host4_fqdn }}"
+ - "{{ host5_fqdn }}"
+ - "{{ host6_fqdn }}"
+ update_dns: yes
+ state: absent
+ register: result
+ failed_when: result.changed
+
diff --git a/tests/host/test_host_allow_create_keytab.yml b/tests/host/test_host_allow_create_keytab.yml
new file mode 100644
index 00000000..eb7b7764
--- /dev/null
+++ b/tests/host/test_host_allow_create_keytab.yml
@@ -0,0 +1,278 @@
+---
+- name: Test host allow_create_keytab
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Get Realm from server name
+ set_fact:
+ ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+ when: ipaserver_realm is not defined
+
+ - name: Set host1_fqdn .. host3_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+ host3_fqdn: "{{ 'host3.' + ipaserver_domain }}"
+
+ - name: Host host1..., host2... and host3... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ state: absent
+
+ - name: Ensure host-groups hostgroup1 and hostgroup2 absent
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1,hostgroup2
+ state: absent
+
+ - name: Ensure users user1 and user2 absent
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ - name: user2
+ state: absent
+
+ - name: Ensure group1 and group2 absent
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1,group2
+ state: absent
+
+ - name: Host host2... and host3... present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host2_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-group hostgroup1 present
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1
+ state: present
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-group hostgroup2 present
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup2
+ state: present
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure users user1 and user2 present
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ first: First1
+ last: Last1
+ - name: user2
+ first: First2
+ last: Last2
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group1 present
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group2 present
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group2
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... present with allow_create_keytab users,groups,hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... present with allow_create_keytab users,groups,hosts and hostgroups again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ force: yes
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ state: absent
+
+ - name: Host host1... present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_create_keytab users,groups,hosts and hostgroups present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_create_keytab users,groups,hosts and hostgroups present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... ensure allow_create_keytab users,groups,hosts and hostgroups absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_create_keytab users,groups,hosts and hostgroups absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_create_keytab_user:
+ - user1
+ - user2
+ allow_create_keytab_group:
+ - group1
+ - group2
+ allow_create_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_create_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1..., host2... and host3... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-groups hostgroup1 and hostgroup2 absent
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1,hostgroup2
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure users user1 and user2 absent
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ - name: user2
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group1 and group2 absent
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1,group2
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/host/test_host_allow_retrieve_keytab.yml b/tests/host/test_host_allow_retrieve_keytab.yml
new file mode 100644
index 00000000..65d86aa6
--- /dev/null
+++ b/tests/host/test_host_allow_retrieve_keytab.yml
@@ -0,0 +1,278 @@
+---
+- name: Test host allow_retrieve_keytab
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Get Realm from server name
+ set_fact:
+ ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+ when: ipaserver_realm is not defined
+
+ - name: Set host1_fqdn .. host3_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+ host3_fqdn: "{{ 'host3.' + ipaserver_domain }}"
+
+ - name: Host host1..., host2... and host3... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ state: absent
+
+ - name: Ensure host-groups hostgroup1 and hostgroup2 absent
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1,hostgroup2
+ state: absent
+
+ - name: Ensure users user1 and user2 absent
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ - name: user2
+ state: absent
+
+ - name: Ensure group1 and group2 absent
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1,group2
+ state: absent
+
+ - name: Host host2... and host3... present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host2_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-group hostgroup1 present
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1
+ state: present
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-group hostgroup2 present
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup2
+ state: present
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure users user1 and user2 present
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ first: First1
+ last: Last1
+ - name: user2
+ first: First2
+ last: Last2
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group1 present
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group2 present
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group2
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... present with allow_retrieve_keytab users,groups,hosts and hostgroups
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... present with allow_retrieve_keytab users,groups,hosts and hostgroups again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ force: yes
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ state: absent
+
+ - name: Host host1... present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_retrieve_keytab users,groups,hosts and hostgroups present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_retrieve_keytab users,groups,hosts and hostgroups present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... ensure allow_retrieve_keytab users,groups,hosts and hostgroups absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... ensure allow_retrieve_keytab users,groups,hosts and hostgroups absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ allow_retrieve_keytab_user:
+ - user1
+ - user2
+ allow_retrieve_keytab_group:
+ - group1
+ - group2
+ allow_retrieve_keytab_host:
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ allow_retrieve_keytab_hostgroup:
+ - hostgroup1
+ - hostgroup2
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1..., host2... and host3... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure host-groups hostgroup1 and hostgroup2 absent
+ ipahostgroup:
+ ipaadmin_password: MyPassword123
+ name: hostgroup1,hostgroup2
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure users user1 and user2 absent
+ ipauser:
+ ipaadmin_password: MyPassword123
+ users:
+ - name: user1
+ - name: user2
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Ensure group1 and group2 absent
+ ipagroup:
+ ipaadmin_password: MyPassword123
+ name: group1,group2
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/host/test_host_managedby_host.yml b/tests/host/test_host_managedby_host.yml
new file mode 100644
index 00000000..78c5a43d
--- /dev/null
+++ b/tests/host/test_host_managedby_host.yml
@@ -0,0 +1,125 @@
+---
+- name: Test host managedby_host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Set host1_fqdn .. host2_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+
+ - name: Host absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ update_dns: yes
+ state: absent
+
+ - name: Host "{{ host1_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host2_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host2_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" managed by "{{ 'host2.' + ipaserver_domain }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host2_fqdn }}"
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" managed by "{{ 'host2.' + ipaserver_domain }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host2_fqdn }}"
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host1_fqdn }}" managed by "{{ groups.ipaserver[0] }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ groups.ipaserver[0] }}"
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" managed by "{{ groups.ipaserver[0] }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ groups.ipaserver[0] }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host1_fqdn }}" not managed by "{{ groups.ipaserver[0] }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ groups.ipaserver[0] }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" not managed by "{{ groups.ipaserver[0] }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ groups.ipaserver[0] }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host "{{ host1_fqdn }}" not managed by "{{ 'host2.' + ipaserver_domain }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host2_fqdn }}"
+ state: absent
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host "{{ host1_fqdn }}" not managed by "{{ 'host2.' + ipaserver_domain }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host2_fqdn }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ update_dns: yes
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/host/test_host_principal.yml b/tests/host/test_host_principal.yml
new file mode 100644
index 00000000..0dce400a
--- /dev/null
+++ b/tests/host/test_host_principal.yml
@@ -0,0 +1,130 @@
+---
+- name: Test host principal
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Get Realm from server name
+ set_fact:
+ ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+ when: ipaserver_realm is not defined
+
+ - name: Set host1_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+
+ - name: Host host1 absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ update_dns: yes
+ state: absent
+
+ - name: Host host1... present with principal host/testhost1...
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... principal host/host1... present (existing already)
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/host1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... principal host/testhost1... present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal: "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... principal host/testhost1... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal: "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... principal host/testhost1... absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal: "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... principal host/testhost1... and host/myhost1... present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... principal host/testhost1... and host/myhost1... present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... principal host/testhost1... and host/myhost1... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host host1... principal host/testhost1... and host/myhost1... absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host host1... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ update_dns: yes
+ state: absent
diff --git a/tests/host/test_host_random.yml b/tests/host/test_host_random.yml
index 0856ddc0..84893f90 100644
--- a/tests/host/test_host_random.yml
+++ b/tests/host/test_host_random.yml
@@ -9,33 +9,78 @@
ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
when: ipaserver_domain is not defined
+ - name: Set host1_fqdn and host2_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+
- name: Test hosts absent
ipahost:
ipaadmin_password: MyPassword123
name:
- - "{{ 'host1.' + ipaserver_domain }}"
- - "{{ 'host2.' + ipaserver_domain }}"
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
update_dns: yes
state: absent
- - name: Host "{{ 'host1.' + ipaserver_domain }}" present with random password
+ - name: Host "{{ host1_fqdn }}" present with random password
ipahost:
ipaadmin_password: MyPassword123
- name: "{{ 'host1.' + ipaserver_domain }}"
+ name: "{{ host1_fqdn }}"
random: yes
force: yes
update_password: on_create
register: ipahost
- failed_when: not ipahost.changed or
- ipahost.host.randompassword is not defined
+ failed_when: not ipahost.changed
+
+ - assert:
+ that:
+ - ipahost.host.randompassword is defined
- name: Print generated random password
debug:
var: ipahost.host.randompassword
- - name: Host "{{ 'host1.' + ipaserver_domain }}" absent
+ - name: Host "{{ host1_fqdn }}" absent
ipahost:
ipaadmin_password: MyPassword123
name:
- - "{{ 'host1.' + ipaserver_domain }}"
+ - "{{ host1_fqdn }}"
+ state: absent
+
+ - name: Hosts "{{ host1_fqdn }}" and "{{ host2_fqdn }}" present with random password
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ random: yes
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ random: yes
+ force: yes
+ update_password: on_create
+ register: ipahost
+ failed_when: not ipahost.changed
+
+ - assert:
+ that:
+ - ipahost.host["{{host1_fqdn }}"].randompassword is
+ defined
+ - ipahost.host["{{host2_fqdn }}"].randompassword is
+ defined
+
+ - name: Print generated random password for "{{host1_fqdn }}"
+ debug:
+ var: ipahost.host["{{host1_fqdn }}"].randompassword
+
+ - name: Print generated random password for "{{host2_fqdn }}"
+ debug:
+ var: ipahost.host["{{host2_fqdn }}"].randompassword
+
+ - name: Hosts "{{ host1_fqdn }}" and "{{ host2_fqdn }}" absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
state: absent
diff --git a/tests/host/test_hosts.yml b/tests/host/test_hosts.yml
new file mode 100644
index 00000000..8e92bf32
--- /dev/null
+++ b/tests/host/test_hosts.yml
@@ -0,0 +1,98 @@
+---
+- name: Test hosts
+ hosts: ipaserver
+ become: true
+ gather_facts: false
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Set host1_fqdn .. host6_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+ host3_fqdn: "{{ 'host3.' + ipaserver_domain }}"
+ host4_fqdn: "{{ 'host4.' + ipaserver_domain }}"
+ host5_fqdn: "{{ 'host5.' + ipaserver_domain }}"
+ host6_fqdn: "{{ 'host6.' + ipaserver_domain }}"
+
+ - name: Host host1..host6 absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ - name: "{{ host6_fqdn }}"
+ state: absent
+
+ - name: Hosts host1..host6 present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ force: yes
+ - name: "{{ host4_fqdn }}"
+ force: yes
+ - name: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host6_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts host1..host6 present again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ force: yes
+ - name: "{{ host4_fqdn }}"
+ force: yes
+ - name: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host6_fqdn }}"
+ force: yes
+ register: result
+ failed_when: result.changed
+
+ - name: Hosts host1..host6 absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ - name: "{{ host6_fqdn }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts host1..host6 absent again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ - name: "{{ host6_fqdn }}"
+ state: absent
+ register: result
+ failed_when: result.changed
diff --git a/tests/host/test_hosts_managedby_host.yml b/tests/host/test_hosts_managedby_host.yml
new file mode 100644
index 00000000..a692745a
--- /dev/null
+++ b/tests/host/test_hosts_managedby_host.yml
@@ -0,0 +1,151 @@
+---
+- name: Test hosts managedby_host
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Set host1_fqdn .. host5_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+ host3_fqdn: "{{ 'host3.' + ipaserver_domain }}"
+ host4_fqdn: "{{ 'host4.' + ipaserver_domain }}"
+ host5_fqdn: "{{ 'host5.' + ipaserver_domain }}"
+
+ - name: Host absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ - "{{ host3_fqdn }}"
+ - "{{ host4_fqdn }}"
+ - "{{ host5_fqdn }}"
+ update_dns: yes
+ state: absent
+
+ - name: Host "{{ host5_fqdn }}" present
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name: "{{ host5_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" present and managed by "{{ 'host5.' + ipaserver_domain }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host4_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host5_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" present and managed by "{{ 'host5.' + ipaserver_domain }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host3_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host4_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ - name: "{{ host5_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ force: yes
+ register: result
+ failed_when: result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" managed by "{{ 'host5.' + ipaserver_domain }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" not managed by "{{ 'host5.' + ipaserver_domain }}"
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" not managed by "{{ 'host5.' + ipaserver_domain }}" again
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ managedby_host: "{{ host5_fqdn }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Hosts "{{ host1_fqdn }}" .. "{{ 'host5.' + ipaserver_domain }}" absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ - name: "{{ host2_fqdn }}"
+ - name: "{{ host3_fqdn }}"
+ - name: "{{ host4_fqdn }}"
+ - name: "{{ host5_fqdn }}"
+ state: absent
+ register: result
+ failed_when: not result.changed
diff --git a/tests/host/test_hosts_principal.yml b/tests/host/test_hosts_principal.yml
new file mode 100644
index 00000000..5918d35d
--- /dev/null
+++ b/tests/host/test_hosts_principal.yml
@@ -0,0 +1,179 @@
+---
+- name: Test hosts principal
+ hosts: ipaserver
+ become: true
+
+ tasks:
+ - name: Get Domain from server name
+ set_fact:
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
+ when: ipaserver_domain is not defined
+
+ - name: Get Realm from server name
+ set_fact:
+ ipaserver_realm: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') | upper }}"
+ when: ipaserver_realm is not defined
+
+ - name: Set host1_fqdn .. host2_fqdn
+ set_fact:
+ host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+ host2_fqdn: "{{ 'host2.' + ipaserver_domain }}"
+
+ - name: Host host1... and host2... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ update_dns: yes
+ state: absent
+
+ - name: Host hostX... present with principal host/testhostX... X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ force: yes
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ force: yes
+ register: result
+ failed_when: not result.changed
+
+ - name: Host hostX... principal 'host/hostX... present (existing already) X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/host1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/host2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host hostX... principal host/testhostX... present again X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host hostX.. principal host/testhostX... absent X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host hostX... principal host/testhostX... absent again X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Host hostX... principal host/testhostX... and host/myhostX... present X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: not result.changed
+
+ - name: Host hostX... principal host/testhostX... and host/myhostX... present again X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ register: result
+ failed_when: result.changed
+
+ - name: Host hostX... principal host/testhostX... and host/myhostX... absent X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ hosts:
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: not result.changed
+
+ - name: Host hostX... principal host/testhostX... and host/myhostX... absent again X=[1,2]
+ ipahost:
+ ipaadmin_password: MyPassword123
+ hosts:
+ - name: "{{ host1_fqdn }}"
+ principal:
+ - "{{ 'host/testhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost1.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ hosts:
+ - name: "{{ host2_fqdn }}"
+ principal:
+ - "{{ 'host/testhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ - "{{ 'host/myhost2.' + ipaserver_domain + '@' + ipaserver_realm }}"
+ action: member
+ state: absent
+ register: result
+ failed_when: result.changed
+
+ - name: Hosts host1... and host2... absent
+ ipahost:
+ ipaadmin_password: MyPassword123
+ name:
+ - "{{ host1_fqdn }}"
+ - "{{ host2_fqdn }}"
+ update_dns: yes
+ state: absent