From 56a8acedf08df59e012b34a7c25564af9918c445 Mon Sep 17 00:00:00 2001 From: Thomas Woerner <twoerner@redhat.com> Date: Mon, 17 Jun 2019 18:08:37 +0200 Subject: [PATCH] ipatopologysegment: Allow domain+ca suffix, new state: checked It is now possible to use domain+ca as suffix, That means that the segment will be handled for the suffixes domain and also ca. The new state checked is returning two lists found and not-found. If a segment exists, the ckecked suffix is added to the found list. If a segment from suffix is not found, it is added to the not-found list. New example playbooks have been added: playbooks/topology/add-topologysegments.yml playbooks/topology/check-topologysegments.yml playbooks/topology/delete-topologysegments.yml The cluster playbook has been extended by the --- playbooks/topology/add-topologysegments.yml | 23 ++ playbooks/topology/check-topologysegments.yml | 23 ++ .../topology/delete-topologysegments.yml | 23 ++ plugins/modules/ipatopologysegment.py | 214 +++++++++++------- 4 files changed, 197 insertions(+), 86 deletions(-) create mode 100644 playbooks/topology/add-topologysegments.yml create mode 100644 playbooks/topology/check-topologysegments.yml create mode 100644 playbooks/topology/delete-topologysegments.yml diff --git a/playbooks/topology/add-topologysegments.yml b/playbooks/topology/add-topologysegments.yml new file mode 100644 index 00000000..b3348ab8 --- /dev/null +++ b/playbooks/topology/add-topologysegments.yml @@ -0,0 +1,23 @@ +--- +- name: Add topology segments + hosts: ipaserver + become: true + gather_facts: false + + vars: + ipatopology_segments: + - {suffix: domain, left: replica1.test.local, right: replica2.test.local} + - {suffix: domain, left: replica2.test.local, right: replica3.test.local} + - {suffix: domain, left: replica3.test.local, right: replica4.test.local} + - {suffix: domain+ca, left: replica4.test.local, right: replica1.test.local} + + tasks: + - name: Add topology segment + ipatopologysegment: + password: "{{ ipaadmin_password }}" + suffix: "{{ item.suffix }}" + name: "{{ item.name | default(omit) }}" + left: "{{ item.left }}" + right: "{{ item.right }}" + state: present + loop: "{{ ipatopology_segments | default([]) }}" diff --git a/playbooks/topology/check-topologysegments.yml b/playbooks/topology/check-topologysegments.yml new file mode 100644 index 00000000..49550573 --- /dev/null +++ b/playbooks/topology/check-topologysegments.yml @@ -0,0 +1,23 @@ +--- +- name: Add topology segments + hosts: ipaserver + become: true + gather_facts: false + + vars: + ipatopology_segments: + - {suffix: domain, left: replica1.test.local, right: replica2.test.local} + - {suffix: domain, left: replica2.test.local, right: replica3.test.local} + - {suffix: domain, left: replica3.test.local, right: replica4.test.local} + - {suffix: domain+ca, left: replica4.test.local, right: replica1.test.local} + + tasks: + - name: Add topology segment + ipatopologysegment: + password: "{{ ipaadmin_password }}" + suffix: "{{ item.suffix }}" + name: "{{ item.name | default(omit) }}" + left: "{{ item.left }}" + right: "{{ item.right }}" + state: checked + loop: "{{ ipatopology_segments | default([]) }}" diff --git a/playbooks/topology/delete-topologysegments.yml b/playbooks/topology/delete-topologysegments.yml new file mode 100644 index 00000000..fd6ea16d --- /dev/null +++ b/playbooks/topology/delete-topologysegments.yml @@ -0,0 +1,23 @@ +--- +- name: Add topology segments + hosts: ipaserver + become: true + gather_facts: false + + vars: + ipatopology_segments: + - {suffix: domain, left: replica1.test.local, right: replica2.test.local} + - {suffix: domain, left: replica2.test.local, right: replica3.test.local} + - {suffix: domain, left: replica3.test.local, right: replica4.test.local} + - {suffix: domain+ca, left: replica4.test.local, right: replica1.test.local} + + tasks: + - name: Add topology segment + ipatopologysegment: + password: "{{ ipaadmin_password }}" + suffix: "{{ item.suffix }}" + name: "{{ item.name | default(omit) }}" + left: "{{ item.left }}" + right: "{{ item.right }}" + state: absent + loop: "{{ ipatopology_segments | default([]) }}" diff --git a/plugins/modules/ipatopologysegment.py b/plugins/modules/ipatopologysegment.py index 20a5d090..19c9051c 100644 --- a/plugins/modules/ipatopologysegment.py +++ b/plugins/modules/ipatopologysegment.py @@ -41,7 +41,7 @@ options: suffix: description: Topology suffix required: true - choices: ["domain", "ca"] + choices: ["domain", "ca", "domain+ca"] name: description: Topology segment name, unique identifier. required: false @@ -59,7 +59,8 @@ options: state: description: State to ensure default: present - choices: ["present", "absent", "enabled", "disabled", "reinitialized"] + choices: ["present", "absent", "enabled", "disabled", "reinitialized" + "checked" ] author: - Thomas Woerner """ @@ -87,9 +88,29 @@ EXAMPLES = """ name: ipaserver.test.local-to-replica1.test.local direction: left-to-right state: reinitialized + +- ipatopologysegment: + suffix: domain+ca + left: ipaserver.test.local + right: ipareplica1.test.local + state: absent + +- ipatopologysegment: + suffix: domain+ca + left: ipaserver.test.local + right: ipareplica1.test.local + state: checked """ RETURN = """ +found: + description: List of found segments + returned: if state is checked + type: list +not-found: + description: List of not found segments + returned: if state is checked + type: list """ from ansible.module_utils.basic import AnsibleModule @@ -128,13 +149,33 @@ def find_cn(module, suffix, name): else: return None +def find_left_right_cn(module, suffix, left, right, name): + if left is not None and right is not None: + left_right = find_left_right(module, suffix, left, right) + if left_right is not None: + if name is not None and \ + left_right["cn"][0] != to_text(name): + module.fail_json( + msg="Left and right nodes do not match " + "given name name (cn) '%s'" % name) + return left_right + # else: Nothing to change + elif name is not None: + cn = find_cn(module, suffix, name) + if cn is not None: + return cn + # else: Nothing to change + else: + module.fail_json( + msg="Either left and right or name need to be set.") + return None def main(): ansible_module = AnsibleModule( argument_spec=dict( principal=dict(type="str", default="admin"), password=dict(type="str", required=False, no_log=True), - suffix=dict(choices=["domain", "ca"], required=True), + suffix=dict(choices=["domain", "ca", "domain+ca"], required=True), name=dict(type="str", aliases=["cn"], default=None), left=dict(type="str", aliases=["leftnode"], default=None), right=dict(type="str", aliases=["rightnode"], default=None), @@ -142,7 +183,7 @@ def main(): choices=["left-to-right", "right-to-left"]), state=dict(type="str", default="present", choices=["present", "absent", "enabled", "disabled", - "reinitialized"]), + "reinitialized", "checked"]), ), supports_check_mode=True, ) @@ -153,7 +194,7 @@ def main(): principal = ansible_module.params.get("principal") password = ansible_module.params.get("password") - suffix = ansible_module.params.get("suffix") + suffixes = ansible_module.params.get("suffix") name = ansible_module.params.get("name") left = ansible_module.params.get("left") right = ansible_module.params.get("right") @@ -169,6 +210,7 @@ def main(): # Init changed = False + exit_args = { } ccache_dir = None ccache_name = None try: @@ -176,100 +218,100 @@ def main(): ccache_dir, ccache_name = temp_kinit(principal, password) api_connect() - command = None + commands = [] - # Get name (cn) from left and right node if set for absent, disabled - # or reinitialized. - if state in ["absent", "disabled", "reinitialized"]: - if left is not None and right is not None: - left_right = find_left_right(ansible_module, suffix, - left, right) - if left_right is not None: + for suffix in suffixes.split("+"): + # Create command + if state in ["present", "enabled"]: + # Make sure topology segment exists + + if left is None or right is None: + ansible_module.fail_json( + msg="Left and right need to be set.") + args = { + "iparepltoposegmentleftnode": to_text(left), + "iparepltoposegmentrightnode": to_text(right), + } + if name is not None: + args["cn"] = to_text(name) + + res_left_right = find_left_right(ansible_module, suffix, + left, right) + if res_left_right is not None: if name is not None and \ - left_right["cn"][0] != to_text(name): + res_left_right["cn"][0] != to_text(name): ansible_module.fail_json( - msg="Left and right nodes do not match " - "given name name (cn) '%s'" % name) - args = { - "cn": left_right["cn"][0] - } - # else: Nothing to change - elif name is not None: - result = find_cn(ansible_module, suffix, name) - if result is not None: + msg="Left and right nodes already used with " + "different name (cn) '%s'" % res_left_right["cn"]) + + # Left and right nodes and also the name can not be + # changed + for key in [ "iparepltoposegmentleftnode", + "iparepltoposegmentrightnode" ]: + if key in args: + del args[key] + if len(args) > 1: + # cn needs to be in args always + commands.append(["topologysegment_mod", args]) + # else: Nothing to change + else: + if name is None: + args["cn"] = to_text("%s-to-%s" % (left, right)) + commands.append(["topologysegment_add", args]) + + elif state in ["absent", "disabled"]: + # Make sure topology segment does not exist + + res_find = find_left_right_cn(ansible_module, suffix, + left, right, name) + if res_find is not None: + # Found either given name or found name from left and right + # node args = { - "cn": result["cn"][0] + "cn": res_find["cn"][0] } - # else: Nothing to change - else: - ansible_module.fail_json( - msg="Either left and right or name need to be set.") - - # Create command - if state in ["present", "enabled"]: - # Make sure topology segment exists - - if left is None or right is None: - ansible_module.fail_json( - msg="Left and right need to be set.") - args = { - "iparepltoposegmentleftnode": to_text(left), - "iparepltoposegmentrightnode": to_text(right), - } - if name is not None: - args["cn"] = to_text(name) - - res_left_right = find_left_right(ansible_module, suffix, - left, right) - if res_left_right is not None: - if name is not None and \ - res_left_right["cn"][0] != to_text(name): - ansible_module.fail_json( - msg="Left and right nodes already used with " - "different name (cn) '%s'" % res_left_right["cn"]) - - # Left and right nodes and also the name can not be - # changed - for key in [ "iparepltoposegmentleftnode", - "iparepltoposegmentrightnode" ]: - if key in args: - del args[key] - if len(args) > 1: - # cn needs to be in args always - command = "topologysegment_mod" - # else: Nothing to change - else: - if name is None: - args["cn"] = to_text("%s-to-%s" % (left, right)) - command = "topologysegment_add" - - elif state in ["absent", "disabled"]: - # Make sure topology segment does not exist + commands.append(["topologysegment_del", args]) - if len(args) > 0: - # Either name defined or found name from left and right node - command = "topologysegment_del" + elif state == "checked": + # Check if topology segment does exists - elif state == "reinitialized": - # Reinitialize segment + res_find = find_left_right_cn(ansible_module, suffix, + left, right, name) + if res_find is not None: + # Found either given name or found name from left and right + # node + exit_args.setdefault("found", []).append(suffix) + else: + # Not found + exit_args.setdefault("not-found", []).append(suffix) - if len(args) > 0: - # Either name defined or found name from left and right node - command = "topologysegment_reinitialize" + elif state == "reinitialized": + # Reinitialize segment - if direction == "left-to-right": - args["left"] = True - elif direction == "right-to-left": - args["right"] = True - else: + if direction not in [ "left-to-right", "right-to-left" ]: ansible_module.fail_json(msg="Unknown direction '%s'" % direction) - else: - ansible_module.fail_json(msg="Unkown state '%s'" % state) + + res_find = find_left_right_cn(ansible_module, suffix, + left, right, name) + if res_find is not None: + # Found either given name or found name from left and right + # node + args = { + "cn": res_find["cn"][0] + } + if direction == "left-to-right": + args["left"] = True + elif direction == "right-to-left": + args["right"] = True + + command.append(["topologysegment_reinitialize", args]) + else: + ansible_module.fail_json(msg="Unkown state '%s'" % state) # Execute command - if command is not None: + for command, args in commands: result = api_command(ansible_module, command, to_text(suffix), args) changed = True @@ -282,7 +324,7 @@ def main(): # Done - ansible_module.exit_json(changed=changed) + ansible_module.exit_json(changed=changed, **exit_args) if __name__ == "__main__": main() -- GitLab