mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-08-05 22:34:40 +00:00
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:
@@ -65,6 +65,79 @@ Example playbook to ensure host presence:
|
|||||||
- "52:54:00:BD:97:1E"
|
- "52:54:00:BD:97:1E"
|
||||||
state: present
|
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:
|
Example playbook to ensure host presence without DNS:
|
||||||
@@ -215,7 +288,7 @@ Example playbook to disable a host:
|
|||||||
update_dns: yes
|
update_dns: yes
|
||||||
state: disabled
|
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:
|
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
|
`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
|
`force` | Force host name even if not in DNS. | no
|
||||||
`reverse` | Reverse DNS detection. | no
|
`reverse` | Reverse DNS detection. | no
|
||||||
`ip_address` \| `ipaddress` | The host IP address. | 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` | Update DNS entries. | 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
|
Return Values
|
||||||
|
|||||||
17
playbooks/host/host-member-ipaddresses-absent.yml
Normal file
17
playbooks/host/host-member-ipaddresses-absent.yml
Normal 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
|
||||||
16
playbooks/host/host-member-ipaddresses-present.yml
Normal file
16
playbooks/host/host-member-ipaddresses-present.yml
Normal 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
|
||||||
24
playbooks/host/host-present-with-several-ip-addresses.yml
Normal file
24
playbooks/host/host-present-with-several-ip-addresses.yml
Normal 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
|
||||||
@@ -42,6 +42,7 @@ try:
|
|||||||
from ipalib.x509 import Encoding
|
from ipalib.x509 import Encoding
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from cryptography.hazmat.primitives.serialization import Encoding
|
from cryptography.hazmat.primitives.serialization import Encoding
|
||||||
|
import socket
|
||||||
import base64
|
import base64
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@@ -285,3 +286,25 @@ def encode_certificate(cert):
|
|||||||
if not six.PY2:
|
if not six.PY2:
|
||||||
encoded = encoded.decode('ascii')
|
encoded = encoded.decode('ascii')
|
||||||
return encoded
|
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
|
||||||
|
|||||||
@@ -176,11 +176,16 @@ options:
|
|||||||
default: true
|
default: true
|
||||||
required: false
|
required: false
|
||||||
ip_address:
|
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"]
|
aliases: ["ipaddress"]
|
||||||
required: false
|
required: false
|
||||||
update_dns:
|
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
|
required: false
|
||||||
description:
|
description:
|
||||||
description: The host description
|
description: The host description
|
||||||
@@ -306,11 +311,16 @@ options:
|
|||||||
default: true
|
default: true
|
||||||
required: false
|
required: false
|
||||||
ip_address:
|
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"]
|
aliases: ["ipaddress"]
|
||||||
required: false
|
required: false
|
||||||
update_dns:
|
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
|
required: false
|
||||||
update_password:
|
update_password:
|
||||||
description:
|
description:
|
||||||
@@ -398,7 +408,8 @@ from ansible.module_utils.basic import AnsibleModule
|
|||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
|
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
|
module_params_get, gen_add_del_lists, encode_certificate, api_get_realm, \
|
||||||
|
is_ipv4_addr, is_ipv6_addr
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
|
||||||
@@ -428,6 +439,32 @@ def find_host(module, name):
|
|||||||
return None
|
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):
|
def show_host(module, name):
|
||||||
_result = api_command(module, "host_show", to_text(name), {})
|
_result = api_command(module, "host_show", to_text(name), {})
|
||||||
return _result["result"]
|
return _result["result"]
|
||||||
@@ -470,16 +507,34 @@ def gen_args(description, locality, location, platform, os, password, random,
|
|||||||
_args["ipakrboktoauthasdelegate"] = ok_to_auth_as_delegate
|
_args["ipakrboktoauthasdelegate"] = ok_to_auth_as_delegate
|
||||||
if force is not None:
|
if force is not None:
|
||||||
_args["force"] = force
|
_args["force"] = force
|
||||||
if reverse is not None:
|
|
||||||
_args["no_reverse"] = not reverse
|
|
||||||
if ip_address is not None:
|
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:
|
if update_dns is not None:
|
||||||
_args["updatedns"] = update_dns
|
_args["updatedns"] = update_dns
|
||||||
|
|
||||||
return _args
|
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(
|
def check_parameters(
|
||||||
module, state, action,
|
module, state, action,
|
||||||
description, locality, location, platform, os, password, random,
|
description, locality, location, platform, os, password, random,
|
||||||
@@ -499,8 +554,7 @@ def check_parameters(
|
|||||||
"os", "password", "random", "mac_address", "sshpubkey",
|
"os", "password", "random", "mac_address", "sshpubkey",
|
||||||
"userclass", "auth_ind", "requires_pre_auth",
|
"userclass", "auth_ind", "requires_pre_auth",
|
||||||
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
||||||
"reverse", "ip_address", "update_dns",
|
"reverse", "update_dns", "update_password"]
|
||||||
"update_password"]
|
|
||||||
for x in invalid:
|
for x in invalid:
|
||||||
if vars()[x] is not None:
|
if vars()[x] is not None:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
@@ -512,7 +566,7 @@ def check_parameters(
|
|||||||
"password", "random", "mac_address", "sshpubkey",
|
"password", "random", "mac_address", "sshpubkey",
|
||||||
"userclass", "auth_ind", "requires_pre_auth",
|
"userclass", "auth_ind", "requires_pre_auth",
|
||||||
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
||||||
"reverse", "ip_address", "update_password"]
|
"reverse", "update_password"]
|
||||||
for x in invalid:
|
for x in invalid:
|
||||||
if vars()[x] is not None:
|
if vars()[x] is not None:
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
@@ -549,9 +603,6 @@ def main():
|
|||||||
default=None, no_log=True),
|
default=None, no_log=True),
|
||||||
random=dict(type="bool", aliases=["random_password"],
|
random=dict(type="bool", aliases=["random_password"],
|
||||||
default=None),
|
default=None),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
certificate=dict(type="list", aliases=["usercertificate"],
|
certificate=dict(type="list", aliases=["usercertificate"],
|
||||||
default=None),
|
default=None),
|
||||||
managedby_host=dict(type="list",
|
managedby_host=dict(type="list",
|
||||||
@@ -608,7 +659,7 @@ def main():
|
|||||||
default=None),
|
default=None),
|
||||||
force=dict(type='bool', default=None),
|
force=dict(type='bool', default=None),
|
||||||
reverse=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),
|
default=None),
|
||||||
update_dns=dict(type="bool", aliases=["updatedns"],
|
update_dns=dict(type="bool", aliases=["updatedns"],
|
||||||
default=None),
|
default=None),
|
||||||
@@ -820,6 +871,7 @@ def main():
|
|||||||
|
|
||||||
# Make sure host exists
|
# Make sure host exists
|
||||||
res_find = find_host(ansible_module, name)
|
res_find = find_host(ansible_module, name)
|
||||||
|
res_find_dnsrecord = find_dnsrecord(ansible_module, name)
|
||||||
|
|
||||||
# Create command
|
# Create command
|
||||||
if state == "present":
|
if state == "present":
|
||||||
@@ -829,6 +881,8 @@ def main():
|
|||||||
random, mac_address, sshpubkey, userclass, auth_ind,
|
random, mac_address, sshpubkey, userclass, auth_ind,
|
||||||
requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
|
requires_pre_auth, ok_as_delegate, ok_to_auth_as_delegate,
|
||||||
force, reverse, ip_address, update_dns)
|
force, reverse, ip_address, update_dns)
|
||||||
|
dnsrecord_args = gen_dnsrecord_args(
|
||||||
|
ansible_module, ip_address, reverse)
|
||||||
|
|
||||||
if action == "host":
|
if action == "host":
|
||||||
# Found the host
|
# Found the host
|
||||||
@@ -938,39 +992,20 @@ def main():
|
|||||||
res_find.get(
|
res_find.get(
|
||||||
"ipaallowedtoperform_read_keys_hostgroup"))
|
"ipaallowedtoperform_read_keys_hostgroup"))
|
||||||
|
|
||||||
else:
|
# IP addresses are not really a member of hosts, but
|
||||||
certificate_add = certificate or []
|
# we will simply treat it as this to enable the
|
||||||
certificate_del = []
|
# addition and removal of IPv4 and IPv6 addresses in
|
||||||
managedby_host_add = managedby_host or []
|
# a simple way.
|
||||||
managedby_host_del = []
|
_dnsrec = res_find_dnsrecord or {}
|
||||||
principal_add = principal or []
|
dnsrecord_a_add, dnsrecord_a_del = gen_add_del_lists(
|
||||||
principal_del = []
|
dnsrecord_args.get("arecord"),
|
||||||
allow_create_keytab_user_add = \
|
_dnsrec.get("arecord"))
|
||||||
allow_create_keytab_user or []
|
dnsrecord_aaaa_add, dnsrecord_aaaa_del = \
|
||||||
allow_create_keytab_user_del = []
|
gen_add_del_lists(
|
||||||
allow_create_keytab_group_add = \
|
dnsrecord_args.get("aaaarecord"),
|
||||||
allow_create_keytab_group or []
|
_dnsrec.get("aaaarecord"))
|
||||||
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 = []
|
|
||||||
|
|
||||||
else:
|
if action != "host" or (action == "host" and res_find is None):
|
||||||
certificate_add = certificate or []
|
certificate_add = certificate or []
|
||||||
certificate_del = []
|
certificate_del = []
|
||||||
managedby_host_add = managedby_host or []
|
managedby_host_add = managedby_host or []
|
||||||
@@ -1001,6 +1036,10 @@ def main():
|
|||||||
allow_retrieve_keytab_hostgroup_add = \
|
allow_retrieve_keytab_hostgroup_add = \
|
||||||
allow_retrieve_keytab_hostgroup or []
|
allow_retrieve_keytab_hostgroup or []
|
||||||
allow_retrieve_keytab_hostgroup_del = []
|
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
|
# Remove canonical principal from principal_del
|
||||||
canonical_principal = "host/" + name + "@" + server_realm
|
canonical_principal = "host/" + name + "@" + server_realm
|
||||||
@@ -1135,6 +1174,36 @@ def main():
|
|||||||
"hostgroup": allow_retrieve_keytab_hostgroup_del,
|
"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":
|
elif state == "absent":
|
||||||
if action == "host":
|
if action == "host":
|
||||||
|
|
||||||
@@ -1215,6 +1284,17 @@ def main():
|
|||||||
"hostgroup": allow_retrieve_keytab_hostgroup,
|
"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":
|
elif state == "disabled":
|
||||||
if res_find is not None:
|
if res_find is not None:
|
||||||
commands.append([name, "host_disable", {}])
|
commands.append([name, "host_disable", {}])
|
||||||
@@ -1259,6 +1339,11 @@ def main():
|
|||||||
# Host is already disabled, ignore error
|
# Host is already disabled, ignore error
|
||||||
if "This entry is already disabled" in msg:
|
if "This entry is already disabled" in msg:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Ignore no modification error.
|
||||||
|
if "no modifications to be performed" in msg:
|
||||||
|
continue
|
||||||
|
|
||||||
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
|
ansible_module.fail_json(msg="%s: %s: %s" % (command, name,
|
||||||
msg))
|
msg))
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@
|
|||||||
- name: Host "{{ host5_fqdn }}" present again
|
- name: Host "{{ host5_fqdn }}" present again
|
||||||
ipahost:
|
ipahost:
|
||||||
ipaadmin_password: MyPassword123
|
ipaadmin_password: MyPassword123
|
||||||
name: "{{ host1_fqdn }}"
|
name: "{{ host5_fqdn }}"
|
||||||
ip_address: "{{ ipv4_prefix + '.205' }}"
|
ip_address: "{{ ipv4_prefix + '.205' }}"
|
||||||
update_dns: yes
|
update_dns: yes
|
||||||
reverse: no
|
reverse: no
|
||||||
|
|||||||
312
tests/host/test_host_ipaddresses.yml
Normal file
312
tests/host/test_host_ipaddresses.yml
Normal 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
|
||||||
Reference in New Issue
Block a user