diff --git a/roles/ipaclient/library/ipaclient_api.py b/roles/ipaclient/library/ipaclient_api.py
index 6b8ce667efa71409b4cc2f83a9d96efecc8baa91..7d4b8298715aa3fa3fc0f4f9571d5dcd7b37036e 100644
--- a/roles/ipaclient/library/ipaclient_api.py
+++ b/roles/ipaclient/library/ipaclient_api.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -39,18 +39,24 @@ description:
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   debug:
     description: Turn on extra debugging
-    required: yes
+    type: bool
+    required: no
+    default: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -70,7 +76,7 @@ ca_enabled:
 subject_base:
   description: The subject base, needed for certmonger
   returned: always
-  type: string
+  type: str
   sample: O=EXAMPLE.COM
 '''
 
@@ -78,7 +84,7 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     paths, x509, NUM_VERSION, serialization, certdb, api,
     delete_persistent_client_session_data, write_tmp_file,
     ipa_generate_password, CalledProcessError, errors, disable_ra, DN,
@@ -89,15 +95,16 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            realm=dict(required=True),
-            hostname=dict(required=True),
+            servers=dict(required=True, type='list', elements='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
             debug=dict(required=False, type='bool', default="false"),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     realm = module.params.get('realm')
diff --git a/roles/ipaclient/library/ipaclient_fix_ca.py b/roles/ipaclient/library/ipaclient_fix_ca.py
index 10e816855f5fc093d7945c8d212e90b349b1098a..238b31638149cfee6f2b3918567b6ea4c26d92c0 100644
--- a/roles/ipaclient/library/ipaclient_fix_ca.py
+++ b/roles/ipaclient/library/ipaclient_fix_ca.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -33,24 +33,29 @@ DOCUMENTATION = '''
 ---
 module: ipaclient_fix_ca
 short_description: Fix IPA ca certificate
-description: Repair Fix IPA ca certificate
+description: Fix IPA ca certificate
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   basedn:
     description: The basedn of the IPA server (of the form dc=example,dc=com)
-    required: no
+    type: str
+    required: yes
   allow_repair:
     description: |
       Allow repair of already joined hosts. Contrary to ipaclient_force_join
       the host entry will not be changed on the server
-    required: no
+    type: bool
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -69,7 +74,7 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     SECURE_PATH, paths, sysrestore, options, NUM_VERSION, get_ca_cert,
     get_ca_certs, errors
 )
@@ -78,14 +83,15 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            realm=dict(required=True),
-            basedn=dict(required=True),
+            servers=dict(required=True, type='list', elements='str'),
+            realm=dict(required=True, type='str'),
+            basedn=dict(required=True, type='str'),
             allow_repair=dict(required=True, type='bool'),
         ),
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_fstore.py b/roles/ipaclient/library/ipaclient_fstore.py
index 62f230b722968eca5699876a7506c4ec51831204..1b4da4eafcf1c2280d7cc717a387656f02560f90 100644
--- a/roles/ipaclient/library/ipaclient_fstore.py
+++ b/roles/ipaclient/library/ipaclient_fstore.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -39,9 +39,10 @@ description: Backup files using IPA client sysrestore
 options:
   backup:
     description: File to backup
-    required: no
+    type: str
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -55,18 +56,19 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, paths, sysrestore
+    setup_logging, check_imports, paths, sysrestore
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            backup=dict(required=True),
+            backup=dict(required=True, type='str'),
         ),
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     backup = module.params.get('backup')
diff --git a/roles/ipaclient/library/ipaclient_get_facts.py b/roles/ipaclient/library/ipaclient_get_facts.py
index e0b87bdaedb407fbf69c5bfa225056bc890b8013..e993139bc77dd3802472c401d428c6479976d5c7 100644
--- a/roles/ipaclient/library/ipaclient_get_facts.py
+++ b/roles/ipaclient/library/ipaclient_get_facts.py
@@ -1,5 +1,26 @@
 # -*- coding: utf-8 -*-
 
+# Authors:
+#   Thomas Woerner <twoerner@redhat.com>
+#
+# Based on ipa-client-install code
+#
+# Copyright (C) 2018-2022  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/>.
+
 from __future__ import (absolute_import, division, print_function)
 
 __metaclass__ = type
@@ -10,7 +31,60 @@ module: ipaclient_get_facts
 short_description: Get facts about IPA client and server configuration.
 description: Get facts about IPA client and server configuration.
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
+"""
+
+EXAMPLES = """
+"""
+
+RETURN = """
+ipa:
+  description: IPA configuration
+  returned: always
+  type: complex
+  contains:
+    packages:
+      description: IPA lib and server bindings
+      type: dict
+      returned: always
+      contains:
+        ipalib:
+          description: Whether ipalib.api binding could be imported.
+          type: bool
+          returned: always
+        ipaserver:
+          description: Whether ipaserver binding could be imported.
+          type: bool
+          returned: always
+    configured:
+      description: IPA components
+      type: dict
+      returned: always
+      contains:
+        client:
+          description: Whether client is configured
+          type: bool
+          returned: always
+        server:
+          description: Whether server is configured
+          type: bool
+          returned: always
+        dns:
+          description: Whether dns is configured
+          type: bool
+          returned: always
+        ca:
+          description: Whether ca is configured
+          type: bool
+          returned: always
+        kra:
+          description: Whether kra is configured
+          type: bool
+          returned: always
+        ntpd:
+          description: Whether ntpd is configured
+          type: bool
+          returned: always
 """
 
 import os
diff --git a/roles/ipaclient/library/ipaclient_get_otp.py b/roles/ipaclient/library/ipaclient_get_otp.py
index a26f972a783c3689775145790eb5f4f1eb21b09c..6be320632c59c8cd2c157192ef1a1a64779c6cb0 100644
--- a/roles/ipaclient/library/ipaclient_get_otp.py
+++ b/roles/ipaclient/library/ipaclient_get_otp.py
@@ -3,7 +3,7 @@
 # Authors:
 #   Florence Blanc-Renaud <frenaud@redhat.com>
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,31 +40,44 @@ options:
   principal:
     description:
       User Principal allowed to promote replicas and join IPA realm
-    required: yes
+    type: str
+    required: no
+    default: admin
   ccache:
     description: The local ccache
-    required: yes
+    type: path
+    required: no
   fqdn:
     description:
       The fully-qualified hostname of the host to add/modify/remove
-    required: no
+    type: str
+    required: yes
   certificates:
     description: A list of host certificates
-    required: yes
+    type: list
+    elements: str
+    required: no
   sshpubkey:
     description: The SSH public key for the host
-    required: yes
+    type: str
+    required: no
   ipaddress:
     description: The IP address for the host
-    required: yes
+    type: str
+    required: no
   random:
     description: Generate a random password to be used in bulk enrollment
-    required: yes
+    type: bool
+    required: no
+    default: no
   state:
     description: The desired host state
-    required: yes
+    type: str
+    choices: ['present', 'absent']
+    default: present
+    required: no
 author:
-    - "Florence Blanc-Renaud"
+    - Florence Blanc-Renaud (@flo-renaud)
 '''
 
 EXAMPLES = '''
@@ -87,11 +100,11 @@ host:
   contains:
     dn:
       description: the DN of the host entry
-      type: string
+      type: str
       returned: always
     fqdn:
       description: the fully qualified host name
-      type: string
+      type: str
       returned: always
     has_keytab:
       description: whether the host entry contains a keytab
@@ -107,19 +120,20 @@ host:
       returned: always
     randompassword:
       description: the OneTimePassword generated for this host
-      type: string
+      type: str
       returned: changed
     certificates:
       description: the list of host certificates
       type: list
+      elements: str
       returned: when present
     sshpubkey:
       description: the SSH public key for the host
-      type: string
+      type: str
       returned: when present
     ipaddress:
       description: the IP address for the host
-      type: string
+      type: str
       returned: when present
 '''
 
@@ -128,9 +142,9 @@ import os
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils import six
 
-from ipalib import api, errors
-from ipaplatform.paths import paths
-from ipapython.ipautil import run
+from ansible.module_utils.ansible_ipa_client import (
+    check_imports, api, errors, paths, run
+)
 
 if six.PY3:
     unicode = str
@@ -276,18 +290,21 @@ def main():
 
     module = AnsibleModule(
         argument_spec=dict(
-            principal=dict(default='admin'),
+            principal=dict(required=False, type='str', default='admin'),
             ccache=dict(required=False, type='path'),
-            fqdn=dict(required=True),
-            certificates=dict(required=False, type='list'),
-            sshpubkey=dict(required=False),
-            ipaddress=dict(required=False),
-            random=dict(default=False, type='bool'),
-            state=dict(default='present', choices=['present', 'absent']),
+            fqdn=dict(required=True, type='str'),
+            certificates=dict(required=False, type='list', elements='str'),
+            sshpubkey=dict(required=False, type='str'),
+            ipaddress=dict(required=False, type='str'),
+            random=dict(required=False, type='bool', default=False),
+            state=dict(required=False, type='str',
+                       choices=['present', 'absent'], default='present'),
         ),
         supports_check_mode=True,
     )
 
+    check_imports(module)
+
     ccache = module.params.get('ccache')
     fqdn = unicode(module.params.get('fqdn'))
     state = module.params.get('state')
diff --git a/roles/ipaclient/library/ipaclient_ipa_conf.py b/roles/ipaclient/library/ipaclient_ipa_conf.py
index 8f1fbad7f2c8af02119582153d5f2c891502589a..e1835711eb0742629bf00bf05036ce7d7f84b1c4 100644
--- a/roles/ipaclient/library/ipaclient_ipa_conf.py
+++ b/roles/ipaclient/library/ipaclient_ipa_conf.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2018  Red Hat
+# Copyright (C) 2018-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,21 +40,27 @@ description:
 options:
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   basedn:
     description: The basedn of the IPA server (of the form dc=example,dc=com)
-    required: no
+    type: str
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -73,23 +79,24 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, paths, sysrestore, configure_ipa_conf
+    setup_logging, check_imports, paths, sysrestore, configure_ipa_conf
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            domain=dict(required=True, default=None),
-            servers=dict(required=True, type='list', default=None),
-            realm=dict(required=True, default=None),
-            hostname=dict(required=True, default=None),
-            basedn=dict(required=True),
+            domain=dict(required=True, type='str'),
+            servers=dict(required=True, type='list', elements='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
+            basedn=dict(required=True, type='str'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_join.py b/roles/ipaclient/library/ipaclient_join.py
index 31c01a4fd5daa50ec7e3bc4cd82288e34f3eb13d..5d41a546a9dc00941a186ccd69129aca3a6a75f0 100644
--- a/roles/ipaclient/library/ipaclient_join.py
+++ b/roles/ipaclient/library/ipaclient_join.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -43,51 +43,67 @@ description:
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   kdc:
     description: The name or address of the host running the KDC
-    required: no
+    type: str
+    required: yes
   basedn:
     description: The basedn of the IPA server (of the form dc=example,dc=com)
-    required: no
+    type: str
+    required: yes
   principal:
     description:
       User Principal allowed to promote replicas and join IPA realm
-    required: yes
+    type: str
+    required: no
   password:
     description: Admin user kerberos password
-    required: yes
+    type: str
+    required: no
   keytab:
     description: Path to backed up keytab from previous enrollment
-    required: yes
+    type: str
+    required: no
   admin_keytab:
     description: The path to a local admin keytab
-    required: yes
+    type: str
+    required: no
   ca_cert_file:
     description:
       A CA certificate to use. Do not acquire the IPA CA certificate via
       automated means
-    required: yes
+    type: str
+    required: no
   force_join:
     description: Force client enrollment even if already enrolled
-    required: yes
+    type: bool
+    required: no
   kinit_attempts:
     description: Repeat the request for host Kerberos ticket X times
-    required: yes
+    type: int
+    required: no
+    default: 5
   debug:
     description: Turn on extra debugging
-    required: yes
+    type: bool
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -130,7 +146,7 @@ import tempfile
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     SECURE_PATH, sysrestore, paths, options, configure_krb5_conf,
     realm_to_suffix, kinit_keytab, GSSError, kinit_password, NUM_VERSION,
     get_ca_cert, get_ca_certs, errors, run
@@ -140,25 +156,26 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
-            kdc=dict(required=True),
-            basedn=dict(required=True),
-            principal=dict(required=False),
-            password=dict(required=False, no_log=True),
-            keytab=dict(required=False),
-            admin_keytab=dict(required=False),
-            ca_cert_file=dict(required=False),
+            servers=dict(required=True, type='list', elements='str'),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
+            kdc=dict(required=True, type='str'),
+            basedn=dict(required=True, type='str'),
+            principal=dict(required=False, type='str'),
+            password=dict(required=False, type='str', no_log=True),
+            keytab=dict(required=False, type='str', no_log=False),
+            admin_keytab=dict(required=False, type='str', no_log=False),
+            ca_cert_file=dict(required=False, type='str'),
             force_join=dict(required=False, type='bool'),
             kinit_attempts=dict(required=False, type='int', default=5),
             debug=dict(required=False, type='bool'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_set_hostname.py b/roles/ipaclient/library/ipaclient_set_hostname.py
index e92496bc46336860229106ceabfc1226f9e86924..fb087a6d7a053d657187aeb58c1486685e0888ae 100644
--- a/roles/ipaclient/library/ipaclient_set_hostname.py
+++ b/roles/ipaclient/library/ipaclient_set_hostname.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2018  Red Hat
+# Copyright (C) 2018-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,9 +40,10 @@ description:
 options:
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -57,19 +58,20 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, sysrestore, paths, tasks
+    setup_logging, check_imports, sysrestore, paths, tasks
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            hostname=dict(required=True),
+            hostname=dict(required=True, type='str'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     hostname = module.params.get('hostname')
diff --git a/roles/ipaclient/library/ipaclient_setup_automount.py b/roles/ipaclient/library/ipaclient_setup_automount.py
index 83c84edbda37306bf659fdd172eef918f2de62ac..091af9a4d703634323b3e906f60ce869d4a3315f 100644
--- a/roles/ipaclient/library/ipaclient_setup_automount.py
+++ b/roles/ipaclient/library/ipaclient_setup_automount.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,15 +40,20 @@ description:
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   sssd:
     description: The installer sssd setting
-    required: yes
+    type: bool
+    required: no
+    default: yes
   automount_location:
     description: The automount location
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -63,23 +68,24 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, options, configure_automount
+    setup_logging, check_imports, options, configure_automount
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
+            servers=dict(required=True, type='list', elements='str'),
             sssd=dict(required=False, type='bool', default='yes'),
-            automount_location=dict(required=False, default=None),
+            automount_location=dict(required=False, type='str', default=None),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     # os.environ['KRB5CCNAME'] = paths.IPA_DNS_CCACHE
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     options.servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_setup_firefox.py b/roles/ipaclient/library/ipaclient_setup_firefox.py
index 276fe61548f84c91be9f5872150eaced40d60573..2852e19d97c861f278386897628edf8fd03b87ba 100644
--- a/roles/ipaclient/library/ipaclient_setup_firefox.py
+++ b/roles/ipaclient/library/ipaclient_setup_firefox.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,14 +40,16 @@ description:
 options:
   domain:
     description: Primary DNS domain of the IPA deployment
+    type: str
     required: yes
   firefox_dir:
     description:
       Specify directory where Firefox is installed (for example
       '/usr/lib/firefox')
+    type: str
     required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -63,20 +65,21 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, sysrestore, paths, options, configure_firefox
+    setup_logging, check_imports, sysrestore, paths, options, configure_firefox
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            domain=dict(required=True),
-            firefox_dir=dict(required=False),
+            domain=dict(required=True, type='str'),
+            firefox_dir=dict(required=False, type='str'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     domain = module.params.get('domain')
diff --git a/roles/ipaclient/library/ipaclient_setup_krb5.py b/roles/ipaclient/library/ipaclient_setup_krb5.py
index f236b0274c8f221895815d8e9f042e27a6aaf73f..98be8ac59954e7c9c6b50e3ccf375d1649467822 100644
--- a/roles/ipaclient/library/ipaclient_setup_krb5.py
+++ b/roles/ipaclient/library/ipaclient_setup_krb5.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2018  Red Hat
+# Copyright (C) 2018-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,33 +40,46 @@ description:
 options:
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: yes
+    type: str
+    required: no
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: yes
+    type: list
+    elements: str
+    required: no
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: yes
+    type: str
+    required: no
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   kdc:
     description: The name or address of the host running the KDC
-    required: yes
+    type: str
+    required: no
   dnsok:
     description: The installer dnsok setting
-    required: yes
+    type: bool
+    required: no
+    default: no
   client_domain:
     description: Primary DNS domain of the IPA deployment
-    required: yes
+    type: str
+    required: no
   sssd:
     description: The installer sssd setting
-    required: yes
+    type: bool
+    required: no
+    default: no
   force:
     description: Installer force parameter
-    required: yes
+    type: bool
+    required: no
+    default: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -84,28 +97,31 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, sysrestore, paths, configure_krb5_conf, logger
+    setup_logging, check_imports, sysrestore, paths, configure_krb5_conf,
+    logger
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            domain=dict(required=False, default=None),
-            servers=dict(required=False, type='list', default=None),
-            realm=dict(required=False, default=None),
-            hostname=dict(required=False, default=None),
-            kdc=dict(required=False, default=None),
+            domain=dict(required=False, type='str', default=None),
+            servers=dict(required=False, type='list', elements='str',
+                         default=None),
+            realm=dict(required=False, type='str', default=None),
+            hostname=dict(required=False, type='str', default=None),
+            kdc=dict(required=False, type='str', default=None),
             dnsok=dict(required=False, type='bool', default=False),
-            client_domain=dict(required=False, default=None),
+            client_domain=dict(required=False, type='str', default=None),
             sssd=dict(required=False, type='bool', default=False),
             force=dict(required=False, type='bool', default=False),
             # on_master=dict(required=False, type='bool', default=False),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_setup_nis.py b/roles/ipaclient/library/ipaclient_setup_nis.py
index f07d391c21867cec8d00f1703f936c18730d5688..6c4141a86fe03184960d80cc9cd698584cc25015 100644
--- a/roles/ipaclient/library/ipaclient_setup_nis.py
+++ b/roles/ipaclient/library/ipaclient_setup_nis.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,12 +40,14 @@ description:
 options:
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   nisdomain:
     description: The NIS domain name
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -59,21 +61,22 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, options, sysrestore, paths, configure_nisdomain,
-    getargspec
+    setup_logging, check_imports, options, sysrestore, paths,
+    configure_nisdomain, getargspec
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            domain=dict(required=True),
-            nisdomain=dict(required=False),
+            domain=dict(required=True, type='str'),
+            nisdomain=dict(required=False, type='str'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     domain = module.params.get('domain')
diff --git a/roles/ipaclient/library/ipaclient_setup_nss.py b/roles/ipaclient/library/ipaclient_setup_nss.py
index be00347e4771844e105c90aab568a975ebc0cf7d..3dc0dccb12f2aa7e2938651e377dda1359e62161 100644
--- a/roles/ipaclient/library/ipaclient_setup_nss.py
+++ b/roles/ipaclient/library/ipaclient_setup_nss.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -39,88 +39,117 @@ description: Create IPA NSS database
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   basedn:
     description: The basedn of the IPA server (of the form dc=example,dc=com)
-    required: no
+    type: str
+    required: yes
   principal:
     description:
       User Principal allowed to promote replicas and join IPA realm
-    required: yes
+    type: str
+    required: no
   subject_base:
     description: |
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: no
+    type: str
+    required: yes
   ca_enabled:
     description: Whether the Certificate Authority is enabled or not
-    required: no
+    type: bool
+    required: yes
   mkhomedir:
     description: Create home directories for users on their first login
-    required: yes
+    type: bool
+    required: no
   on_master:
     description: Whether the configuration is done on the master or not
-    required: yes
+    type: bool
+    required: no
   dnsok:
     description: The installer dnsok setting
-    required: yes
+    type: bool
+    required: no
+    default: no
   enable_dns_updates:
     description: |
       Configures the machine to attempt dns updates when the ip address
       changes
-    required: yes
+    type: bool
+    required: no
   all_ip_addresses:
     description: |
       All routable IP addresses configured on any interface will be added
       to DNS
-    required: yes
+    type: bool
+    required: no
+    default: no
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   request_cert:
     description: Request certificate for the machine
-    required: yes
+    type: bool
+    required: no
+    default: no
   preserve_sssd:
     description: Preserve old SSSD configuration if possible
-    required: yes
+    type: bool
+    required: no
   no_ssh:
     description: Do not configure OpenSSH client
-    required: yes
+    type: bool
+    required: no
   no_sshd:
     description: Do not configure OpenSSH server
-    required: yes
+    type: bool
+    required: no
   no_sudo:
     description: Do not configure SSSD as data source for sudo
-    required: yes
+    type: bool
+    required: no
   fixed_primary:
     description: Configure sssd to use fixed server as primary IPA server
-    required: yes
+    type: bool
+    required: no
   permit:
     description: Disable access rules by default, permit all access
-    required: yes
+    type: bool
+    required: no
   no_krb5_offline_passwords:
     description:
       Configure SSSD not to store user password when the server is offline
-    required: yes
+    type: bool
+    required: no
   no_dns_sshfp:
     description: Do not automatically create DNS SSHFP records
-    required: yes
+    type: bool
+    required: no
+    default: no
   nosssd_files:
     description: >
       The dist of nss_ldap or nss-pam-ldapd files if sssd is disabled
     required: yes
     type: dict
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -144,7 +173,7 @@ import time
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     options, sysrestore, paths, ansible_module_get_parsed_ip_addresses,
     api, errors, create_ipa_nssdb, ipautil, ScriptError, CLIENT_INSTALL_ERROR,
     get_certs_from_ldap, DN, certstore, x509, logger, certdb,
@@ -158,13 +187,13 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
-            basedn=dict(required=True),
-            principal=dict(required=False),
-            subject_base=dict(required=True),
+            servers=dict(required=True, type='list', elements='str'),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
+            basedn=dict(required=True, type='str'),
+            principal=dict(required=False, type='str'),
+            subject_base=dict(required=True, type='str'),
             ca_enabled=dict(required=True, type='bool'),
             mkhomedir=dict(required=False, type='bool'),
             on_master=dict(required=False, type='bool'),
@@ -172,7 +201,8 @@ def main():
 
             enable_dns_updates=dict(required=False, type='bool'),
             all_ip_addresses=dict(required=False, type='bool', default=False),
-            ip_addresses=dict(required=False, type='list', default=None),
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=None),
             request_cert=dict(required=False, type='bool', default=False),
             preserve_sssd=dict(required=False, type='bool'),
             no_ssh=dict(required=False, type='bool'),
@@ -184,10 +214,11 @@ def main():
             no_dns_sshfp=dict(required=False, type='bool', default=False),
             nosssd_files=dict(required=True, type='dict'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     cli_server = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_setup_ntp.py b/roles/ipaclient/library/ipaclient_setup_ntp.py
index 908c310ea826dc59996280db0dfa0264a1866fa6..6540e76fa446e064c92c2c25fca3280698ce93c1 100644
--- a/roles/ipaclient/library/ipaclient_setup_ntp.py
+++ b/roles/ipaclient/library/ipaclient_setup_ntp.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,24 +40,34 @@ description:
 options:
   ntp_servers:
     description: ntp servers to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   ntp_pool:
     description: ntp server pool to use
-    required: yes
+    type: str
+    required: no
   no_ntp:
     description: Do not configure ntp
-    required: yes
+    type: bool
+    required: no
+    default: no
   on_master:
     description: Whether the configuration is done on the master or not
-    required: yes
+    type: bool
+    required: no
+    default: no
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: yes
+    type: list
+    elements: str
+    required: no
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -68,7 +78,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     options, sysrestore, paths, sync_time, logger, ipadiscovery,
     timeconf, getargspec
 )
@@ -78,19 +88,22 @@ def main():
     module = AnsibleModule(
         argument_spec=dict(
             # basic
-            ntp_servers=dict(required=False, type='list', default=None),
-            ntp_pool=dict(required=False, default=None),
+            ntp_servers=dict(required=False, type='list', elements='str',
+                             default=None),
+            ntp_pool=dict(required=False, type='str', default=None),
             no_ntp=dict(required=False, type='bool', default=False),
             # force_ntpd=dict(required=False, type='bool', default=False),
             on_master=dict(required=False, type='bool', default=False),
             # additional
-            servers=dict(required=False, type='list', default=None),
-            domain=dict(required=False, default=None),
+            servers=dict(required=False, type='list', elements='str',
+                         default=None),
+            domain=dict(required=False, type='str', default=None),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     # module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     options.ntp_servers = module.params.get('ntp_servers')
diff --git a/roles/ipaclient/library/ipaclient_setup_ssh.py b/roles/ipaclient/library/ipaclient_setup_ssh.py
index 8da49cdc75e9cba5f9285d415350651b8a2de395..412e5a6ddd1e56cb4e60fd55189fae31562d5656 100644
--- a/roles/ipaclient/library/ipaclient_setup_ssh.py
+++ b/roles/ipaclient/library/ipaclient_setup_ssh.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,21 +40,31 @@ description:
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   no_ssh:
     description: Do not configure OpenSSH client
-    required: yes
+    type: bool
+    required: no
+    default: no
   ssh_trust_dns:
     description: Configure OpenSSH client to trust DNS SSHFP records
-    required: yes
+    type: bool
+    required: no
+    default: no
   no_sshd:
     description: Do not configure OpenSSH server
-    required: yes
+    type: bool
+    required: no
+    default: no
   sssd:
     description: The installer sssd setting
-    required: yes
+    type: bool
+    required: no
+    default: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -71,7 +81,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     options, sysrestore, paths, configure_ssh_config, configure_sshd_config
 )
 
@@ -79,16 +89,17 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
+            servers=dict(required=True, type='list', elements='str'),
             no_ssh=dict(required=False, type='bool', default='no'),
             ssh_trust_dns=dict(required=False, type='bool', default='no'),
             no_sshd=dict(required=False, type='bool', default='no'),
             sssd=dict(required=False, type='bool', default='no'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     options.servers = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_setup_sssd.py b/roles/ipaclient/library/ipaclient_setup_sssd.py
index 2ba33a9ba91512615b5c3014673e0aa364d4c797..06eef023bc907e6543446393bde12d01e6633dce 100644
--- a/roles/ipaclient/library/ipaclient_setup_sssd.py
+++ b/roles/ipaclient/library/ipaclient_setup_sssd.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -33,60 +33,75 @@ ANSIBLE_METADATA = {
 
 DOCUMENTATION = '''
 ---
-module: ipaclient_setup_ssd
+module: ipaclient_setup_sssd
 short_description: Setup sssd for IPA client
 description:
   Setup sssd for IPA client
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   on_master:
     description: Whether the configuration is done on the master or not
-    required: yes
+    type: bool
+    required: no
   no_ssh:
     description: Do not configure OpenSSH client
-    required: yes
+    type: bool
+    required: no
   no_sshd:
     description: Do not configure OpenSSH server
-    required: yes
+    type: bool
+    required: no
   no_sudo:
     description: Do not configure SSSD as data source for sudo
-    required: yes
+    type: bool
+    required: no
   all_ip_addresses:
     description:
       All routable IP addresses configured on any interface will be added
       to DNS
-    required: yes
+    type: bool
+    required: no
   fixed_primary:
     description: Configure sssd to use fixed server as primary IPA server
-    required: yes
+    type: bool
+    required: no
   permit:
     description: Disable access rules by default, permit all access
-    required: yes
+    type: bool
+    required: no
   enable_dns_updates:
     description:
       Configures the machine to attempt dns updates when the ip address
       changes
-    required: yes
+    type: bool
+    required: no
   preserve_sssd:
     description: Preserve old SSSD configuration if possible
-    required: yes
+    type: bool
+    required: no
   no_krb5_offline_passwords:
     description:
       Configure SSSD not to store user password when the server is offline
-    required: yes
+    type: bool
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -104,17 +119,18 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging, options, sysrestore, paths, configure_sssd_conf, logger
+    setup_logging, check_imports, options, sysrestore, paths,
+    configure_sssd_conf, logger
 )
 
 
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
+            servers=dict(required=True, type='list', elements='str'),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
             on_master=dict(required=False, type='bool'),
             no_ssh=dict(required=False, type='bool'),
             no_sshd=dict(required=False, type='bool'),
@@ -127,12 +143,13 @@ def main():
             preserve_sssd=dict(required=False, type='bool'),
             no_krb5_offline_passwords=dict(required=False, type='bool'),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
     # ansible_log = AnsibleModuleLog(module, logger)
     # options.set_logger(ansible_log)
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     cli_server = module.params.get('servers')
diff --git a/roles/ipaclient/library/ipaclient_test.py b/roles/ipaclient/library/ipaclient_test.py
index 46eaec87f2a7419db7fd056cbaf552d6e75b0bce..449460a7cd2b9e056ee049b7f69bae041daca870 100644
--- a/roles/ipaclient/library/ipaclient_test.py
+++ b/roles/ipaclient/library/ipaclient_test.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -40,70 +40,99 @@ description:
 options:
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: yes
+    type: str
+    required: no
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: yes
+    type: list
+    elements: str
+    required: no
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: yes
+    type: str
+    required: no
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   ntp_servers:
     description: ntp servers to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   ntp_pool:
     description: ntp server pool to use
-    required: yes
+    type: str
+    required: no
   no_ntp:
     description: Do not configure ntp
-    required: yes
+    type: bool
+    required: no
+    default: no
   force_ntpd:
     description:
       Stop and disable any time&date synchronization services besides ntpd
       Deprecated since 4.7
-    required: yes
+    type: bool
+    required: no
+    default: no
   nisdomain:
     description: The NIS domain name
-    required: yes
+    type: str
+    required: no
   no_nisdomain:
     description: Do not configure NIS domain name
-    required: yes
+    type: bool
+    required: no
+    default: no
   kinit_attempts:
     description: Repeat the request for host Kerberos ticket X times
-    required: yes
+    type: int
+    required: no
   ca_cert_files:
     description:
       List of files containing CA certificates for the service certificate
       files
-    required: yes
+    type: list
+    elements: str
+    required: no
   configure_firefox:
     description: Configure Firefox to use IPA domain credentials
-    required: yes
+    type: bool
+    required: no
+    default: no
   firefox_dir:
     description:
       Specify directory where Firefox is installed (for example
       '/usr/lib/firefox')
-    required: yes
+    type: str
+    required: no
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   all_ip_addresses:
     description:
       All routable IP addresses configured on any interface will be added
       to DNS
-    required: yes
+    type: bool
+    required: no
+    default: no
   on_master:
     description: Whether the configuration is done on the master or not
-    required: yes
+    type: bool
+    required: no
+    default: no
   enable_dns_updates:
     description:
       Configures the machine to attempt dns updates when the ip address
       changes
-    required: yes
+    type: bool
+    required: no
+    default: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -142,36 +171,37 @@ servers:
   description: The list of detected or passed in IPA servers.
   returned: always
   type: list
+  elements: str
   sample: ["server1.example.com","server2.example.com"]
 domain:
   description: The DNS domain of the detected or passed in IPA deployment.
   returned: always
-  type: string
+  type: str
   sample: example.com
 realm:
   description: The Kerberos realm of the detected or passed in IPA deployment.
   returned: always
-  type: string
+  type: str
   sample: EXAMPLE.COM
 kdc:
   description: The detected KDC server name.
   returned: always
-  type: string
+  type: str
   sample: server1.example.com
 basedn:
   description: The basedn of the detected IPA server.
   returned: always
-  type: string
+  type: str
   sample: dc=example,dc=com
 hostname:
   description: The detected or passed in FQDN hostname of the client.
   returned: always
-  type: string
+  type: str
   sample: client1.example.com
 client_domain:
   description: The domain name of the client.
   returned: always
-  type: string
+  type: str
   sample: example.com
 dnsok:
   description: True if DNS discovery worked and not passed in any servers.
@@ -181,6 +211,7 @@ ntp_servers:
   description: The list of detected NTP servers.
   returned: always
   type: list
+  elements: str
   sample: ["ntp.example.com"]
 ipa_python_version:
   description: >
@@ -192,7 +223,9 @@ ipa_python_version:
 nosssd_files:
   description: >
     The dist of nss_ldap or nss-pam-ldapd files if sssd is disabled
+  returned: always
   type: list
+  elements: str
 '''
 
 import os
@@ -205,7 +238,7 @@ except ImportError:
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     paths, sysrestore, options, CheckedIPAddress, validate_domain_name,
     logger, x509, normalize_hostname, installer, version, ScriptError,
     CLIENT_INSTALL_ERROR, tasks, check_ldap_conf, timeconf, constants,
@@ -270,31 +303,36 @@ def main():
     module = AnsibleModule(
         argument_spec=dict(
             # basic
-            domain=dict(required=False, default=None),
-            servers=dict(required=False, type='list', default=None),
-            realm=dict(required=False, default=None),
-            hostname=dict(required=False, default=None),
-            ntp_servers=dict(required=False, type='list', default=None),
-            ntp_pool=dict(required=False, default=None),
+            domain=dict(required=False, type='str', default=None),
+            servers=dict(required=False, type='list', elements='str',
+                         default=None),
+            realm=dict(required=False, type='str', default=None),
+            hostname=dict(required=False, type='str', default=None),
+            ntp_servers=dict(required=False, type='list', elements='str',
+                             default=None),
+            ntp_pool=dict(required=False, type='str', default=None),
             no_ntp=dict(required=False, type='bool', default=False),
             force_ntpd=dict(required=False, type='bool', default=False),
-            nisdomain=dict(required=False, default=None),
+            nisdomain=dict(required=False, type='str', default=None),
             no_nisdomain=dict(required=False, type='bool', default='no'),
             kinit_attempts=dict(required=False, type='int'),
-            ca_cert_files=dict(required=False, type='list', default=None),
+            ca_cert_files=dict(required=False, type='list', elements='str',
+                               default=None),
             configure_firefox=dict(required=False, type='bool', default=False),
-            firefox_dir=dict(required=False),
-            ip_addresses=dict(required=False, type='list', default=None),
+            firefox_dir=dict(required=False, type='str'),
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=None),
             all_ip_addresses=dict(required=False, type='bool', default=False),
             on_master=dict(required=False, type='bool', default=False),
             # sssd
             enable_dns_updates=dict(required=False, type='bool',
                                     default=False),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     # module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     options.domain_name = module.params.get('domain')
diff --git a/roles/ipaclient/library/ipaclient_test_keytab.py b/roles/ipaclient/library/ipaclient_test_keytab.py
index b12b0def4edfbfde53ae66ce2eb043be289a18ce..a86b2378d16d73c6fd4aa9f50ffe22d5402462b8 100644
--- a/roles/ipaclient/library/ipaclient_test_keytab.py
+++ b/roles/ipaclient/library/ipaclient_test_keytab.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -42,24 +42,31 @@ description:
 options:
   servers:
     description: Fully qualified name of IPA servers to enroll to
-    required: no
+    type: list
+    elements: str
+    required: yes
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: no
+    type: str
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   kdc:
     description: The name or address of the host running the KDC
-    required: no
+    type: str
+    required: yes
   kinit_attempts:
     description: Repeat the request for host Kerberos ticket X times
-    required: yes
+    type: int
+    default: 5
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -91,6 +98,7 @@ krb5_keytab_ok:
 ca_crt_exists:
   description: The flag describes if ca.crt exists.
   returned: always
+  type: str
 krb5_conf_ok:
   description: The flag describes if krb5.conf on the host is usable.
   returned: always
@@ -106,7 +114,7 @@ import tempfile
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_client import (
-    setup_logging,
+    setup_logging, check_imports,
     SECURE_PATH, paths, kinit_keytab, run, GSSError, configure_krb5_conf
 )
 
@@ -114,17 +122,18 @@ from ansible.module_utils.ansible_ipa_client import (
 def main():
     module = AnsibleModule(
         argument_spec=dict(
-            servers=dict(required=True, type='list'),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
-            kdc=dict(required=True),
+            servers=dict(required=True, type='list', elements='str'),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
+            kdc=dict(required=True, type='str'),
             kinit_attempts=dict(required=False, type='int', default=5),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     servers = module.params.get('servers')
diff --git a/roles/ipaclient/module_utils/ansible_ipa_client.py b/roles/ipaclient/module_utils/ansible_ipa_client.py
index 304db30b3e9511c4b414c8dfc7760c2d9ab1972b..3116c7de34e0f0c92d41987c5d77314e38c04dae 100644
--- a/roles/ipaclient/module_utils/ansible_ipa_client.py
+++ b/roles/ipaclient/module_utils/ansible_ipa_client.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-client-install code
 #
-# Copyright (C) 2017  Red Hat
+# Copyright (C) 2017-2022  Red Hat
 # see file 'COPYING' for use and warranty information
 #
 # This program is free software; you can redistribute it and/or modify
@@ -46,17 +46,36 @@ __all__ = ["gssapi", "version", "ipadiscovery", "api", "errors", "x509",
            "configure_nslcd_conf", "configure_ssh_config",
            "configure_sshd_config", "configure_automount",
            "configure_firefox", "sync_time", "check_ldap_conf",
-           "sssd_enable_ifp", "getargspec"]
+           "sssd_enable_ifp", "getargspec", "paths", "options",
+           "IPA_PYTHON_VERSION", "NUM_VERSION", "certdb", "get_ca_cert",
+           "ipalib", "logger", "ipautil", "installer"]
 
 import sys
 
-# HACK: workaround for Ansible 2.9
-# https://github.com/ansible/ansible/issues/68361
-if 'ansible.executor' in sys.modules:
-    for attr in __all__:
-        setattr(sys.modules[__name__], attr, None)
-
-else:
+# Import getargspec from inspect or provide own getargspec for
+# Python 2 compatibility with Python 3.11+.
+try:
+    from inspect import getargspec
+except ImportError:
+    from collections import namedtuple
+    from inspect import getfullargspec
+
+    # The code is copied from Python 3.10 inspect.py
+    # Authors: Ka-Ping Yee <ping@lfw.org>
+    #          Yury Selivanov <yselivanov@sprymix.com>
+    ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
+
+    def getargspec(func):
+        args, varargs, varkw, defaults, kwonlyargs, _kwonlydefaults, \
+            ann = getfullargspec(func)
+        if kwonlyargs or ann:
+            raise ValueError(
+                "Function has keyword-only parameters or annotations"
+                ", use inspect.signature() API which can support them")
+        return ArgSpec(args, varargs, varkw, defaults)
+
+
+try:
     from ipapython.version import NUM_VERSION, VERSION
 
     if NUM_VERSION < 30201:
@@ -113,33 +132,12 @@ else:
         import gssapi
         import logging
 
-        # Import getargspec from inspect or provide own getargspec for
-        # Python 2 compatibility with Python 3.11+.
-        try:
-            from inspect import getargspec
-        except ImportError:
-            from collections import namedtuple
-            from inspect import getfullargspec
-
-            # The code is copied from Python 3.10 inspect.py
-            # Authors: Ka-Ping Yee <ping@lfw.org>
-            #          Yury Selivanov <yselivanov@sprymix.com>
-            ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
-
-            def getargspec(func):
-                args, varargs, varkw, defaults, kwonlyargs, _kwonlydefaults, \
-                    ann = getfullargspec(func)
-                if kwonlyargs or ann:
-                    raise ValueError(
-                        "Function has keyword-only parameters or annotations"
-                        ", use inspect.signature() API which can support them")
-                return ArgSpec(args, varargs, varkw, defaults)
-
         from ipapython import version
         try:
             from ipaclient.install import ipadiscovery
         except ImportError:
             from ipaclient import ipadiscovery
+        import ipalib
         from ipalib import api, errors, x509
         from ipalib import constants
         try:
@@ -312,6 +310,15 @@ else:
 
         raise Exception("freeipa version '%s' is too old" % VERSION)
 
+except ImportError as _err:
+    ANSIBLE_IPA_CLIENT_MODULE_IMPORT_ERROR = str(_err)
+
+    for attr in __all__:
+        setattr(sys.modules[__name__], attr, None)
+
+else:
+    ANSIBLE_IPA_CLIENT_MODULE_IMPORT_ERROR = None
+
 
 def setup_logging():
     standard_logging_setup(
@@ -333,3 +340,8 @@ def ansible_module_get_parsed_ip_addresses(ansible_module,
             ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e))
         ip_addrs.append(ip_parsed)
     return ip_addrs
+
+
+def check_imports(module):
+    if ANSIBLE_IPA_CLIENT_MODULE_IMPORT_ERROR is not None:
+        module.fail_json(msg=ANSIBLE_IPA_CLIENT_MODULE_IMPORT_ERROR)