Skip to content
Snippets Groups Projects
Select Git revision
  • e7b9e97a84dd446380059b145138967c2ffcaf6e
  • master default protected
  • v1.14.7
  • v1.14.6
  • v1.14.5
  • v1.14.4
  • v1.14.3
  • v1.14.2
  • v1.14.1
  • v1.14.0
  • v1.13.2
  • v1.13.1
  • v1.13.0
  • v1.12.1
  • v1.12.0
  • v1.11.1
  • v1.11.0
  • v1.10.0
  • v1.9.2
  • v1.9.1
  • v1.9.0
  • v1.8.4
22 results

ipatopologysegment.py

Blame
  • ipatopologysegment.py 11.73 KiB
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    # Authors:
    #   Thomas Woerner <twoerner@redhat.com>
    #
    # Copyright (C) 2019 Red Hat
    # see file 'COPYING' for use and warranty information
    #
    # This program is free software; you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    ANSIBLE_METADATA = {
        "metadata_version": "1.0",
        "supported_by": "community",
        "status": ["preview"],
    }
    
    DOCUMENTATION = """
    ---
    module: ipatopologysegment
    short description: Manage FreeIPA topology segments
    description: Manage FreeIPA topology segments
    options:
      ipaadmin_principal:
        description: The admin principal
        default: admin
      ipaadmin_password:
        description: The admin password
        required: false
      suffix:
        description: Topology suffix
        required: true
        choices: ["domain", "ca", "domain+ca"]
      name:
        description: Topology segment name, unique identifier.
        required: false
        aliases: ["cn"]
      left:
        description: Left replication node - an IPA server
        aliases: ["leftnode"]
      right:
        description: Right replication node - an IPA server
        aliases: ["rightnode"]
      direction:
        description: The direction a segment will be reinitialized
        required: false
        choices: ["left-to-right", "right-to-left"]
      state:
        description: State to ensure
        default: present
        choices: ["present", "absent", "enabled", "disabled", "reinitialized",
                  "checked" ]
    author:
        - Thomas Woerner
    """
    
    EXAMPLES = """
    - ipatopologysegment:
        suffix: domain
        left: ipaserver.test.local
        right: ipareplica1.test.local
        state: present
    
    - ipatopologysegment:
        suffix: domain
        name: ipaserver.test.local-to-replica1.test.local
        state: absent
    
    - ipatopologysegment:
        suffix: domain
        left: ipaserver.test.local
        right: ipareplica1.test.local
        state: absent
    
    - ipatopologysegment:
        suffix: ca
        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
    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
    
    
    def find_left_right(module, suffix, left, right):
        _args = {
            "iparepltoposegmentleftnode": to_text(left),
            "iparepltoposegmentrightnode": to_text(right),
        }
        _result = api_command(module, "topologysegment_find",
                              to_text(suffix), _args)
        if len(_result["result"]) > 1:
            module.fail_json(
                msg="Combination of left node '%s' and right node '%s' is "
                "not unique for suffix '%s'" % (left, right, suffix))
        elif len(_result["result"]) == 1:
            return _result["result"][0]
    
        return None
    
    
    def find_cn(module, suffix, name):
        _args = {
            "cn": to_text(name),
        }
        _result = api_command(module, "topologysegment_find",
                              to_text(suffix), _args)
        if len(_result["result"]) > 1:
            module.fail_json(
                msg="CN '%s' is not unique for suffix '%s'" % (name, suffix))
        elif len(_result["result"]) == 1:
            return _result["result"][0]
    
        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(
                ipaadmin_principal=dict(type="str", default="admin"),
                ipaadmin_password=dict(type="str", required=False, no_log=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),
                direction=dict(type="str", default=None,
                               choices=["left-to-right", "right-to-left"]),
                state=dict(type="str", default="present",
                           choices=["present", "absent", "enabled", "disabled",
                                    "reinitialized", "checked"]),
            ),
            supports_check_mode=True,
        )
    
        ansible_module._ansible_debug = True
    
        # Get parameters
    
        ipaadmin_principal = ansible_module.params.get("ipaadmin_principal")
        ipaadmin_password = ansible_module.params.get("ipaadmin_password")
        suffixes = ansible_module.params.get("suffix")
        name = ansible_module.params.get("name")
        left = ansible_module.params.get("left")
        right = ansible_module.params.get("right")
        direction = ansible_module.params.get("direction")
        state = ansible_module.params.get("state")
    
        # Check parameters
    
        if state != "reinitialized" and direction is not None:
            ansible_module.fail_json(
                msg="Direction is not supported in this mode.")
    
        # Init
    
        changed = False
        exit_args = {}
        ccache_dir = None
        ccache_name = None
        try:
            if not valid_creds(ansible_module, ipaadmin_principal):
                ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
                                                     ipaadmin_password)
            api_connect()
    
            commands = []
    
            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 \
                           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
                            commands.append(["topologysegment_mod", args, suffix])
                        # else: Nothing to change
                    else:
                        if name is None:
                            args["cn"] = to_text("%s-to-%s" % (left, right))
                        commands.append(["topologysegment_add", args, suffix])
    
                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": res_find["cn"][0]
                        }
                        commands.append(["topologysegment_del", args, suffix])
    
                elif state == "checked":
                    # Check if topology segment does exists
    
                    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)
    
                elif state == "reinitialized":
                    # Reinitialize segment
    
                    if direction not in ["left-to-right", "right-to-left"]:
                        ansible_module.fail_json(msg="Unknown direction '%s'" %
                                                 direction)
    
                    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
    
                        commands.append(["topologysegment_reinitialize", args,
                                         suffix])
                    else:
                        params = []
                        if name is not None:
                            params.append("name=%s" % name)
                        if left is not None:
                            params.append("left=%s" % left)
                        if right is not None:
                            params.append("right=%s" % right)
                        ansible_module.fail_json(
                            msg="No entry '%s' for suffix '%s'" %
                            (",".join(params), suffix))
    
                else:
                    ansible_module.fail_json(msg="Unkown state '%s'" % state)
    
            # Check mode exit
            if ansible_module.check_mode:
                ansible_module.exit_json(changed=len(commands) > 0, **exit_args)
    
            # Execute command
    
            for command, args, _suffix in commands:
                api_command(ansible_module, command, to_text(_suffix), args)
                changed = True
    
        except Exception as e:
            ansible_module.fail_json(msg=str(e))
    
        finally:
            temp_kdestroy(ccache_dir, ccache_name)
    
        # Done
    
        ansible_module.exit_json(changed=changed, **exit_args)
    
    
    if __name__ == "__main__":
        main()