import ansible-freeipa-0.1.12-6.el8
This commit is contained in:
parent
0695dc66b6
commit
d2eec6cc08
@ -1 +1 @@
|
||||
583ac570c030eb68a2026a506054f2f93587beb4 SOURCES/ansible-freeipa-0.1.8.tar.gz
|
||||
5d09d3b590e8568d04edb288c9c515e308f3168f SOURCES/ansible-freeipa-0.1.12.tar.gz
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/ansible-freeipa-0.1.8.tar.gz
|
||||
SOURCES/ansible-freeipa-0.1.12.tar.gz
|
||||
|
@ -0,0 +1,556 @@
|
||||
From abbd15e6f50718119b4dd0380913d2d646eb7638 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Mon, 3 Aug 2020 19:23:07 -0300
|
||||
Subject: [PATCH] Add support for option `name_from_ip` in ipadnszone module.
|
||||
|
||||
IPA CLI has an option `name_from_ip` that provide a name for a zone
|
||||
from the reverse IP address, so that it can be used to, for example,
|
||||
manage PTR DNS records.
|
||||
|
||||
This patch adds a similar attribute to ipadnszone module, where it
|
||||
will try to find the proper zone name, using DNS resolve, or provide
|
||||
a sane default, if a the zone name cannot be resolved.
|
||||
|
||||
The option `name_from_ip` must be used instead of `name` in playbooks,
|
||||
and it is a string, and not a list.
|
||||
|
||||
A new example playbook was added:
|
||||
|
||||
playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
|
||||
A new test playbook was added:
|
||||
|
||||
tests/dnszone/test_dnszone_name_from_ip.yml
|
||||
---
|
||||
README-dnszone.md | 3 +-
|
||||
playbooks/dnszone/dnszone-reverse-from-ip.yml | 10 ++
|
||||
plugins/modules/ipadnszone.py | 65 +++++++++-
|
||||
tests/dnszone/test_dnszone_name_from_ip.yml | 112 ++++++++++++++++++
|
||||
4 files changed, 186 insertions(+), 4 deletions(-)
|
||||
create mode 100644 playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
create mode 100644 tests/dnszone/test_dnszone_name_from_ip.yml
|
||||
|
||||
diff --git a/README-dnszone.md b/README-dnszone.md
|
||||
index 9c9b12c..48b019a 100644
|
||||
--- a/README-dnszone.md
|
||||
+++ b/README-dnszone.md
|
||||
@@ -163,7 +163,8 @@ Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
-`name` \| `zone_name` | The zone name string or list of strings. | yes
|
||||
+`name` \| `zone_name` | The zone name string or list of strings. | no
|
||||
+`name_from_ip` | Derive zone name from reverse of IP (PTR). | no
|
||||
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
|
||||
| `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
|
||||
| `port` - The custom port that should be used on this server. | no
|
||||
diff --git a/playbooks/dnszone/dnszone-reverse-from-ip.yml b/playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
new file mode 100644
|
||||
index 0000000..5693872
|
||||
--- /dev/null
|
||||
+++ b/playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
@@ -0,0 +1,10 @@
|
||||
+---
|
||||
+- name: Playbook to ensure DNS zone exist
|
||||
+ hosts: ipaserver
|
||||
+ become: true
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: Ensure zone exist, finding zone name from IP address.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 10.1.2.3
|
||||
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
|
||||
index c5e812a..901bfef 100644
|
||||
--- a/plugins/modules/ipadnszone.py
|
||||
+++ b/plugins/modules/ipadnszone.py
|
||||
@@ -43,6 +43,10 @@ options:
|
||||
required: true
|
||||
type: list
|
||||
alises: ["zone_name"]
|
||||
+ name_from_ip:
|
||||
+ description: Derive zone name from reverse of IP (PTR).
|
||||
+ required: false
|
||||
+ type: str
|
||||
forwarders:
|
||||
description: The list of global DNS forwarders.
|
||||
required: false
|
||||
@@ -197,6 +201,12 @@ from ansible.module_utils.ansible_freeipa_module import (
|
||||
is_ipv6_addr,
|
||||
is_valid_port,
|
||||
) # noqa: E402
|
||||
+import netaddr
|
||||
+import six
|
||||
+
|
||||
+
|
||||
+if six.PY3:
|
||||
+ unicode = str
|
||||
|
||||
|
||||
class DNSZoneModule(FreeIPABaseModule):
|
||||
@@ -354,6 +364,31 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
if not zone and self.ipa_params.skip_nameserver_check is not None:
|
||||
return self.ipa_params.skip_nameserver_check
|
||||
|
||||
+ def __reverse_zone_name(self, ipaddress):
|
||||
+ """
|
||||
+ Infer reverse zone name from an ip address.
|
||||
+
|
||||
+ This function uses the same heuristics as FreeIPA to infer the zone
|
||||
+ name from ip.
|
||||
+ """
|
||||
+ try:
|
||||
+ ip = netaddr.IPAddress(str(ipaddress))
|
||||
+ except (netaddr.AddrFormatError, ValueError):
|
||||
+ net = netaddr.IPNetwork(ipaddress)
|
||||
+ items = net.ip.reverse_dns.split('.')
|
||||
+ prefixlen = net.prefixlen
|
||||
+ ip_version = net.version
|
||||
+ else:
|
||||
+ items = ip.reverse_dns.split('.')
|
||||
+ prefixlen = 24 if ip.version == 4 else 64
|
||||
+ ip_version = ip.version
|
||||
+ if ip_version == 4:
|
||||
+ return u'.'.join(items[4 - prefixlen // 8:])
|
||||
+ elif ip_version == 6:
|
||||
+ return u'.'.join(items[32 - prefixlen // 4:])
|
||||
+ else:
|
||||
+ self.fail_json(msg="Invalid IP version for reverse zone.")
|
||||
+
|
||||
def get_zone(self, zone_name):
|
||||
get_zone_args = {"idnsname": zone_name, "all": True}
|
||||
response = self.api_command("dnszone_find", args=get_zone_args)
|
||||
@@ -368,14 +403,33 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
return zone, is_zone_active
|
||||
|
||||
def get_zone_names(self):
|
||||
- if len(self.ipa_params.name) > 1 and self.ipa_params.state != "absent":
|
||||
+ zone_names = self.__get_zone_names_from_params()
|
||||
+ if len(zone_names) > 1 and self.ipa_params.state != "absent":
|
||||
self.fail_json(
|
||||
msg=("Please provide a single name. Multiple values for 'name'"
|
||||
"can only be supplied for state 'absent'.")
|
||||
)
|
||||
|
||||
+ return zone_names
|
||||
+
|
||||
+ def __get_zone_names_from_params(self):
|
||||
+ if not self.ipa_params.name:
|
||||
+ return [self.__reverse_zone_name(self.ipa_params.name_from_ip)]
|
||||
return self.ipa_params.name
|
||||
|
||||
+ def check_ipa_params(self):
|
||||
+ if not self.ipa_params.name and not self.ipa_params.name_from_ip:
|
||||
+ self.fail_json(
|
||||
+ msg="Either `name` or `name_from_ip` must be provided."
|
||||
+ )
|
||||
+ if self.ipa_params.state != "present" and self.ipa_params.name_from_ip:
|
||||
+ self.fail_json(
|
||||
+ msg=(
|
||||
+ "Cannot use argument `name_from_ip` with state `%s`."
|
||||
+ % self.ipa_params.state
|
||||
+ )
|
||||
+ )
|
||||
+
|
||||
def define_ipa_commands(self):
|
||||
for zone_name in self.get_zone_names():
|
||||
# Look for existing zone in IPA
|
||||
@@ -434,8 +488,9 @@ def get_argument_spec():
|
||||
ipaadmin_principal=dict(type="str", default="admin"),
|
||||
ipaadmin_password=dict(type="str", required=False, no_log=True),
|
||||
name=dict(
|
||||
- type="list", default=None, required=True, aliases=["zone_name"]
|
||||
+ type="list", default=None, required=False, aliases=["zone_name"]
|
||||
),
|
||||
+ name_from_ip=dict(type="str", default=None, required=False),
|
||||
forwarders=dict(
|
||||
type="list",
|
||||
default=None,
|
||||
@@ -475,7 +530,11 @@ def get_argument_spec():
|
||||
|
||||
|
||||
def main():
|
||||
- DNSZoneModule(argument_spec=get_argument_spec()).ipa_run()
|
||||
+ DNSZoneModule(
|
||||
+ argument_spec=get_argument_spec(),
|
||||
+ mutually_exclusive=[["name", "name_from_ip"]],
|
||||
+ required_one_of=[["name", "name_from_ip"]],
|
||||
+ ).ipa_run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
diff --git a/tests/dnszone/test_dnszone_name_from_ip.yml b/tests/dnszone/test_dnszone_name_from_ip.yml
|
||||
new file mode 100644
|
||||
index 0000000..9bd2eb0
|
||||
--- /dev/null
|
||||
+++ b/tests/dnszone/test_dnszone_name_from_ip.yml
|
||||
@@ -0,0 +1,112 @@
|
||||
+---
|
||||
+- name: Test dnszone
|
||||
+ hosts: ipaserver
|
||||
+ become: yes
|
||||
+ gather_facts: yes
|
||||
+
|
||||
+ tasks:
|
||||
+
|
||||
+ # Setup
|
||||
+ - name: Ensure zone is absent.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ item }}"
|
||||
+ state: absent
|
||||
+ with_items:
|
||||
+ - 2.0.192.in-addr.arpa.
|
||||
+ - 0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa.
|
||||
+ - 1.0.0.0.e.f.a.c.8.b.d.0.1.0.0.2.ip6.arpa.
|
||||
+
|
||||
+ # tests
|
||||
+ - name: Ensure zone exists for reverse IP.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.0.2.3/24
|
||||
+ register: ipv4_zone
|
||||
+ failed_when: not ipv4_zone.changed or ipv4_zone.failed
|
||||
+
|
||||
+ - name: Ensure zone exists for reverse IP, again.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.0.2.3/24
|
||||
+ register: result
|
||||
+ failed_when: result.changed or result.failed
|
||||
+
|
||||
+ - name: Ensure zone exists for reverse IP, given the zone name.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ ipv4_zone.dnszone.name }}"
|
||||
+ register: result
|
||||
+ failed_when: result.changed or result.failed
|
||||
+
|
||||
+ - name: Modify existing zone, using `name_from_ip`.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.0.2.3/24
|
||||
+ default_ttl: 1234
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Modify existing zone, using `name_from_ip`, again.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.0.2.3/24
|
||||
+ default_ttl: 1234
|
||||
+ register: result
|
||||
+ failed_when: result.changed or result.failed
|
||||
+
|
||||
+ - name: Ensure ipv6 zone exists for reverse IPv6.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: fd00::0001
|
||||
+ register: ipv6_zone
|
||||
+ failed_when: not ipv6_zone.changed or ipv6_zone.failed
|
||||
+
|
||||
+ # - debug:
|
||||
+ # msg: "{{ipv6_zone}}"
|
||||
+
|
||||
+ - name: Ensure ipv6 zone was created.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ ipv6_zone.dnszone.name }}"
|
||||
+ register: result
|
||||
+ failed_when: result.changed or result.failed
|
||||
+
|
||||
+ - name: Ensure ipv6 zone exists for reverse IPv6, again.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: fd00::0001
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Ensure second ipv6 zone exists for reverse IPv6.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 2001:db8:cafe:1::1
|
||||
+ register: ipv6_sec_zone
|
||||
+ failed_when: not ipv6_sec_zone.changed or ipv6_zone.failed
|
||||
+
|
||||
+ - name: Ensure second ipv6 zone was created.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ ipv6_sec_zone.dnszone.name }}"
|
||||
+ register: result
|
||||
+ failed_when: result.changed or result.failed
|
||||
+
|
||||
+ - name: Ensure second ipv6 zone exists for reverse IPv6, again.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 2001:db8:cafe:1::1
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ # Cleanup
|
||||
+ - name: Ensure zone is absent.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ item }}"
|
||||
+ state: absent
|
||||
+ with_items:
|
||||
+ - "{{ ipv6_zone.dnszone.name }}"
|
||||
+ - "{{ ipv6_sec_zone.dnszone.name }}"
|
||||
+ - "{{ ipv4_zone.dnszone.name }}"
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 531e544b30e69f436d14c4ce18c67998c1a0774b Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Wed, 5 Aug 2020 15:13:46 -0300
|
||||
Subject: [PATCH] Added support for client defined result data in
|
||||
FReeIPABaseModule
|
||||
|
||||
Modified support for processing result of IPA API commands so that
|
||||
client code can define its own processing and add return values to
|
||||
self.exit_args based on command result.
|
||||
|
||||
If a subclass need to process the result of IPA API commands it should
|
||||
override the method `process_command_result`. The default implementation
|
||||
will simply evaluate if `changed` should be true.
|
||||
---
|
||||
.../module_utils/ansible_freeipa_module.py | 22 +++++++++++++------
|
||||
plugins/modules/ipadnszone.py | 8 +++++++
|
||||
2 files changed, 23 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 4799e5a..30302b4 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -619,7 +619,7 @@ class FreeIPABaseModule(AnsibleModule):
|
||||
if exc_val:
|
||||
self.fail_json(msg=str(exc_val))
|
||||
|
||||
- self.exit_json(changed=self.changed, user=self.exit_args)
|
||||
+ self.exit_json(changed=self.changed, **self.exit_args)
|
||||
|
||||
def get_command_errors(self, command, result):
|
||||
"""Look for erros into command results."""
|
||||
@@ -658,14 +658,22 @@ class FreeIPABaseModule(AnsibleModule):
|
||||
except Exception as excpt:
|
||||
self.fail_json(msg="%s: %s: %s" % (command, name, str(excpt)))
|
||||
else:
|
||||
- if "completed" in result:
|
||||
- if result["completed"] > 0:
|
||||
- self.changed = True
|
||||
- else:
|
||||
- self.changed = True
|
||||
-
|
||||
+ self.process_command_result(name, command, args, result)
|
||||
self.get_command_errors(command, result)
|
||||
|
||||
+ def process_command_result(self, name, command, args, result):
|
||||
+ """
|
||||
+ Process an API command result.
|
||||
+
|
||||
+ This method can be overriden in subclasses, and change self.exit_values
|
||||
+ to return data in the result for the controller.
|
||||
+ """
|
||||
+ if "completed" in result:
|
||||
+ if result["completed"] > 0:
|
||||
+ self.changed = True
|
||||
+ else:
|
||||
+ self.changed = True
|
||||
+
|
||||
def require_ipa_attrs_change(self, command_args, ipa_attrs):
|
||||
"""
|
||||
Compare given args with current object attributes.
|
||||
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
|
||||
index 901bfef..6a90fa2 100644
|
||||
--- a/plugins/modules/ipadnszone.py
|
||||
+++ b/plugins/modules/ipadnszone.py
|
||||
@@ -472,6 +472,14 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
}
|
||||
self.add_ipa_command("dnszone_mod", zone_name, args)
|
||||
|
||||
+ def process_command_result(self, name, command, args, result):
|
||||
+ super(DNSZoneModule, self).process_command_result(
|
||||
+ name, command, args, result
|
||||
+ )
|
||||
+ if command == "dnszone_add" and self.ipa_params.name_from_ip:
|
||||
+ dnszone_exit_args = self.exit_args.setdefault('dnszone', {})
|
||||
+ dnszone_exit_args['name'] = name
|
||||
+
|
||||
|
||||
def get_argument_spec():
|
||||
forwarder_spec = dict(
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 41e8226d0c03e06816626d78cecbc2aebf547691 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Wed, 5 Aug 2020 15:14:43 -0300
|
||||
Subject: [PATCH] Return the zone_name when adding a zone with name_from_ip.
|
||||
|
||||
When adding a zone using the option name_from_ip, the user have
|
||||
little control over the final name of the zone, and if this name
|
||||
is to be used in further processing in a playbook it might lead to
|
||||
errors if the inferred name does not match what the user wanted to.
|
||||
|
||||
By returning the actual inferred zone name, the name can be safely
|
||||
used for other tasks in the playbook.
|
||||
---
|
||||
README-dnszone.md | 11 +++++++++++
|
||||
playbooks/dnszone/dnszone-reverse-from-ip.yml | 7 ++++++-
|
||||
plugins/modules/ipadnszone.py | 8 ++++++++
|
||||
3 files changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/README-dnszone.md b/README-dnszone.md
|
||||
index 48b019a..3f4827b 100644
|
||||
--- a/README-dnszone.md
|
||||
+++ b/README-dnszone.md
|
||||
@@ -190,6 +190,17 @@ Variable | Description | Required
|
||||
`skip_nameserver_check` | Force DNS zone creation even if nameserver is not resolvable | no
|
||||
|
||||
|
||||
+Return Values
|
||||
+=============
|
||||
+
|
||||
+ipadnszone
|
||||
+----------
|
||||
+
|
||||
+Variable | Description | Returned When
|
||||
+-------- | ----------- | -------------
|
||||
+`dnszone` | DNS Zone dict with zone name infered from `name_from_ip`. <br>Options: | If `state` is `present`, `name_from_ip` is used, and a zone was created.
|
||||
+ | `name` - The name of the zone created, inferred from `name_from_ip`. | Always
|
||||
+
|
||||
Authors
|
||||
=======
|
||||
|
||||
diff --git a/playbooks/dnszone/dnszone-reverse-from-ip.yml b/playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
index 5693872..218a318 100644
|
||||
--- a/playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
+++ b/playbooks/dnszone/dnszone-reverse-from-ip.yml
|
||||
@@ -7,4 +7,9 @@
|
||||
- name: Ensure zone exist, finding zone name from IP address.
|
||||
ipadnszone:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
- name_from_ip: 10.1.2.3
|
||||
+ name_from_ip: 10.1.2.3/24
|
||||
+ register: result
|
||||
+
|
||||
+ - name: Zone name inferred from `name_from_ip`
|
||||
+ debug:
|
||||
+ msg: "Zone created: {{ result.dnszone.name }}"
|
||||
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
|
||||
index 6a90fa2..93eac07 100644
|
||||
--- a/plugins/modules/ipadnszone.py
|
||||
+++ b/plugins/modules/ipadnszone.py
|
||||
@@ -192,6 +192,14 @@ EXAMPLES = """
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
+dnszone:
|
||||
+ description: DNS Zone dict with zone name infered from `name_from_ip`.
|
||||
+ returned:
|
||||
+ If `state` is `present`, `name_from_ip` is used, and a zone was created.
|
||||
+ options:
|
||||
+ name:
|
||||
+ description: The name of the zone created, inferred from `name_from_ip`.
|
||||
+ returned: always
|
||||
"""
|
||||
|
||||
from ipapython.dnsutil import DNSName # noqa: E402
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 46bbc7bbd7a4e01d07b0390aee8c799aaa5ac895 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Mon, 17 Aug 2020 15:52:38 -0300
|
||||
Subject: [PATCH] Document usage of `name_from_ip`.
|
||||
|
||||
Since `name_from_ip` has a similar, but not equal, behavior to `name`,
|
||||
and as the inferred DNS zone might depend on DNS configuration and
|
||||
can be different than the user expects, it has some limited usage,
|
||||
and the user must be aware of its effects.
|
||||
|
||||
This change to the documentation enhance the documentation including
|
||||
more details on the attribute usage.
|
||||
---
|
||||
README-dnszone.md | 42 ++++++++++++++++++++++++++++++++++-
|
||||
plugins/modules/ipadnszone.py | 4 +++-
|
||||
2 files changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/README-dnszone.md b/README-dnszone.md
|
||||
index 3f4827b..c5a7ab3 100644
|
||||
--- a/README-dnszone.md
|
||||
+++ b/README-dnszone.md
|
||||
@@ -152,6 +152,46 @@ Example playbook to remove a zone:
|
||||
|
||||
```
|
||||
|
||||
+Example playbook to create a zone for reverse DNS lookup, from an IP address:
|
||||
+
|
||||
+```yaml
|
||||
+
|
||||
+---
|
||||
+- name: dnszone present
|
||||
+ hosts: ipaserver
|
||||
+ become: true
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: Ensure zone for reverse DNS lookup is present.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.168.1.2
|
||||
+ state: present
|
||||
+```
|
||||
+
|
||||
+Note that, on the previous example the zone created with `name_from_ip` might be "1.168.192.in-addr.arpa.", "168.192.in-addr.arpa.", or "192.in-addr.arpa.", depending on the DNS response the system get while querying for zones, and for this reason, when creating a zone using `name_from_ip`, the inferred zone name is returned to the controller, in the attribute `dnszone.name`. Since the zone inferred might not be what a user expects, `name_from_ip` can only be used with `state: present`. To have more control over the zone name, the prefix length for the IP address can be provided.
|
||||
+
|
||||
+Example playbook to create a zone for reverse DNS lookup, from an IP address, given the prefix length and displaying the resulting zone name:
|
||||
+
|
||||
+```yaml
|
||||
+
|
||||
+---
|
||||
+- name: dnszone present
|
||||
+ hosts: ipaserver
|
||||
+ become: true
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: Ensure zone for reverse DNS lookup is present.
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name_from_ip: 192.168.1.2/24
|
||||
+ state: present
|
||||
+ register: result
|
||||
+ - name: Display inferred zone name.
|
||||
+ debug:
|
||||
+ msg: "Zone name: {{ result.dnszone.name }}"
|
||||
+```
|
||||
+
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -164,7 +204,7 @@ Variable | Description | Required
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`name` \| `zone_name` | The zone name string or list of strings. | no
|
||||
-`name_from_ip` | Derive zone name from reverse of IP (PTR). | no
|
||||
+`name_from_ip` | Derive zone name from reverse of IP (PTR). Can only be used with `state: present`. | no
|
||||
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
|
||||
| `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
|
||||
| `port` - The custom port that should be used on this server. | no
|
||||
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
|
||||
index 93eac07..ff6bfff 100644
|
||||
--- a/plugins/modules/ipadnszone.py
|
||||
+++ b/plugins/modules/ipadnszone.py
|
||||
@@ -44,7 +44,9 @@ options:
|
||||
type: list
|
||||
alises: ["zone_name"]
|
||||
name_from_ip:
|
||||
- description: Derive zone name from reverse of IP (PTR).
|
||||
+ description: |
|
||||
+ Derive zone name from reverse of IP (PTR).
|
||||
+ Can only be used with `state: present`.
|
||||
required: false
|
||||
type: str
|
||||
forwarders:
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,435 @@
|
||||
From 78b635ae78346fdfb298dd0d0c82ae1ff34b754a Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Tue, 23 Jun 2020 17:53:47 -0300
|
||||
Subject: [PATCH] Add suppport for changing password of symmetric vaults.
|
||||
|
||||
Allows changing passwords of symmetric waults, using a new variable
|
||||
`new_password` (or the file-base version, `new_password_file`). The
|
||||
old password must be passed using the `password` or `password_file`
|
||||
variables that also received new aliases `old_password` and
|
||||
`old_password_file`, respectively.
|
||||
|
||||
Tests were modyfied to reflect the changes.
|
||||
---
|
||||
README-vault.md | 23 +++-
|
||||
.../vault/change-password-symmetric-vault.yml | 2 +-
|
||||
plugins/modules/ipavault.py | 129 +++++++++++++++---
|
||||
tests/vault/test_vault_symmetric.yml | 64 +++++++++
|
||||
4 files changed, 194 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/README-vault.md b/README-vault.md
|
||||
index c7ae6916..fa1d3e11 100644
|
||||
--- a/README-vault.md
|
||||
+++ b/README-vault.md
|
||||
@@ -165,6 +165,22 @@ Example playbook to make sure vault data is absent in a symmetric vault:
|
||||
state: absent
|
||||
```
|
||||
|
||||
+Example playbook to change the password of a symmetric:
|
||||
+
|
||||
+```yaml
|
||||
+---
|
||||
+- name: Playbook to handle vaults
|
||||
+ hosts: ipaserver
|
||||
+ become: true
|
||||
+
|
||||
+ tasks:
|
||||
+ - ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ old_password: SomeVAULTpassword
|
||||
+ new_password: SomeNEWpassword
|
||||
+```
|
||||
+
|
||||
Example playbook to make sure vault is absent:
|
||||
|
||||
```yaml
|
||||
@@ -197,8 +213,11 @@ Variable | Description | Required
|
||||
`name` \| `cn` | The list of vault name strings. | yes
|
||||
`description` | The vault description string. | no
|
||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||
-`password ` \| `vault_password` \| `ipavaultpassword` | Vault password. | no
|
||||
-`public_key ` \| `vault_public_key` \| `ipavaultpublickey` | Base64 encoded vault public key. | no
|
||||
+`password` \| `vault_password` \| `ipavaultpassword` \| `old_password`| Vault password. | no
|
||||
+`password_file` \| `vault_password_file` \| `old_password_file`| File containing Base64 encoded Vault password. | no
|
||||
+`new_password` | Vault new password. | no
|
||||
+`new_password_file` | File containing Base64 encoded new Vault password. | no
|
||||
+`public_key ` \| `vault_public_key` \| `old_password_file` | Base64 encoded vault public key. | no
|
||||
`public_key_file` \| `vault_public_key_file` | Path to file with public key. | no
|
||||
`private_key `\| `vault_private_key` | Base64 encoded vault private key. Used only to retrieve data. | no
|
||||
`private_key_file` \| `vault_private_key_file` | Path to file with private key. Used only to retrieve data. | no
|
||||
diff --git a/playbooks/vault/change-password-symmetric-vault.yml b/playbooks/vault/change-password-symmetric-vault.yml
|
||||
index 3871f45d..396a79f6 100644
|
||||
--- a/playbooks/vault/change-password-symmetric-vault.yml
|
||||
+++ b/playbooks/vault/change-password-symmetric-vault.yml
|
||||
@@ -10,7 +10,7 @@
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: symvault
|
||||
password: SomeVAULTpassword
|
||||
- - name: Change vault passord.
|
||||
+ - name: Change vault password.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: symvault
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index ad5dd413..46c6fcdb 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -69,12 +69,20 @@
|
||||
description: password to be used on symmetric vault.
|
||||
required: false
|
||||
type: string
|
||||
- aliases: ["ipavaultpassword", "vault_password"]
|
||||
+ aliases: ["ipavaultpassword", "vault_password", "old_password"]
|
||||
password_file:
|
||||
description: file with password to be used on symmetric vault.
|
||||
required: false
|
||||
type: string
|
||||
- aliases: ["vault_password_file"]
|
||||
+ aliases: ["vault_password_file", "old_password_file"]
|
||||
+ new_password:
|
||||
+ description: new password to be used on symmetric vault.
|
||||
+ required: false
|
||||
+ type: string
|
||||
+ new_password_file:
|
||||
+ description: file with new password to be used on symmetric vault.
|
||||
+ required: false
|
||||
+ type: string
|
||||
salt:
|
||||
description: Vault salt.
|
||||
required: false
|
||||
@@ -235,7 +243,15 @@
|
||||
state: retrieved
|
||||
register: result
|
||||
- debug:
|
||||
- msg: "{{ result.data | b64decode }}"
|
||||
+ msg: "{{ result.data }}"
|
||||
+
|
||||
+# Change password of a symmetric vault
|
||||
+- ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ username: admin
|
||||
+ old_password: SomeVAULTpassword
|
||||
+ new_password: SomeNEWpassword
|
||||
|
||||
# Ensure vault symvault is absent
|
||||
- ipavault:
|
||||
@@ -416,18 +432,29 @@ def check_parameters(module, state, action, description, username, service,
|
||||
shared, users, groups, services, owners, ownergroups,
|
||||
ownerservices, vault_type, salt, password, password_file,
|
||||
public_key, public_key_file, private_key,
|
||||
- private_key_file, vault_data, datafile_in, datafile_out):
|
||||
+ private_key_file, vault_data, datafile_in, datafile_out,
|
||||
+ new_password, new_password_file):
|
||||
invalid = []
|
||||
if state == "present":
|
||||
invalid = ['private_key', 'private_key_file', 'datafile_out']
|
||||
|
||||
+ if all([password, password_file]) \
|
||||
+ or all([new_password, new_password_file]):
|
||||
+ module.fail_json(msg="Password specified multiple times.")
|
||||
+
|
||||
+ if any([new_password, new_password_file]) \
|
||||
+ and not any([password, password_file]):
|
||||
+ module.fail_json(
|
||||
+ msg="Either `password` or `password_file` must be provided to "
|
||||
+ "change symmetric vault password.")
|
||||
+
|
||||
if action == "member":
|
||||
invalid.extend(['description'])
|
||||
|
||||
elif state == "absent":
|
||||
invalid = ['description', 'salt', 'vault_type', 'private_key',
|
||||
'private_key_file', 'datafile_in', 'datafile_out',
|
||||
- 'vault_data']
|
||||
+ 'vault_data', 'new_password', 'new_password_file']
|
||||
|
||||
if action == "vault":
|
||||
invalid.extend(['users', 'groups', 'services', 'owners',
|
||||
@@ -437,7 +464,7 @@ def check_parameters(module, state, action, description, username, service,
|
||||
elif state == "retrieved":
|
||||
invalid = ['description', 'salt', 'datafile_in', 'users', 'groups',
|
||||
'owners', 'ownergroups', 'public_key', 'public_key_file',
|
||||
- 'vault_data']
|
||||
+ 'vault_data', 'new_password', 'new_password_file']
|
||||
if action == 'member':
|
||||
module.fail_json(
|
||||
msg="State `retrieved` do not support action `member`.")
|
||||
@@ -458,11 +485,17 @@ def check_parameters(module, state, action, description, username, service,
|
||||
def check_encryption_params(module, state, action, vault_type, salt,
|
||||
password, password_file, public_key,
|
||||
public_key_file, private_key, private_key_file,
|
||||
- vault_data, datafile_in, datafile_out, res_find):
|
||||
+ vault_data, datafile_in, datafile_out,
|
||||
+ new_password, new_password_file, res_find):
|
||||
vault_type_invalid = []
|
||||
+
|
||||
+ if res_find is not None:
|
||||
+ vault_type = res_find['ipavaulttype']
|
||||
+
|
||||
if vault_type == "standard":
|
||||
vault_type_invalid = ['public_key', 'public_key_file', 'password',
|
||||
- 'password_file', 'salt']
|
||||
+ 'password_file', 'salt', 'new_password',
|
||||
+ 'new_password_file']
|
||||
|
||||
if vault_type is None or vault_type == "symmetric":
|
||||
vault_type_invalid = ['public_key', 'public_key_file',
|
||||
@@ -473,8 +506,14 @@ def check_encryption_params(module, state, action, vault_type, salt,
|
||||
msg="Symmetric vault requires password or password_file "
|
||||
"to store data or change `salt`.")
|
||||
|
||||
+ if any([new_password, new_password_file]) and res_find is None:
|
||||
+ module.fail_json(
|
||||
+ msg="Cannot modify password of inexistent vault.")
|
||||
+
|
||||
if vault_type == "asymmetric":
|
||||
- vault_type_invalid = ['password', 'password_file']
|
||||
+ vault_type_invalid = [
|
||||
+ 'password', 'password_file', 'new_password', 'new_password_file'
|
||||
+ ]
|
||||
if not any([public_key, public_key_file]) and res_find is None:
|
||||
module.fail_json(
|
||||
msg="Assymmetric vault requires public_key "
|
||||
@@ -487,6 +526,43 @@ def check_encryption_params(module, state, action, vault_type, salt,
|
||||
(param, vault_type or 'symmetric'))
|
||||
|
||||
|
||||
+def change_password(module, res_find, password, password_file, new_password,
|
||||
+ new_password_file):
|
||||
+ """
|
||||
+ Change the password of a symmetric vault.
|
||||
+
|
||||
+ To change the password of a vault, it is needed to retrieve the stored
|
||||
+ data with the current password, and store the data again, with the new
|
||||
+ password, forcing it to override the old one.
|
||||
+ """
|
||||
+ # verify parameters.
|
||||
+ if not any([new_password, new_password_file]):
|
||||
+ return []
|
||||
+ if res_find["ipavaulttype"][0] != "symmetric":
|
||||
+ module.fail_json(msg="Cannot change password of `%s` vault."
|
||||
+ % res_find["ipavaulttype"])
|
||||
+
|
||||
+ # prepare arguments to retrieve data.
|
||||
+ name = res_find["cn"][0]
|
||||
+ args = {}
|
||||
+ if password:
|
||||
+ args["password"] = password
|
||||
+ if password_file:
|
||||
+ args["password"] = password_file
|
||||
+ # retrieve current stored data
|
||||
+ result = api_command(module, 'vault_retrieve', name, args)
|
||||
+ args['data'] = result['result']['data']
|
||||
+
|
||||
+ # modify arguments to store data with new password.
|
||||
+ if password:
|
||||
+ args["password"] = new_password
|
||||
+ if password_file:
|
||||
+ args["password"] = new_password_file
|
||||
+ args["override_password"] = True
|
||||
+ # return the command to store data with the new password.
|
||||
+ return [(name, "vault_archive", args)]
|
||||
+
|
||||
+
|
||||
def main():
|
||||
ansible_module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
@@ -533,10 +609,18 @@ def main():
|
||||
datafile_out=dict(type="str", required=False, default=None,
|
||||
aliases=['out']),
|
||||
vault_password=dict(type="str", required=False, default=None,
|
||||
- aliases=['ipavaultpassword', 'password'],
|
||||
- no_log=True),
|
||||
+ no_log=True,
|
||||
+ aliases=['ipavaultpassword', 'password',
|
||||
+ "old_password"]),
|
||||
vault_password_file=dict(type="str", required=False, default=None,
|
||||
- no_log=False, aliases=['password_file']),
|
||||
+ no_log=False,
|
||||
+ aliases=[
|
||||
+ 'password_file', "old_password_file"
|
||||
+ ]),
|
||||
+ new_password=dict(type="str", required=False, default=None,
|
||||
+ no_log=True),
|
||||
+ new_password_file=dict(type="str", required=False, default=None,
|
||||
+ no_log=False),
|
||||
# state
|
||||
action=dict(type="str", default="vault",
|
||||
choices=["vault", "data", "member"]),
|
||||
@@ -546,6 +630,7 @@ def main():
|
||||
supports_check_mode=True,
|
||||
mutually_exclusive=[['username', 'service', 'shared'],
|
||||
['datafile_in', 'vault_data'],
|
||||
+ ['new_password', 'new_password_file'],
|
||||
['vault_password', 'vault_password_file'],
|
||||
['vault_public_key', 'vault_public_key_file']],
|
||||
)
|
||||
@@ -576,6 +661,8 @@ def main():
|
||||
salt = module_params_get(ansible_module, "vault_salt")
|
||||
password = module_params_get(ansible_module, "vault_password")
|
||||
password_file = module_params_get(ansible_module, "vault_password_file")
|
||||
+ new_password = module_params_get(ansible_module, "new_password")
|
||||
+ new_password_file = module_params_get(ansible_module, "new_password_file")
|
||||
public_key = module_params_get(ansible_module, "vault_public_key")
|
||||
public_key_file = module_params_get(ansible_module,
|
||||
"vault_public_key_file")
|
||||
@@ -614,7 +701,8 @@ def main():
|
||||
service, shared, users, groups, services, owners,
|
||||
ownergroups, ownerservices, vault_type, salt, password,
|
||||
password_file, public_key, public_key_file, private_key,
|
||||
- private_key_file, vault_data, datafile_in, datafile_out)
|
||||
+ private_key_file, vault_data, datafile_in, datafile_out,
|
||||
+ new_password, new_password_file)
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
@@ -660,7 +748,7 @@ def main():
|
||||
ansible_module, state, action, vault_type, salt, password,
|
||||
password_file, public_key, public_key_file, private_key,
|
||||
private_key_file, vault_data, datafile_in, datafile_out,
|
||||
- res_find)
|
||||
+ new_password, new_password_file, res_find)
|
||||
|
||||
# Found the vault
|
||||
if action == "vault":
|
||||
@@ -721,7 +809,6 @@ def main():
|
||||
owner_add_args = gen_member_args(
|
||||
args, owner_add, ownergroups_add, ownerservice_add)
|
||||
if owner_add_args is not None:
|
||||
- # ansible_module.warn("OWNER ADD: %s" % owner_add_args)
|
||||
commands.append(
|
||||
[name, 'vault_add_owner', owner_add_args])
|
||||
|
||||
@@ -729,7 +816,6 @@ def main():
|
||||
owner_del_args = gen_member_args(
|
||||
args, owner_del, ownergroups_del, ownerservice_del)
|
||||
if owner_del_args is not None:
|
||||
- # ansible_module.warn("OWNER DEL: %s" % owner_del_args)
|
||||
commands.append(
|
||||
[name, 'vault_remove_owner', owner_del_args])
|
||||
|
||||
@@ -758,19 +844,22 @@ def main():
|
||||
if any([vault_data, datafile_in]):
|
||||
commands.append([name, "vault_archive", pwdargs])
|
||||
|
||||
+ cmds = change_password(
|
||||
+ ansible_module, res_find, password, password_file,
|
||||
+ new_password, new_password_file)
|
||||
+ commands.extend(cmds)
|
||||
+
|
||||
elif state == "retrieved":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="Vault `%s` not found to retrieve data." % name)
|
||||
|
||||
- vault_type = res_find['cn']
|
||||
-
|
||||
# verify data encription args
|
||||
check_encryption_params(
|
||||
ansible_module, state, action, vault_type, salt, password,
|
||||
password_file, public_key, public_key_file, private_key,
|
||||
private_key_file, vault_data, datafile_in, datafile_out,
|
||||
- res_find)
|
||||
+ new_password, new_password_file, res_find)
|
||||
|
||||
pwdargs = data_storage_args(
|
||||
args, vault_data, password, password_file, private_key,
|
||||
@@ -813,7 +902,6 @@ def main():
|
||||
errors = []
|
||||
for name, command, args in commands:
|
||||
try:
|
||||
- # ansible_module.warn("RUN: %s %s %s" % (command, name, args))
|
||||
result = api_command(ansible_module, command, name, args)
|
||||
|
||||
if command == 'vault_archive':
|
||||
@@ -829,7 +917,6 @@ def main():
|
||||
raise Exception("No data retrieved.")
|
||||
changed = False
|
||||
else:
|
||||
- # ansible_module.warn("RESULT: %s" % (result))
|
||||
if "completed" in result:
|
||||
if result["completed"] > 0:
|
||||
changed = True
|
||||
diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml
|
||||
index c9429f4f..a6072d88 100644
|
||||
--- a/tests/vault/test_vault_symmetric.yml
|
||||
+++ b/tests/vault/test_vault_symmetric.yml
|
||||
@@ -178,6 +178,61 @@
|
||||
register: result
|
||||
failed_when: result.data != 'Hello World.' or result.changed
|
||||
|
||||
+ - name: Change vault password.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ new_password: SomeNEWpassword
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Retrieve data from symmetric vault, with wrong password.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ state: retrieved
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "Invalid credentials" not in result.msg
|
||||
+
|
||||
+ - name: Change vault password, with wrong `old_password`.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ new_password: SomeNEWpassword
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "Invalid credentials" not in result.msg
|
||||
+
|
||||
+ - name: Retrieve data from symmetric vault, with new password.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeNEWpassword
|
||||
+ state: retrieved
|
||||
+ register: result
|
||||
+ failed_when: result.data != 'Hello World.' or result.changed
|
||||
+
|
||||
+ - name: Try to add vault with multiple passwords.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: inexistentvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ password_file: "{{ ansible_env.HOME }}/password.txt"
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg
|
||||
+
|
||||
+ - name: Try to add vault with multiple new passwords.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: inexistentvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ new_password: SomeVAULTpassword
|
||||
+ new_password_file: "{{ ansible_env.HOME }}/password.txt"
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg
|
||||
+
|
||||
- name: Ensure symmetric vault is absent
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -194,5 +249,14 @@
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
+ - name: Try to change password of inexistent vault.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: inexistentvault
|
||||
+ password: SomeVAULTpassword
|
||||
+ new_password: SomeNEWpassword
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "Cannot modify password of inexistent vault" not in result.msg
|
||||
+
|
||||
- name: Cleanup testing environment.
|
||||
import_tasks: env_cleanup.yml
|
@ -0,0 +1,302 @@
|
||||
From 75d16c2da4a5621943873a26343eb0f2acc2a925 Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Oliveira Campos <seocam@seocam.com>
|
||||
Date: Mon, 3 Aug 2020 11:54:44 -0300
|
||||
Subject: [PATCH] Allow multiple dns zones to be absent.
|
||||
|
||||
This PR allow ipadnszone module to ensure that multiple dns zones
|
||||
are absent at once, to be consistent with other ansible-freeipa
|
||||
modules.
|
||||
|
||||
To fix this issue, it was required that custom arguents must be
|
||||
passed using keyword arguments so that `get_ipa_command_args()`
|
||||
is kept generic.
|
||||
---
|
||||
README-dnszone.md | 2 +-
|
||||
.../module_utils/ansible_freeipa_module.py | 4 +-
|
||||
plugins/modules/ipadnszone.py | 126 ++++++++++--------
|
||||
tests/dnszone/test_dnszone.yml | 37 +++++
|
||||
4 files changed, 107 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/README-dnszone.md b/README-dnszone.md
|
||||
index 766efe5..9c9b12c 100644
|
||||
--- a/README-dnszone.md
|
||||
+++ b/README-dnszone.md
|
||||
@@ -163,7 +163,7 @@ Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
-`name` \| `zone_name` | The zone name string. | yes
|
||||
+`name` \| `zone_name` | The zone name string or list of strings. | yes
|
||||
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
|
||||
| `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
|
||||
| `port` - The custom port that should be used on this server. | no
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 122ea2e..1e55693 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -506,7 +506,7 @@ class FreeIPABaseModule(AnsibleModule):
|
||||
# when needed.
|
||||
self.ipa_params = AnsibleFreeIPAParams(self)
|
||||
|
||||
- def get_ipa_command_args(self):
|
||||
+ def get_ipa_command_args(self, **kwargs):
|
||||
"""
|
||||
Return a dict to be passed to an IPA command.
|
||||
|
||||
@@ -538,7 +538,7 @@ class FreeIPABaseModule(AnsibleModule):
|
||||
elif hasattr(self, param_name):
|
||||
method = getattr(self, param_name)
|
||||
if callable(method):
|
||||
- value = method()
|
||||
+ value = method(**kwargs)
|
||||
|
||||
# We don't have a way to guess the value so fail.
|
||||
else:
|
||||
diff --git a/plugins/modules/ipadnszone.py b/plugins/modules/ipadnszone.py
|
||||
index 717978e..c5e812a 100644
|
||||
--- a/plugins/modules/ipadnszone.py
|
||||
+++ b/plugins/modules/ipadnszone.py
|
||||
@@ -41,7 +41,7 @@ options:
|
||||
name:
|
||||
description: The zone name string.
|
||||
required: true
|
||||
- type: str
|
||||
+ type: list
|
||||
alises: ["zone_name"]
|
||||
forwarders:
|
||||
description: The list of global DNS forwarders.
|
||||
@@ -268,7 +268,7 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
|
||||
return True
|
||||
|
||||
- def get_ipa_nsec3paramrecord(self):
|
||||
+ def get_ipa_nsec3paramrecord(self, **kwargs):
|
||||
nsec3param_rec = self.ipa_params.nsec3param_rec
|
||||
if nsec3param_rec is not None:
|
||||
error_msg = (
|
||||
@@ -280,7 +280,7 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
self.fail_json(msg=error_msg)
|
||||
return nsec3param_rec
|
||||
|
||||
- def get_ipa_idnsforwarders(self):
|
||||
+ def get_ipa_idnsforwarders(self, **kwargs):
|
||||
if self.ipa_params.forwarders is not None:
|
||||
forwarders = []
|
||||
for forwarder in self.ipa_params.forwarders:
|
||||
@@ -304,14 +304,14 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
|
||||
return forwarders
|
||||
|
||||
- def get_ipa_idnsallowtransfer(self):
|
||||
+ def get_ipa_idnsallowtransfer(self, **kwargs):
|
||||
if self.ipa_params.allow_transfer is not None:
|
||||
error_msg = "Invalid ip_address for DNS allow_transfer: %s"
|
||||
self.validate_ips(self.ipa_params.allow_transfer, error_msg)
|
||||
|
||||
return (";".join(self.ipa_params.allow_transfer) or "none") + ";"
|
||||
|
||||
- def get_ipa_idnsallowquery(self):
|
||||
+ def get_ipa_idnsallowquery(self, **kwargs):
|
||||
if self.ipa_params.allow_query is not None:
|
||||
error_msg = "Invalid ip_address for DNS allow_query: %s"
|
||||
self.validate_ips(self.ipa_params.allow_query, error_msg)
|
||||
@@ -334,81 +334,89 @@ class DNSZoneModule(FreeIPABaseModule):
|
||||
|
||||
return ".".join((name, domain))
|
||||
|
||||
- def get_ipa_idnssoarname(self):
|
||||
+ def get_ipa_idnssoarname(self, **kwargs):
|
||||
if self.ipa_params.admin_email is not None:
|
||||
return DNSName(
|
||||
self._replace_at_symbol_in_rname(self.ipa_params.admin_email)
|
||||
)
|
||||
|
||||
- def get_ipa_idnssoamname(self):
|
||||
+ def get_ipa_idnssoamname(self, **kwargs):
|
||||
if self.ipa_params.name_server is not None:
|
||||
return DNSName(self.ipa_params.name_server)
|
||||
|
||||
- def get_ipa_skip_overlap_check(self):
|
||||
- if not self.zone and self.ipa_params.skip_overlap_check is not None:
|
||||
+ def get_ipa_skip_overlap_check(self, **kwargs):
|
||||
+ zone = kwargs.get('zone')
|
||||
+ if not zone and self.ipa_params.skip_overlap_check is not None:
|
||||
return self.ipa_params.skip_overlap_check
|
||||
|
||||
- def get_ipa_skip_nameserver_check(self):
|
||||
- if not self.zone and self.ipa_params.skip_nameserver_check is not None:
|
||||
+ def get_ipa_skip_nameserver_check(self, **kwargs):
|
||||
+ zone = kwargs.get('zone')
|
||||
+ if not zone and self.ipa_params.skip_nameserver_check is not None:
|
||||
return self.ipa_params.skip_nameserver_check
|
||||
|
||||
def get_zone(self, zone_name):
|
||||
get_zone_args = {"idnsname": zone_name, "all": True}
|
||||
response = self.api_command("dnszone_find", args=get_zone_args)
|
||||
|
||||
+ zone = None
|
||||
+ is_zone_active = False
|
||||
+
|
||||
if response["count"] == 1:
|
||||
- self.zone = response["result"][0]
|
||||
- self.is_zone_active = self.zone.get("idnszoneactive") == ["TRUE"]
|
||||
- return self.zone
|
||||
+ zone = response["result"][0]
|
||||
+ is_zone_active = zone.get("idnszoneactive") == ["TRUE"]
|
||||
|
||||
- # Zone doesn't exist yet
|
||||
- self.zone = None
|
||||
- self.is_zone_active = False
|
||||
+ return zone, is_zone_active
|
||||
+
|
||||
+ def get_zone_names(self):
|
||||
+ if len(self.ipa_params.name) > 1 and self.ipa_params.state != "absent":
|
||||
+ self.fail_json(
|
||||
+ msg=("Please provide a single name. Multiple values for 'name'"
|
||||
+ "can only be supplied for state 'absent'.")
|
||||
+ )
|
||||
|
||||
- @property
|
||||
- def zone_name(self):
|
||||
return self.ipa_params.name
|
||||
|
||||
def define_ipa_commands(self):
|
||||
- # Look for existing zone in IPA
|
||||
- self.get_zone(self.zone_name)
|
||||
- args = self.get_ipa_command_args()
|
||||
- just_added = False
|
||||
-
|
||||
- if self.ipa_params.state in ["present", "enabled", "disabled"]:
|
||||
- if not self.zone:
|
||||
- # Since the zone doesn't exist we just create it
|
||||
- # with given args
|
||||
- self.add_ipa_command("dnszone_add", self.zone_name, args)
|
||||
- self.is_zone_active = True
|
||||
- just_added = True
|
||||
-
|
||||
- else:
|
||||
- # Zone already exist so we need to verify if given args
|
||||
- # matches the current config. If not we updated it.
|
||||
- if self.require_ipa_attrs_change(args, self.zone):
|
||||
- self.add_ipa_command("dnszone_mod", self.zone_name, args)
|
||||
-
|
||||
- if self.ipa_params.state == "enabled" and not self.is_zone_active:
|
||||
- self.add_ipa_command("dnszone_enable", self.zone_name)
|
||||
-
|
||||
- if self.ipa_params.state == "disabled" and self.is_zone_active:
|
||||
- self.add_ipa_command("dnszone_disable", self.zone_name)
|
||||
-
|
||||
- if self.ipa_params.state == "absent":
|
||||
- if self.zone:
|
||||
- self.add_ipa_command("dnszone_del", self.zone_name)
|
||||
-
|
||||
- # Due to a bug in FreeIPA dnszone-add won't set
|
||||
- # SOA Serial. The good news is that dnszone-mod does the job.
|
||||
- # See: https://pagure.io/freeipa/issue/8227
|
||||
- # Because of that, if the zone was just added with a given serial
|
||||
- # we run mod just after to workaround the bug
|
||||
- if just_added and self.ipa_params.serial is not None:
|
||||
- args = {
|
||||
- "idnssoaserial": self.ipa_params.serial,
|
||||
- }
|
||||
- self.add_ipa_command("dnszone_mod", self.zone_name, args)
|
||||
+ for zone_name in self.get_zone_names():
|
||||
+ # Look for existing zone in IPA
|
||||
+ zone, is_zone_active = self.get_zone(zone_name)
|
||||
+ args = self.get_ipa_command_args(zone=zone)
|
||||
+ just_added = False
|
||||
+
|
||||
+ if self.ipa_params.state in ["present", "enabled", "disabled"]:
|
||||
+ if not zone:
|
||||
+ # Since the zone doesn't exist we just create it
|
||||
+ # with given args
|
||||
+ self.add_ipa_command("dnszone_add", zone_name, args)
|
||||
+ is_zone_active = True
|
||||
+ just_added = True
|
||||
+
|
||||
+ else:
|
||||
+ # Zone already exist so we need to verify if given args
|
||||
+ # matches the current config. If not we updated it.
|
||||
+ if self.require_ipa_attrs_change(args, zone):
|
||||
+ self.add_ipa_command("dnszone_mod", zone_name, args)
|
||||
+
|
||||
+ if self.ipa_params.state == "enabled" and not is_zone_active:
|
||||
+ self.add_ipa_command("dnszone_enable", zone_name)
|
||||
+
|
||||
+ if self.ipa_params.state == "disabled" and is_zone_active:
|
||||
+ self.add_ipa_command("dnszone_disable", zone_name)
|
||||
+
|
||||
+ if self.ipa_params.state == "absent":
|
||||
+ if zone:
|
||||
+ self.add_ipa_command("dnszone_del", zone_name)
|
||||
+
|
||||
+ # Due to a bug in FreeIPA dnszone-add won't set
|
||||
+ # SOA Serial. The good news is that dnszone-mod does the job.
|
||||
+ # See: https://pagure.io/freeipa/issue/8227
|
||||
+ # Because of that, if the zone was just added with a given serial
|
||||
+ # we run mod just after to workaround the bug
|
||||
+ if just_added and self.ipa_params.serial is not None:
|
||||
+ args = {
|
||||
+ "idnssoaserial": self.ipa_params.serial,
|
||||
+ }
|
||||
+ self.add_ipa_command("dnszone_mod", zone_name, args)
|
||||
|
||||
|
||||
def get_argument_spec():
|
||||
@@ -426,7 +434,7 @@ def get_argument_spec():
|
||||
ipaadmin_principal=dict(type="str", default="admin"),
|
||||
ipaadmin_password=dict(type="str", required=False, no_log=True),
|
||||
name=dict(
|
||||
- type="str", default=None, required=True, aliases=["zone_name"]
|
||||
+ type="list", default=None, required=True, aliases=["zone_name"]
|
||||
),
|
||||
forwarders=dict(
|
||||
type="list",
|
||||
diff --git a/tests/dnszone/test_dnszone.yml b/tests/dnszone/test_dnszone.yml
|
||||
index f7bd1f0..bd820df 100644
|
||||
--- a/tests/dnszone/test_dnszone.yml
|
||||
+++ b/tests/dnszone/test_dnszone.yml
|
||||
@@ -149,3 +149,40 @@
|
||||
forwarders: []
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
+
|
||||
+ - name: Create zones test1
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: test1.testzone.local
|
||||
+
|
||||
+ - name: Create zones test2
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: test2.testzone.local
|
||||
+
|
||||
+ - name: Create zones test3
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: test3.testzone.local
|
||||
+
|
||||
+ - name: Ensure multiple zones are absent
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - test1.testzone.local
|
||||
+ - test2.testzone.local
|
||||
+ - test3.testzone.local
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure multiple zones are absent, again
|
||||
+ ipadnszone:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - test1.testzone.local
|
||||
+ - test2.testzone.local
|
||||
+ - test3.testzone.local
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,628 @@
|
||||
# Skipping 3ab575bcac310166e7d29c5a5349d90482f4e629 as it is reorganizing
|
||||
# service module test test_service.yml and
|
||||
# test_service_without_skip_host_check.yml
|
||||
|
||||
From b5e93c705fc56f6592121aa09bfb9f6dce5cee35 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Tue, 11 Aug 2020 16:23:15 -0300
|
||||
Subject: [PATCH] Fix `allow_retrieve_keytab_host` in service module.
|
||||
|
||||
The attribute `allow_retrieve_keytab_host` was not working due to
|
||||
wrong processing of the input and verification if the values should
|
||||
be updated. Both the issues are fixed by this change.
|
||||
|
||||
Tests were added to better verify service keytab members.
|
||||
---
|
||||
plugins/modules/ipaservice.py | 4 +-
|
||||
tests/service/env_cleanup.yml | 68 +++++
|
||||
tests/service/env_setup.yml | 73 +++++
|
||||
tests/service/env_vars.yml | 15 +
|
||||
tests/service/test_service_keytab.yml | 397 ++++++++++++++++++++++++++
|
||||
5 files changed, 555 insertions(+), 2 deletions(-)
|
||||
create mode 100644 tests/service/env_cleanup.yml
|
||||
create mode 100644 tests/service/env_setup.yml
|
||||
create mode 100644 tests/service/env_vars.yml
|
||||
create mode 100644 tests/service/test_service_keytab.yml
|
||||
|
||||
diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py
|
||||
index b0d2535..8bc390d 100644
|
||||
--- a/plugins/modules/ipaservice.py
|
||||
+++ b/plugins/modules/ipaservice.py
|
||||
@@ -460,7 +460,7 @@ def main():
|
||||
allow_retrieve_keytab_group = module_params_get(
|
||||
ansible_module, "allow_retrieve_keytab_group")
|
||||
allow_retrieve_keytab_host = module_params_get(
|
||||
- ansible_module, "allow_create_keytab_host")
|
||||
+ ansible_module, "allow_retrieve_keytab_host")
|
||||
allow_retrieve_keytab_hostgroup = module_params_get(
|
||||
ansible_module, "allow_retrieve_keytab_hostgroup")
|
||||
delete_continue = module_params_get(ansible_module, "delete_continue")
|
||||
@@ -727,7 +727,7 @@ def main():
|
||||
# Allow retrieve keytab
|
||||
if len(allow_retrieve_keytab_user_add) > 0 or \
|
||||
len(allow_retrieve_keytab_group_add) > 0 or \
|
||||
- len(allow_retrieve_keytab_hostgroup_add) > 0 or \
|
||||
+ len(allow_retrieve_keytab_host_add) > 0 or \
|
||||
len(allow_retrieve_keytab_hostgroup_add) > 0:
|
||||
commands.append(
|
||||
[name, "service_allow_retrieve_keytab",
|
||||
diff --git a/tests/service/env_cleanup.yml b/tests/service/env_cleanup.yml
|
||||
new file mode 100644
|
||||
index 0000000..f96a75b
|
||||
--- /dev/null
|
||||
+++ b/tests/service/env_cleanup.yml
|
||||
@@ -0,0 +1,68 @@
|
||||
+---
|
||||
+# Cleanup tasks for the service module tests.
|
||||
+- name: Ensure services are absent.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - "HTTP/{{ svc_fqdn }}"
|
||||
+ - "HTTP/{{ nohost_fqdn }}"
|
||||
+ - HTTP/svc.ihavenodns.info
|
||||
+ - HTTP/no.idontexist.local
|
||||
+ - "cifs/{{ host1_fqdn }}"
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure host "{{ svc_fqdn }}" is absent
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "{{ svc_fqdn }}"
|
||||
+ update_dns: yes
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure host is absent
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ - "{{ nohost_fqdn }}"
|
||||
+ - svc.ihavenodns.info
|
||||
+ update_dns: no
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure testing users are absent.
|
||||
+ ipauser:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure testing groups are absent.
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure testing hostgroup hostgroup01 is absent.
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - hostgroup01
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Ensure testing hostgroup hostgroup02 is absent.
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - hostgroup02
|
||||
+ state: absent
|
||||
+
|
||||
+- name: Remove IP address for "nohost" host.
|
||||
+ ipadnsrecord:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ zone_name: "{{ test_domain }}."
|
||||
+ name: nohost
|
||||
+ del_all: yes
|
||||
+ state: absent
|
||||
diff --git a/tests/service/env_setup.yml b/tests/service/env_setup.yml
|
||||
new file mode 100644
|
||||
index 0000000..309cfc0
|
||||
--- /dev/null
|
||||
+++ b/tests/service/env_setup.yml
|
||||
@@ -0,0 +1,73 @@
|
||||
+# Setup environment for service module tests.
|
||||
+---
|
||||
+- name: Setup variables and facts.
|
||||
+ include_tasks: env_vars.yml
|
||||
+
|
||||
+# Cleanup before setup.
|
||||
+- name: Cleanup test environment.
|
||||
+ include_tasks: env_cleanup.yml
|
||||
+
|
||||
+- name: Add IP address for "nohost" host.
|
||||
+ ipadnsrecord:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ zone_name: "{{ test_domain }}."
|
||||
+ name: nohost
|
||||
+ a_ip_address: "{{ ipv4_prefix + '.100' }}"
|
||||
+
|
||||
+- name: Add hosts for tests.
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ hosts:
|
||||
+ - name: "{{ host1_fqdn }}"
|
||||
+ ip_address: "{{ ipv4_prefix + '.101' }}"
|
||||
+ - name: "{{ host2_fqdn }}"
|
||||
+ ip_address: "{{ ipv4_prefix + '.102' }}"
|
||||
+ - name: "{{ svc_fqdn }}"
|
||||
+ ip_address: "{{ ipv4_prefix + '.201' }}"
|
||||
+ - name: svc.ihavenodns.info
|
||||
+ force: yes
|
||||
+ update_dns: yes
|
||||
+
|
||||
+- name: Ensure testing user user01 is present.
|
||||
+ ipauser:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: user01
|
||||
+ first: user01
|
||||
+ last: last
|
||||
+
|
||||
+- name: Ensure testing user user02 is present.
|
||||
+ ipauser:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: user02
|
||||
+ first: user02
|
||||
+ last: last
|
||||
+
|
||||
+- name: Ensure testing group group01 is present.
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: group01
|
||||
+
|
||||
+- name: Ensure testing group group02 is present.
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: group02
|
||||
+
|
||||
+- name: Ensure testing hostgroup hostgroup01 is present.
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: hostgroup01
|
||||
+
|
||||
+- name: Ensure testing hostgroup hostgroup02 is present.
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: hostgroup02
|
||||
+
|
||||
+- name: Ensure services are absent.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name:
|
||||
+ - "HTTP/{{ svc_fqdn }}"
|
||||
+ - "HTTP/{{ nohost_fqdn }}"
|
||||
+ - HTTP/svc.ihavenodns.info
|
||||
+ - HTTP/no.idontexist.info
|
||||
+ state: absent
|
||||
diff --git a/tests/service/env_vars.yml b/tests/service/env_vars.yml
|
||||
new file mode 100644
|
||||
index 0000000..eb53c7a
|
||||
--- /dev/null
|
||||
+++ b/tests/service/env_vars.yml
|
||||
@@ -0,0 +1,15 @@
|
||||
+---
|
||||
+ - name: Get Domain from server name
|
||||
+ set_fact:
|
||||
+ test_domain: "{{ ansible_fqdn.split('.')[1:] | join('.') }}"
|
||||
+
|
||||
+ - name: Set host1, host2 and svc hosts fqdn
|
||||
+ set_fact:
|
||||
+ host1_fqdn: "{{ 'host1.' + test_domain }}"
|
||||
+ host2_fqdn: "{{ 'host2.' + test_domain }}"
|
||||
+ svc_fqdn: "{{ 'svc.' + test_domain }}"
|
||||
+ nohost_fqdn: "{{ 'nohost.' + test_domain }}"
|
||||
+
|
||||
+ - name: Get IPv4 address prefix from server node
|
||||
+ set_fact:
|
||||
+ ipv4_prefix: "{{ ansible_default_ipv4.address.split('.')[:-1] | join('.') }}"
|
||||
diff --git a/tests/service/test_service_keytab.yml b/tests/service/test_service_keytab.yml
|
||||
new file mode 100644
|
||||
index 0000000..0918802
|
||||
--- /dev/null
|
||||
+++ b/tests/service/test_service_keytab.yml
|
||||
@@ -0,0 +1,397 @@
|
||||
+---
|
||||
+- name: Test service
|
||||
+ hosts: ipaserver
|
||||
+ become: yes
|
||||
+
|
||||
+ tasks:
|
||||
+ # setup
|
||||
+ - name: Setup test envirnoment.
|
||||
+ include_tasks: env_setup.yml
|
||||
+
|
||||
+ # Add service to test keytab create/retrieve attributes.
|
||||
+ - name: Ensure test service is present
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ pac_type:
|
||||
+ - MS-PAC
|
||||
+ - PAD
|
||||
+ auth_ind: otp
|
||||
+ force: yes
|
||||
+ requires_pre_auth: yes
|
||||
+ ok_as_delegate: no
|
||||
+ ok_to_auth_as_delegate: no
|
||||
+
|
||||
+ # tests
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for users.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for users, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for users.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for users, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for group.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for group, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for group.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for group, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for host.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for host, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for host.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for host, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for hostgroup.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab present for hostgroup, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for hostgroup.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ state: absent
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_create_keytab absent for hostgroup, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_create_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for users.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for users, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for users.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for users, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_user:
|
||||
+ - user01
|
||||
+ - user02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for group.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for group, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for group.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for group, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_group:
|
||||
+ - group01
|
||||
+ - group02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for host.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for host, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for host.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for host, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_host:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ - "{{ host2_fqdn }}"
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for hostgroup.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab present for hostgroup, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for hostgroup.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Service "HTTP/{{ svc_fqdn }}" members allow_retrieve_keytab absent for hostgroup, again.
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "HTTP/{{ svc_fqdn }}"
|
||||
+ allow_retrieve_keytab_hostgroup:
|
||||
+ - hostgroup01
|
||||
+ - hostgroup02
|
||||
+ action: member
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ # cleanup
|
||||
+ - name: Clean-up envirnoment.
|
||||
+ include_tasks: env_cleanup.yml
|
||||
--
|
||||
2.26.2
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
||||
From 563a03d94bfc29799ea964dab61a1ba35818b9bb Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Oliveira Campos <seocam@seocam.com>
|
||||
Date: Thu, 30 Jul 2020 09:50:24 -0300
|
||||
Subject: [PATCH] Fixed error msgs on FreeIPABaseModule subclasses
|
||||
|
||||
When a fail_json is called a SystemExit exeception is raised.
|
||||
Since the FreeIPABaseModule has an internal context manager to deal
|
||||
with exceptions this ContextManager captures the SystemExit. After
|
||||
dealing destroying the kinit session the SystemExit must be raised again
|
||||
to allow the fail_json to work properly.
|
||||
---
|
||||
plugins/module_utils/ansible_freeipa_module.py | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 122ea2e..a59e6e2 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -610,12 +610,15 @@ class FreeIPABaseModule(AnsibleModule):
|
||||
exit the module with proper arguments.
|
||||
|
||||
"""
|
||||
- if exc_val:
|
||||
- self.fail_json(msg=str(exc_val))
|
||||
-
|
||||
# TODO: shouldn't we also disconnect from api backend?
|
||||
temp_kdestroy(self.ccache_dir, self.ccache_name)
|
||||
|
||||
+ if exc_type == SystemExit:
|
||||
+ raise
|
||||
+
|
||||
+ if exc_val:
|
||||
+ self.fail_json(msg=str(exc_val))
|
||||
+
|
||||
self.exit_json(changed=self.changed, user=self.exit_args)
|
||||
|
||||
def get_command_errors(self, command, result):
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,327 @@
|
||||
From 3e5c54d4fdb10deda9b7e4deaf2c537b132711c9 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 31 Jul 2020 11:30:51 -0300
|
||||
Subject: [PATCH] Fix identification of existing vault type.
|
||||
|
||||
In some scenarios, the value of the vault type is returned as a tuple,
|
||||
rather than a string, this made some changes to existing vault to fail.
|
||||
With this change, the vault type is correctly retrieved, if it was not
|
||||
provided by the user.
|
||||
---
|
||||
plugins/modules/ipavault.py | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index 6a3c73e..8562ff7 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -494,8 +494,10 @@ def check_encryption_params(module, state, action, vault_type, salt,
|
||||
new_password, new_password_file, res_find):
|
||||
vault_type_invalid = []
|
||||
|
||||
- if res_find is not None:
|
||||
+ if vault_type is None and res_find is not None:
|
||||
vault_type = res_find['ipavaulttype']
|
||||
+ if isinstance(vault_type, (tuple, list)):
|
||||
+ vault_type = vault_type[0]
|
||||
|
||||
if vault_type == "standard":
|
||||
vault_type_invalid = ['public_key', 'public_key_file', 'password',
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From d52364bac923f2935b948882d5825e7488b0e9cf Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 31 Jul 2020 11:32:36 -0300
|
||||
Subject: [PATCH] Fix random salt generation.
|
||||
|
||||
The generation of a random salt, when one was not provided, was in the
|
||||
wrong place and being generated too late to be used properly. Also, the
|
||||
generation of the value was duplicated.
|
||||
---
|
||||
plugins/modules/ipavault.py | 13 +++++--------
|
||||
1 file changed, 5 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index 8562ff7..dffd972 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -768,7 +768,12 @@ def main():
|
||||
commands.append([name, "vault_mod_internal", args])
|
||||
|
||||
else:
|
||||
+ if vault_type == 'symmetric' \
|
||||
+ and 'ipavaultsalt' not in args:
|
||||
+ args['ipavaultsalt'] = os.urandom(32)
|
||||
+
|
||||
commands.append([name, "vault_add_internal", args])
|
||||
+
|
||||
if vault_type != 'standard' and vault_data is None:
|
||||
vault_data = ''
|
||||
|
||||
@@ -826,14 +831,6 @@ def main():
|
||||
commands.append(
|
||||
[name, 'vault_remove_owner', owner_del_args])
|
||||
|
||||
- if vault_type == 'symmetric' \
|
||||
- and 'ipavaultsalt' not in args:
|
||||
- args['ipavaultsalt'] = os.urandom(32)
|
||||
-
|
||||
- if vault_type == 'symmetric' \
|
||||
- and 'ipavaultsalt' not in args:
|
||||
- args['ipavaultsalt'] = os.urandom(32)
|
||||
-
|
||||
elif action in "member":
|
||||
# Add users and groups
|
||||
if any([users, groups, services]):
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From daee6a6c744a740329ca231a277229567619e10c Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 31 Jul 2020 11:33:47 -0300
|
||||
Subject: [PATCH] Fix verification of parameters for modifying `salt`
|
||||
attribute.
|
||||
|
||||
When modifying an existing vault to change the value of `salt`, the
|
||||
password must also change. It is fine to "change" the password to the
|
||||
same value, thus only changing the salt value.
|
||||
---
|
||||
plugins/modules/ipavault.py | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index dffd972..a608e64 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -517,6 +517,16 @@ def check_encryption_params(module, state, action, vault_type, salt,
|
||||
module.fail_json(
|
||||
msg="Cannot modify password of inexistent vault.")
|
||||
|
||||
+ if (
|
||||
+ salt is not None
|
||||
+ and not(
|
||||
+ any([password, password_file])
|
||||
+ and any([new_password, new_password_file])
|
||||
+ )
|
||||
+ ):
|
||||
+ module.fail_json(
|
||||
+ msg="Vault `salt` can only change when changing the password.")
|
||||
+
|
||||
if vault_type == "asymmetric":
|
||||
vault_type_invalid = [
|
||||
'password', 'password_file', 'new_password', 'new_password_file'
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 4ef4e706b79fdbb43e462b1a7130fc2cad5894b2 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 31 Jul 2020 11:42:13 -0300
|
||||
Subject: [PATCH] Modify tests to verify password was changed correctly.
|
||||
|
||||
Modify and add tests to verify that a password change has the correct
|
||||
effect on ipavault.
|
||||
---
|
||||
tests/vault/test_vault_symmetric.yml | 36 ++++++++++++++++++----------
|
||||
1 file changed, 23 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml
|
||||
index bedc221..9294331 100644
|
||||
--- a/tests/vault/test_vault_symmetric.yml
|
||||
+++ b/tests/vault/test_vault_symmetric.yml
|
||||
@@ -178,6 +178,15 @@
|
||||
register: result
|
||||
failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
+ - name: Retrieve data from symmetric vault, with wrong password.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeWRONGpassword
|
||||
+ state: retrieved
|
||||
+ register: result
|
||||
+ failed_when: not result.failed or "Invalid credentials" not in result.msg
|
||||
+
|
||||
- name: Change vault password.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -187,43 +196,44 @@
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Retrieve data from symmetric vault, with wrong password.
|
||||
+ - name: Retrieve data from symmetric vault, with new password.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: symvault
|
||||
- password: SomeVAULTpassword
|
||||
+ password: SomeNEWpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: not result.failed or "Invalid credentials" not in result.msg
|
||||
+ failed_when: result.data != 'Hello World.' or result.changed
|
||||
|
||||
- - name: Change vault password, with wrong `old_password`.
|
||||
+ - name: Retrieve data from symmetric vault, with old password.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: symvault
|
||||
password: SomeVAULTpassword
|
||||
- new_password: SomeNEWpassword
|
||||
+ state: retrieved
|
||||
register: result
|
||||
failed_when: not result.failed or "Invalid credentials" not in result.msg
|
||||
|
||||
- - name: Retrieve data from symmetric vault, with new password.
|
||||
+ - name: Change symmetric vault salt, changing password
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: symvault
|
||||
password: SomeNEWpassword
|
||||
- state: retrieved
|
||||
+ new_password: SomeVAULTpassword
|
||||
+ salt: AAAAAAAAAAAAAAAAAAAAAAA=
|
||||
register: result
|
||||
- failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
+ failed_when: not result.changed
|
||||
|
||||
- - name: Try to add vault with multiple passwords.
|
||||
+ - name: Change symmetric vault salt, without changing password
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
- name: inexistentvault
|
||||
+ name: symvault
|
||||
password: SomeVAULTpassword
|
||||
- password_file: "{{ ansible_env.HOME }}/password.txt"
|
||||
+ new_password: SomeVAULTpassword
|
||||
+ salt: MTIzNDU2Nzg5MDEyMzQ1Ngo=
|
||||
register: result
|
||||
- failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg
|
||||
+ failed_when: not result.changed
|
||||
|
||||
- - name: Try to add vault with multiple new passwords.
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: inexistentvault
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 8ca282e276477b52d0850d4c01feb3d8e7a5be6d Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 31 Jul 2020 11:44:33 -0300
|
||||
Subject: [PATCH] Modified and added tests to verify correct `salt` update
|
||||
behavior.
|
||||
|
||||
---
|
||||
tests/vault/test_vault_symmetric.yml | 35 ++++++++++++++++++++++++----
|
||||
1 file changed, 31 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml
|
||||
index 9294331..1604a01 100644
|
||||
--- a/tests/vault/test_vault_symmetric.yml
|
||||
+++ b/tests/vault/test_vault_symmetric.yml
|
||||
@@ -234,14 +234,41 @@
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
+ - name: Try to change symmetric vault salt, without providing any password
|
||||
ipavault:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
- name: inexistentvault
|
||||
- password: SomeVAULTpassword
|
||||
+ name: symvault
|
||||
+ salt: MTIzNDU2Nzg5MDEyMzQ1Ngo=
|
||||
+ register: result
|
||||
+ failed_when: not result.failed and "Vault `salt` can only change when changing the password." not in result.msg
|
||||
+
|
||||
+ - name: Try to change symmetric vault salt, without providing `password`
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ salt: MTIzNDU2Nzg5MDEyMzQ1Ngo=
|
||||
new_password: SomeVAULTpassword
|
||||
- new_password_file: "{{ ansible_env.HOME }}/password.txt"
|
||||
register: result
|
||||
- failed_when: not result.failed or "parameters are mutually exclusive" not in result.msg
|
||||
+ failed_when: not result.failed and "Vault `salt` can only change when changing the password." not in result.msg
|
||||
+
|
||||
+ - name: Try to change symmetric vault salt, without providing `new_password`
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ salt: MTIzNDU2Nzg5MDEyMzQ1Ngo=
|
||||
+ password: SomeVAULTpassword
|
||||
+ register: result
|
||||
+ failed_when: not result.failed and "Vault `salt` can only change when changing the password." not in result.msg
|
||||
+
|
||||
+ - name: Try to change symmetric vault salt, using wrong password.
|
||||
+ ipavault:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: symvault
|
||||
+ password: SomeWRONGpassword
|
||||
+ new_password: SomeWRONGpassword
|
||||
+ salt: MDEyMzQ1Njc4OTAxMjM0NQo=
|
||||
+ register: result
|
||||
+ failed_when: not result.failed
|
||||
|
||||
- name: Ensure symmetric vault is absent
|
||||
ipavault:
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 3c2700f68beade3513e0e44415d8eb4fb23026e8 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 14 Aug 2020 10:43:30 -0300
|
||||
Subject: [PATCH] Fixed Vault return value usage from `data` to `vault.data`.
|
||||
|
||||
A test was failing due to use of old ipavault module return structure
|
||||
and some places on the documentation were alse referring to it. All
|
||||
ocurrences were fixed.
|
||||
---
|
||||
README-vault.md | 2 +-
|
||||
plugins/modules/ipavault.py | 2 +-
|
||||
tests/vault/test_vault_symmetric.yml | 2 +-
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/README-vault.md b/README-vault.md
|
||||
index 91d311d..e7a31a2 100644
|
||||
--- a/README-vault.md
|
||||
+++ b/README-vault.md
|
||||
@@ -197,7 +197,7 @@ Example playbook to make sure vault is absent:
|
||||
state: absent
|
||||
register: result
|
||||
- debug:
|
||||
- msg: "{{ result.data }}"
|
||||
+ msg: "{{ result.vault.data }}"
|
||||
```
|
||||
|
||||
Variables
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index a608e64..8060976 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -243,7 +243,7 @@ EXAMPLES = """
|
||||
state: retrieved
|
||||
register: result
|
||||
- debug:
|
||||
- msg: "{{ result.data }}"
|
||||
+ msg: "{{ result.vault.data }}"
|
||||
|
||||
# Change password of a symmetric vault
|
||||
- ipavault:
|
||||
diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml
|
||||
index 1604a01..5394c71 100644
|
||||
--- a/tests/vault/test_vault_symmetric.yml
|
||||
+++ b/tests/vault/test_vault_symmetric.yml
|
||||
@@ -203,7 +203,7 @@
|
||||
password: SomeNEWpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from symmetric vault, with old password.
|
||||
ipavault:
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,112 @@
|
||||
From e57e4908f936c524085fb5853fe4493c7711ab3f Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Thu, 25 Jun 2020 16:26:30 -0300
|
||||
Subject: [PATCH] Fixes service disable when service has no certificates
|
||||
attached.
|
||||
|
||||
Services without certificates, but with keytabs were not being
|
||||
disabled. This change allows execution of service_disable if
|
||||
there is a certificate or if has_keytab is true.
|
||||
|
||||
A new test was added to verify the issue:
|
||||
|
||||
tests/service/test_service_disable.yml
|
||||
---
|
||||
plugins/modules/ipaservice.py | 8 +--
|
||||
tests/service/test_service_disable.yml | 68 ++++++++++++++++++++++++++
|
||||
2 files changed, 73 insertions(+), 3 deletions(-)
|
||||
create mode 100644 tests/service/test_service_disable.yml
|
||||
|
||||
diff --git a/plugins/modules/ipaservice.py b/plugins/modules/ipaservice.py
|
||||
index 23a0d6b3..b0d25355 100644
|
||||
--- a/plugins/modules/ipaservice.py
|
||||
+++ b/plugins/modules/ipaservice.py
|
||||
@@ -812,9 +812,11 @@ def main():
|
||||
|
||||
elif state == "disabled":
|
||||
if action == "service":
|
||||
- if res_find is not None and \
|
||||
- len(res_find.get('usercertificate', [])) > 0:
|
||||
- commands.append([name, 'service_disable', {}])
|
||||
+ if res_find is not None:
|
||||
+ has_cert = bool(res_find.get('usercertificate'))
|
||||
+ has_keytab = res_find.get('has_keytab', False)
|
||||
+ if has_cert or has_keytab:
|
||||
+ commands.append([name, 'service_disable', {}])
|
||||
else:
|
||||
ansible_module.fail_json(
|
||||
msg="Invalid action '%s' for state '%s'" %
|
||||
diff --git a/tests/service/test_service_disable.yml b/tests/service/test_service_disable.yml
|
||||
new file mode 100644
|
||||
index 00000000..3b4a88fb
|
||||
--- /dev/null
|
||||
+++ b/tests/service/test_service_disable.yml
|
||||
@@ -0,0 +1,68 @@
|
||||
+---
|
||||
+- name: Playbook to manage IPA service.
|
||||
+ hosts: ipaserver
|
||||
+ become: yes
|
||||
+ gather_facts: yes
|
||||
+
|
||||
+ tasks:
|
||||
+ - name: Ensure service is absent
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "mysvc1/{{ ansible_fqdn }}"
|
||||
+
|
||||
+ - name: Ensure service is present
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "mysvc1/{{ ansible_fqdn }}"
|
||||
+ certificate:
|
||||
+ - MIIC/zCCAeegAwIBAgIUMNHIbn+hhrOVew/2WbkteisV29QwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEdGVzdDAeFw0yMDAyMDQxNDQxMDhaFw0zMDAyMDExNDQxMDhaMA8xDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+XVVGFYpHVkcDfVnNInE1Y/pFciegdzqTjMwUWlRL4Zt3u96GhaMLRbtk+OfEkzLUAhWBOwEraELJzMLJOMvjYF3C+TiGO7dStFLikZmccuSsSIXjnzIPwBXa8KvgRVRyGLoVvGbLJvmjfMXp0nIToTx/i74KF9S++WEes9H5ErJ99CDhLKFgq0amnvsgparYXhypHaRLnikn0vQINt55YoEd1s4KrvEcD2VdZkIMPbLRu2zFvMprF3cjQQG4LT9ggfEXNIPZ1nQWAnAsu7OJEkNF+E4Mkmpcxj9aGUVt5bsq1D+Tzj3GsidSX0nSNcZ2JltXRnL/5v63g5cZyE+nAgMBAAGjUzBRMB0GA1UdDgQWBBRV0j7JYukuH/r/t9+QeNlRLXDlEDAfBgNVHSMEGDAWgBRV0j7JYukuH/r/t9+QeNlRLXDlEDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCgVy1+1kNwHs5y1Zp0WjMWGCJC6/zw7FDG4OW5r2GJiCXZYdJ0UonY9ZtoVLJPrp2/DAv1m5DtnDhBYqicuPgLzEkOS1KdTi20Otm/J4yxLLrZC5W4x0XOeSVPXOJuQWfwQ5pPvKkn6WxYUYkGwIt1OH2nSMngkbami3CbSmKZOCpgQIiSlQeDJ8oGjWFMLDymYSHoVOIXHwNoooyEiaio3693l6noobyGv49zyCVLVR1DC7i6RJ186ql0av+D4vPoiF5mX7+sKC2E8xEj9uKQ5GTWRh59VnRBVC/SiMJ/H78tJnBAvoBwXxSEvj8Z3Kjm/BQqZfv4IBsA5yqV7MVq
|
||||
+ force: no
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Obtain keytab
|
||||
+ shell: ipa-getkeytab -s "{{ ansible_fqdn }}" -p "mysvc1/{{ ansible_fqdn }}" -k mysvc1.keytab
|
||||
+
|
||||
+ - name: Verify keytab
|
||||
+ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}"
|
||||
+ register: result
|
||||
+ failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
+
|
||||
+ - name: Ensure service is disabled
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "mysvc1/{{ ansible_fqdn }}"
|
||||
+ state: disabled
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Verify keytab
|
||||
+ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}"
|
||||
+ register: result
|
||||
+ failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
+
|
||||
+ - name: Obtain keytab
|
||||
+ shell: ipa-getkeytab -s "{{ ansible_fqdn }}" -p "mysvc1/{{ ansible_fqdn }}" -k mysvc1.keytab
|
||||
+
|
||||
+ - name: Verify keytab
|
||||
+ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}"
|
||||
+ register: result
|
||||
+ failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
+
|
||||
+ - name: Ensure service is disabled
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "mysvc1/{{ ansible_fqdn }}"
|
||||
+ state: disabled
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Verify keytab
|
||||
+ shell: ipa service-find "mysvc1/{{ ansible_fqdn }}"
|
||||
+ register: result
|
||||
+ failed_when: result.failed or result.stdout | regex_search(" Keytab. true")
|
||||
+
|
||||
+ - name: Ensure service is absent
|
||||
+ ipaservice:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: "mysvc1/{{ ansible_fqdn }}"
|
@ -0,0 +1,300 @@
|
||||
From e96ef4e98e523f20c25777308c093ebbff272b2d Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Wed, 5 Aug 2020 15:24:15 -0300
|
||||
Subject: [PATCH] Updated documentation for ipavault module in the source code.
|
||||
|
||||
This change fixes a wrong parameter name in the documentation of
|
||||
RESULT_VALUES, and also provide a correct YAML snippet to ensure
|
||||
presence of an asymmetric vault with a formatted private key.
|
||||
---
|
||||
plugins/modules/ipavault.py | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index 46c6fcd..84645c7 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -267,7 +267,7 @@ EXAMPLES = """
|
||||
username: user01
|
||||
description: An asymmetric vault
|
||||
vault_type: asymmetric
|
||||
- public_key:
|
||||
+ public_key: |
|
||||
LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTR
|
||||
HTkFEQ0JpUUtCZ1FDdGFudjRkK3ptSTZ0T3ova1RXdGowY3AxRAowUENoYy8vR0pJMTUzTi
|
||||
9CN3UrN0h3SXlRVlZoNUlXZG1UcCtkWXYzd09yeVpPbzYvbHN5eFJaZ2pZRDRwQ3VGCjlxM
|
||||
@@ -303,7 +303,7 @@ EXAMPLES = """
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
-user:
|
||||
+data:
|
||||
description: The vault data.
|
||||
returned: If state is retrieved.
|
||||
type: string
|
||||
--
|
||||
2.26.2
|
||||
|
||||
From 7dd0b547c47b4fd617960490b8553a5036e3b30c Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Mon, 10 Aug 2020 16:02:09 -0300
|
||||
Subject: [PATCH] Modified return value for ipavault module.
|
||||
|
||||
The ipavault module was returning a single string value when retrieving
|
||||
data. To keep consistency with other modules, it should return a dict
|
||||
with the `data` variable in it.
|
||||
|
||||
This change modifies the result of ipavault to be a dict and also fixes
|
||||
relevant tests, examples and documentation.
|
||||
---
|
||||
README-vault.md | 5 +++++
|
||||
.../vault/retrive-data-asymmetric-vault.yml | 2 +-
|
||||
.../vault/retrive-data-symmetric-vault.yml | 2 +-
|
||||
plugins/modules/ipavault.py | 19 +++++++++++++------
|
||||
tests/vault/test_vault_asymmetric.yml | 12 ++++++------
|
||||
tests/vault/test_vault_standard.yml | 8 ++++----
|
||||
tests/vault/test_vault_symmetric.yml | 14 +++++++-------
|
||||
7 files changed, 37 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/README-vault.md b/README-vault.md
|
||||
index fa1d3e1..91d311d 100644
|
||||
--- a/README-vault.md
|
||||
+++ b/README-vault.md
|
||||
@@ -248,6 +248,11 @@ Variable | Description | Returned When
|
||||
-------- | ----------- | -------------
|
||||
`data` | The data stored in the vault. | If `state` is `retrieved`.
|
||||
|
||||
+Variable | Description | Returned When
|
||||
+-------- | ----------- | -------------
|
||||
+`vault` | Vault dict with archived data. (dict) <br>Options: | If `state` is `retrieved`.
|
||||
+ | `data` - The vault data. | Always
|
||||
+
|
||||
|
||||
Notes
|
||||
=====
|
||||
diff --git a/playbooks/vault/retrive-data-asymmetric-vault.yml b/playbooks/vault/retrive-data-asymmetric-vault.yml
|
||||
index 5f67c59..f71f826 100644
|
||||
--- a/playbooks/vault/retrive-data-asymmetric-vault.yml
|
||||
+++ b/playbooks/vault/retrive-data-asymmetric-vault.yml
|
||||
@@ -14,4 +14,4 @@
|
||||
state: retrieved
|
||||
register: result
|
||||
- debug:
|
||||
- msg: "Data: {{ result.data }}"
|
||||
+ msg: "Data: {{ result.vault.data }}"
|
||||
diff --git a/playbooks/vault/retrive-data-symmetric-vault.yml b/playbooks/vault/retrive-data-symmetric-vault.yml
|
||||
index 163f8b9..24692a8 100644
|
||||
--- a/playbooks/vault/retrive-data-symmetric-vault.yml
|
||||
+++ b/playbooks/vault/retrive-data-symmetric-vault.yml
|
||||
@@ -14,4 +14,4 @@
|
||||
state: retrieved
|
||||
register: result
|
||||
- debug:
|
||||
- msg: "{{ result.data | b64decode }}"
|
||||
+ msg: "{{ result.vault.data }}"
|
||||
diff --git a/plugins/modules/ipavault.py b/plugins/modules/ipavault.py
|
||||
index 84645c7..6a3c73e 100644
|
||||
--- a/plugins/modules/ipavault.py
|
||||
+++ b/plugins/modules/ipavault.py
|
||||
@@ -303,10 +303,15 @@ EXAMPLES = """
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
-data:
|
||||
- description: The vault data.
|
||||
- returned: If state is retrieved.
|
||||
- type: string
|
||||
+vault:
|
||||
+ description: Vault dict with archived data.
|
||||
+ returned: If state is `retrieved`.
|
||||
+ type: dict
|
||||
+ options:
|
||||
+ data:
|
||||
+ description: The vault data.
|
||||
+ returned: always
|
||||
+ type: string
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -910,9 +915,11 @@ def main():
|
||||
if 'result' not in result:
|
||||
raise Exception("No result obtained.")
|
||||
if 'data' in result['result']:
|
||||
- exit_args['data'] = result['result']['data']
|
||||
+ data_return = exit_args.setdefault('vault', {})
|
||||
+ data_return['data'] = result['result']['data']
|
||||
elif 'vault_data' in result['result']:
|
||||
- exit_args['data'] = result['result']['vault_data']
|
||||
+ data_return = exit_args.setdefault('vault', {})
|
||||
+ data_return['data'] = result['result']['vault_data']
|
||||
else:
|
||||
raise Exception("No data retrieved.")
|
||||
changed = False
|
||||
diff --git a/tests/vault/test_vault_asymmetric.yml b/tests/vault/test_vault_asymmetric.yml
|
||||
index 1a1d3dc..268922c 100644
|
||||
--- a/tests/vault/test_vault_asymmetric.yml
|
||||
+++ b/tests/vault/test_vault_asymmetric.yml
|
||||
@@ -42,7 +42,7 @@
|
||||
private_key: "{{ lookup('file', 'private.pem') | b64encode }}"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from asymmetric vault into file {{ ansible_env.HOME }}/data.txt.
|
||||
ipavault:
|
||||
@@ -75,7 +75,7 @@
|
||||
private_key: "{{ lookup('file', 'private.pem') | b64encode }}"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'The world of π is half rounded.' or result.changed
|
||||
+ failed_when: result.vault.data != 'The world of π is half rounded.' or result.changed
|
||||
|
||||
- name: Archive data in asymmetric vault, from file.
|
||||
ipavault:
|
||||
@@ -93,7 +93,7 @@
|
||||
private_key: "{{ lookup('file', 'private.pem') | b64encode }}"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Another World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Another World.' or result.changed
|
||||
|
||||
- name: Archive data with single character to asymmetric vault
|
||||
ipavault:
|
||||
@@ -110,7 +110,7 @@
|
||||
private_key: "{{ lookup('file', 'private.pem') | b64encode }}"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'c' or result.changed
|
||||
+ failed_when: result.vault.data != 'c' or result.changed
|
||||
|
||||
- name: Ensure asymmetric vault is absent
|
||||
ipavault:
|
||||
@@ -161,7 +161,7 @@
|
||||
private_key: "{{ lookup('file', 'private.pem') | b64encode }}"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from asymmetric vault, with password file.
|
||||
ipavault:
|
||||
@@ -170,7 +170,7 @@
|
||||
private_key_file: "{{ ansible_env.HOME }}/private.pem"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Ensure asymmetric vault is absent
|
||||
ipavault:
|
||||
diff --git a/tests/vault/test_vault_standard.yml b/tests/vault/test_vault_standard.yml
|
||||
index 5e0da98..6ccb0d5 100644
|
||||
--- a/tests/vault/test_vault_standard.yml
|
||||
+++ b/tests/vault/test_vault_standard.yml
|
||||
@@ -39,7 +39,7 @@
|
||||
name: stdvault
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from standard vault into file {{ ansible_env.HOME }}/data.txt.
|
||||
ipavault:
|
||||
@@ -70,7 +70,7 @@
|
||||
name: stdvault
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'The world of π is half rounded.' or result.changed
|
||||
+ failed_when: result.vault.data != 'The world of π is half rounded.' or result.changed
|
||||
|
||||
- name: Archive data in standard vault, from file.
|
||||
ipavault:
|
||||
@@ -87,7 +87,7 @@
|
||||
name: stdvault
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Another World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Another World.' or result.changed
|
||||
|
||||
- name: Archive data with single character to standard vault
|
||||
ipavault:
|
||||
@@ -103,7 +103,7 @@
|
||||
name: stdvault
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'c' or result.changed
|
||||
+ failed_when: result.vault.data != 'c' or result.changed
|
||||
|
||||
- name: Ensure standard vault is absent
|
||||
ipavault:
|
||||
diff --git a/tests/vault/test_vault_symmetric.yml b/tests/vault/test_vault_symmetric.yml
|
||||
index a6072d8..bedc221 100644
|
||||
--- a/tests/vault/test_vault_symmetric.yml
|
||||
+++ b/tests/vault/test_vault_symmetric.yml
|
||||
@@ -43,7 +43,7 @@
|
||||
password: SomeVAULTpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from symmetric vault into file {{ ansible_env.HOME }}/data.txt.
|
||||
ipavault:
|
||||
@@ -77,7 +77,7 @@
|
||||
password: SomeVAULTpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'The world of π is half rounded.' or result.changed
|
||||
+ failed_when: result.vault.data != 'The world of π is half rounded.' or result.changed
|
||||
|
||||
- name: Archive data in symmetric vault, from file.
|
||||
ipavault:
|
||||
@@ -95,7 +95,7 @@
|
||||
password: SomeVAULTpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Another World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Another World.' or result.changed
|
||||
|
||||
- name: Archive data with single character to symmetric vault
|
||||
ipavault:
|
||||
@@ -113,7 +113,7 @@
|
||||
password: SomeVAULTpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'c' or result.changed
|
||||
+ failed_when: result.vault.data != 'c' or result.changed
|
||||
|
||||
- name: Ensure symmetric vault is absent
|
||||
ipavault:
|
||||
@@ -167,7 +167,7 @@
|
||||
password: SomeVAULTpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Retrieve data from symmetric vault, with password file.
|
||||
ipavault:
|
||||
@@ -176,7 +176,7 @@
|
||||
password_file: "{{ ansible_env.HOME }}/password.txt"
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Change vault password.
|
||||
ipavault:
|
||||
@@ -212,7 +212,7 @@
|
||||
password: SomeNEWpassword
|
||||
state: retrieved
|
||||
register: result
|
||||
- failed_when: result.data != 'Hello World.' or result.changed
|
||||
+ failed_when: result.vault.data != 'Hello World.' or result.changed
|
||||
|
||||
- name: Try to add vault with multiple passwords.
|
||||
ipavault:
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 80aac15de9026055ae2b9972859939cf7925b813 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Tue, 30 Jun 2020 17:32:19 +0200
|
||||
Subject: [PATCH] action_plugins/ipaclient_get_otp: Discovered python needed in
|
||||
task_vars
|
||||
|
||||
Ansible is now also supporting discovered_python_interpreter for
|
||||
action_plugins. task_vars needs to be non Null and contain a setting for
|
||||
discovered_python_interpreter. The ipaclient_get_otp action_plugin
|
||||
therefore needed to be adapted.
|
||||
---
|
||||
roles/ipaclient/action_plugins/ipaclient_get_otp.py | 4 ++--
|
||||
roles/ipaclient/tasks/install.yml | 1 -
|
||||
2 files changed, 2 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/roles/ipaclient/action_plugins/ipaclient_get_otp.py b/roles/ipaclient/action_plugins/ipaclient_get_otp.py
|
||||
index dcddc0a..8e04ad9 100644
|
||||
--- a/roles/ipaclient/action_plugins/ipaclient_get_otp.py
|
||||
+++ b/roles/ipaclient/action_plugins/ipaclient_get_otp.py
|
||||
@@ -164,7 +164,8 @@ class ActionModule(ActionBase):
|
||||
return result
|
||||
|
||||
data = self._execute_module(module_name='ipaclient_get_facts',
|
||||
- module_args=dict(), task_vars=None)
|
||||
+ module_args=dict(), task_vars=task_vars)
|
||||
+
|
||||
try:
|
||||
domain = data['ansible_facts']['ipa']['domain']
|
||||
realm = data['ansible_facts']['ipa']['realm']
|
||||
@@ -245,4 +246,3 @@ class ActionModule(ActionBase):
|
||||
finally:
|
||||
# delete the local temp directory
|
||||
shutil.rmtree(local_temp_dir, ignore_errors=True)
|
||||
- run_cmd(['/usr/bin/kdestroy', '-c', tmp_ccache])
|
||||
diff --git a/roles/ipaclient/tasks/install.yml b/roles/ipaclient/tasks/install.yml
|
||||
index 0de3dea..4421f0c 100644
|
||||
--- a/roles/ipaclient/tasks/install.yml
|
||||
+++ b/roles/ipaclient/tasks/install.yml
|
||||
@@ -134,7 +134,6 @@
|
||||
"Password cannot be set on enrolled host" not
|
||||
in result_ipaclient_get_otp.msg
|
||||
delegate_to: "{{ result_ipaclient_test.servers[0] }}"
|
||||
- delegate_facts: yes
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Install - Report error for OTP generation
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,132 @@
|
||||
From 6132a947e65fb9c3a1ec5c059aed34afb06a67df Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Mon, 29 Jun 2020 13:12:12 +0200
|
||||
Subject: [PATCH] ipa[host]group: Fix membermanager unknow user issue
|
||||
|
||||
If a unknown membermanager user presence will be ensured, the unknown user
|
||||
error was ignored. This has been fixed in ipagroup. The code for the error
|
||||
handling in ipagroup and ipahostgroup has been adapted because of this.
|
||||
|
||||
New tests for tests/[host]group/test_[host]group_membermnager.yml have been
|
||||
added.
|
||||
---
|
||||
plugins/modules/ipagroup.py | 19 +++++++++----------
|
||||
plugins/modules/ipahostgroup.py | 13 +++++++------
|
||||
tests/group/test_group_membermanager.yml | 11 ++++++++++-
|
||||
.../test_hostgroup_membermanager.yml | 11 ++++++++++-
|
||||
4 files changed, 36 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipagroup.py b/plugins/modules/ipagroup.py
|
||||
index 915bc499..903c256d 100644
|
||||
--- a/plugins/modules/ipagroup.py
|
||||
+++ b/plugins/modules/ipagroup.py
|
||||
@@ -507,16 +507,15 @@ def main():
|
||||
# All "already a member" and "not a member" failures in the
|
||||
# result are ignored. All others are reported.
|
||||
errors = []
|
||||
- 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))
|
||||
+ for failed_item in result.get("failed", []):
|
||||
+ failed = result["failed"][failed_item]
|
||||
+ for member_type in failed:
|
||||
+ for member, failure in failed[member_type]:
|
||||
+ if "already a member" in failure \
|
||||
+ or "not a member" in failure:
|
||||
+ continue
|
||||
+ errors.append("%s: %s %s: %s" % (
|
||||
+ command, member_type, member, failure))
|
||||
if len(errors) > 0:
|
||||
ansible_module.fail_json(msg=", ".join(errors))
|
||||
|
||||
diff --git a/plugins/modules/ipahostgroup.py b/plugins/modules/ipahostgroup.py
|
||||
index 4c18e940..5f615160 100644
|
||||
--- a/plugins/modules/ipahostgroup.py
|
||||
+++ b/plugins/modules/ipahostgroup.py
|
||||
@@ -423,14 +423,15 @@ def main():
|
||||
# All "already a member" and "not a member" failures in the
|
||||
# result are ignored. All others are reported.
|
||||
errors = []
|
||||
- if "failed" in result and "member" in result["failed"]:
|
||||
- failed = result["failed"]["member"]
|
||||
+ for failed_item in result.get("failed", []):
|
||||
+ failed = result["failed"][failed_item]
|
||||
for member_type in failed:
|
||||
for member, failure in failed[member_type]:
|
||||
- if "already a member" not in failure \
|
||||
- and "not a member" not in failure:
|
||||
- errors.append("%s: %s %s: %s" % (
|
||||
- command, member_type, member, failure))
|
||||
+ 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))
|
||||
|
||||
diff --git a/tests/group/test_group_membermanager.yml b/tests/group/test_group_membermanager.yml
|
||||
index 1d38654f..661f26d6 100644
|
||||
--- a/tests/group/test_group_membermanager.yml
|
||||
+++ b/tests/group/test_group_membermanager.yml
|
||||
@@ -8,7 +8,7 @@
|
||||
- name: Ensure user manangeruser1 and manageruser2 is absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
- name: manageruser1,manageruser2
|
||||
+ name: manageruser1,manageruser2,unknown_user
|
||||
state: absent
|
||||
|
||||
- name: Ensure group testgroup, managergroup1 and managergroup2 are absent
|
||||
@@ -185,6 +185,15 @@
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
+ - name: Ensure unknown membermanager_user member failure
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: testgroup
|
||||
+ membermanager_user: unknown_user
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed or "no such entry" not in result.msg
|
||||
+
|
||||
- name: Ensure group testgroup, managergroup1 and managergroup2 are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
diff --git a/tests/hostgroup/test_hostgroup_membermanager.yml b/tests/hostgroup/test_hostgroup_membermanager.yml
|
||||
index c32d1088..c0f65460 100644
|
||||
--- a/tests/hostgroup/test_hostgroup_membermanager.yml
|
||||
+++ b/tests/hostgroup/test_hostgroup_membermanager.yml
|
||||
@@ -15,7 +15,7 @@
|
||||
- name: Ensure user manangeruser1 and manageruser2 is absent
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
- name: manageruser1,manageruser2
|
||||
+ name: manageruser1,manageruser2,unknown_user
|
||||
state: absent
|
||||
|
||||
- name: Ensure group managergroup1 and managergroup2 are absent
|
||||
@@ -200,6 +200,15 @@
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
+ - name: Ensure unknown membermanager_user member failure
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: testhostgroup
|
||||
+ membermanager_user: unknown_user
|
||||
+ action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed or "no such entry" not in result.msg
|
||||
+
|
||||
- name: Ensure host-group testhostgroup is absent
|
||||
ipahostgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
@ -0,0 +1,150 @@
|
||||
From 8ce5fd147aafc34e43dbe4246565c48eace2e115 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Thu, 2 Jul 2020 12:02:33 +0200
|
||||
Subject: [PATCH] ipa[server,replica]: Fix pkcs12 info regressions introduced
|
||||
with CA-less
|
||||
|
||||
With the CA-less patches the types for the pkcs12 infos have been changed
|
||||
to lists in the modules. This is resulting in a bad conversion from None
|
||||
to [''] for the parameters. Because of this a normal replica deployment is
|
||||
failing as [''] is not a valid value.
|
||||
|
||||
The install.yml files for ipareplica and also ipaserver have been changed
|
||||
in the way that the pkcs12 values are checked if they are None. The
|
||||
parameter will simply be omitted in this case and the parameter in the
|
||||
module will become None by default.
|
||||
---
|
||||
roles/ipareplica/tasks/install.yml | 18 +++++++++---------
|
||||
roles/ipaserver/tasks/install.yml | 10 +++++-----
|
||||
2 files changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
|
||||
index fc7f83e..c2a6222 100644
|
||||
--- a/roles/ipareplica/tasks/install.yml
|
||||
+++ b/roles/ipareplica/tasks/install.yml
|
||||
@@ -281,7 +281,7 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
installer_ccache: "{{ result_ipareplica_prepare.installer_ccache }}"
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
- _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}"
|
||||
+ _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info if result_ipareplica_prepare._dirsrv_pkcs12_info != None else omit }}"
|
||||
subject_base: "{{ result_ipareplica_prepare.subject_base }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
_add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}"
|
||||
@@ -345,7 +345,7 @@
|
||||
config_master_host_name:
|
||||
"{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
|
||||
# We need to point to the master in ipa default conf when certmonger
|
||||
@@ -407,8 +407,8 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
_ca_file: "{{ result_ipareplica_prepare._ca_file }}"
|
||||
- _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info if result_ipareplica_prepare._dirsrv_pkcs12_info != None else omit }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}"
|
||||
@@ -429,7 +429,7 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
_ca_file: "{{ result_ipareplica_prepare._ca_file }}"
|
||||
- _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info }}"
|
||||
+ _http_pkcs12_info: "{{ result_ipareplica_prepare._http_pkcs12_info if result_ipareplica_prepare._http_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
|
||||
@@ -507,7 +507,7 @@
|
||||
_kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"
|
||||
_kra_host_name: "{{ result_ipareplica_prepare.config_kra_host_name }}"
|
||||
_ca_file: "{{ result_ipareplica_prepare._ca_file }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
|
||||
@@ -529,7 +529,7 @@
|
||||
_kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"
|
||||
_kra_host_name: "{{ result_ipareplica_prepare.config_kra_host_name }}"
|
||||
_subject_base: "{{ result_ipareplica_prepare._subject_base }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
config_setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}"
|
||||
@@ -554,7 +554,7 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
_ca_file: "{{ result_ipareplica_prepare._ca_file }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
|
||||
@@ -574,7 +574,7 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
_ca_file: "{{ result_ipareplica_prepare._ca_file }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
ds_ca_subject: "{{ result_ipareplica_setup_ds.ds_ca_subject }}"
|
||||
diff --git a/roles/ipaserver/tasks/install.yml b/roles/ipaserver/tasks/install.yml
|
||||
index 30f9da2..687f72d 100644
|
||||
--- a/roles/ipaserver/tasks/install.yml
|
||||
+++ b/roles/ipaserver/tasks/install.yml
|
||||
@@ -203,7 +203,7 @@
|
||||
# no_host_dns: "{{ result_ipaserver_test.no_host_dns }}"
|
||||
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
|
||||
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default(omit) }}"
|
||||
- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}"
|
||||
+ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}"
|
||||
external_cert_files:
|
||||
"{{ ipaserver_external_cert_files | default(omit) }}"
|
||||
subject_base: "{{ result_ipaserver_prepare.subject_base }}"
|
||||
@@ -240,7 +240,7 @@
|
||||
no_hbac_allow: "{{ ipaserver_no_hbac_allow }}"
|
||||
idstart: "{{ result_ipaserver_test.idstart }}"
|
||||
idmax: "{{ result_ipaserver_test.idmax }}"
|
||||
- _pkinit_pkcs12_info: "{{ result_ipaserver_test._pkinit_pkcs12_info }}"
|
||||
+ _pkinit_pkcs12_info: "{{ result_ipaserver_test._pkinit_pkcs12_info if result_ipaserver_test._pkinit_pkcs12_info != None else omit }}"
|
||||
|
||||
- name: Install - Setup custodia
|
||||
ipaserver_setup_custodia:
|
||||
@@ -270,7 +270,7 @@
|
||||
no_pkinit: "{{ result_ipaserver_test.no_pkinit }}"
|
||||
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
|
||||
dirsrv_cert_files: "{{ ipaserver_dirsrv_cert_files | default([]) }}"
|
||||
- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}"
|
||||
+ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}"
|
||||
external_ca: "{{ ipaserver_external_ca }}"
|
||||
external_ca_type: "{{ ipaserver_external_ca_type | default(omit) }}"
|
||||
external_ca_profile:
|
||||
@@ -334,7 +334,7 @@
|
||||
idmax: "{{ result_ipaserver_test.idmax }}"
|
||||
http_cert_files: "{{ ipaserver_http_cert_files | default([]) }}"
|
||||
no_ui_redirect: "{{ ipaserver_no_ui_redirect }}"
|
||||
- _http_pkcs12_info: "{{ result_ipaserver_test._http_pkcs12_info }}"
|
||||
+ _http_pkcs12_info: "{{ result_ipaserver_test._http_pkcs12_info if result_ipaserver_test._http_pkcs12_info != None else omit }}"
|
||||
|
||||
- name: Install - Setup KRA
|
||||
ipaserver_setup_kra:
|
||||
@@ -394,7 +394,7 @@
|
||||
idstart: "{{ result_ipaserver_test.idstart }}"
|
||||
idmax: "{{ result_ipaserver_test.idmax }}"
|
||||
dirsrv_config_file: "{{ ipaserver_dirsrv_config_file | default(omit) }}"
|
||||
- _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info }}"
|
||||
+ _dirsrv_pkcs12_info: "{{ result_ipaserver_test._dirsrv_pkcs12_info if result_ipaserver_test._dirsrv_pkcs12_info != None else omit }}"
|
||||
|
||||
- name: Install - Setup client
|
||||
include_role:
|
||||
--
|
||||
2.26.2
|
||||
|
@ -0,0 +1,132 @@
|
||||
From 1d7fb31b8bfa00babd7c753b354d7344b531cd77 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Mon, 29 Jun 2020 14:50:56 +0200
|
||||
Subject: [PATCH] ipa[user,host]: Fail on duplucate names in the users and
|
||||
hosts lists
|
||||
|
||||
It was possible to have several entries for names with the hosts and users
|
||||
lists. This resulted sometimes in errors but also unexpected changes. A new
|
||||
check has been added to make sure that the names in the users and hosts
|
||||
lists are unique.
|
||||
|
||||
New tests have been added to verify this in the existing files:
|
||||
- tests/host/test_hosts.yml
|
||||
- tests/user/test_users.yml
|
||||
---
|
||||
plugins/modules/ipahost.py | 7 +++++++
|
||||
plugins/modules/ipauser.py | 7 +++++++
|
||||
tests/host/test_hosts.yml | 15 +++++++++++++++
|
||||
tests/user/test_users.yml | 19 +++++++++++++++++++
|
||||
4 files changed, 48 insertions(+)
|
||||
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index 7a981f16..1fe11dc5 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -799,10 +799,15 @@ def main():
|
||||
server_realm = api_get_realm()
|
||||
|
||||
commands = []
|
||||
+ host_set = set()
|
||||
|
||||
for host in names:
|
||||
if isinstance(host, dict):
|
||||
name = host.get("name")
|
||||
+ if name in host_set:
|
||||
+ ansible_module.fail_json(
|
||||
+ msg="host '%s' is used more than once" % name)
|
||||
+ host_set.add(name)
|
||||
description = host.get("description")
|
||||
locality = host.get("locality")
|
||||
location = host.get("location")
|
||||
@@ -1337,6 +1342,8 @@ def main():
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
+ del host_set
|
||||
+
|
||||
# Execute commands
|
||||
|
||||
errors = []
|
||||
diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py
|
||||
index b8152ee4..03713a41 100644
|
||||
--- a/plugins/modules/ipauser.py
|
||||
+++ b/plugins/modules/ipauser.py
|
||||
@@ -958,10 +958,15 @@ def main():
|
||||
# commands
|
||||
|
||||
commands = []
|
||||
+ user_set = set()
|
||||
|
||||
for user in names:
|
||||
if isinstance(user, dict):
|
||||
name = user.get("name")
|
||||
+ if name in user_set:
|
||||
+ ansible_module.fail_json(
|
||||
+ msg="user '%s' is used more than once" % name)
|
||||
+ user_set.add(name)
|
||||
# present
|
||||
first = user.get("first")
|
||||
last = user.get("last")
|
||||
@@ -1370,6 +1375,8 @@ def main():
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
+ del user_set
|
||||
+
|
||||
# Execute commands
|
||||
|
||||
errors = []
|
||||
diff --git a/tests/host/test_hosts.yml b/tests/host/test_hosts.yml
|
||||
index 30fd6538..f82cc612 100644
|
||||
--- a/tests/host/test_hosts.yml
|
||||
+++ b/tests/host/test_hosts.yml
|
||||
@@ -96,3 +96,18 @@
|
||||
state: absent
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
+
|
||||
+ - name: Duplicate names in hosts failure test
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ hosts:
|
||||
+ - name: "{{ host1_fqdn }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ host2_fqdn }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ host3_fqdn }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ host3_fqdn }}"
|
||||
+ force: yes
|
||||
+ register: result
|
||||
+ failed_when: result.changed or "is used more than once" not in result.msg
|
||||
diff --git a/tests/user/test_users.yml b/tests/user/test_users.yml
|
||||
index 5b5d4538..81c7b608 100644
|
||||
--- a/tests/user/test_users.yml
|
||||
+++ b/tests/user/test_users.yml
|
||||
@@ -85,6 +85,25 @@
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
+ - name: Duplicate names in users failure test
|
||||
+ ipauser:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ users:
|
||||
+ - name: user1
|
||||
+ givenname: user1
|
||||
+ last: Last
|
||||
+ - name: user2
|
||||
+ first: user2
|
||||
+ last: Last
|
||||
+ - name: user3
|
||||
+ first: user3
|
||||
+ last: Last
|
||||
+ - name: user3
|
||||
+ first: user3
|
||||
+ last: Last
|
||||
+ register: result
|
||||
+ failed_when: result.changed or "is used more than once" not in result.msg
|
||||
+
|
||||
- name: Remove test users
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
@ -0,0 +1,271 @@
|
||||
From 7a2eaa6f535b1353d46bcfa8b0b2484b15ff3863 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Tue, 7 Jul 2020 17:13:09 +0200
|
||||
Subject: [PATCH] ipareplica: Fix missing parameters for several modules
|
||||
|
||||
The parameters master_host_name, config_setup_ca, dirman_password have not
|
||||
been set for some modules. Also there was no ldap2 connection within
|
||||
ipareplica_setup_kra. All this resulted in improper configuration where
|
||||
for example KRA deployment failed in the end.
|
||||
|
||||
A conversion warning in ipareplica_setup_adtrust has also been fixed for
|
||||
the setup_ca parameter.
|
||||
|
||||
Fixes #314 (IPA replica installation failure - DS enabled SSL - second part)
|
||||
---
|
||||
.../library/ipareplica_create_ipa_conf.py | 1 +
|
||||
.../library/ipareplica_ds_apply_updates.py | 1 +
|
||||
.../library/ipareplica_ds_enable_ssl.py | 1 +
|
||||
.../library/ipareplica_setup_adtrust.py | 2 +-
|
||||
.../library/ipareplica_setup_custodia.py | 1 +
|
||||
.../library/ipareplica_setup_http.py | 2 +-
|
||||
.../ipareplica/library/ipareplica_setup_kra.py | 18 ++++++++++++++++++
|
||||
.../ipareplica/library/ipareplica_setup_krb.py | 7 +++++++
|
||||
roles/ipareplica/tasks/install.yml | 8 ++++++++
|
||||
9 files changed, 39 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/roles/ipareplica/library/ipareplica_create_ipa_conf.py b/roles/ipareplica/library/ipareplica_create_ipa_conf.py
|
||||
index 3a85a6f..c475469 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_create_ipa_conf.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_create_ipa_conf.py
|
||||
@@ -262,6 +262,7 @@ def main():
|
||||
config.subject_base = options.subject_base
|
||||
config.dirman_password = dirman_password
|
||||
config.ca_host_name = ca_host_name
|
||||
+ config.setup_ca = options.setup_ca
|
||||
|
||||
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
|
||||
installer._remote_api = remote_api
|
||||
diff --git a/roles/ipareplica/library/ipareplica_ds_apply_updates.py b/roles/ipareplica/library/ipareplica_ds_apply_updates.py
|
||||
index 3796874..71008b3 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_ds_apply_updates.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_ds_apply_updates.py
|
||||
@@ -177,6 +177,7 @@ def main():
|
||||
config = gen_ReplicaConfig()
|
||||
config.dirman_password = dirman_password
|
||||
config.subject_base = options.subject_base
|
||||
+ config.master_host_name = master_host_name
|
||||
|
||||
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
|
||||
|
||||
diff --git a/roles/ipareplica/library/ipareplica_ds_enable_ssl.py b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
|
||||
index a1b638e..3e4090d 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
|
||||
@@ -173,6 +173,7 @@ def main():
|
||||
config = gen_ReplicaConfig()
|
||||
config.dirman_password = dirman_password
|
||||
config.subject_base = options.subject_base
|
||||
+ config.master_host_name = master_host_name
|
||||
|
||||
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
|
||||
# installer._remote_api = remote_api
|
||||
diff --git a/roles/ipareplica/library/ipareplica_setup_adtrust.py b/roles/ipareplica/library/ipareplica_setup_adtrust.py
|
||||
index c830ebf..734e56d 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_setup_adtrust.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_setup_adtrust.py
|
||||
@@ -110,7 +110,7 @@ def main():
|
||||
# additional
|
||||
ccache=dict(required=True),
|
||||
_top_dir=dict(required=True),
|
||||
- setup_ca=dict(required=True),
|
||||
+ setup_ca=dict(required=True, type='bool'),
|
||||
config_master_host_name=dict(required=True),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
diff --git a/roles/ipareplica/library/ipareplica_setup_custodia.py b/roles/ipareplica/library/ipareplica_setup_custodia.py
|
||||
index 5a74e87..2e95c26 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_setup_custodia.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_setup_custodia.py
|
||||
@@ -169,6 +169,7 @@ def main():
|
||||
config.promote = installer.promote
|
||||
config.kra_enabled = kra_enabled
|
||||
config.kra_host_name = kra_host_name
|
||||
+ config.setup_ca = options.setup_ca
|
||||
|
||||
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
|
||||
|
||||
diff --git a/roles/ipareplica/library/ipareplica_setup_http.py b/roles/ipareplica/library/ipareplica_setup_http.py
|
||||
index 987ea95..3fa4807 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_setup_http.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_setup_http.py
|
||||
@@ -164,7 +164,7 @@ def main():
|
||||
config.subject_base = options.subject_base
|
||||
config.dirman_password = dirman_password
|
||||
config.setup_ca = options.setup_ca
|
||||
- # config.master_host_name = master_host_name
|
||||
+ config.master_host_name = master_host_name
|
||||
config.ca_host_name = ca_host_name
|
||||
config.promote = installer.promote
|
||||
|
||||
diff --git a/roles/ipareplica/library/ipareplica_setup_kra.py b/roles/ipareplica/library/ipareplica_setup_kra.py
|
||||
index 3149c10..0b2f681 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_setup_kra.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_setup_kra.py
|
||||
@@ -120,6 +120,9 @@ options:
|
||||
_subject_base:
|
||||
description: The installer _subject_base setting
|
||||
required: no
|
||||
+ dirman_password:
|
||||
+ description: Directory Manager (master) password
|
||||
+ required: no
|
||||
author:
|
||||
- Thomas Woerner
|
||||
'''
|
||||
@@ -173,10 +176,12 @@ def main():
|
||||
_ca_enabled=dict(required=False, type='bool'),
|
||||
_kra_enabled=dict(required=False, type='bool'),
|
||||
_kra_host_name=dict(required=False),
|
||||
+ _ca_host_name=dict(required=False),
|
||||
_top_dir=dict(required=True),
|
||||
_add_to_ipaservers=dict(required=True, type='bool'),
|
||||
_ca_subject=dict(required=True),
|
||||
_subject_base=dict(required=True),
|
||||
+ dirman_password=dict(required=True, no_log=True),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -233,6 +238,7 @@ def main():
|
||||
ca_enabled = ansible_module.params.get('_ca_enabled')
|
||||
kra_enabled = ansible_module.params.get('_kra_enabled')
|
||||
kra_host_name = ansible_module.params.get('_kra_host_name')
|
||||
+ ca_host_name = ansible_module.params.get('_ca_host_name')
|
||||
|
||||
options.subject_base = ansible_module.params.get('subject_base')
|
||||
if options.subject_base is not None:
|
||||
@@ -243,6 +249,7 @@ def main():
|
||||
|
||||
options._ca_subject = ansible_module.params.get('_ca_subject')
|
||||
options._subject_base = ansible_module.params.get('_subject_base')
|
||||
+ dirman_password = ansible_module.params.get('dirman_password')
|
||||
|
||||
# init #
|
||||
|
||||
@@ -254,14 +261,25 @@ def main():
|
||||
constants.DEFAULT_CONFIG)
|
||||
api_bootstrap_finalize(env)
|
||||
config = gen_ReplicaConfig()
|
||||
+ config.dirman_password = dirman_password
|
||||
config.subject_base = options.subject_base
|
||||
config.promote = installer.promote
|
||||
config.kra_enabled = kra_enabled
|
||||
config.kra_host_name = kra_host_name
|
||||
+ config.ca_host_name = ca_host_name
|
||||
+ config.master_host_name = master_host_name
|
||||
|
||||
remote_api = gen_remote_api(master_host_name, paths.ETC_IPA)
|
||||
installer._remote_api = remote_api
|
||||
|
||||
+ conn = remote_api.Backend.ldap2
|
||||
+ ccache = os.environ['KRB5CCNAME']
|
||||
+
|
||||
+ # There is a api.Backend.ldap2.connect call somewhere in ca, ds, dns or
|
||||
+ # ntpinstance
|
||||
+ api.Backend.ldap2.connect()
|
||||
+ conn.connect(ccache=ccache)
|
||||
+
|
||||
with redirect_stdout(ansible_log):
|
||||
ansible_log.debug("-- INSTALL KRA --")
|
||||
|
||||
diff --git a/roles/ipareplica/library/ipareplica_setup_krb.py b/roles/ipareplica/library/ipareplica_setup_krb.py
|
||||
index c8d09f7..4500a6f 100644
|
||||
--- a/roles/ipareplica/library/ipareplica_setup_krb.py
|
||||
+++ b/roles/ipareplica/library/ipareplica_setup_krb.py
|
||||
@@ -63,6 +63,9 @@ options:
|
||||
_top_dir:
|
||||
description: The installer _top_dir setting
|
||||
required: no
|
||||
+ dirman_password:
|
||||
+ description: Directory Manager (master) password
|
||||
+ required: no
|
||||
author:
|
||||
- Thomas Woerner
|
||||
'''
|
||||
@@ -98,6 +101,7 @@ def main():
|
||||
ccache=dict(required=True),
|
||||
_pkinit_pkcs12_info=dict(required=False, type='list'),
|
||||
_top_dir=dict(required=True),
|
||||
+ dirman_password=dict(required=True, no_log=True),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -126,6 +130,7 @@ def main():
|
||||
'_pkinit_pkcs12_info')
|
||||
|
||||
options._top_dir = ansible_module.params.get('_top_dir')
|
||||
+ dirman_password = ansible_module.params.get('dirman_password')
|
||||
|
||||
# init #
|
||||
|
||||
@@ -141,8 +146,10 @@ def main():
|
||||
constants.DEFAULT_CONFIG)
|
||||
api_bootstrap_finalize(env)
|
||||
config = gen_ReplicaConfig()
|
||||
+ config.dirman_password = dirman_password
|
||||
config.master_host_name = config_master_host_name
|
||||
config.subject_base = options.subject_base
|
||||
+ config.setup_ca = options.setup_ca
|
||||
|
||||
ccache = os.environ['KRB5CCNAME']
|
||||
|
||||
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
|
||||
index c2a6222..ddb3f85 100644
|
||||
--- a/roles/ipareplica/tasks/install.yml
|
||||
+++ b/roles/ipareplica/tasks/install.yml
|
||||
@@ -226,6 +226,8 @@
|
||||
setup_adtrust: "{{ result_ipareplica_test.setup_adtrust }}"
|
||||
setup_kra: "{{ result_ipareplica_test.setup_kra }}"
|
||||
setup_dns: "{{ ipareplica_setup_dns }}"
|
||||
+ ### server ###
|
||||
+ setup_ca: "{{ ipareplica_setup_ca }}"
|
||||
### ssl certificate ###
|
||||
dirsrv_cert_files: "{{ ipareplica_dirsrv_cert_files | default([]) }}"
|
||||
### client ###
|
||||
@@ -332,6 +334,7 @@
|
||||
_ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
|
||||
_subject_base: "{{ result_ipareplica_prepare._subject_base }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
+ setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}"
|
||||
|
||||
- name: Install - Setup KRB
|
||||
ipareplica_setup_krb:
|
||||
@@ -347,6 +350,7 @@
|
||||
ccache: "{{ result_ipareplica_prepare.ccache }}"
|
||||
_pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info if result_ipareplica_prepare._pkinit_pkcs12_info != None else omit }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
+ dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
|
||||
# We need to point to the master in ipa default conf when certmonger
|
||||
# asks for HTTP certificate in newer ipa versions. In these versions
|
||||
@@ -388,6 +392,7 @@
|
||||
_ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
|
||||
_subject_base: "{{ result_ipareplica_prepare._subject_base }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
+ setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}"
|
||||
master:
|
||||
"{{ result_ipareplica_install_ca_certs.config_master_host_name }}"
|
||||
when: result_ipareplica_test.change_master_for_certmonger
|
||||
@@ -471,6 +476,7 @@
|
||||
_ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
|
||||
_subject_base: "{{ result_ipareplica_prepare._subject_base }}"
|
||||
dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
+ setup_ca: "{{ result_ipareplica_prepare.config_setup_ca }}"
|
||||
when: result_ipareplica_test.change_master_for_certmonger
|
||||
|
||||
- name: Install - Setup otpd
|
||||
@@ -611,10 +617,12 @@
|
||||
_ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
|
||||
_kra_enabled: "{{ result_ipareplica_prepare._kra_enabled }}"
|
||||
_kra_host_name: "{{ result_ipareplica_prepare.config_kra_host_name }}"
|
||||
+ _ca_host_name: "{{ result_ipareplica_prepare.config_ca_host_name }}"
|
||||
_top_dir: "{{ result_ipareplica_prepare._top_dir }}"
|
||||
_add_to_ipaservers: "{{ result_ipareplica_prepare._add_to_ipaservers }}"
|
||||
_ca_subject: "{{ result_ipareplica_prepare._ca_subject }}"
|
||||
_subject_base: "{{ result_ipareplica_prepare._subject_base }}"
|
||||
+ dirman_password: "{{ ipareplica_dirman_password }}"
|
||||
when: result_ipareplica_test.setup_kra
|
||||
|
||||
- name: Install - Restart KDC
|
||||
--
|
||||
2.26.2
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,177 +0,0 @@
|
||||
From 3780a9a00e77ae0fd2944b36adad446d094fc90f Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Tue, 11 Feb 2020 10:34:39 +0100
|
||||
Subject: [PATCH] ansible_freeipa_module: Fix comparison of bool parameters in
|
||||
compare_args_ipa
|
||||
|
||||
Bool types are not iterable. Therefore the comparison using sets was failing
|
||||
with a TypeError. This prevented to change the bool parameters for hosts.
|
||||
|
||||
A test for the host module has been added to verify that the bool parameters
|
||||
can be modified.
|
||||
|
||||
New test:
|
||||
|
||||
tests/host/test_host_bool_params.yml
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1784514
|
||||
---
|
||||
.../module_utils/ansible_freeipa_module.py | 18 ++-
|
||||
tests/host/test_host_bool_params.yml | 119 ++++++++++++++++++
|
||||
2 files changed, 133 insertions(+), 4 deletions(-)
|
||||
create mode 100644 tests/host/test_host_bool_params.yml
|
||||
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 8154a12..9e97b88 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -222,10 +222,20 @@ def compare_args_ipa(module, args, ipa):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
if isinstance(ipa_arg[0], unicode) and isinstance(arg[0], int):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
- # module.warn("%s <=> %s" % (arg, ipa_arg))
|
||||
- if set(arg) != set(ipa_arg):
|
||||
- # module.warn("DIFFERENT")
|
||||
- return False
|
||||
+ # module.warn("%s <=> %s" % (repr(arg), repr(ipa_arg)))
|
||||
+ try:
|
||||
+ arg_set = set(arg)
|
||||
+ ipa_arg_set = set(ipa_arg)
|
||||
+ except TypeError:
|
||||
+ if arg != ipa_arg:
|
||||
+ # module.warn("%s != %s" % (repr(arg), repr(ipa_arg)))
|
||||
+ return False
|
||||
+ else:
|
||||
+ if arg_set != ipa_arg_set:
|
||||
+ # module.warn("%s != %s" % (repr(arg), repr(ipa_arg)))
|
||||
+ return False
|
||||
+
|
||||
+ # module.warn("%s == %s" % (repr(arg), repr(ipa_arg)))
|
||||
|
||||
return True
|
||||
|
||||
diff --git a/tests/host/test_host_bool_params.yml b/tests/host/test_host_bool_params.yml
|
||||
new file mode 100644
|
||||
index 0000000..824ea99
|
||||
--- /dev/null
|
||||
+++ b/tests/host/test_host_bool_params.yml
|
||||
@@ -0,0 +1,119 @@
|
||||
+---
|
||||
+- name: Test host bool parameters
|
||||
+ 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 }}"
|
||||
+
|
||||
+ - name: Host absent
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ update_dns: yes
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth, ok_as_delegate and ok_to_auth_as_delegate
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ force: yes
|
||||
+ requires_pre_auth: yes
|
||||
+ ok_as_delegate: yes
|
||||
+ ok_to_auth_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth, ok_as_delegate and ok_to_auth_as_delegate again
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ requires_pre_auth: yes
|
||||
+ ok_as_delegate: yes
|
||||
+ ok_to_auth_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth, ok_as_delegate and ok_to_auth_as_delegate set to no
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ requires_pre_auth: no
|
||||
+ ok_as_delegate: no
|
||||
+ ok_to_auth_as_delegate: no
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth, ok_as_delegate and ok_to_auth_as_delegate set to no again
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ requires_pre_auth: no
|
||||
+ ok_as_delegate: no
|
||||
+ ok_to_auth_as_delegate: no
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ requires_pre_auth: yes
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with requires_pre_auth again
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ requires_pre_auth: yes
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with ok_as_delegate
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ ok_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with ok_as_delegate again
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ ok_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with ok_to_auth_as_delegate
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ ok_to_auth_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Host "{{ host1_fqdn }}" present with ok_to_auth_as_delegate again
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: "{{ host1_fqdn }}"
|
||||
+ ok_to_auth_as_delegate: yes
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Host absent
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name:
|
||||
+ - "{{ host1_fqdn }}"
|
||||
+ update_dns: yes
|
||||
+ state: absent
|
@ -1,838 +0,0 @@
|
||||
From 3865ce657e3ea1b621aa054c792201aedfde2d11 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Fri, 7 Feb 2020 10:11:38 +0100
|
||||
Subject: [PATCH] ipahbacrule: Fix handing of members with action hbacrule
|
||||
|
||||
Changing members (host, hostgroup, hbacsvc, hbacsvcgroup, user, group) with
|
||||
action hbacrule was not working due to the use of the wrong parameter
|
||||
prefix. This has been fixed and the old members are removed correctly now.
|
||||
|
||||
The test script has been reworked completely to verify the fix.
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1787996
|
||||
---
|
||||
plugins/modules/ipahbacrule.py | 24 +-
|
||||
tests/hbacrule/test_hbacrule.yml | 549 +++++++++++++++++++++++--------
|
||||
2 files changed, 432 insertions(+), 141 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipahbacrule.py b/plugins/modules/ipahbacrule.py
|
||||
index 385876b..82340c2 100644
|
||||
--- a/plugins/modules/ipahbacrule.py
|
||||
+++ b/plugins/modules/ipahbacrule.py
|
||||
@@ -344,41 +344,41 @@ def main():
|
||||
# Generate addition and removal lists
|
||||
host_add = list(
|
||||
set(host or []) -
|
||||
- set(res_find.get("member_host", [])))
|
||||
+ set(res_find.get("memberhost_host", [])))
|
||||
host_del = list(
|
||||
- set(res_find.get("member_host", [])) -
|
||||
+ set(res_find.get("memberhost_host", [])) -
|
||||
set(host or []))
|
||||
hostgroup_add = list(
|
||||
set(hostgroup or []) -
|
||||
- set(res_find.get("member_hostgroup", [])))
|
||||
+ set(res_find.get("memberhost_hostgroup", [])))
|
||||
hostgroup_del = list(
|
||||
- set(res_find.get("member_hostgroup", [])) -
|
||||
+ set(res_find.get("memberhost_hostgroup", [])) -
|
||||
set(hostgroup or []))
|
||||
|
||||
hbacsvc_add = list(
|
||||
set(hbacsvc or []) -
|
||||
- set(res_find.get("member_hbacsvc", [])))
|
||||
+ set(res_find.get("memberservice_hbacsvc", [])))
|
||||
hbacsvc_del = list(
|
||||
- set(res_find.get("member_hbacsvc", [])) -
|
||||
+ set(res_find.get("memberservice_hbacsvc", [])) -
|
||||
set(hbacsvc or []))
|
||||
hbacsvcgroup_add = list(
|
||||
set(hbacsvcgroup or []) -
|
||||
- set(res_find.get("member_hbacsvcgroup", [])))
|
||||
+ set(res_find.get("memberservice_hbacsvcgroup", [])))
|
||||
hbacsvcgroup_del = list(
|
||||
- set(res_find.get("member_hbacsvcgroup", [])) -
|
||||
+ set(res_find.get("memberservice_hbacsvcgroup", [])) -
|
||||
set(hbacsvcgroup or []))
|
||||
|
||||
user_add = list(
|
||||
set(user or []) -
|
||||
- set(res_find.get("member_user", [])))
|
||||
+ set(res_find.get("memberuser_user", [])))
|
||||
user_del = list(
|
||||
- set(res_find.get("member_user", [])) -
|
||||
+ set(res_find.get("memberuser_user", [])) -
|
||||
set(user or []))
|
||||
group_add = list(
|
||||
set(group or []) -
|
||||
- set(res_find.get("member_group", [])))
|
||||
+ set(res_find.get("memberuser_group", [])))
|
||||
group_del = list(
|
||||
- set(res_find.get("member_group", [])) -
|
||||
+ set(res_find.get("memberuser_group", [])) -
|
||||
set(group or []))
|
||||
|
||||
# Add hosts and hostgroups
|
||||
diff --git a/tests/hbacrule/test_hbacrule.yml b/tests/hbacrule/test_hbacrule.yml
|
||||
index a5615cc..38858d3 100644
|
||||
--- a/tests/hbacrule/test_hbacrule.yml
|
||||
+++ b/tests/hbacrule/test_hbacrule.yml
|
||||
@@ -1,338 +1,629 @@
|
||||
---
|
||||
-- name: Tests
|
||||
+- name: Playbook to handle hbacrules
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
- gather_facts: false
|
||||
|
||||
tasks:
|
||||
- - name: Ensure HBAC Rule allhosts is absent
|
||||
- ipahbacrule:
|
||||
+ - name: Get Domain from server name
|
||||
+ set_fact:
|
||||
+ ipaserver_domain: "{{ groups.ipaserver[0].split('.')[1:] | join ('.') }}"
|
||||
+ when: ipaserver_domain is not defined
|
||||
+
|
||||
+ # CLEANUP TEST ITEMS
|
||||
+
|
||||
+ - name: Ensure test hosts are absent
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test hostgroups are absent
|
||||
+ ipahostgroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts,sshd-pinky,loginRule
|
||||
+ name: testhostgroup01,testhostgroup02,testhostgroup03,testhostgroup04
|
||||
state: absent
|
||||
|
||||
- - name: User pinky absent
|
||||
+ - name: Ensure test users are absent
|
||||
ipauser:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: pinky
|
||||
+ name: testuser01,testuser02,testuser03,testuser04
|
||||
state: absent
|
||||
|
||||
- - name: User group login absent
|
||||
+ - name: Ensure test user groups are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: login
|
||||
+ name: testgroup01,testgroup02,testgroup03,testgroup04
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test HBAC Services are absent
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc01,testhbacsvc02,testhbacsvc03,testhbacsvc04
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test HBAC Service Groups are absent
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup01,testhbacsvcgroup02,testhbacsvcgroup03,testhbacsvcgroup04
|
||||
state: absent
|
||||
|
||||
- - name: User pinky present
|
||||
+ # CREATE TEST ITEMS
|
||||
+
|
||||
+ - name: Ensure hosts "{{ 'host[1..4].' + ipaserver_domain }}" are present
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ hosts:
|
||||
+ - name: "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ force: yes
|
||||
+ - name: "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ force: yes
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure host-group testhostgroup01 is present
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhostgroup01
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure host-group testhostgroup02 is present
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhostgroup02
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure host-group testhostgroup03 is present
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhostgroup03
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure host-group testhostgroup04 is present
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhostgroup04
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure testusers are present
|
||||
ipauser:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: pinky
|
||||
- uid: 10001
|
||||
- gid: 100
|
||||
- phone: "+555123457"
|
||||
- email: pinky@acme.com
|
||||
- principalexpiration: "20220119235959"
|
||||
- #passwordexpiration: "2022-01-19 23:59:59"
|
||||
- first: pinky
|
||||
- last: Acme
|
||||
+ users:
|
||||
+ - name: testuser01
|
||||
+ first: test
|
||||
+ last: user01
|
||||
+ - name: testuser02
|
||||
+ first: test
|
||||
+ last: user02
|
||||
+ - name: testuser03
|
||||
+ first: test
|
||||
+ last: user03
|
||||
+ - name: testuser04
|
||||
+ first: test
|
||||
+ last: user04
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: User group login present
|
||||
+ - name: Ensure user group testgroup01 is present
|
||||
ipagroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: login
|
||||
+ name: testgroup01
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule allhosts is present
|
||||
- ipahbacrule:
|
||||
+ - name: Ensure user group testgroup02 is present
|
||||
+ ipagroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- usercategory: all
|
||||
+ name: testgroup02
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule allhosts is present again
|
||||
- ipahbacrule:
|
||||
+ - name: Ensure user group testgroup03 is present
|
||||
+ ipagroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- usercategory: all
|
||||
+ name: testgroup03
|
||||
register: result
|
||||
- failed_when: result.changed
|
||||
+ failed_when: not result.changed
|
||||
|
||||
- - name: Ensure host "{{ groups.ipaserver[0] }}" is present in HBAC Rule allhosts
|
||||
+ - name: Ensure user group testgroup04 is present
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testgroup04
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service testhbacsvc01 is present
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc01
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service testhbacsvc02 is present
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc02
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service testhbacsvc03 is present
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc03
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service testhbacsvc04 is present
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc04
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service Group testhbacsvcgroup01 is present
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup01
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service Group testhbacsvcgroup02 is present
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup02
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service Group testhbacsvcgroup03 is present
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup03
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC Service Group testhbacsvcgroup04 is present
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup04
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure test HBAC rule hbacrule01 is absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- host: "{{ groups.ipaserver[0] }}"
|
||||
- action: member
|
||||
+ name: hbacrule01
|
||||
+ state: absent
|
||||
+
|
||||
+ # ENSURE HBACRULE
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present
|
||||
+ ipahbacrule:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: hbacrule01
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure host "{{ groups.ipaserver[0] }}" is present in HBAC Rule allhosts again
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- host: "{{ groups.ipaserver[0] }}"
|
||||
- action: member
|
||||
+ name: hbacrule01
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is present
|
||||
+ # CHANGE HBACRULE WITH ALL MEMBERS
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present with hosts, hostgroups, users, groups, hbassvcs and hbacsvcgroups
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hostcategory: all
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
+ user: testuser01,testuser02
|
||||
+ group: testgroup01,testgroup02
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is present again
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present with hosts, hostgroups, users, groups, hbassvcs and hbacsvcgroups again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hostcategory: all
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
+ user: testuser01,testuser02
|
||||
+ group: testgroup01,testgroup02
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure user pinky is present in HBAC Rule sshd-pinky
|
||||
+ # REMOVE MEMBERS ONE BY ONE
|
||||
+
|
||||
+ - name: Ensure test HBAC rule hbacrule01 host members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure user pinky is present in HBAC Rule sshd-pinky again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 host members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC service sshd is present in HBAC Rule sshd-pinky
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hostgroup members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hbacsvc: sshd
|
||||
+ name: hbacrule01
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC service sshd is present in HBAC Rule sshd-pinky again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hostgroup members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hbacsvc: sshd
|
||||
+ name: hbacrule01
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule loginRule is present with HBAC service sshd
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- group: login
|
||||
+ name: hbacrule01
|
||||
+ user: testuser01,testuser02
|
||||
+ state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule loginRule is present with HBAC service sshd again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- group: login
|
||||
+ name: hbacrule01
|
||||
+ user: testuser01,testuser02
|
||||
+ state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure user pinky is present in HBAC Rule loginRule
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user group members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ group: testgroup01,testgroup02
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure user pinky is present in HBAC Rule loginRule again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user group members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ group: testgroup01,testgroup02
|
||||
+ state: absent
|
||||
action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure user pinky is absent in HBAC Rule loginRule
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvc members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- user: pinky
|
||||
- action: member
|
||||
+ name: hbacrule01
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure user pinky is absent in HBAC Rule loginRule again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvc members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
- user: pinky
|
||||
- action: member
|
||||
+ name: hbacrule01
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule loginRule is absent
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvcgroup members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
+ name: hbacrule01
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule loginRule is absent again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvcgroup members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: loginRule
|
||||
+ name: hbacrule01
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC service sshd is absent in HBAC Rule sshd-pinky
|
||||
+ # ADD MEMBERS BACK
|
||||
+
|
||||
+ - name: Ensure test HBAC rule hbacrule01 host members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hbacsvc: sshd
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
action: member
|
||||
- state: absent
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC service sshd is absent in HBAC Rule sshd-pinky again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 host members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- hbacsvc: sshd
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
action: member
|
||||
- state: absent
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure user pinky is absent in HBAC Rule sshd-pinky
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hostgroup members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
action: member
|
||||
- state: absent
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure user pinky is absent in HBAC Rule sshd-pinky again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hostgroup members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- user: pinky
|
||||
+ name: hbacrule01
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
action: member
|
||||
- state: absent
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is disabled
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: disabled
|
||||
+ name: hbacrule01
|
||||
+ user: testuser01,testuser02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is disabled again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: disabled
|
||||
+ name: hbacrule01
|
||||
+ user: testuser01,testuser02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is enabled
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user group members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: enabled
|
||||
+ name: hbacrule01
|
||||
+ group: testgroup01,testgroup02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is enabled again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 user group members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: enabled
|
||||
+ name: hbacrule01
|
||||
+ group: testgroup01,testgroup02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is absent
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvc members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: absent
|
||||
+ name: hbacrule01
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule sshd-pinky is absent again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvc members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: sshd-pinky
|
||||
- state: absent
|
||||
+ name: hbacrule01
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure host "{{ groups.ipaserver[0] }}" is absent in HBAC Rule allhosts
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvcgroup members are present
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- host: "{{ groups.ipaserver[0] }}"
|
||||
+ name: hbacrule01
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
action: member
|
||||
- state: absent
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure host "{{ groups.ipaserver[0] }}" is absent in HBAC Rule allhosts again
|
||||
+ - name: Ensure test HBAC rule hbacrule01 hbacsvcgroup members are present again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
- host: "{{ groups.ipaserver[0] }}"
|
||||
+ name: hbacrule01
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
action: member
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ # CHANGE TO DIFFERENT MEMBERS
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present with different hosts, hostgroups, users, groups, hbassvcs and hbacsvcgroups
|
||||
+ ipahbacrule:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup03,testhostgroup04
|
||||
+ user: testuser03,testuser04
|
||||
+ group: testgroup03,testgroup04
|
||||
+ hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
+ hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 is present with different hosts, hostgroups, users, groups, hbassvcs and hbacsvcgroups again
|
||||
+ ipahbacrule:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup03,testhostgroup04
|
||||
+ user: testuser03,testuser04
|
||||
+ group: testgroup03,testgroup04
|
||||
+ hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
+ hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ # ENSURE OLD TEST MEMBERS ARE ABSENT
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 members (same) are present
|
||||
+ ipahbacrule:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup01,testhostgroup02
|
||||
+ user: testuser01,testuser02
|
||||
+ group: testgroup01,testgroup02
|
||||
+ hbacsvc: testhbacsvc01,testhbacsvc02
|
||||
+ hbacsvcgroup: testhbacsvcgroup01,testhbacsvcgroup02
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule allhosts is absent
|
||||
+ # ENSURE NEW TEST MEMBERS ARE ABSENT
|
||||
+
|
||||
+ - name: Ensure HBAC rule hbacrule01 members are absent
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup03,testhostgroup04
|
||||
+ user: testuser03,testuser04
|
||||
+ group: testgroup03,testgroup04
|
||||
+ hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
+ hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- - name: Ensure HBAC Rule allhosts is absent again
|
||||
+ - name: Ensure HBAC rule hbacrule01 members are absent again
|
||||
ipahbacrule:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: allhosts
|
||||
+ name: hbacrule01
|
||||
+ host:
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ hostgroup: testhostgroup03,testhostgroup04
|
||||
+ user: testuser03,testuser04
|
||||
+ group: testgroup03,testgroup04
|
||||
+ hbacsvc: testhbacsvc03,testhbacsvc04
|
||||
+ hbacsvcgroup: testhbacsvcgroup03,testhbacsvcgroup04
|
||||
state: absent
|
||||
+ action: member
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- - name: User pinky absent
|
||||
+ # CLEANUP TEST ITEMS
|
||||
+
|
||||
+ - name: Ensure test HBAC rule hbacrule01 is absent
|
||||
+ ipahbacrule:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: hbacrule01
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test hosts are absent
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name:
|
||||
+ - "{{ 'testhost01.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost02.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost03.' + ipaserver_domain }}"
|
||||
+ - "{{ 'testhost04.' + ipaserver_domain }}"
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test hostgroups are absent
|
||||
+ ipahostgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhostgroup01,testhostgroup02,testhostgroup03,testhostgroup04
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test users are absent
|
||||
ipauser:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: pinky
|
||||
+ name: testuser01,testuser02,testuser03,testuser04
|
||||
state: absent
|
||||
|
||||
- - name: User group login absent
|
||||
+ - name: Ensure test user groups are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: MyPassword123
|
||||
- name: login
|
||||
+ name: testgroup01,testgroup02,testgroup03,testgroup04
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test HBAC Services are absent
|
||||
+ ipahbacsvc:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvc01,testhbacsvc02,testhbacsvc03,testhbacsvc04
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure test HBAC Service Groups are absent
|
||||
+ ipahbacsvcgroup:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ name: testhbacsvcgroup01,testhbacsvcgroup02,testhbacsvcgroup03,testhbacsvcgroup04
|
||||
state: absent
|
@ -1,106 +0,0 @@
|
||||
From 22d8784da29dcfede0744ef6b691b4506eae5deb Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Thu, 20 Feb 2020 12:58:11 +0100
|
||||
Subject: [PATCH] ipahost: Do not fail on missing DNS or zone when no IP
|
||||
address given
|
||||
|
||||
If no IP address is given and either DNS is not configured or if the zone is
|
||||
not found then ipahost may not fail in dnsrecord_find.
|
||||
|
||||
The error happened for example by ensuring the absence of a host that is not
|
||||
part of the domain or for a host that has been added with force and is using
|
||||
a domain that is not served by the DNS server in the domain. It also
|
||||
happened if there was no DNS server in the domain at all.
|
||||
|
||||
A new test case has been added to test_host_ipaddresses.yml
|
||||
|
||||
The fix requires ipalib_errors provided by ansible_freeipa_module.
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1804838
|
||||
---
|
||||
plugins/modules/ipahost.py | 17 +++++++++++++++--
|
||||
tests/host/test_host_ipaddresses.yml | 9 +++++++++
|
||||
2 files changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index 558560e..062f768 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -409,7 +409,7 @@
|
||||
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, \
|
||||
- is_ipv4_addr, is_ipv6_addr
|
||||
+ is_ipv4_addr, is_ipv6_addr, ipalib_errors
|
||||
import six
|
||||
|
||||
|
||||
@@ -871,7 +871,20 @@ def main():
|
||||
|
||||
# Make sure host exists
|
||||
res_find = find_host(ansible_module, name)
|
||||
- res_find_dnsrecord = find_dnsrecord(ansible_module, name)
|
||||
+ try:
|
||||
+ res_find_dnsrecord = find_dnsrecord(ansible_module, name)
|
||||
+ except ipalib_errors.NotFound as e:
|
||||
+ msg = str(e)
|
||||
+ if ip_address is None and \
|
||||
+ ("DNS is not configured" in msg or \
|
||||
+ "DNS zone not found" in msg):
|
||||
+ # IP address(es) not given and no DNS support in IPA
|
||||
+ # -> Ignore failure
|
||||
+ # IP address(es) not given and DNS zone is not found
|
||||
+ # -> Ignore failure
|
||||
+ res_find_dnsrecord = None
|
||||
+ else:
|
||||
+ ansible_module.fail_json(msg="%s: %s" % (host, msg))
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
diff --git a/tests/host/test_host_ipaddresses.yml b/tests/host/test_host_ipaddresses.yml
|
||||
index 0a97dd5..136a610 100644
|
||||
--- a/tests/host/test_host_ipaddresses.yml
|
||||
+++ b/tests/host/test_host_ipaddresses.yml
|
||||
@@ -301,6 +301,15 @@
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
+ - name: Absent host01.ihavenodns.info test
|
||||
+ ipahost:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ hosts:
|
||||
+ - name: host01.ihavenodns.info
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
- name: Host absent
|
||||
ipahost:
|
||||
ipaadmin_password: MyPassword123
|
||||
From 4d94cb09a9fb09dd2576223b9be7f77d515202fb Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Thu, 20 Feb 2020 12:54:32 +0100
|
||||
Subject: [PATCH] ansible_freeipa_module: Import ipalib.errors as ipalib_errors
|
||||
|
||||
For beeing able to catch ipalib.errors.NotFound errors in ipahost it is
|
||||
needed to import ipalib.errors. ipalib.errors is now imported as
|
||||
ipalib_errors to not have name conflicts with the errors list used in some
|
||||
of the modules.
|
||||
|
||||
Related: https://bugzilla.redhat.com/show_bug.cgi?id=1804838
|
||||
---
|
||||
plugins/module_utils/ansible_freeipa_module.py | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 6acdbef..5066de3 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -28,6 +28,7 @@
|
||||
import gssapi
|
||||
from datetime import datetime
|
||||
from ipalib import api
|
||||
+from ipalib import errors as ipalib_errors
|
||||
from ipalib.config import Env
|
||||
from ipalib.constants import DEFAULT_CONFIG, LDAP_GENERALIZED_TIME_FORMAT
|
||||
try:
|
@ -1,51 +0,0 @@
|
||||
From 24515e40ad289552d45bddd33c7a0dda93117a7f Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Wed, 18 Dec 2019 12:28:03 +0100
|
||||
Subject: [PATCH] ipahost: Enhanced failure msg for member params used without
|
||||
member action
|
||||
|
||||
The failure message if member parameters like certificate, managedby_host,
|
||||
principal, allow_create_keytab_* and allow_retrieve_keytab_* are used
|
||||
without member action for state absent has been enhanced to propose the
|
||||
member action.
|
||||
---
|
||||
plugins/modules/ipahost.py | 20 +++++++++++++-------
|
||||
1 file changed, 13 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index ec5e196..8ee9532 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -511,19 +511,25 @@ def check_parameters(
|
||||
"userclass", "auth_ind", "requires_pre_auth",
|
||||
"ok_as_delegate", "ok_to_auth_as_delegate", "force",
|
||||
"reverse", "ip_address", "update_password"]
|
||||
+ 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))
|
||||
if action == "host":
|
||||
- invalid.extend([
|
||||
+ invalid = [
|
||||
"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))
|
||||
+ "allow_retrieve_keytab_hostgroup"
|
||||
+ ]
|
||||
+ for x in invalid:
|
||||
+ if vars()[x] is not None:
|
||||
+ module.fail_json(
|
||||
+ msg="Argument '%s' can only be used with action "
|
||||
+ "'member' for state '%s'" % (x, state))
|
||||
|
||||
|
||||
def main():
|
@ -1,57 +0,0 @@
|
||||
From 0816b0773b1535780c7c3e5f05bda39434ab6bac Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Fri, 14 Feb 2020 13:21:54 +0100
|
||||
Subject: [PATCH] ipahost: Fail on action member for new hosts, fix
|
||||
dnsrecord_add reverse flag
|
||||
|
||||
The check to make sure that member can not be used on non existing hosts
|
||||
has bee missing. Also the reverse flag for the dnsrecord_add call was None
|
||||
if the varaible was not set.
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1803026
|
||||
---
|
||||
plugins/modules/ipahost.py | 23 +++++++++++++++--------
|
||||
1 file changed, 15 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index a5fd482..558560e 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -1005,6 +1005,11 @@ def main():
|
||||
dnsrecord_args.get("aaaarecord"),
|
||||
_dnsrec.get("aaaarecord"))
|
||||
|
||||
+ else:
|
||||
+ if res_find is None:
|
||||
+ ansible_module.fail_json(
|
||||
+ msg="No host '%s'" % name)
|
||||
+
|
||||
if action != "host" or (action == "host" and res_find is None):
|
||||
certificate_add = certificate or []
|
||||
certificate_del = []
|
||||
@@ -1178,15 +1183,17 @@ def main():
|
||||
domain_name = name[name.find(".")+1:]
|
||||
host_name = name[:name.find(".")]
|
||||
|
||||
+ _args = {"idnsname": host_name}
|
||||
+ if reverse is not None:
|
||||
+ _args["a_extra_create_reverse"] = reverse
|
||||
+ _args["aaaa_extra_create_reverse"] = reverse
|
||||
+ if len(dnsrecord_a_add) > 0:
|
||||
+ _args["arecord"] = dnsrecord_a_add
|
||||
+ if len(dnsrecord_aaaa_add) > 0:
|
||||
+ _args["aaaarecord"] = dnsrecord_aaaa_add
|
||||
+
|
||||
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
|
||||
- }])
|
||||
+ "dnsrecord_add", _args])
|
||||
|
||||
if len(dnsrecord_a_del) > 0 or len(dnsrecord_aaaa_del) > 0:
|
||||
domain_name = name[name.find(".")+1:]
|
@ -1,78 +0,0 @@
|
||||
From b6100f0c19e2caf73ab70bbc572d3e47e6066b48 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Tue, 17 Dec 2019 14:04:43 +0100
|
||||
Subject: [PATCH] ipahost: Fix choices of auth_ind parameter, allow to reset
|
||||
parameter
|
||||
|
||||
The choices for the auth_ind parameter have been wrong. The choices are now
|
||||
['radius', 'otp', 'pkinit', 'hardened', '']. The empty string has been added
|
||||
to be able to rest auth_ind for the host entry.
|
||||
---
|
||||
README-host.md | 2 +-
|
||||
plugins/modules/ipahost.py | 15 ++++++++++++---
|
||||
2 files changed, 13 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/README-host.md b/README-host.md
|
||||
index edec8d9..be5ad79 100644
|
||||
--- a/README-host.md
|
||||
+++ b/README-host.md
|
||||
@@ -280,7 +280,7 @@ Variable | Description | Required
|
||||
`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
|
||||
+`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. Use empty string to reset auth_ind to the initial value. 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
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index ec5e196..b130395 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -147,9 +147,10 @@
|
||||
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.
|
||||
+ Use empty string to reset auth_ind to the initial value.
|
||||
type: list
|
||||
aliases: ["krbprincipalauthind"]
|
||||
- choices: ["radius", "otp", "pkinit", "hardened"]
|
||||
+ choices: ["radius", "otp", "pkinit", "hardened", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -277,9 +278,10 @@
|
||||
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.
|
||||
+ Use empty string to reset auth_ind to the initial value.
|
||||
type: list
|
||||
aliases: ["krbprincipalauthind"]
|
||||
- choices: ["radius", "otp", "pkinit", "hardened"]
|
||||
+ choices: ["radius", "otp", "pkinit", "hardened", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -590,7 +592,7 @@ def main():
|
||||
default=None),
|
||||
auth_ind=dict(type='list', aliases=["krbprincipalauthind"],
|
||||
default=None,
|
||||
- choices=['password', 'radius', 'otp']),
|
||||
+ choices=['radius', 'otp', 'pkinit', 'hardened', '']),
|
||||
requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
|
||||
default=None),
|
||||
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],
|
||||
@@ -835,6 +837,13 @@ def main():
|
||||
if x in args:
|
||||
del args[x]
|
||||
|
||||
+ # Ignore auth_ind if it is empty (for resetting)
|
||||
+ # and not set in for the host
|
||||
+ if "krbprincipalauthind" not in res_find and \
|
||||
+ "krbprincipalauthind" in args and \
|
||||
+ args["krbprincipalauthind"] == ['']:
|
||||
+ del args["krbprincipalauthind"]
|
||||
+
|
||||
# For all settings is args, check if there are
|
||||
# different settings in the find result.
|
||||
# If yes: modify
|
@ -1,179 +0,0 @@
|
||||
From 4dd1d25eacd1481be0a881a017144ff4d3396ccd Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Thu, 6 Feb 2020 15:38:00 +0100
|
||||
Subject: [PATCH] ipapwpolicy: Use global_policy if name is not set
|
||||
|
||||
If the name is not set, the policy global_policy is now used. It was needed
|
||||
before to explicitly name the global_policy. Also a check has been added
|
||||
to fail early if global_policy is used with state absent.
|
||||
|
||||
The README for pwpolicy has been extended with an example for global_policy
|
||||
and also the description of the name variable.
|
||||
|
||||
The test has also been extended to check a change of maxlife for
|
||||
global_policy and that global_policy can not be used with state: absent
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1797532
|
||||
---
|
||||
README-pwpolicy.md | 19 +++++++++++--
|
||||
plugins/modules/ipapwpolicy.py | 9 ++++--
|
||||
tests/pwpolicy/test_pwpolicy.yml | 49 ++++++++++++++++++++++++++++++++
|
||||
3 files changed, 73 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/README-pwpolicy.md b/README-pwpolicy.md
|
||||
index 16306b7..847b32d 100644
|
||||
--- a/README-pwpolicy.md
|
||||
+++ b/README-pwpolicy.md
|
||||
@@ -56,7 +56,7 @@ Example playbook to ensure presence of pwpolicies for exisiting group ops:
|
||||
maxfail: 3
|
||||
```
|
||||
|
||||
-Example playbook to ensure absence of pwpolicies for group ops
|
||||
+Example playbook to ensure absence of pwpolicies for group ops:
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -72,6 +72,21 @@ Example playbook to ensure absence of pwpolicies for group ops
|
||||
state: absent
|
||||
```
|
||||
|
||||
+Example playbook to ensure maxlife is set to 49 in global policy:
|
||||
+
|
||||
+```yaml
|
||||
+---
|
||||
+- name: Playbook to handle pwpolicies
|
||||
+ hosts: ipaserver
|
||||
+ become: true
|
||||
+
|
||||
+ tasks:
|
||||
+ # Ensure absence of pwpolicies for group ops
|
||||
+ - ipapwpolicy:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ maxlife: 49
|
||||
+```
|
||||
+
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -83,7 +98,7 @@ Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
-`name` \| `cn` | The list of pwpolicy name strings. | no
|
||||
+`name` \| `cn` | The list of pwpolicy name strings. If name is not given, `global_policy` will be used automatically. | no
|
||||
`maxlife` \| `krbmaxpwdlife` | Maximum password lifetime in days. (int) | no
|
||||
`minlife` \| `krbminpwdlife` | Minimum password lifetime in hours. (int) | no
|
||||
`history` \| `krbpwdhistorylength` | Password history size. (int) | no
|
||||
diff --git a/plugins/modules/ipapwpolicy.py b/plugins/modules/ipapwpolicy.py
|
||||
index 9437b59..f168703 100644
|
||||
--- a/plugins/modules/ipapwpolicy.py
|
||||
+++ b/plugins/modules/ipapwpolicy.py
|
||||
@@ -167,7 +167,7 @@ def main():
|
||||
ipaadmin_password=dict(type="str", required=False, no_log=True),
|
||||
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
- required=True),
|
||||
+ required=False),
|
||||
# present
|
||||
|
||||
maxlife=dict(type="int", aliases=["krbmaxpwdlife"], default=None),
|
||||
@@ -218,6 +218,9 @@ def main():
|
||||
|
||||
# Check parameters
|
||||
|
||||
+ if names is None:
|
||||
+ names = ["global_policy"]
|
||||
+
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
@@ -225,8 +228,10 @@ def main():
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
+ ansible_module.fail_json(msg="No name given.")
|
||||
+ if "global_policy" in names:
|
||||
ansible_module.fail_json(
|
||||
- msg="No name given.")
|
||||
+ msg="'global_policy' can not be made absent.")
|
||||
invalid = ["maxlife", "minlife", "history", "minclasses",
|
||||
"minlength", "priority", "maxfail", "failinterval",
|
||||
"lockouttime"]
|
||||
diff --git a/tests/pwpolicy/test_pwpolicy.yml b/tests/pwpolicy/test_pwpolicy.yml
|
||||
index 5c69345..f93f275 100644
|
||||
--- a/tests/pwpolicy/test_pwpolicy.yml
|
||||
+++ b/tests/pwpolicy/test_pwpolicy.yml
|
||||
@@ -5,10 +5,30 @@
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
+ - name: Ensure maxlife of 90 for global_policy
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ maxlife: 90
|
||||
+
|
||||
+ - name: Ensure absence of group ops
|
||||
+ ipagroup:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: ops
|
||||
+ state: absent
|
||||
+
|
||||
+ - name: Ensure absence of pwpolicies for group ops
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ name: ops
|
||||
+ state: absent
|
||||
+
|
||||
- name: Ensure presence of group ops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ops
|
||||
+ state: present
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
|
||||
- name: Ensure presence of pwpolicies for group ops
|
||||
ipapwpolicy:
|
||||
@@ -42,6 +62,28 @@
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
+ - name: Ensure maxlife of 49 for global_policy
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ maxlife: 49
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
+ - name: Ensure maxlife of 49 for global_policy again
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ maxlife: 49
|
||||
+ register: result
|
||||
+ failed_when: result.changed
|
||||
+
|
||||
+ - name: Ensure absence of pwpoliciy global_policy will fail
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: SomeADMINpassword
|
||||
+ state: absent
|
||||
+ register: result
|
||||
+ ignore_errors: True
|
||||
+ failed_when: result is defined and result
|
||||
+
|
||||
- name: Ensure absence of pwpolicies for group ops
|
||||
ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -50,6 +92,13 @@
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
+ - name: Ensure maxlife of 90 for global_policy
|
||||
+ ipapwpolicy:
|
||||
+ ipaadmin_password: MyPassword123
|
||||
+ maxlife: 90
|
||||
+ register: result
|
||||
+ failed_when: not result.changed
|
||||
+
|
||||
- name: Ensure absence of pwpolicies for group ops
|
||||
ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
@ -1,116 +0,0 @@
|
||||
From 36c1c837086c42049f09cf689a1ebd61627abae0 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Tue, 17 Dec 2019 15:30:45 +0100
|
||||
Subject: [PATCH] ipauser: Allow reset of userauthtype, do not depend on
|
||||
first,last for mod
|
||||
|
||||
It was not possible to reset the userauthtype. The empty string has been
|
||||
added to userauthtype for this.
|
||||
|
||||
Also ipauser will only depend on given first and last name if the user
|
||||
does not exist yet. For the update operation these parameters are not
|
||||
needed anymore.
|
||||
---
|
||||
README-user.md | 2 +-
|
||||
plugins/modules/ipauser.py | 38 ++++++++++++++++++++++++++------------
|
||||
2 files changed, 27 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/README-user.md b/README-user.md
|
||||
index 56772a7..991121c 100644
|
||||
--- a/README-user.md
|
||||
+++ b/README-user.md
|
||||
@@ -408,7 +408,7 @@ Variable | Description | Required
|
||||
`manager` | List of manager user names. | no
|
||||
`carlicense` | List of car licenses. | no
|
||||
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no
|
||||
-`userauthtype` | List of supported user authentication types. Choices: `password`, `radius` and `otp` | no
|
||||
+`userauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp` and ``. Use empty string to reset userauthtype to the initial value. | no
|
||||
`userclass` | User category. (semantics placed on this attribute are for local interpretation). | no
|
||||
`radius` | RADIUS proxy configuration | no
|
||||
`radiususer` | RADIUS proxy username | no
|
||||
diff --git a/plugins/modules/ipauser.py b/plugins/modules/ipauser.py
|
||||
index ac45295..36e8bae 100644
|
||||
--- a/plugins/modules/ipauser.py
|
||||
+++ b/plugins/modules/ipauser.py
|
||||
@@ -153,9 +153,12 @@
|
||||
required: false
|
||||
aliases: ["ipasshpubkey"]
|
||||
userauthtype:
|
||||
- description: List of supported user authentication types
|
||||
- choices=['password', 'radius', 'otp']
|
||||
+ description:
|
||||
+ List of supported user authentication types
|
||||
+ Use empty string to reset userauthtype to the initial value.
|
||||
+ choices=['password', 'radius', 'otp', '']
|
||||
required: false
|
||||
+ aliases: ["ipauserauthtype"]
|
||||
userclass:
|
||||
description:
|
||||
- User category
|
||||
@@ -310,9 +313,12 @@
|
||||
required: false
|
||||
aliases: ["ipasshpubkey"]
|
||||
userauthtype:
|
||||
- description: List of supported user authentication types
|
||||
- choices=['password', 'radius', 'otp']
|
||||
+ description:
|
||||
+ List of supported user authentication types
|
||||
+ Use empty string to reset userauthtype to the initial value.
|
||||
+ choices=['password', 'radius', 'otp', '']
|
||||
required: false
|
||||
+ aliases: ["ipauserauthtype"]
|
||||
userclass:
|
||||
description:
|
||||
- User category
|
||||
@@ -701,7 +707,7 @@ def main():
|
||||
default=None),
|
||||
userauthtype=dict(type='list', aliases=["ipauserauthtype"],
|
||||
default=None,
|
||||
- choices=['password', 'radius', 'otp']),
|
||||
+ choices=['password', 'radius', 'otp', '']),
|
||||
userclass=dict(type="list", aliases=["class"],
|
||||
default=None),
|
||||
radius=dict(type="str", aliases=["ipatokenradiusconfiglink"],
|
||||
@@ -845,13 +851,6 @@ def main():
|
||||
if names is not None and len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one user can be added at a time using name.")
|
||||
- if action != "member":
|
||||
- # Only check first and last here if names is set
|
||||
- if names is not None:
|
||||
- if first is None:
|
||||
- ansible_module.fail_json(msg="First name is needed")
|
||||
- if last is None:
|
||||
- ansible_module.fail_json(msg="Last name is needed")
|
||||
|
||||
check_parameters(
|
||||
ansible_module, state, action,
|
||||
@@ -1011,6 +1010,13 @@ def main():
|
||||
if "noprivate" in args:
|
||||
del args["noprivate"]
|
||||
|
||||
+ # Ignore userauthtype if it is empty (for resetting)
|
||||
+ # and not set in for the user
|
||||
+ if "ipauserauthtype" not in res_find and \
|
||||
+ "ipauserauthtype" in args and \
|
||||
+ args["ipauserauthtype"] == ['']:
|
||||
+ del args["ipauserauthtype"]
|
||||
+
|
||||
# For all settings is args, check if there are
|
||||
# different settings in the find result.
|
||||
# If yes: modify
|
||||
@@ -1019,6 +1025,14 @@ def main():
|
||||
commands.append([name, "user_mod", args])
|
||||
|
||||
else:
|
||||
+ # Make sure we have a first and last name
|
||||
+ if first is None:
|
||||
+ ansible_module.fail_json(
|
||||
+ msg="First name is needed")
|
||||
+ if last is None:
|
||||
+ ansible_module.fail_json(
|
||||
+ msg="Last name is needed")
|
||||
+
|
||||
commands.append([name, "user_add", args])
|
||||
|
||||
# Handle members: principal, manager, certificate and
|
@ -1,915 +0,0 @@
|
||||
From 167c76311da72c2bfabf4b2bce9e128c11d519d0 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Wed, 12 Feb 2020 16:54:13 +0100
|
||||
Subject: [PATCH] ipahost: Add support for several IP addresses and also to
|
||||
change them
|
||||
|
||||
ipahost was so far ignoring IP addresses when the host already existed.
|
||||
This happened because host_mod is not providing functionality to do this.
|
||||
Now ipaddress is a list and it is possible to ensure a host with several
|
||||
IP addresses (these can be IPv4 and IPv6). Also it is possible to ensure
|
||||
presence and absence of IP addresses for an exising host using action
|
||||
member.
|
||||
|
||||
There are no IP address conclict checks as this would lead into issues with
|
||||
updating an existing host that already is using a duplicate IP address for
|
||||
example for round-robin (RR). Also this might lead into issues with ensuring
|
||||
a new host with several IP addresses in this case. Also to ensure a list of
|
||||
hosts with changing the IP address of one host to another in the list would
|
||||
result in issues here.
|
||||
|
||||
New example playbooks have been added:
|
||||
|
||||
playbooks/host/host-present-with-several-ip-addresses.yml
|
||||
playbooks/host/host-member-ipaddresses-absent.yml
|
||||
playbooks/host/host-member-ipaddresses-present.yml
|
||||
|
||||
A new test has been added for verification:
|
||||
|
||||
tests/host/test_host_ipaddresses.yml
|
||||
|
||||
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1783976
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1783979
|
||||
---
|
||||
README-host.md | 79 ++++-
|
||||
.../host/host-member-ipaddresses-absent.yml | 17 +
|
||||
.../host/host-member-ipaddresses-present.yml | 16 +
|
||||
...host-present-with-several-ip-addresses.yml | 24 ++
|
||||
.../module_utils/ansible_freeipa_module.py | 23 ++
|
||||
plugins/modules/ipahost.py | 179 +++++++---
|
||||
tests/host/test_host_ipaddresses.yml | 312 ++++++++++++++++++
|
||||
7 files changed, 600 insertions(+), 50 deletions(-)
|
||||
create mode 100644 playbooks/host/host-member-ipaddresses-absent.yml
|
||||
create mode 100644 playbooks/host/host-member-ipaddresses-present.yml
|
||||
create mode 100644 playbooks/host/host-present-with-several-ip-addresses.yml
|
||||
create mode 100644 tests/host/test_host_ipaddresses.yml
|
||||
|
||||
diff --git a/README-host.md b/README-host.md
|
||||
index be5ad79..ecc59a9 100644
|
||||
--- a/README-host.md
|
||||
+++ b/README-host.md
|
||||
@@ -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
|
||||
diff --git a/playbooks/host/host-member-ipaddresses-absent.yml b/playbooks/host/host-member-ipaddresses-absent.yml
|
||||
new file mode 100644
|
||||
index 0000000..2466dbd
|
||||
--- /dev/null
|
||||
+++ b/playbooks/host/host-member-ipaddresses-absent.yml
|
||||
@@ -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
|
||||
diff --git a/playbooks/host/host-member-ipaddresses-present.yml b/playbooks/host/host-member-ipaddresses-present.yml
|
||||
new file mode 100644
|
||||
index 0000000..f473993
|
||||
--- /dev/null
|
||||
+++ b/playbooks/host/host-member-ipaddresses-present.yml
|
||||
@@ -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
|
||||
diff --git a/playbooks/host/host-present-with-several-ip-addresses.yml b/playbooks/host/host-present-with-several-ip-addresses.yml
|
||||
new file mode 100644
|
||||
index 0000000..4956562
|
||||
--- /dev/null
|
||||
+++ b/playbooks/host/host-present-with-several-ip-addresses.yml
|
||||
@@ -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
|
||||
diff --git a/plugins/module_utils/ansible_freeipa_module.py b/plugins/module_utils/ansible_freeipa_module.py
|
||||
index 9e97b88..6acdbef 100644
|
||||
--- a/plugins/module_utils/ansible_freeipa_module.py
|
||||
+++ b/plugins/module_utils/ansible_freeipa_module.py
|
||||
@@ -42,6 +42,7 @@
|
||||
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
|
||||
diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
|
||||
index dba4181..a5fd482 100644
|
||||
--- a/plugins/modules/ipahost.py
|
||||
+++ b/plugins/modules/ipahost.py
|
||||
@@ -176,11 +176,16 @@
|
||||
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 @@
|
||||
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._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))
|
||||
|
||||
diff --git a/tests/host/test_host_ipaddresses.yml b/tests/host/test_host_ipaddresses.yml
|
||||
new file mode 100644
|
||||
index 0000000..0a97dd5
|
||||
--- /dev/null
|
||||
+++ b/tests/host/test_host_ipaddresses.yml
|
||||
@@ -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
|
||||
From 8f32cb04c1e161e1e3217f10413685a2cc9bf492 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Woerner <twoerner@redhat.com>
|
||||
Date: Thu, 13 Feb 2020 14:10:38 +0100
|
||||
Subject: [PATCH] tests/host/test_host: Fix use of wrong host in the host5 test
|
||||
|
||||
host1 was used instead of host5 in the repeated host5 test. This lead to an
|
||||
error with the new IP address handling in ipahost. It was correctly
|
||||
reporting a change for host1 which resulted in a failed test.
|
||||
---
|
||||
tests/host/test_host.yml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/host/test_host.yml b/tests/host/test_host.yml
|
||||
index 1a555a1..f3ec11d 100644
|
||||
--- a/tests/host/test_host.yml
|
||||
+++ b/tests/host/test_host.yml
|
||||
@@ -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
|
@ -5,28 +5,33 @@
|
||||
|
||||
Summary: Roles and playbooks to deploy FreeIPA servers, replicas and clients
|
||||
Name: ansible-freeipa
|
||||
Version: 0.1.8
|
||||
Release: 3%{?dist}
|
||||
Version: 0.1.12
|
||||
Release: 6%{?dist}
|
||||
URL: https://github.com/freeipa/ansible-freeipa
|
||||
License: GPLv3+
|
||||
Source: https://github.com/freeipa/ansible-freeipa/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
|
||||
Patch1: ansible-freeipa-0.1.8-ipahost-Fix-choices-of-auth_ind-parameter-allow-to-reset-parameter_rhbz#1783992.patch
|
||||
Patch2: ansible-freeipa-0.1.8-ipauser-Allow-reset-of-userauthtype-do-not-depend-on-first-last-for-mod_rhbz#1784474.patch
|
||||
Patch3: ansible-freeipa-0.1.8-ipahost-Enhanced-failure-msg-for-member-params-used-without-member-action_rhbz#1783948.patch
|
||||
Patch4: ansible-freeipa-0.1.8-Add-missing-attributes-to-ipasudorule_rhbz#1788168,1788035,1788024.patch
|
||||
Patch5: ansible-freeipa-0.1.8-ipapwpolicy-Use-global_policy-if-name-is-not-set_rhbz#1797532.patch
|
||||
Patch6: ansible-freeipa-0.1.8-ipahbacrule-Fix-handing-of-members-with-action-hbacrule_rhbz#1787996.patch
|
||||
Patch7: ansible-freeipa-0.1.8-ansible_freeipa_module-Fix-comparison-of-bool-parameters-in-compare_args_ipa_rhbz#1784514.patch
|
||||
Patch8: ansible-freeipa-ipahost-Add-support-for-several-IP-addresses-and-also-to-change-them_rhbz#1783979,1783976.patch
|
||||
Patch9: ansible-freeipa-0.1.8-ipahost-Fail-on-action-member-for-new-hosts-fix-dnsrecord_add-reverse-flag_rhbz#1803026.patch
|
||||
Patch10: ansible-freeipa-0.1.8-ipahost-Do-not-fail-on-missing-DNS-or-zone-when-no-IP-address-given_rhbz#1804838.patch
|
||||
Patch1: ansible-freeipa-0.1.12-Fixes-service-disable-when-service-has-no-certificates-attached_rhbz#1836294.patch
|
||||
Patch2: ansible-freeipa-0.1.12-Add-suppport-for-changing-password-of-symmetric-vaults_rhbz#1839197.patch
|
||||
Patch3: ansible-freeipa-0.1.12-Fix-forwardzone-issues_rhbz#1843826,1843828,1843829,1843830,1843831.patch
|
||||
Patch4: ansible-freeipa-0.1.12-ipa-host-group-Fix-membermanager-unknow-user-issue_rhbz#1848426.patch
|
||||
Patch5: ansible-freeipa-0.1.12-ipa-user,host-Fail-on-duplucate-names-in-the-users-and-hosts-lists_rhbz#1822683.patch
|
||||
Patch6: ansible-freeipa-0.1.12-action_plugins-ipaclient_get_otp-Discovered-python-n_rhbz#1852714.patch
|
||||
Patch7: ansible-freeipa-0.1.12-ipa-server-replica-Fix-pkcs12-info-regressions-intro_rhbz#1853284.patch
|
||||
Patch8: ansible-freeipa-0.1.12-ipareplica-Fix-missing-parameters-for-several-module_hbz#1855299.patch
|
||||
Patch9: ansible-freeipa-0.1.12-Allow-multiple-dns-zones-to-be-absent_rhbz#1845058.patch
|
||||
Patch10: ansible-freeipa-0.1.12-Fixed-error-msgs-on-FreeIPABaseModule-subclasses_rhbz#1845051.patch
|
||||
Patch11: ansible-freeipa-0.1.12-Fix-allow_retrieve_keytab_host-in-service-module_rhbz#1868020.patch
|
||||
Patch12: ansible-freeipa-0.1.12-Modified-return-value-for-ipavault-module_rhbz#1867909.patch
|
||||
Patch13: ansible-freeipa-0.1.12-Add-support-for-option-name_from_ip-in-ipadnszone-mo_rhbz#1845056.patch
|
||||
Patch14: ansible-freeipa-0.1.12-Fixes-password-behavior-on-Vault-module_rhbz#1839200.patch
|
||||
BuildArch: noarch
|
||||
|
||||
#Requires: ansible
|
||||
|
||||
%description
|
||||
ansible-freeipa provides Ansible roles and playbooks to install and uninstall
|
||||
FreeIPA servers, replicas and clients also modules for management.
|
||||
FreeIPA servers, replicas and clients. Also modules for group, host, topology
|
||||
and user management.
|
||||
|
||||
Note: The ansible playbooks and roles require a configured ansible environment
|
||||
where the ansible nodes are reachable and are properly set up to have an IP
|
||||
@ -38,6 +43,9 @@ Features
|
||||
- Cluster deployments: Server, replicas and clients in one playbook
|
||||
- One-time-password (OTP) support for client installation
|
||||
- Repair mode for clients
|
||||
- Modules for dns forwarder management
|
||||
- Modules for dns record management
|
||||
- Modules for dns zone management
|
||||
- Modules for group management
|
||||
- Modules for hbacrule management
|
||||
- Modules for hbacsvc management
|
||||
@ -45,11 +53,13 @@ Features
|
||||
- Modules for host management
|
||||
- Modules for hostgroup management
|
||||
- Modules for pwpolicy management
|
||||
- Modules for service management
|
||||
- Modules for sudocmd management
|
||||
- Modules for sudocmdgroup management
|
||||
- Modules for sudorule management
|
||||
- Modules for topology management
|
||||
- Modules for user management
|
||||
- Modules for vault management
|
||||
|
||||
Supported FreeIPA Versions
|
||||
|
||||
@ -69,23 +79,25 @@ Supported Distributions
|
||||
Requirements
|
||||
|
||||
Controller
|
||||
|
||||
- Ansible version: 2.8+ (ansible-freeipa is an Ansible Collection)
|
||||
- /usr/bin/kinit is required on the controller if a one time password (OTP)
|
||||
/usr/bin/kinit is required on the controller if a one time password (OTP)
|
||||
is used
|
||||
- python3-gssapi is required on the controller if a one time password (OTP)
|
||||
is used with keytab to install the client.
|
||||
|
||||
Node
|
||||
|
||||
- Supported FreeIPA version (see above)
|
||||
- Supported distribution (needed for package installation only, see above)
|
||||
|
||||
Limitations
|
||||
|
||||
External CA support is not supported or working. The currently needed two step
|
||||
process is an issue for the processing in the role. The configuration of the
|
||||
server is partly done already and needs to be continued after the CSR has been
|
||||
handled. This is for example breaking the deployment of a server with replicas
|
||||
or clients in one playbook.
|
||||
External signed CA is now supported. But the currently needed two step process
|
||||
is an issue for the processing in a simple playbook.
|
||||
Work is planned to have a new method to handle CSR for external signed CAs in
|
||||
a separate step before starting the server installation.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
@ -100,6 +112,10 @@ or clients in one playbook.
|
||||
%patch8 -p1
|
||||
%patch9 -p1
|
||||
%patch10 -p1
|
||||
%patch11 -p1
|
||||
%patch12 -p1
|
||||
%patch13 -p1
|
||||
%patch14 -p1
|
||||
# Fix python modules and module utils:
|
||||
# - Remove shebang
|
||||
# - Remove execute flag
|
||||
@ -130,11 +146,84 @@ cp -rp plugins/* %{buildroot}%{_datadir}/ansible/plugins/
|
||||
%{_datadir}/ansible/roles/ipaclient
|
||||
%{_datadir}/ansible/plugins/module_utils
|
||||
%{_datadir}/ansible/plugins/modules
|
||||
%doc README.md
|
||||
%doc README-*.md
|
||||
%doc README*.md
|
||||
%doc playbooks
|
||||
|
||||
%changelog
|
||||
* Tue Aug 18 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-6
|
||||
- Allow to manage multiple dnszone entries
|
||||
Resolves: RHBZ#1845058
|
||||
- Fixed error msgs on FreeIPABaseModule subclasses
|
||||
Resolves: RHBZ#1845051
|
||||
- Fix `allow_create_keytab_host` in service module
|
||||
Resolves: RHBZ#1868020
|
||||
- Modified return value for ipavault module
|
||||
Resolves: RHBZ#1867909
|
||||
- Add support for option `name_from_ip` in ipadnszone module
|
||||
Resolves: RHBZ#1845056
|
||||
- Fixe password behavior on Vault module
|
||||
Resolves: RHBZ#1839200
|
||||
|
||||
* Tue Jul 14 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-5
|
||||
- ipareplica: Fix failure while deploying KRA
|
||||
Resolves: RHBZ#1855299
|
||||
|
||||
* Thu Jul 02 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-4
|
||||
- ipa[server,replica]: Fix pkcs12 info regressions introduced with CA-less
|
||||
Resolves: RHBZ#1853284
|
||||
|
||||
* Wed Jul 01 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-3
|
||||
- action_plugins/ipaclient_get_otp: Discovered python needed in task_vars
|
||||
Resolves: RHBZ#1852714
|
||||
|
||||
* Mon Jun 29 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-2
|
||||
- Fixes service disable when service has no certificates attached
|
||||
Resolves: RHBZ#1836294
|
||||
- Add suppport for changing password of symmetric vaults
|
||||
Resolves: RHBZ#1839197
|
||||
- Fix forwardzone issues
|
||||
Resolves: RHBZ#1843826
|
||||
Resolves: RHBZ#1843828
|
||||
Resolves: RHBZ#1843829
|
||||
Resolves: RHBZ#1843830
|
||||
Resolves: RHBZ#1843831
|
||||
- ipa[host]group: Fix membermanager unknow user issue
|
||||
Resolves: RHBZ#1848426
|
||||
- ipa[user,host]: Fail on duplucate names in the users and hosts lists
|
||||
Resolves: RHBZ#1822683
|
||||
|
||||
* Mon Jun 15 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.12-1
|
||||
- Update to version 0.1.12 bug fix only release
|
||||
Related: RHBZ#1818768
|
||||
|
||||
* Thu Jun 11 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.11-1
|
||||
- Update to version 0.1.11
|
||||
Related: RHBZ#1818768
|
||||
|
||||
* Mon Apr 27 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.10-1
|
||||
- Update to version 0.1.10:
|
||||
- ipaclient: Not delete keytab when ipaclient_on_master is true
|
||||
- New module to manage dns forwarder zones in ipa
|
||||
- Enhancements of sudorule module tests
|
||||
- Gracefully handle RuntimeError raised during parameter validation in
|
||||
fail_jso
|
||||
- ipareplica_prepare: Fix module DOCUMENTATION
|
||||
- ipa[server,replica,client]: setup_logging wrapper for
|
||||
standard_logging_setup
|
||||
- Created FreeIPABaseModule class to facilitate creation of new modules
|
||||
- New IPADNSZone module
|
||||
- Add admin password to the ipadnsconfig module tests
|
||||
- Added alias module arguments in dnszone module
|
||||
- Fixed a bug in AnsibleFreeIPAParams
|
||||
- utils/build-galaxy-release: Do not add release tag to version for galaxy
|
||||
- ipaserver docs: Calm down module linter
|
||||
- galaxy.yml: Add system tag
|
||||
- ipareplica_setup_kra: Remove unused ccache parameter
|
||||
- ipareplica_setup_krb: krb is assigned to but never used
|
||||
- utils/galaxy: Make galaxy scripts more generic
|
||||
- galaxyfy-playbook.py: Fixed script name
|
||||
Related: RHBZ#1818768
|
||||
|
||||
* Thu Feb 20 2020 Thomas Woerner <twoerner@redhat.com> - 0.1.8-3
|
||||
- ipahost: Do not fail on missing DNS or zone when no IP address given
|
||||
Resolves: RHBZ#1804838
|
||||
|
Loading…
Reference in New Issue
Block a user