Merge pull request #203 from t-woerner/ipahost_ipaddresses

ipahost: Add support for several IP addresses and also to change them
This commit is contained in:
Varun Mylaraiah
2020-02-14 15:52:09 +05:30
committed by GitHub
8 changed files with 601 additions and 51 deletions

View File

@@ -65,6 +65,79 @@ Example playbook to ensure host presence:
- "52:54:00:BD:97:1E"
state: present
```
Compared to `ipa host-add` command no IP address conflict check is done as the ipahost module supports to have several IPv4 and IPv6 addresses for a host.
Example playbook to ensure host presence with several IP addresses:
```yaml
---
- name: Playbook to handle hosts
hosts: ipaserver
become: true
tasks:
# Ensure host is present
- ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
description: Example host
ip_address:
- 192.168.0.123
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b3
- fe80::20c:29ff:fe02:a1b4
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
```
Example playbook to ensure IP addresses are present for a host:
```yaml
---
- name: Playbook to handle hosts
hosts: ipaserver
become: true
tasks:
# Ensure host is present
- ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
ip_address:
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b4
action: member
state: present
```
Example playbook to ensure IP addresses are absent for a host:
```yaml
---
- name: Playbook to handle hosts
hosts: ipaserver
become: true
tasks:
# Ensure host is present
- ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
ip_address:
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b4
action: member
state: absent
```
Example playbook to ensure host presence without DNS:
@@ -215,7 +288,7 @@ Example playbook to disable a host:
update_dns: yes
state: disabled
```
`update_dns` controls if the DNS entries will be updated.
`update_dns` controls if the DNS entries will be updated in this case. For `state` present it is controlling the update of the DNS SSHFP records, but not the the other DNS records.
Example playbook to ensure a host is absent:
@@ -286,8 +359,8 @@ Variable | Description | Required
`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
`ip_address` \| `ipaddress` | The host IP address list. It can contain IPv4 and IPv6 addresses. No conflict check for IP addresses is done. | no
`update_dns` | For existing hosts: DNS SSHFP records are updated with `state` present and all DNS entries for a host removed with `state` absent. | no
Return Values

View File

@@ -0,0 +1,17 @@
---
- name: Host member IP addresses absent
hosts: ipaserver
become: true
tasks:
- name: Ensure host01.example.com IP addresses absent
ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
ip_address:
- 192.168.0.123
- fe80::20c:29ff:fe02:a1b3
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b4
action: member
state: absent

View File

@@ -0,0 +1,16 @@
---
- name: Host member IP addresses present
hosts: ipaserver
become: true
tasks:
- name: Ensure host01.example.com IP addresses present
ipahost:
ipaadmin_password: MyPassword123
name: host01.example.com
ip_address:
- 192.168.0.123
- fe80::20c:29ff:fe02:a1b3
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b4
action: member

View File

@@ -0,0 +1,24 @@
---
- name: Host present with several IP addresses
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
- fe80::20c:29ff:fe02:a1b3
- 192.168.0.124
- fe80::20c:29ff:fe02:a1b4
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

View File

@@ -42,6 +42,7 @@ try:
from ipalib.x509 import Encoding
except ImportError:
from cryptography.hazmat.primitives.serialization import Encoding
import socket
import base64
import six
@@ -285,3 +286,25 @@ def encode_certificate(cert):
if not six.PY2:
encoded = encoded.decode('ascii')
return encoded
def is_ipv4_addr(ipaddr):
"""
Test if figen IP address is a valid IPv4 address
"""
try:
socket.inet_pton(socket.AF_INET, ipaddr)
except socket.error:
return False
return True
def is_ipv6_addr(ipaddr):
"""
Test if figen IP address is a valid IPv6 address
"""
try:
socket.inet_pton(socket.AF_INET6, ipaddr)
except socket.error:
return False
return True

View File

@@ -176,11 +176,16 @@ options:
default: true
required: false
ip_address:
description: The host IP address
description:
The host IP address list (IPv4 and IPv6). No IP address conflict
check will be done.
aliases: ["ipaddress"]
required: false
update_dns:
description: Update DNS entries
description:
Controls the update of the DNS SSHFP records for existing hosts and
the removal of all DNS entries if a host gets removed with state
absent.
required: false
description:
description: The host description
@@ -306,11 +311,16 @@ options:
default: true
required: false
ip_address:
description: The host IP address
description:
The host IP address list (IPv4 and IPv6). No IP address conflict
check will be done.
aliases: ["ipaddress"]
required: false
update_dns:
description: Update DNS entries
description:
Controls the update of the DNS SSHFP records for existing hosts and
the removal of all DNS entries if a host gets removed with state
absent.
required: false
update_password:
description:
@@ -398,7 +408,8 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
temp_kdestroy, valid_creds, api_connect, api_command, compare_args_ipa, \
module_params_get, gen_add_del_lists, encode_certificate, api_get_realm
module_params_get, gen_add_del_lists, encode_certificate, api_get_realm, \
is_ipv4_addr, is_ipv6_addr
import six
@@ -428,6 +439,32 @@ def find_host(module, name):
return None
def find_dnsrecord(module, name):
domain_name = name[name.find(".")+1:]
host_name = name[:name.find(".")]
_args = {
"all": True,
"idnsname": to_text(host_name),
}
_result = api_command(module, "dnsrecord_find", to_text(domain_name),
_args)
if len(_result["result"]) > 1:
module.fail_json(
msg="There is more than one host '%s'" % (name))
elif len(_result["result"]) == 1:
_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
def show_host(module, name):
_result = api_command(module, "host_show", to_text(name), {})
return _result["result"]
@@ -470,16 +507,34 @@ def gen_args(description, locality, location, platform, os, password, random,
_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
# IP addresses are handed extra, therefore it is needed to set
# the force option here to make sure that host-add is able to
# add a host without IP address.
_args["force"] = True
if update_dns is not None:
_args["updatedns"] = update_dns
return _args
def gen_dnsrecord_args(module, ip_address, reverse):
_args = {}
if reverse is not None:
_args["a_extra_create_reverse"] = reverse
_args["aaaa_extra_create_reverse"] = reverse
if ip_address is not None:
for ip in ip_address:
if is_ipv4_addr(ip):
_args.setdefault("arecord", []).append(ip)
elif is_ipv6_addr(ip):
_args.setdefault("aaaarecord", []).append(ip)
else:
module.fail_json(msg="'%s' is not a valid IP address." % ip)
return _args
def check_parameters(
module, state, action,
description, locality, location, platform, os, password, random,
@@ -499,8 +554,7 @@ def check_parameters(
"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"]
"reverse", "update_dns", "update_password"]
for x in invalid:
if vars()[x] is not None:
module.fail_json(
@@ -512,7 +566,7 @@ def check_parameters(
"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"]
"reverse", "update_password"]
for x in invalid:
if vars()[x] is not None:
module.fail_json(
@@ -549,9 +603,6 @@ def main():
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",
@@ -608,7 +659,7 @@ def main():
default=None),
force=dict(type='bool', default=None),
reverse=dict(type='bool', default=None),
ip_address=dict(type="str", aliases=["ipaddress"],
ip_address=dict(type="list", aliases=["ipaddress"],
default=None),
update_dns=dict(type="bool", aliases=["updatedns"],
default=None),
@@ -820,6 +871,7 @@ def main():
# Make sure host exists
res_find = find_host(ansible_module, name)
res_find_dnsrecord = find_dnsrecord(ansible_module, name)
# Create command
if state == "present":
@@ -829,6 +881,8 @@ def main():
random, mac_address, sshpubkey, userclass, auth_ind,
requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
force, reverse, ip_address, update_dns)
dnsrecord_args = gen_dnsrecord_args(
ansible_module, ip_address, reverse)
if action == "host":
# Found the host
@@ -938,39 +992,20 @@ def main():
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 = []
# IP addresses are not really a member of hosts, but
# we will simply treat it as this to enable the
# addition and removal of IPv4 and IPv6 addresses in
# a simple way.
_dnsrec = res_find_dnsrecord or {}
dnsrecord_a_add, dnsrecord_a_del = gen_add_del_lists(
dnsrecord_args.get("arecord"),
_dnsrec.get("arecord"))
dnsrecord_aaaa_add, dnsrecord_aaaa_del = \
gen_add_del_lists(
dnsrecord_args.get("aaaarecord"),
_dnsrec.get("aaaarecord"))
else:
if action != "host" or (action == "host" and res_find is None):
certificate_add = certificate or []
certificate_del = []
managedby_host_add = managedby_host or []
@@ -1001,6 +1036,10 @@ def main():
allow_retrieve_keytab_hostgroup_add = \
allow_retrieve_keytab_hostgroup or []
allow_retrieve_keytab_hostgroup_del = []
dnsrecord_a_add = dnsrecord_args.get("arecord") or []
dnsrecord_a_del = []
dnsrecord_aaaa_add = dnsrecord_args.get("aaaarecord") or []
dnsrecord_aaaa_del = []
# Remove canonical principal from principal_del
canonical_principal = "host/" + name + "@" + server_realm
@@ -1135,6 +1174,36 @@ def main():
"hostgroup": allow_retrieve_keytab_hostgroup_del,
}])
if len(dnsrecord_a_add) > 0 or len(dnsrecord_aaaa_add) > 0:
domain_name = name[name.find(".")+1:]
host_name = name[:name.find(".")]
commands.append([domain_name,
"dnsrecord_add",
{
"idnsname": host_name,
"arecord": dnsrecord_a_add,
"a_extra_create_reverse": reverse,
"aaaarecord": dnsrecord_aaaa_add,
"aaaa_extra_create_reverse": reverse
}])
if len(dnsrecord_a_del) > 0 or len(dnsrecord_aaaa_del) > 0:
domain_name = name[name.find(".")+1:]
host_name = name[:name.find(".")]
# There seems to be an issue with dnsrecord_del (not
# for dnsrecord_add) if aaaarecord is an empty list.
# Therefore this is done differently here:
_args = {"idnsname": host_name}
if len(dnsrecord_a_del) > 0:
_args["arecord"] = dnsrecord_a_del
if len(dnsrecord_aaaa_del) > 0:
_args["aaaarecord"] = dnsrecord_aaaa_del
commands.append([domain_name,
"dnsrecord_del", _args])
elif state == "absent":
if action == "host":
@@ -1215,6 +1284,17 @@ def main():
"hostgroup": allow_retrieve_keytab_hostgroup,
}])
dnsrecord_args = gen_dnsrecord_args(ansible_module,
ip_address, reverse)
if "arecord" in dnsrecord_args or \
"aaaarecord" in dnsrecord_args:
domain_name = name[name.find(".")+1:]
host_name = name[:name.find(".")]
dnsrecord_args["idnsname"] = host_name
commands.append([domain_name, "dnsrecord_del",
dnsrecord_args])
elif state == "disabled":
if res_find is not None:
commands.append([name, "host_disable", {}])
@@ -1259,6 +1339,11 @@ def main():
# Host is already disabled, ignore error
if "This entry is already disabled" in msg:
continue
# Ignore no modification error.
if "no modifications to be performed" in msg:
continue
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
msg))

View File

@@ -129,7 +129,7 @@
- name: Host "{{ host5_fqdn }}" present again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
name: "{{ host5_fqdn }}"
ip_address: "{{ ipv4_prefix + '.205' }}"
update_dns: yes
reverse: no

View File

@@ -0,0 +1,312 @@
---
- name: Test host IP addresses
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 }}"
- name: Get IPv4 address prefix from server node
set_fact:
ipv4_prefix: "{{ ansible_default_ipv4.address.split('.')[:-1] |
join('.') }}"
- name: Host absent
ipahost:
ipaadmin_password: MyPassword123
name:
- "{{ host1_fqdn }}"
- "{{ host2_fqdn }}"
- "{{ host3_fqdn }}"
update_dns: yes
state: absent
- name: Host "{{ host1_fqdn }}" present
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.201' }}"
- fe80::20c:29ff:fe02:a1b2
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' }}"
- fe80::20c:29ff:fe02:a1b2
update_dns: yes
reverse: no
register: result
failed_when: result.changed
- name: Host "{{ host1_fqdn }}" present again with new IP address
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
update_dns: yes
reverse: no
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" present again with new IP address again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
update_dns: yes
reverse: no
register: result
failed_when: result.changed
- name: Host "{{ host1_fqdn }}" member IPv4 address present
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: "{{ ipv4_prefix + '.201' }}"
action: member
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" member IPv4 address present again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: "{{ ipv4_prefix + '.201' }}"
action: member
register: result
failed_when: result.changed
- name: Host "{{ host1_fqdn }}" member IPv4 address absent
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: "{{ ipv4_prefix + '.201' }}"
action: member
state: absent
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" member IPv4 address absent again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: "{{ ipv4_prefix + '.201' }}"
action: member
state: absent
register: result
failed_when: result.changed
- name: Host "{{ host1_fqdn }}" member IPv6 address present
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: fe80::20c:29ff:fe02:a1b2
action: member
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" member IPv6 address present again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: fe80::20c:29ff:fe02:a1b2
action: member
register: result
failed_when: result.changed
- name: Host "{{ host1_fqdn }}" member IPv6 address absent
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: fe80::20c:29ff:fe02:a1b2
action: member
state: absent
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" member IPv6 address absent again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address: fe80::20c:29ff:fe02:a1b2
action: member
state: absent
register: result
- name: Host "{{ host1_fqdn }}" member all ip-addresses absent
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
action: member
state: absent
register: result
failed_when: not result.changed
- name: Host "{{ host1_fqdn }}" all member ip-addresses absent again
ipahost:
ipaadmin_password: MyPassword123
name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
action: member
state: absent
register: result
failed_when: result.changed
- name: Hosts "{{ host1_fqdn }}" and "{{ host2_fqdn }}" present with same IP addresses
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
- name: "{{ host2_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: not result.changed
- name: Hosts "{{ host1_fqdn }}" and "{{ host2_fqdn }}" present with same IP addresses again
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host1_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
- name: "{{ host2_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: result.changed
- name: Hosts "{{ host3_fqdn }}" present with same IP addresses
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: not result.changed
- name: Hosts "{{ host3_fqdn }}" present with same IP addresses again
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: result.changed
- name: Host "{{ host3_fqdn }}" present with differnt IP addresses
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.111' }}"
- fe80::20c:29ff:fe02:a1b1
- "{{ ipv4_prefix + '.121' }}"
- fe80::20c:29ff:fe02:a1b2
register: result
failed_when: not result.changed
- name: Host "{{ host3_fqdn }}" present with different IP addresses again
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.111' }}"
- fe80::20c:29ff:fe02:a1b1
- "{{ ipv4_prefix + '.121' }}"
- fe80::20c:29ff:fe02:a1b2
register: result
failed_when: result.changed
- name: Host "{{ host3_fqdn }}" present with old IP addresses
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: not result.changed
- name: Host "{{ host3_fqdn }}" present with old IP addresses again
ipahost:
ipaadmin_password: MyPassword123
hosts:
- name: "{{ host3_fqdn }}"
ip_address:
- "{{ ipv4_prefix + '.211' }}"
- fe80::20c:29ff:fe02:a1b3
- "{{ ipv4_prefix + '.221' }}"
- fe80::20c:29ff:fe02:a1b4
register: result
failed_when: result.changed
- name: Host absent
ipahost:
ipaadmin_password: MyPassword123
name:
- "{{ host1_fqdn }}"
- "{{ host2_fqdn }}"
- "{{ host3_fqdn }}"
update_dns: yes
state: absent