diff --git a/README-idoverrideuser.md b/README-idoverrideuser.md new file mode 100644 index 0000000000..5411841e23 --- /dev/null +++ b/README-idoverrideuser.md @@ -0,0 +1,503 @@ +Idoverrideuser module +============ + +Description +----------- + +The idoverrideuser module allows to ensure presence and absence of idoverrideusers and idoverrideuser members. + + +Use Cases +--------- + +With idoverrideuser it is possible to manage user attributes within ID views. These attributes are for example the login name, home directory, certificate for authentication or SSH keys. + + +Features +-------- + +* Idoverrideuser management + + +Supported FreeIPA Versions +-------------------------- + +FreeIPA versions 4.4.0 and up are supported by the ipaidoverrideuser module. + + +Requirements +------------ + +**Controller** +* Ansible version: 2.13 + +**Node** +* Supported FreeIPA version (see above) + + +Usage +===== + +Example inventory file + +```ini +[ipaserver] +ipaserver.test.local +``` + + +Example playbook to make sure test user test_user is present in idview test_idview + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview. + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with description + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with description + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + description: "test_user description" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without description + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without description + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + description: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with internal name test_123_user + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with internal name test_123_user + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + name: test_123_user +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without internal name + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without internal name + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + name: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with uid 20001 + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with uid 20001 + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + uid: 20001 +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without uid + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without uid + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + uid: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with gecos "Gecos Test" + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with gecos "Gecos Test" + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gecos: Gecos Test +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without gecos + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without gecos + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gecos: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with gidnumber + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with gidnumber + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gidnumber: 20001 +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without gidnumber + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without gidnumber + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gidnumber: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with homedir /Users + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with homedir /Users + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + homedir: /Users +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without homedir + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without homedir + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + homedir: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with shell + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with shell + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + shell: /bin/someshell +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without shell + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without shell + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + shell: "" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with sshpubkey + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with sshpubkey + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + sshpubkey: + - ssh-rsa AAAAB3NzaC1yc2EAAADAQABAAABgQCqmVDpEX5gnSjKuv97Ay ... +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without sshpubkey + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without sshpubkey + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + sshpubkey: [] +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with 1 certificate + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with 1 certificate + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with 3 certificate members + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with 3 certificate members + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without 2 certificate members + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without 2 certificate members + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + state: absent +``` + + +Example playbook to make sure test user test_user is present in idview test_idview without certificates + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview without certificates + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: [] +``` + + +Example playbook to make sure test user test_user is present in idview test_idview with enabling falling back to AD DC LDAP when resolving AD trusted objects. (For two-way trusts only.) + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview with fallback_to_ldap enabled + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + fallback_to_ldap: true +``` + + +Example playbook to make sure test user test_user is absent in idview test_idview + +```yaml +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is absent in idview test_idview + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + continue: true + state: absent +``` + + +Variables +--------- + +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 +`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no +`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to true. (bool) | no +`idview` \| `idviewcn` | The doverrideuser idview string. | yes +`anchor` \| `ipaanchoruuid` | The list of anchors to override. | yes +`description` \| `desc` | Description | no +`name` \| `login` | The user (internally uid) | no +`uid` \| `uidnumber` | User ID Number (int or "") | no +`gecos` | GECOS | no +`gidnumber` | Group ID Number (int or ""). | no +`homedir` \| `homedirectory` | Home directory. | no +`shell` \| `loginshell` | Login shell. | no +`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no +`certificate` \| `usercertificate` | List of Base-64 encoded user certificates. This variable can also be used with `action: member`. | no +`fallback_to_ldap` | Allow falling back to AD DC LDAP when resolving AD trusted objects. For two-way trusts only. | no +`delete_continue` \| `continue` | Continuous mode. Don't stop on errors. Valid only if `state` is `absent`. | no +`nomembers` \| `no_members` | Suppress processing of membership attributes. Valid only if `state` is `absent`. | no +`action` | Work on idoverrideuser or member level. It can be on of `member` or `idoverrideuser` and defaults to `idoverrideuser`. | no +`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no + + +Authors +======= + +Thomas Woerner diff --git a/README.md b/README.md index 09afe310d1..fd87aa0590 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Features * Modules for hbacsvcgroup management * Modules for host management * Modules for hostgroup management +* Modules for idoverrideuser management * Modules for idrange management * Modules for idview management * Modules for location management @@ -441,6 +442,7 @@ Modules in plugin/modules * [ipahbacsvcgroup](README-hbacsvcgroup.md) * [ipahost](README-host.md) * [ipahostgroup](README-hostgroup.md) +* [idoverrideuser](README-idoverrideuser.md) * [idrange](README-idrange.md) * [idview](README-idview.md) * [ipalocation](README-location.md) diff --git a/playbooks/idoverrideuser/idoverrideuser-absent.yml b/playbooks/idoverrideuser/idoverrideuser-absent.yml new file mode 100644 index 0000000000..3a60d16708 --- /dev/null +++ b/playbooks/idoverrideuser/idoverrideuser-absent.yml @@ -0,0 +1,13 @@ +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is absent in idview test_idview + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + continue: true + state: absent diff --git a/playbooks/idoverrideuser/idoverrideuser-certificate-absent.yml b/playbooks/idoverrideuser/idoverrideuser-certificate-absent.yml new file mode 100644 index 0000000000..d9e2014dc6 --- /dev/null +++ b/playbooks/idoverrideuser/idoverrideuser-certificate-absent.yml @@ -0,0 +1,15 @@ +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user certificate member is absent in idview test_idview + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + action: member + state: absent diff --git a/playbooks/idoverrideuser/idoverrideuser-certificate-present.yml b/playbooks/idoverrideuser/idoverrideuser-certificate-present.yml new file mode 100644 index 0000000000..4d9b435106 --- /dev/null +++ b/playbooks/idoverrideuser/idoverrideuser-certificate-present.yml @@ -0,0 +1,14 @@ +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user certificate member is present in idview test_idview + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + action: member diff --git a/playbooks/idoverrideuser/idoverrideuser-present.yml b/playbooks/idoverrideuser/idoverrideuser-present.yml new file mode 100644 index 0000000000..4bcb279621 --- /dev/null +++ b/playbooks/idoverrideuser/idoverrideuser-present.yml @@ -0,0 +1,11 @@ +--- +- name: Playbook to manage idoverrideuser + hosts: ipaserver + become: false + + tasks: + - name: Ensure test user test_user is present in idview test_idview. + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user diff --git a/plugins/modules/ipaidoverrideuser.py b/plugins/modules/ipaidoverrideuser.py new file mode 100644 index 0000000000..2dc75091fc --- /dev/null +++ b/plugins/modules/ipaidoverrideuser.py @@ -0,0 +1,631 @@ +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner +# +# Copyright (C) 2023 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 . + +from __future__ import (absolute_import, division, print_function) + +__metaclass__ = type + +ANSIBLE_METADATA = { + "metadata_version": "1.0", + "supported_by": "community", + "status": ["preview"], +} + +# No rename support: 'ID overrides cannot be renamed' +# ipaserver/plugins/idviews.py:baseidoverride_mod:pre_callback + +DOCUMENTATION = """ +--- +module: ipaidoverrideuser +short_description: Manage FreeIPA idoverrideuser +description: Manage FreeIPA idoverrideuser and idoverrideuser members +extends_documentation_fragment: + - ipamodule_base_docs +options: + idview: + description: The idoverrideuser idview string. + type: str + required: true + aliases: ["idviewcn"] + anchor: + description: The list of anchors to override + type: list + elements: str + required: true + aliases: ["ipaanchoruuid"] + description: + description: Description + type: str + required: False + aliases: ["desc"] + name: + description: The user (internally uid) + type: str + required: False + aliases: ["login"] + uid: + description: User ID Number (int or "") + type: str + required: False + aliases: ["uidnumber"] + gecos: + description: GECOS + required: False + type: str + gidnumber: + description: Group ID Number (int or "") + required: False + type: str + homedir: + description: Home directory + type: str + required: False + aliases: ["homedirectory"] + shell: + description: Login shell + type: str + required: False + aliases: ["loginshell"] + sshpubkey: + description: List of SSH public keys + type: list + element: str + required: False + aliases: ["ipasshpubkey"] + certificate: + description: List of Base-64 encoded user certificates + type: list + elements: str + required: False + aliases: ["usercertificate"] + fallback_to_ldap: + description: | + Allow falling back to AD DC LDAP when resolving AD trusted objects. + For two-way trusts only. + required: False + type: bool + delete_continue: + description: | + Continuous mode. Don't stop on errors. + Valid only if `state` is `absent`. + required: false + type: bool + aliases: ["continue"] + nomembers: + description: | + Suppress processing of membership attributes. + Valid only if `state` is `absent`. + type: str + required: False + aliases: ["no_members"] + action: + description: Work on idoverrideuser or member level. + choices: ["idoverrideuser", "member"] + default: idoverrideuser + type: str + state: + description: The state to ensure. + choices: ["present", "absent"] + default: present + type: str +author: + - Thomas Woerner (@t-woerner) +""" + +EXAMPLES = """ +# Ensure test user test_user is present in idview test_idview +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + +# Ensure test user test_user is present in idview test_idview with description +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + description: "test_user description" + +# Ensure test user test_user is present in idview test_idview without +# description +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + description: "" + +# Ensure test user test_user is present in idview test_idview with internal +# name test_123_user +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + name: test_123_user + +# Ensure test user test_user is present in idview test_idview without internal +# name +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + name: "" + +# Ensure test user test_user is present in idview test_idview with uid 20001 +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + uid: 20001 + +# Ensure test user test_user is present in idview test_idview without uid +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + uid: "" + +# Ensure test user test_user is present in idview test_idview with gecos +# "Gecos Test" +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gecos: Gecos Test + +# Ensure test user test_user is present in idview test_idview without gecos +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gecos: "" + +# Ensure test user test_user is present in idview test_idview with gidnumber +# 20001 +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gidnumber: 20001 + +# Ensure test user test_user is present in idview test_idview without +# gidnumber +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + gidnumber: "" + +# Ensure test user test_user is present in idview test_idview with homedir +# /Users +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + homedir: /Users + +# Ensure test user test_user is present in idview test_idview without homedir +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + homedir: "" + +# Ensure test user test_user is present in idview test_idview with shell +# /bin/someshell +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + shell: /bin/someshell + +# Ensure test user test_user is present in idview test_idview without shell +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + shell: "" + +# Ensure test user test_user is present in idview test_idview with sshpubkey +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + sshpubkey: + - ssh-rsa AAAAB3NzaC1yc2EAAADAQABAAABgQCqmVDpEX5gnSjKuv97Ay ... + +# Ensure test user test_user is present in idview test_idview without +# sshpubkey +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + sshpubkey: [] + +# Ensure test user test_user is present in idview test_idview with 1 +# certificate +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + +# Ensure test user test_user is present in idview test_idview with 3 +# certificate members +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + +# Ensure test user test_user is present in idview test_idview without +# 2 certificate members +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + state: absent + +# Ensure test user test_user is present in idview test_idview without +# certificates +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + certificate: [] + +# Ensure test user test_user is absent in idview test_idview +- ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + idview: test_idview + anchor: test_user + continue: true + state: absent +""" + +RETURN = """ +""" + + +from ansible.module_utils.ansible_freeipa_module import \ + IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \ + gen_intersection_list, encode_certificate +from ansible.module_utils import six + +if six.PY3: + unicode = str + + +def find_idoverrideuser(module, idview, anchor): + """Find if a idoverrideuser with the given name already exist.""" + try: + _result = module.ipa_command("idoverrideuser_show", idview, + {"ipaanchoruuid": anchor, + "all": True}) + except Exception: # pylint: disable=broad-except + # An exception is raised if idoverrideuser anchor is not found. + return None + + _res = _result["result"] + certs = _res.get("usercertificate") + if certs is not None: + _res["usercertificate"] = [encode_certificate(cert) for cert in certs] + return _res + + +def gen_args(anchor, description, name, uid, gecos, gidnumber, homedir, shell, + sshpubkey): + # fallback_to_ldap and nomembers are only runtime tuning parameters + _args = {} + if anchor is not None: + _args["ipaanchoruuid"] = anchor + if description is not None: + _args["description"] = description + if name is not None: + _args["uid"] = name + if uid is not None: + _args["uidnumber"] = uid + if gecos is not None: + _args["gecos"] = gecos + if gidnumber is not None: + _args["gidnumber"] = gidnumber + if homedir is not None: + _args["homedirectory"] = homedir + if shell is not None: + _args["loginshell"] = shell + if sshpubkey is not None: + _args["ipasshpubkey"] = sshpubkey + return _args + + +def gen_args_runtime(fallback_to_ldap, nomembers): + _args = {} + if fallback_to_ldap is not None: + _args["fallback_to_ldap"] = fallback_to_ldap + if nomembers is not None: + _args["no_members"] = nomembers + return _args + + +def gen_member_args(certificate): + _args = {} + if certificate is not None: + _args["usercertificate"] = certificate + return _args + + +def merge_dicts(dict1, dict2): + ret = dict1.copy() + ret.update(dict2) + return ret + + +def main(): + ansible_module = IPAAnsibleModule( + argument_spec=dict( + # general + idview=dict(type="str", required=True, aliases=["idviewcn"]), + anchor=dict(type="list", elements="str", required=True, + aliases=["ipaanchoruuid"]), + + # present + description=dict(type="str", required=False, aliases=["desc"]), + name=dict(type="str", required=False, aliases=["login"]), + uid=dict(type="str", required=False, aliases=["uidnumber"]), + gecos=dict(type="str", required=False), + gidnumber=dict(type="str", required=False), + homedir=dict(type="str", required=False, + aliases=["homedirectory"]), + shell=dict(type="str", required=False, aliases=["loginshell"]), + sshpubkey=dict(type="list", elements="str", required=False, + aliases=["ipasshpubkey"]), + certificate=dict(type="list", elements="str", required=False, + aliases=["usercertificate"]), + fallback_to_ldap=dict(type="bool", required=False), + nomembers=dict(type="bool", required=False, + aliases=["no_members"]), + + # absent + delete_continue=dict(type="bool", required=False, + aliases=['continue'], default=None), + + # No rename support: 'ID overrides cannot be renamed' + # ipaserver/plugins/idviews.py:baseidoverride_mod:pre_callback + + # action + action=dict(type="str", default="idoverrideuser", + choices=["member", "idoverrideuser"]), + # state + state=dict(type="str", default="present", + choices=["present", "absent"]), + ), + supports_check_mode=True, + ) + + ansible_module._ansible_debug = True + + # Get parameters + + # general + idview = ansible_module.params_get("idview") + anchors = ansible_module.params_get("anchor") + + # present + description = ansible_module.params_get("description") + name = ansible_module.params_get("name") + uid = ansible_module.params_get("uid") + gecos = ansible_module.params_get("gecos") + gidnumber = ansible_module.params_get("gidnumber") + homedir = ansible_module.params_get("homedir") + shell = ansible_module.params_get("shell") + sshpubkey = ansible_module.params_get("sshpubkey") + certificate = ansible_module.params_get("certificate") + fallback_to_ldap = ansible_module.params_get("fallback_to_ldap") + nomembers = ansible_module.params_get("nomembers") + action = ansible_module.params_get("action") + + # absent + delete_continue = ansible_module.params_get("delete_continue") + + # state + state = ansible_module.params_get("state") + + # Check parameters + + invalid = [] + + if state == "present": + if len(anchors) != 1: + ansible_module.fail_json( + msg="Only one idoverrideuser can be added at a time.") + invalid = ["delete_continue"] + if action == "member": + invalid += ["description", "name", "uid", "gecos", "gidnumber", + "homedir", "shell", "sshpubkey"] + + if state == "absent": + if len(anchors) < 1: + ansible_module.fail_json(msg="No name given.") + invalid = ["description", "name", "uid", "gecos", "gidnumber", + "homedir", "shell", "sshpubkey", "nomembers"] + if action == "idoverrideuser": + invalid += ["certificate"] + + ansible_module.params_fail_used_invalid(invalid, state, action) + + # Ensure parameter values are valid and have proper type. + def int_or_empty_param(value, param): + if value is not None and value != "": + try: + value = int(value) + except ValueError: + ansible_module.fail_json( + msg="Invalid value '%s' for argument '%s'" % (value, param) + ) + return value + + uid = int_or_empty_param(uid, "uid") + gidnumber = int_or_empty_param(gidnumber, "gidnumber") + + if certificate is not None: + certificate = [cert.strip() for cert in certificate] + + # Init + + changed = False + exit_args = {} + + # Connect to IPA API + with ansible_module.ipa_connect(): + + runtime_args = gen_args_runtime(fallback_to_ldap, nomembers) + commands = [] + for anchor in anchors: + # Make sure idoverrideuser exists + res_find = find_idoverrideuser(ansible_module, idview, anchor) + + # add/del lists + certificate_add, certificate_del = [], [] + + # Create command + if state == "present": + + # Generate args + args = gen_args(anchor, description, name, uid, gecos, + gidnumber, homedir, shell, sshpubkey) + # fallback_to_ldap and nomembers are only runtime tuning + # parameters + all_args = merge_dicts(args, runtime_args) + + if action == "idoverrideuser": + # Found the idoverrideuser + if res_find is not None: + # For idempotency: Remove empty sshpubkey list if + # there are no sshpubkey in the found entry. + if "ipasshpubkey" in args and \ + len(args["ipasshpubkey"]) < 1 and \ + "ipasshpubkey" not in res_find: + del args["ipasshpubkey"] + # For all settings is args, check if there are + # different settings in the find result. + # If yes: modify + if not compare_args_ipa(ansible_module, args, + res_find): + commands.append([idview, "idoverrideuser_mod", + all_args]) + else: + commands.append([idview, "idoverrideuser_add", + all_args]) + res_find = {} + + member_args = gen_member_args(certificate) + if not compare_args_ipa(ansible_module, member_args, + res_find): + + # Generate addition and removal lists + certificate_add, certificate_del = gen_add_del_lists( + certificate, res_find.get("usercertificate")) + + elif action == "member": + if res_find is None: + ansible_module.fail_json( + msg="No idoverrideuser '%s' in idview '%s'" % + (anchor, idview)) + + # Reduce add lists for certificate + # to new entries only that are not in res_find. + if certificate is not None: + certificate_add = gen_add_list( + certificate, res_find.get("usercertificate")) + + elif state == "absent": + if action == "idoverrideuser": + if res_find is not None: + commands.append( + [idview, "idoverrideuser_del", + merge_dicts( + { + "ipaanchoruuid": anchor, + "continue": delete_continue + }, + runtime_args + )] + ) + + elif action == "member": + if res_find is None: + ansible_module.fail_json( + msg="No idoverrideuser '%s' in idview '%s'" % + (anchor, idview)) + + # Reduce del lists of member_host and member_hostgroup, + # to the entries only that are in res_find. + if certificate is not None: + certificate_del = gen_intersection_list( + certificate, res_find.get("usercertificate")) + + else: + ansible_module.fail_json(msg="Unkown state '%s'" % state) + + # Member management + + # Add members + if certificate_add: + commands.append([idview, "idoverrideuser_add_cert", + merge_dicts( + { + "ipaanchoruuid": anchor, + "usercertificate": certificate_add + }, + runtime_args + )]) + + # Remove members + + if certificate_del: + commands.append([idview, "idoverrideuser_remove_cert", + merge_dicts( + { + "ipaanchoruuid": anchor, + "usercertificate": certificate_del + }, + runtime_args + )]) + + # Execute commands + + changed = ansible_module.execute_ipa_commands(commands) + + # Done + + ansible_module.exit_json(changed=changed, **exit_args) + + +if __name__ == "__main__": + main() diff --git a/tests/idoverrideuser/test_idoverrideuser.yml b/tests/idoverrideuser/test_idoverrideuser.yml new file mode 100644 index 0000000000..f3d5503398 --- /dev/null +++ b/tests/idoverrideuser/test_idoverrideuser.yml @@ -0,0 +1,506 @@ +--- +- name: Test idoverrideuser + hosts: "{{ ipa_test_host | default('ipaserver') }}" + become: false + gather_facts: false + module_defaults: + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + ipaidview: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + ipauser: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + + tasks: + + # CLEANUP TEST ITEMS + + - name: Ensure test user test_user does not exist + ipauser: + name: test_user + state: absent + + - name: Ensure test user test_user is absent in idview test_idview + ipaidoverrideuser: + idview: test_idview + anchor: test_user + continue: true + state: absent + + - name: Ensure test idview test_idview does not exist + ipaidview: + name: test_idview + state: absent + + # CREATE TEST ITEMS + + - name: Ensure test user test_user exists + ipauser: + name: test_user + first: test + last: user + + - name: Ensure test idview test_idview exists + ipaidview: + name: test_idview + + - name: Generate self-signed certificates. + ansible.builtin.shell: + cmd: | + openssl req -x509 -newkey rsa:2048 -days 365 -nodes -keyout "private{{ item }}.key" -out "cert{{ item }}.pem" -subj '/CN=test' + openssl x509 -outform der -in "cert{{ item }}.pem" -out "cert{{ item }}.der" + base64 "cert{{ item }}.der" -w5000 > "cert{{ item }}.b64" + with_items: [1, 2, 3] + become: no + delegate_to: localhost + + # TESTS + + - name: Ensure test user test_user is present in idview test_idview + ipaidoverrideuser: + idview: test_idview + anchor: test_user + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + register: result + failed_when: result.changed or result.failed + + # description + + - name: Ensure test user test_user is present in idview test_idview with description + ipaidoverrideuser: + idview: test_idview + anchor: test_user + description: "test_user description" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with description, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + description: "test_user description" + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without description + ipaidoverrideuser: + idview: test_idview + anchor: test_user + description: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without description, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + description: "" + register: result + failed_when: result.changed or result.failed + + # name + + - name: Ensure test user test_user is present in idview test_idview with internal name test_123_user + ipaidoverrideuser: + idview: test_idview + anchor: test_user + name: test_123_user + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with internal name test_123_user, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + name: test_123_user + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without internal name + ipaidoverrideuser: + idview: test_idview + anchor: test_user + name: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without internal name, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + name: "" + register: result + failed_when: result.changed or result.failed + + # uid + + - name: Ensure test user test_user is present in idview test_idview with uid 20001 + ipaidoverrideuser: + idview: test_idview + anchor: test_user + uid: 20001 + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with uid 20001, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + uid: 20001 + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without uid + ipaidoverrideuser: + idview: test_idview + anchor: test_user + uid: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without uid, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + uid: "" + register: result + failed_when: result.changed or result.failed + + # gecos + + - name: Ensure test user test_user is present in idview test_idview with gecos "Gecos Test" + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gecos: Gecos Test öäüÇœß + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with gecos "Gecos Test", again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gecos: Gecos Test öäüÇœß + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without gecos + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gecos: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without gecos, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gecos: "" + register: result + failed_when: result.changed or result.failed + + # gidnumber + + - name: Ensure test user test_user is present in idview test_idview with gidnumber 20001 + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gidnumber: 20001 + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with gidnumber 20001, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gidnumber: 20001 + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without gidnumber + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gidnumber: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without gidnumber, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + gidnumber: "" + register: result + failed_when: result.changed or result.failed + + # homedir + + - name: Ensure test user test_user is present in idview test_idview with homedir /Users + ipaidoverrideuser: + idview: test_idview + anchor: test_user + homedir: /Users + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with homedir /Users, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + homedir: /Users + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without homedir + ipaidoverrideuser: + idview: test_idview + anchor: test_user + homedir: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without homedir, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + homedir: "" + register: result + failed_when: result.changed or result.failed + + # shell + + - name: Ensure test user test_user is present in idview test_idview with shell /bin/someshell + ipaidoverrideuser: + idview: test_idview + anchor: test_user + shell: /bin/someshell + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with shell /bin/someshell, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + shell: /bin/someshell + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without shell + ipaidoverrideuser: + idview: test_idview + anchor: test_user + shell: "" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without shell, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + shell: "" + register: result + failed_when: result.changed or result.failed + + # sshpubkey + + - name: Ensure test user test_user is present in idview test_idview with sshpubkey + ipaidoverrideuser: + idview: test_idview + anchor: test_user + sshpubkey: + # yamllint disable-line rule:line-length + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local # noqa 204 + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with sshpubkey, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + sshpubkey: + # yamllint disable-line rule:line-length + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqmVDpEX5gnSjKuv97AyzOhaUMMKz8ahOA3GY77tVC4o68KNgMCmDSEG1/kOIaElngNLaCha3p/2iAcU9Bi1tLKUlm2bbO5NHNwHfRxY/3cJtq+/7D1vxJzqThYwI4F9vr1WxyY2+mMTv3pXbfAJoR8Mu06XaEY5PDetlDKjHLuNWF+/O7ZU8PsULTa1dJZFrtXeFpmUoLoGxQBvlrlcPI1zDciCSU24t27Zan5Py2l5QchyI7yhCyMM77KDtj5+AFVpmkb9+zq50rYJAyFVeyUvwjzErvQrKJzYpA0NyBp7vskWbt36M16/M/LxEK7HA6mkcakO3ESWx5MT1LAjvdlnxbWG3787MxweHXuB8CZU+9bZPFBaJ+VQtOfJ7I8eH0S16moPC4ak8FlcFvOH8ERDPWLFDqfy09yaZ7bVIF0//5ZI7Nf3YDe3S7GrBX5ieYuECyP6UNkTx9BRsAQeVvXEc6otzB7iCSnYBMGUGzCqeigoAWaVQUONsSR3Uatks= pinky@ipaserver.el81.local # noqa 204 + + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without sshpubkey + ipaidoverrideuser: + idview: test_idview + anchor: test_user + sshpubkey: [] + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without sshpubkey, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + sshpubkey: [] + register: result + failed_when: result.changed or result.failed + + # certificate + + - name: Ensure test user test_user is present in idview test_idview with 1 certificate + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with 1 certificate, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with 1 certificate member + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + action: member + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with 3 certificate members + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview with 3 certificate members, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without certificate members + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + state: absent + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without certificate members, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + state: absent + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without certificates + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: [] + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without certificates, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: [] + register: result + failed_when: result.changed or result.failed + + - name: Ensure test user test_user is present in idview test_idview without certificate members + ipaidoverrideuser: + idview: test_idview + anchor: test_user + certificate: + - "{{ lookup('file', 'cert1.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert2.b64', rstrip=False) }}" + - "{{ lookup('file', 'cert3.b64', rstrip=False) }}" + action: member + state: absent + register: result + failed_when: result.changed or result.failed + + # no fallback_to_ldap tests + + # absent + + - name: Ensure test user test_user is absent in idview test_idview + ipaidoverrideuser: + idview: test_idview + anchor: test_user + continue: true + state: absent + register: result + failed_when: not result.changed or result.failed + + - name: Ensure test user test_user is absent in idview test_idview, again + ipaidoverrideuser: + idview: test_idview + anchor: test_user + continue: true + state: absent + register: result + failed_when: result.changed or result.failed + + # CLEANUP TEST ITEMS + + - name: Ensure test user test_user does not exist + ipauser: + name: test_user + state: absent + + - name: Ensure test user test_user is absent in idview test_idview + ipaidoverrideuser: + idview: test_idview + anchor: test_user + continue: true + state: absent + + - name: Ensure test idview test_idview does not exist + ipaidview: + name: test_idview + state: absent + + - name: Remove certificate files. # noqa: deprecated-command-syntax + ansible.builtin.shell: + cmd: rm -f "private{{ item }}.key" "cert{{ item }}.pem" "cert{{ item }}.der" "cert{{ item }}.b64" + with_items: [1, 2, 3] + become: no + delegate_to: localhost diff --git a/tests/idoverrideuser/test_idoverrideuser_client_context.yml b/tests/idoverrideuser/test_idoverrideuser_client_context.yml new file mode 100644 index 0000000000..0e5f312f87 --- /dev/null +++ b/tests/idoverrideuser/test_idoverrideuser_client_context.yml @@ -0,0 +1,40 @@ +--- +- name: Test idoverrideuser + hosts: ipaclients, ipaserver + # It is normally not needed to set "become" to "true" for a module test. + # Only set it to true if it is needed to execute commands as root. + become: false + # Enable "gather_facts" only if "ansible_facts" variable needs to be used. + gather_facts: false + + tasks: + - name: Include FreeIPA facts. + ansible.builtin.include_tasks: ../env_freeipa_facts.yml + + # Test will only be executed if host is not a server. + - name: Execute with server context in the client. + ipaidoverrideuser: + ipaadmin_password: SomeADMINpassword + ipaapi_context: server + name: ThisShouldNotWork + register: result + failed_when: not (result.failed and result.msg is regex("No module named '*ipaserver'*")) + when: ipa_host_is_client + +# Import basic module tests, and execute with ipa_context set to 'client'. +# If ipaclients is set, it will be executed using the client, if not, +# ipaserver will be used. +# +# With this setup, tests can be executed against an IPA client, against +# an IPA server using "client" context, and ensure that tests are executed +# in upstream CI. + +- name: Test idoverrideuser using client context, in client host. + import_playbook: test_idoverrideuser.yml + when: groups['ipaclients'] + vars: + ipa_test_host: ipaclients + +- name: Test idoverrideuser using client context, in server host. + import_playbook: test_idoverrideuser.yml + when: groups['ipaclients'] is not defined or not groups['ipaclients'] diff --git a/utils/ansible-freeipa.spec.in b/utils/ansible-freeipa.spec.in index ed0cfb29dc..69633cc18c 100644 --- a/utils/ansible-freeipa.spec.in +++ b/utils/ansible-freeipa.spec.in @@ -48,6 +48,7 @@ Features - Modules for hbacsvcgroup management - Modules for host management - Modules for hostgroup management +- Modules for idoverrideuser management - Modules for idrange management - Modules for idview management - Modules for location management