From 44e2718aa1388eb2f3d50a7f7f7dd373541b3b4e Mon Sep 17 00:00:00 2001
From: Thomas Woerner <twoerner@redhat.com>
Date: Fri, 30 Sep 2022 15:29:56 +0200
Subject: [PATCH] ipahost: Fix documentation sections and agument spec

ansible-test with ansible-2.14 is adding a lot of new tests to ensure
that the documentation section and the agument spec is complete. Needed
changes:

DOCUMENTATION section

- `type: str` needs to be set for string parameters
- `type: list` needs to be set for list parameters
- `elements: str` needs to be given for list of string parameters
- `suboptions` instead of `options` needs to be used for dict parameters
- `required` tags need to be fixed according to the `argument_spec`
- `aliases` tag needs to match `argument_spec`
- `type` tag needs to match `argument_spec`
- `default` tag needs to match `argument_spec`
- `author` needs to be given with the github user also: `Name (@user)`

RETURN section

- `contains` needs to be used instead of `options` for dicts
- `type: str` needs to be used for string parameters

argument_spec

- `elements="str"` needs to be added to all list of string parameters
- `no_log=False` or `no_log=True` needs to be set for all parameters
  that have `key` in the name or for dicts also in one the key names

The `copyright` date is extended with `-2022`.

Additional changes:

- Parameter sshpubkey changed to list of strings in argument_spec
- New test test/host/test_host_sshpubkey.yml
---
 plugins/modules/ipahost.py         | 174 +++++++++++++++++++++--------
 tests/host/test_host_sshpubkey.yml | 137 +++++++++++++++++++++++
 2 files changed, 264 insertions(+), 47 deletions(-)
 create mode 100644 tests/host/test_host_sshpubkey.yml

diff --git a/plugins/modules/ipahost.py b/plugins/modules/ipahost.py
index ee6aab23..ea388e80 100644
--- a/plugins/modules/ipahost.py
+++ b/plugins/modules/ipahost.py
@@ -3,7 +3,7 @@
 # Authors:
 #   Thomas Woerner <twoerner@redhat.com>
 #
-# Copyright (C) 2019 Red Hat
+# Copyright (C) 2019-2022 Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -39,106 +39,139 @@ extends_documentation_fragment:
 options:
   name:
     description: The full qualified domain name.
+    type: list
+    elements: str
     aliases: ["fqdn"]
-    required: true
-
+    required: false
   hosts:
     description: The list of user host dicts
     required: false
-    options:
+    type: list
+    elements: dict
+    suboptions:
       name:
         description: The host (internally uid).
+        type: str
         aliases: ["fqdn"]
         required: true
       description:
         description: The host description
+        type: str
         required: false
       locality:
         description: Host locality (e.g. "Baltimore, MD")
+        type: str
         required: false
       location:
         description: Host location (e.g. "Lab 2")
+        type: str
         aliases: ["ns_host_location"]
         required: false
       platform:
         description: Host hardware platform (e.g. "Lenovo T61")
+        type: str
         aliases: ["ns_hardware_platform"]
         required: false
       os:
         description: Host operating system and version (e.g. "Fedora 9")
+        type: str
         aliases: ["ns_os_version"]
         required: false
       password:
         description: Password used in bulk enrollment
+        type: str
         aliases: ["user_password", "userpassword"]
         required: false
       random:
         description:
           Initiate the generation of a random password to be used in bulk
           enrollment
+        type: bool
         aliases: ["random_password"]
         required: false
       certificate:
         description: List of base-64 encoded host certificates
         type: list
+        elements: str
         aliases: ["usercertificate"]
         required: false
       managedby_host:
         description: List of hosts that can manage this host
         type: list
-        aliases: ["principalname", "krbprincipalname"]
+        elements: str
         required: false
       principal:
         description: List of principal aliases for this host
         type: list
+        elements: str
         aliases: ["principalname", "krbprincipalname"]
         required: false
       allow_create_keytab_user:
         description: Users allowed to create a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_write_keys_user"]
         required: false
       allow_create_keytab_group:
         description: Groups allowed to create a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_write_keys_group"]
         required: false
       allow_create_keytab_host:
         description: Hosts allowed to create a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_write_keys_host"]
         required: false
       allow_create_keytab_hostgroup:
         description: Hostgroups allowed to create a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
         required: false
       allow_retrieve_keytab_user:
         description: Users allowed to retrieve a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_read_keys_user"]
         required: false
       allow_retrieve_keytab_group:
         description: Groups allowed to retrieve a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_read_keys_group"]
         required: false
       allow_retrieve_keytab_host:
         description: Hosts allowed to retrieve a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_read_keys_host"]
         required: false
       allow_retrieve_keytab_hostgroup:
         description: Hostgroups allowed to retrieve a keytab of this host
+        type: list
+        elements: str
         aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
         required: false
       mac_address:
         description: List of hardware MAC addresses.
         type: list
+        elements: str
         aliases: ["macaddress"]
         required: false
       sshpubkey:
         description: List of SSH public keys
         type: list
+        elements: str
         aliases: ["ipasshpubkey"]
         required: false
       userclass:
         description:
           Host category (semantics placed on this attribute are for local
           interpretation)
+        type: list
+        elements: str
         aliases: ["class"]
         required: false
       auth_ind:
@@ -149,6 +182,7 @@ options:
           for custom configurations. Use empty string to reset auth_ind
           to the initial value.
         type: list
+        elements: str
         aliases: ["krbprincipalauthind"]
         choices: ["radius", "otp", "pkinit", "hardened", ""]
         required: false
@@ -170,15 +204,18 @@ options:
         required: false
       force:
         description: Force host name even if not in DNS
+        type: bool
         required: false
       reverse:
         description: Reverse DNS detection
-        default: true
+        type: bool
         required: false
       ip_address:
         description:
           The host IP address list (IPv4 and IPv6). No IP address conflict
           check will be done.
+        type: list
+        elements: str
         aliases: ["ipaddress"]
         required: false
       update_dns:
@@ -186,96 +223,127 @@ options:
           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.
+        type: bool
+        aliases: ["updatedns"]
         required: false
   description:
     description: The host description
+    type: str
     required: false
   locality:
     description: Host locality (e.g. "Baltimore, MD")
+    type: str
     required: false
   location:
     description: Host location (e.g. "Lab 2")
+    type: str
     aliases: ["ns_host_location"]
     required: false
   platform:
     description: Host hardware platform (e.g. "Lenovo T61")
+    type: str
     aliases: ["ns_hardware_platform"]
     required: false
   os:
     description: Host operating system and version (e.g. "Fedora 9")
+    type: str
     aliases: ["ns_os_version"]
     required: false
   password:
     description: Password used in bulk enrollment
+    type: str
     aliases: ["user_password", "userpassword"]
     required: false
   random:
     description:
       Initiate the generation of a random password to be used in bulk
       enrollment
+    type: bool
     aliases: ["random_password"]
     required: false
   certificate:
     description: List of base-64 encoded host certificates
     type: list
+    elements: str
     aliases: ["usercertificate"]
     required: false
   managedby_host:
     description: List of hosts that can manage this host
     type: list
-    aliases: ["principalname", "krbprincipalname"]
+    elements: str
     required: false
   principal:
     description: List of principal aliases for this host
     type: list
+    elements: str
     aliases: ["principalname", "krbprincipalname"]
     required: false
   allow_create_keytab_user:
     description: Users allowed to create a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_write_keys_user"]
     required: false
   allow_create_keytab_group:
     description: Groups allowed to create a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_write_keys_group"]
     required: false
   allow_create_keytab_host:
     description: Hosts allowed to create a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_write_keys_host"]
     required: false
   allow_create_keytab_hostgroup:
     description: Hostgroups allowed to create a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
     required: false
   allow_retrieve_keytab_user:
     description: Users allowed to retrieve a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_read_keys_user"]
     required: false
   allow_retrieve_keytab_group:
     description: Groups allowed to retrieve a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_read_keys_group"]
     required: false
   allow_retrieve_keytab_host:
     description: Hosts allowed to retrieve a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_read_keys_host"]
     required: false
   allow_retrieve_keytab_hostgroup:
     description: Hostgroups allowed to retrieve a keytab of this host
+    type: list
+    elements: str
     aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
     required: false
   mac_address:
     description: List of hardware MAC addresses.
     type: list
+    elements: str
     aliases: ["macaddress"]
     required: false
   sshpubkey:
     description: List of SSH public keys
     type: list
+    elements: str
     aliases: ["ipasshpubkey"]
     required: false
   userclass:
     description:
       Host category (semantics placed on this attribute are for local
       interpretation)
+    type: list
+    elements: str
     aliases: ["class"]
     required: false
   auth_ind:
@@ -286,6 +354,7 @@ options:
       for custom configurations. Use empty string to reset auth_ind
       to the initial value.
     type: list
+    elements: str
     aliases: ["krbprincipalauthind"]
     choices: ["radius", "otp", "pkinit", "hardened", ""]
     required: false
@@ -300,21 +369,25 @@ options:
     aliases: ["ipakrbokasdelegate"]
     required: false
   ok_to_auth_as_delegate:
-    description: The service is allowed to authenticate on behalf of a client
+    description:
+      The service is allowed to authenticate on behalf of a client
     type: bool
     aliases: ["ipakrboktoauthasdelegate"]
     required: false
   force:
     description: Force host name even if not in DNS
+    type: bool
     required: false
   reverse:
     description: Reverse DNS detection
-    default: true
+    type: bool
     required: false
   ip_address:
     description:
       The host IP address list (IPv4 and IPv6). No IP address conflict
       check will be done.
+    type: list
+    elements: str
     aliases: ["ipaddress"]
     required: false
   update_dns:
@@ -322,23 +395,27 @@ options:
       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.
+    type: bool
+    aliases: ["updatedns"]
     required: false
   update_password:
     description:
       Set password for a host in present state only on creation or always
-    default: 'always'
+    type: str
     choices: ["always", "on_create"]
   action:
     description: Work on host or member level
+    type: str
     default: "host"
     choices: ["member", "host"]
   state:
     description: State to ensure
+    type: str
     default: present
     choices: ["present", "absent",
               "disabled"]
 author:
-    - Thomas Woerner
+  - Thomas Woerner (@t-woerner)
 """
 
 EXAMPLES = """
@@ -391,17 +468,19 @@ host:
   description: Host dict with random password
   returned: If random is yes and user did not exist or update_password is yes
   type: dict
-  options:
+  contains:
     randompassword:
       description: The generated random password
+      type: str
       returned: If only one user is handled by the module
     name:
       description: The user name of the user that got a new random password
       returned: If several users are handled by the module
       type: dict
-      options:
+      contains:
         randompassword:
           description: The generated random password
+          type: str
           returned: always
 """
 
@@ -628,52 +707,52 @@ 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",
-                            default=None),
-        principal=dict(type="list", aliases=["krbprincipalname"],
+        certificate=dict(type="list", elements="str",
+                         aliases=["usercertificate"], default=None),
+        managedby_host=dict(type="list", elements="str", default=None),
+        principal=dict(type="list", elements="str",
+                       aliases=["principalname", "krbprincipalname"],
                        default=None),
         allow_create_keytab_user=dict(
-            type="list",
+            type="list", elements="str",
             aliases=["ipaallowedtoperform_write_keys_user"],
-            default=None),
+            default=None, no_log=False),
         allow_create_keytab_group=dict(
-            type="list",
+            type="list", elements="str",
             aliases=["ipaallowedtoperform_write_keys_group"],
-            default=None),
+            default=None, no_log=False),
         allow_create_keytab_host=dict(
-            type="list",
+            type="list", elements="str",
             aliases=["ipaallowedtoperform_write_keys_host"],
-            default=None),
+            default=None, no_log=False),
         allow_create_keytab_hostgroup=dict(
-            type="list",
+            type="list", elements="str",
             aliases=["ipaallowedtoperform_write_keys_hostgroup"],
-            default=None),
+            default=None, no_log=False),
         allow_retrieve_keytab_user=dict(
-            type="list",
-            aliases=["ipaallowedtoperform_write_keys_user"],
-            default=None),
+            type="list", elements="str",
+            aliases=["ipaallowedtoperform_read_keys_user"],
+            default=None, no_log=False),
         allow_retrieve_keytab_group=dict(
-            type="list",
-            aliases=["ipaallowedtoperform_write_keys_group"],
-            default=None),
+            type="list", elements="str",
+            aliases=["ipaallowedtoperform_read_keys_group"],
+            default=None, no_log=False),
         allow_retrieve_keytab_host=dict(
-            type="list",
-            aliases=["ipaallowedtoperform_write_keys_host"],
-            default=None),
+            type="list", elements="str",
+            aliases=["ipaallowedtoperform_read_keys_host"],
+            default=None, no_log=False),
         allow_retrieve_keytab_hostgroup=dict(
-            type="list",
-            aliases=["ipaallowedtoperform_write_keys_hostgroup"],
-            default=None),
-        mac_address=dict(type="list", aliases=["macaddress"],
+            type="list", elements="str",
+            aliases=["ipaallowedtoperform_read_keys_hostgroup"],
+            default=None, no_log=False),
+        mac_address=dict(type="list", elements="str", aliases=["macaddress"],
                          default=None),
-        sshpubkey=dict(type="str", aliases=["ipasshpubkey"],
+        sshpubkey=dict(type="list", elements="str", aliases=["ipasshpubkey"],
                        default=None),
-        userclass=dict(type="list", aliases=["class"],
+        userclass=dict(type="list", elements="str", aliases=["class"],
                        default=None),
-        auth_ind=dict(type='list', aliases=["krbprincipalauthind"],
-                      default=None,
+        auth_ind=dict(type='list', elements="str",
+                      aliases=["krbprincipalauthind"], default=None,
                       choices=['radius', 'otp', 'pkinit', 'hardened', '']),
         requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
                                default=None),
@@ -684,7 +763,7 @@ def main():
                                     default=None),
         force=dict(type='bool', default=None),
         reverse=dict(type='bool', default=None),
-        ip_address=dict(type="list", aliases=["ipaddress"],
+        ip_address=dict(type="list", elements="str", aliases=["ipaddress"],
                         default=None),
         update_dns=dict(type="bool", aliases=["updatedns"],
                         default=None),
@@ -697,8 +776,8 @@ def main():
     ansible_module = IPAAnsibleModule(
         argument_spec=dict(
             # general
-            name=dict(type="list", aliases=["fqdn"], default=None,
-                      required=False),
+            name=dict(type="list", elements="str", aliases=["fqdn"],
+                      default=None, required=False),
 
             hosts=dict(type="list", default=None,
                        options=dict(
@@ -764,7 +843,8 @@ def main():
     allow_retrieve_keytab_hostgroup = ansible_module.params_get(
         "allow_retrieve_keytab_hostgroup")
     mac_address = ansible_module.params_get("mac_address")
-    sshpubkey = ansible_module.params_get("sshpubkey")
+    sshpubkey = ansible_module.params_get("sshpubkey",
+                                          allow_empty_string=True)
     userclass = ansible_module.params_get("userclass")
     auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
     requires_pre_auth = ansible_module.params_get("requires_pre_auth")
diff --git a/tests/host/test_host_sshpubkey.yml b/tests/host/test_host_sshpubkey.yml
new file mode 100644
index 00000000..c9c79fd6
--- /dev/null
+++ b/tests/host/test_host_sshpubkey.yml
@@ -0,0 +1,137 @@
+---
+- name: Test host sshpubkey
+  hosts: ipaserver
+  become: true
+
+  tasks:
+  - name: Get Domain from server name
+    set_fact:
+      ipaserver_domain: "{{ ansible_facts['fqdn'].split('.')[1:] | join ('.') }}"
+    when: ipaserver_domain is not defined
+
+  - name: Set host1_fqdn
+    set_fact:
+      host1_fqdn: "{{ 'host1.' + ipaserver_domain }}"
+
+  - name: Host host1 absent
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name:
+      - "{{ host1_fqdn }}"
+      update_dns: yes
+      state: absent
+
+  - name: Host host1 present
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name:
+      - "{{ host1_fqdn }}"
+      update_dns: yes
+      force: yes
+
+  - name: Host host1... present with sshpubkey
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      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: Host host1... present with sshpubkey again
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      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: Host host1... present with other sshpubkey
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      sshpubkey:
+      # yamllint disable-line rule:line-length
+      - AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Host host1... present with other sshpubkey again
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      sshpubkey:
+      # yamllint disable-line rule:line-length
+      - AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Host host1... present with two sshpubkeys
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      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
+      # yamllint disable-line rule:line-length
+      - AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Host host1... present with two sshpubkeys again
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      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
+      # yamllint disable-line rule:line-length
+      - AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Host host1... present with empty sshpubkey list
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      sshpubkey: []
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Host host1... present with empty sshpubkey list
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      sshpubkey: []
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Host host1... present with two sshpubkeys
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      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
+      # yamllint disable-line rule:line-length
+      - AAAAB3NzaC1yc2EAAAADAQABAAABgQDc8MIjaSrxLYHvu+hduoF4m6NUFSlXZWzYbd3BK4L47/U4eiXoOS6dcfuZJDjmLfOipc7XVp7NADwAgA1yBOAjbeVpXr2tC8w8saZibl75WBOEjDfNroiOh/f/ojrwwHg05QTVSZHs27sU1HBPyCQM/FHVM6EnRfmyiBkEBA/3ca0PJ9UJhWb2XisCaz6y6QcTh4gQnvHzgmEmK31GwiKnmBSEQuj8P5NGCO8RlN3cq3zpRpMDEoBRCjQYicllf/5P43r5OGvS1LhTiAMfyqE37URezNQa7aozBpH1GhIwAmjAtm84jXQjxUgZPYC0aSLuADYErScOP4792r6koH9t/DM5/M+jG2c4PNWynDczUw6Eaxl5E3hU0Ee9UN0Oee7iBnVenS/QMeZNyo5lMA/HXT5lrYiJGTYM0shRjGXXYBbJZhWerguSWDAdUd1gvuGP1nb7/+/Cvb46+HX7zYouS5Ojo0yPzMZ07X142jnKAfx9LnKdMUCwBJzbtoJ91Zc= pinky@ipaserver.el81.local  # noqa 204
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Host host1... present with empty sshpubkey list
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name: "{{ host1_fqdn }}"
+      sshpubkey: []
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Host host1... absent
+    ipahost:
+      ipaadmin_password: SomeADMINpassword
+      name:
+      - "{{ host1_fqdn }}"
+      state: absent
-- 
GitLab