diff --git a/roles/ipaserver/library/ipaserver_enable_ipa.py b/roles/ipaserver/library/ipaserver_enable_ipa.py
index 332c72ffe867d749780d7bdbfef8980d1f86d239..0292a6583b11906c95236fb20763b098ed53e9e9 100644
--- a/roles/ipaserver/library/ipaserver_enable_ipa.py
+++ b/roles/ipaserver/library/ipaserver_enable_ipa.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-server-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,15 +39,18 @@ description: Enable IPA
 options:
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: no
+    type: bool
+    required: yes
   setup_ca:
     description: Configure a dogtag CA
-    required: no
+    type: bool
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -58,6 +61,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
+    check_imports,
     AnsibleModuleLog, setup_logging, options, paths, api, sysrestore, tasks,
     service, bindinstance, redirect_stdout, services
 )
@@ -66,13 +70,14 @@ from ansible.module_utils.ansible_ipa_server import (
 def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
-            hostname=dict(required=False),
+            hostname=dict(required=False, type='str'),
             setup_dns=dict(required=True, type='bool'),
             setup_ca=dict(required=True, type='bool'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_load_cache.py b/roles/ipaserver/library/ipaserver_load_cache.py
index e3f6fd32ae5c8175d105b90e1296ee5d24fed04d..0806c1d11a1249ca1b927d360b12e09952448ea1 100644
--- a/roles/ipaserver/library/ipaserver_load_cache.py
+++ b/roles/ipaserver/library/ipaserver_load_cache.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: Load cache file
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -54,7 +55,7 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    setup_logging, options, paths, read_cache
+    check_imports, setup_logging, options, paths, read_cache
 )
 
 
@@ -62,11 +63,12 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
+            dm_password=dict(required=True, type='str', no_log=True),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
 
     # set values ############################################################
diff --git a/roles/ipaserver/library/ipaserver_master_password.py b/roles/ipaserver/library/ipaserver_master_password.py
index 3021498ba77ef60dc7ffc69f6830e3dd221da56d..d048a839882d2586d2572e5702ed09e83c368d0a 100644
--- a/roles/ipaserver/library/ipaserver_master_password.py
+++ b/roles/ipaserver/library/ipaserver_master_password.py
@@ -5,7 +5,7 @@
 #
 # Based on ipa-server-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:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   master_password:
     description: kerberos master password (normally autogenerated)
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -54,6 +56,7 @@ EXAMPLES = '''
 RETURN = '''
 password:
   description: The master password
+  type: str
   returned: always
 '''
 
@@ -61,6 +64,7 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
+    check_imports,
     setup_logging, options, paths, read_cache, ipa_generate_password
 )
 
@@ -69,13 +73,14 @@ def main():
     module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            master_password=dict(required=False, no_log=True),
+            dm_password=dict(required=True, type='str', no_log=True),
+            master_password=dict(required=False, type='str', no_log=True),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     module._ansible_debug = True
+    check_imports(module)
     setup_logging()
 
     options.dm_password = module.params.get('dm_password')
diff --git a/roles/ipaserver/library/ipaserver_prepare.py b/roles/ipaserver/library/ipaserver_prepare.py
index 7a65a9f57ae96c897349631046a8563050c2b822..f8277c11f1e403549d023958e0d5d88a6bbb21f1 100644
--- a/roles/ipaserver/library/ipaserver_prepare.py
+++ b/roles/ipaserver/library/ipaserver_prepare.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,116 +39,176 @@ description: Prepare IPA server deployment
 options:
   force:
     description: Installer force parameter
-    required: yes
+    type: bool
+    default: no
+    required: no
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: str
+    required: yes
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   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: yes
+    type: str
+    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
   no_host_dns:
     description: Do not use DNS for hostname lookup during installation
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_kra:
     description: Configure a dogtag KRA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   external_ca:
     description: External ca setting
-    required: yes
+    type: bool
+    required: no
   external_ca_type:
     description: Type of the external CA
-    required: yes
+    type: str
+    required: no
   external_ca_profile:
     description:
       Specify the certificate profile/template to use at the external CA
-    required: yes
+    type: str
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   allow_zone_overlap:
     description: Create DNS zone even if it already exists
-    required: yes
+    type: bool
+    default: no
+    required: no
   reverse_zones:
     description: The reverse DNS zones to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_reverse:
     description: Do not create new reverse DNS zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_reverse:
     description: Create necessary reverse zones
-    required: yes
+    type: bool
+    default: no
+    required: no
   forwarders:
     description: Add DNS forwarders
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_forwarders:
     description: Do not add any DNS forwarders, use root servers instead
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_forwarders:
     description: Use DNS forwarders configured in /etc/resolv.conf
-    required: yes
+    type: bool
+    default: no
+    required: no
   forward_policy:
     description: DNS forwarding policy for global forwarders
-    required: yes
+    type: str
+    choices: ['first', 'only']
+    required: no
   no_dnssec_validation:
     description: Disable DNSSEC validation
-    required: yes
+    type: bool
+    default: no
+    required: no
   enable_compat:
     description: Enable support for trusted domains for old clients
-    required: yes
+    type: bool
+    default: no
+    required: no
   netbios_name:
     description: NetBIOS name of the IPA domain
-    required: yes
+    type: str
+    required: no
   rid_base:
     description: Start value for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    required: no
   secondary_rid_base:
     description:
       Start value of the secondary range for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
+  random_serial_numbers:
+    description: Enable random serial numbers
+    type: bool
+    default: no
+    required: no
   sid_generation_always:
     description: Enable SID generation always
-    required: yes
+    type: bool
+    default: no
+    required: no
   _hostname_overridden:
     description: The installer _hostname_overridden setting
-    required: yes
+    type: bool
+    default: no
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -161,8 +221,8 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
-    ansible_module_get_parsed_ip_addresses,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore,
+    paths, ansible_module_get_parsed_ip_addresses,
     redirect_stdout, adtrust, api, default_subject_base,
     default_ca_subject_dn, ipautil, installutils, ca, kra, dns,
     get_server_ip_address, no_matching_interface_for_ip_address_warning,
@@ -175,13 +235,15 @@ def main():
         argument_spec=dict(
             # basic
             force=dict(required=False, type='bool', default=False),
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            ip_addresses=dict(required=False, type='list', default=[]),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=False),
-            ca_cert_files=dict(required=False, type='list', default=[]),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=[]),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
+            ca_cert_files=dict(required=False, type='list', elements='str',
+                               default=[]),
             no_host_dns=dict(required=False, type='bool', default=False),
             # server
             setup_adtrust=dict(required=False, type='bool', default=False),
@@ -191,26 +253,30 @@ def main():
             # client
             # certificate system
             external_ca=dict(required=False, type='bool'),
-            external_ca_type=dict(required=False),
-            external_ca_profile=dict(required=False),
-            external_cert_files=dict(required=False, type='list', default=[]),
-            subject_base=dict(required=False),
-            ca_subject=dict(required=False),
+            external_ca_type=dict(required=False, type='str'),
+            external_ca_profile=dict(required=False, type='str'),
+            external_cert_files=dict(required=False, type='list',
+                                     elements='str', default=[]),
+            subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
             # dns
             allow_zone_overlap=dict(required=False, type='bool',
                                     default=False),
-            reverse_zones=dict(required=False, type='list', default=[]),
+            reverse_zones=dict(required=False, type='list', elements='str',
+                               default=[]),
             no_reverse=dict(required=False, type='bool', default=False),
             auto_reverse=dict(required=False, type='bool', default=False),
-            forwarders=dict(required=False, type='list', default=[]),
+            forwarders=dict(required=False, type='list', elements='str',
+                            default=[]),
             no_forwarders=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
-            forward_policy=dict(default=None, choices=['first', 'only']),
+            forward_policy=dict(required=False, type='str',
+                                choices=['first', 'only'], default=None),
             no_dnssec_validation=dict(required=False, type='bool',
                                       default=False),
             # ad trust
             enable_compat=dict(required=False, type='bool', default=False),
-            netbios_name=dict(required=False),
+            netbios_name=dict(required=False, type='str'),
             rid_base=dict(required=False, type='int'),
             secondary_rid_base=dict(required=False, type='int'),
 
@@ -223,10 +289,11 @@ def main():
             _hostname_overridden=dict(required=False, type='bool',
                                       default=False),
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_set_ds_password.py b/roles/ipaserver/library/ipaserver_set_ds_password.py
index f4d767be2d0a185c909d3e80d851d12704df69af..f339fbc48ffe1c918b6d56908d2af715b8b40bb7 100644
--- a/roles/ipaserver/library/ipaserver_set_ds_password.py
+++ b/roles/ipaserver/library/ipaserver_set_ds_password.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,64 +39,86 @@ description: Set DS password
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: 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
   setup_ca:
     description: Configure a dogtag CA
-    required: no
+    type: bool
+    required: yes
   idstart:
     description: The starting value for the IDs range (default random)
-    required: no
+    type: int
+    required: yes
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: no
+    type: int
+    required: yes
   no_hbac_allow:
     description: Don't install allow_all HBAC rule
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   dirsrv_config_file:
     description:
       The path to LDIF file that will be used to modify configuration of
       dse.ldif during installation of the directory server instance
-    required: yes
+    type: str
+    required: no
   _dirsrv_pkcs12_info:
     description: The installer _dirsrv_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
   dirsrv_cert_files:
     description:
       Files containing the Directory Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   domainlevel:
     description: The domain level
-    required: yes
+    type: int
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -107,6 +129,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
+    check_imports,
     MAX_DOMAIN_LEVEL, AnsibleModuleLog, options, sysrestore, paths,
     api_Backend_ldap2, ds_init_info, redirect_stdout, setup_logging
 )
@@ -116,25 +139,28 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
             # server
             setup_ca=dict(required=True, type='bool'),
             idstart=dict(required=True, type='int'),
             idmax=dict(required=True, type='int'),
             no_hbac_allow=dict(required=False, type='bool', default=False),
             no_pkinit=dict(required=False, type='bool', default=False),
-            dirsrv_config_file=dict(required=False),
-            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            dirsrv_config_file=dict(required=False, type='str'),
+            _dirsrv_pkcs12_info=dict(required=False, type='list',
+                                     elements='str'),
             # ssl certificate
-            dirsrv_cert_files=dict(required=False, type='list', default=[]),
-            subject_base=dict(required=False),
-            ca_subject=dict(required=False),
+            dirsrv_cert_files=dict(required=False, type='list', elements='str',
+                                   default=[]),
+            subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
             # certificate system
-            external_cert_files=dict(required=False, type='list', default=[]),
+            external_cert_files=dict(required=False, type='list',
+                                     elements='str', default=[]),
             # additional
             domainlevel=dict(required=False, type='int',
                              default=MAX_DOMAIN_LEVEL),
@@ -142,6 +168,7 @@ def main():
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_adtrust.py b/roles/ipaserver/library/ipaserver_setup_adtrust.py
index 428d25286e6b2f450b04ccfa7347a0a93ba87916..820748be96f6e68d78f39bb1d0e43283369a856e 100644
--- a/roles/ipaserver/library/ipaserver_setup_adtrust.py
+++ b/roles/ipaserver/library/ipaserver_setup_adtrust.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,31 +39,42 @@ description: Setup trust ad
 options:
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   enable_compat:
     description: Enable support for trusted domains for old clients
-    required: yes
+    type: bool
+    default: no
+    required: no
   rid_base:
     description: Start value for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    required: no
   secondary_rid_base:
     description:
       Start value of the secondary range for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    required: no
   adtrust_netbios_name:
     description: The adtrust netbios_name setting
-    required: no
+    type: str
+    required: yes
   adtrust_reset_netbios_name:
     description: The adtrust reset_netbios_name setting
-    required: no
+    type: bool
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -74,7 +85,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     api_Backend_ldap2, redirect_stdout, adtrust, api
 )
 
@@ -83,7 +94,7 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            hostname=dict(required=False),
+            hostname=dict(required=False, type='str'),
             setup_ca=dict(required=False, type='bool', default=False),
             setup_adtrust=dict(required=False, type='bool', default=False),
             # ad trust
@@ -91,12 +102,13 @@ def main():
             rid_base=dict(required=False, type='int'),
             secondary_rid_base=dict(required=False, type='int'),
             # additional
-            adtrust_netbios_name=dict(required=True),
+            adtrust_netbios_name=dict(required=True, type='str'),
             adtrust_reset_netbios_name=dict(required=True, type='bool'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_ca.py b/roles/ipaserver/library/ipaserver_setup_ca.py
index 8c01e3c9cffb2237fc920d7a1f198af2946792c5..815edca7d99a6fc76fc703e1f299bbe74a89ceaf 100644
--- a/roles/ipaserver/library/ipaserver_setup_ca.py
+++ b/roles/ipaserver/library/ipaserver_setup_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
@@ -39,119 +39,169 @@ description: Setup CA
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: str
+    required: yes
   master_password:
     description: kerberos master password (normally autogenerated)
-    required: no
+    type: str
+    required: yes
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   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: yes
+    type: str
+    required: no
   no_host_dns:
     description: Do not use DNS for hostname lookup during installation
-    required: yes
+    type: bool
+    default: no
+    required: no
   pki_config_override:
     description: Path to ini file with config overrides
-    required: yes
+    type: str
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_kra:
     description: Configure a dogtag KRA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
   idstart:
     description: The starting value for the IDs range (default random)
-    required: no
+    type: int
+    required: yes
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: no
+    type: int
+    required: yes
   no_hbac_allow:
     description: Don't install allow_all HBAC rule
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   dirsrv_config_file:
     description:
       The path to LDIF file that will be used to modify configuration of
       dse.ldif during installation of the directory server instance
-    required: yes
+    type: str
+    required: no
   dirsrv_cert_files:
     description:
       Files containing the Directory Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   _dirsrv_pkcs12_info:
     description: The installer _dirsrv_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
   external_ca:
     description: External ca setting
-    required: yes
+    type: bool
+    default: no
+    required: no
   external_ca_type:
     description: Type of the external CA
-    required: yes
+    type: str
+    required: no
   external_ca_profile:
     description:
       Specify the certificate profile/template to use at the external CA
-    required: yes
+    type: str
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   _subject_base:
     description: The installer _subject_base setting
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   _ca_subject:
     description: The installer _ca_subject setting
-    required: yes
+    type: str
+    required: no
   ca_signing_algorithm:
     description: Signing algorithm of the IPA CA certificate
-    required: yes
+    type: str
+    required: no
   _random_serial_numbers:
     description: The installer _random_serial_numbers setting
+    type: bool
     required: yes
   reverse_zones:
     description: The reverse DNS zones to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_reverse:
     description: Do not create new reverse DNS zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_forwarders:
     description: Use DNS forwarders configured in /etc/resolv.conf
-    required: yes
+    type: bool
+    default: no
+    required: no
   domainlevel:
     description: The domain level
-    required: yes
+    type: int
+    required: no
   _http_ca_cert:
     description: The installer _http_ca_cert setting
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -164,7 +214,7 @@ import os
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     ansible_module_get_parsed_ip_addresses,
     api_Backend_ldap2, redirect_stdout, ca, installutils, ds_init_info,
     custodiainstance, write_cache, x509, decode_certificate
@@ -175,15 +225,16 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            master_password=dict(required=True, no_log=True),
-            ip_addresses=dict(required=False, type='list', default=[]),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=False),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            master_password=dict(required=True, type='str', no_log=True),
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=[]),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
             no_host_dns=dict(required=False, type='bool', default=False),
-            pki_config_override=dict(required=False),
+            pki_config_override=dict(required=False, type='str'),
             # server
             setup_adtrust=dict(required=False, type='bool', default=False),
             setup_kra=dict(required=False, type='bool', default=False),
@@ -193,32 +244,36 @@ def main():
             idmax=dict(required=True, type='int'),
             no_hbac_allow=dict(required=False, type='bool', default=False),
             no_pkinit=dict(required=False, type='bool', default=False),
-            dirsrv_config_file=dict(required=False),
-            dirsrv_cert_files=dict(required=False, type='list'),
-            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            dirsrv_config_file=dict(required=False, type='str'),
+            dirsrv_cert_files=dict(required=False, type='list',
+                                   elements='str'),
+            _dirsrv_pkcs12_info=dict(required=False, type='list',
+                                     elements='str'),
             # certificate system
             external_ca=dict(required=False, type='bool', default=False),
-            external_ca_type=dict(required=False),
-            external_ca_profile=dict(required=False),
+            external_ca_type=dict(required=False, type='str'),
+            external_ca_profile=dict(required=False, type='str'),
             external_cert_files=dict(required=False, type='list',
-                                     default=None),
-            subject_base=dict(required=False),
-            _subject_base=dict(required=False),
-            ca_subject=dict(required=False),
-            _ca_subject=dict(required=False),
-            ca_signing_algorithm=dict(required=False),
+                                     elements='str', default=None),
+            subject_base=dict(required=False, type='str'),
+            _subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
+            _ca_subject=dict(required=False, type='str'),
+            ca_signing_algorithm=dict(required=False, type='str'),
             _random_serial_numbers=dict(required=True, type='bool'),
             # dns
-            reverse_zones=dict(required=False, type='list', default=[]),
+            reverse_zones=dict(required=False, type='list', elements='str',
+                               default=[]),
             no_reverse=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
             # additional
             domainlevel=dict(required=False, type='int'),
-            _http_ca_cert=dict(required=False),
+            _http_ca_cert=dict(required=False, type='str'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_custodia.py b/roles/ipaserver/library/ipaserver_setup_custodia.py
index a788ad1268bbf58eb99f96cfe1bfe1527a30b0fe..be337c1d502e0c97074fdf9266a69dd061eb5b19 100644
--- a/roles/ipaserver/library/ipaserver_setup_custodia.py
+++ b/roles/ipaserver/library/ipaserver_setup_custodia.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,15 +39,19 @@ description: Setup custodia
 options:
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -58,7 +62,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    setup_logging, AnsibleModuleLog, options,
+    check_imports, setup_logging, AnsibleModuleLog, options,
     api_Backend_ldap2,
     custodiainstance, redirect_stdout
 )
@@ -68,13 +72,14 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            realm=dict(required=True),
-            hostname=dict(required=False),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
             setup_ca=dict(required=False, type='bool', default=False),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_dns.py b/roles/ipaserver/library/ipaserver_setup_dns.py
index 1ed1fe4fe6655773f97ba3b0426e28d103b9d025..cf31eda93ae163544912ed84ae560017ba32c62e 100644
--- a/roles/ipaserver/library/ipaserver_setup_dns.py
+++ b/roles/ipaserver/library/ipaserver_setup_dns.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,42 +39,61 @@ description: Setup DNS
 options:
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   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
   setup_dns:
     description: Configure bind with our zone
-    required: no
+    type: bool
+    required: yes
   setup_ca:
     description: Configure a dogtag CA
-    required: no
+    type: bool
+    required: yes
   zonemgr:
     description: DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN
-    required: yes
+    type: str
+    required: no
   forwarders:
     description: Add DNS forwarders
-    required: no
+    type: list
+    elements: str
+    required: yes
   forward_policy:
     description: DNS forwarding policy for global forwarders
-    required: yes
+    type: str
+    choices: ['first', 'only']
+    default: 'first'
+    required: no
   no_dnssec_validation:
     description: Disable DNSSEC validation
-    required: yes
+    type: bool
+    default: no
+    required: no
   dns_ip_addresses:
     description: The dns ip_addresses setting
-    required: no
+    type: list
+    elements: str
+    required: yes
   dns_reverse_zones:
     description: The dns reverse_zones setting
-    required: no
+    type: list
+    elements: str
+    required: yes
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -85,7 +104,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, paths, dns,
+    check_imports, AnsibleModuleLog, setup_logging, options, paths, dns,
     ansible_module_get_parsed_ip_addresses, sysrestore, api_Backend_ldap2,
     redirect_stdout, bindinstance
 )
@@ -95,26 +114,29 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            ip_addresses=dict(required=False, type='list', default=[]),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=True),
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=[]),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=True, type='str'),
             # server
             setup_dns=dict(required=True, type='bool'),
             setup_ca=dict(required=True, type='bool'),
             # dns
-            zonemgr=dict(required=False),
-            forwarders=dict(required=True, type='list'),
-            forward_policy=dict(default='first', choices=['first', 'only']),
+            zonemgr=dict(required=False, type='str'),
+            forwarders=dict(required=True, type='list', elements='str'),
+            forward_policy=dict(required=False, choices=['first', 'only'],
+                                default='first'),
             no_dnssec_validation=dict(required=False, type='bool',
                                       default=False),
             # additional
-            dns_ip_addresses=dict(required=True, type='list'),
-            dns_reverse_zones=dict(required=True, type='list'),
+            dns_ip_addresses=dict(required=True, type='list', elements='str'),
+            dns_reverse_zones=dict(required=True, type='list', elements='str'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_ds.py b/roles/ipaserver/library/ipaserver_setup_ds.py
index 76fb4b73c93c95ffedcb0272b9ff0622caec1ec3..4479daaaf8248e21112e2e8065a4dd71adb44ba1 100644
--- a/roles/ipaserver/library/ipaserver_setup_ds.py
+++ b/roles/ipaserver/library/ipaserver_setup_ds.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,61 +39,83 @@ description: Configure directory server
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: 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: yes
+    type: str
+    required: no
   idstart:
     description: The starting value for the IDs range (default random)
-    required: no
+    type: int
+    required: yes
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: no
+    type: int
+    required: yes
   no_hbac_allow:
     description: Don't install allow_all HBAC rule
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   dirsrv_config_file:
     description:
       The path to LDIF file that will be used to modify configuration of
       dse.ldif during installation of the directory server instance
-    required: yes
+    type: str
+    required: no
   dirsrv_cert_files:
     description:
       Files containing the Directory Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   _dirsrv_pkcs12_info:
     description: The installer _dirsrv_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -104,7 +126,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     api_Backend_ldap2, redirect_stdout, api, NUM_VERSION, tasks,
     dsinstance, ntpinstance, IPAAPI_USER
 )
@@ -114,24 +136,27 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=False),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
             # server
             idstart=dict(required=True, type='int'),
             idmax=dict(required=True, type='int'),
             no_hbac_allow=dict(required=False, type='bool', default=False),
             no_pkinit=dict(required=False, type='bool', default=False),
-            dirsrv_config_file=dict(required=False),
+            dirsrv_config_file=dict(required=False, type='str'),
             # ssl certificate
-            dirsrv_cert_files=dict(required=False, type='list', default=[]),
-            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            dirsrv_cert_files=dict(required=False, type='list', elements='str',
+                                   default=[]),
+            _dirsrv_pkcs12_info=dict(required=False, type='list',
+                                     elements='str'),
             # certificate system
-            external_cert_files=dict(required=False, type='list', default=[]),
-            subject_base=dict(required=False),
-            ca_subject=dict(required=False),
+            external_cert_files=dict(required=False, type='list',
+                                     elements='str', default=[]),
+            subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
 
             # additional
             setup_ca=dict(required=False, type='bool', default=False),
@@ -139,6 +164,7 @@ def main():
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_http.py b/roles/ipaserver/library/ipaserver_setup_http.py
index 5f72b1cbe49a2d05e0a67f5621ae76c4e0464b58..cd6478eeb8d951f8aa2568cf563ca3659e022118 100644
--- a/roles/ipaserver/library/ipaserver_setup_http.py
+++ b/roles/ipaserver/library/ipaserver_setup_http.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,107 +39,155 @@ description: Setup HTTP
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: str
+    required: yes
   master_password:
     description: kerberos master password (normally autogenerated)
-    required: no
+    type: 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: yes
+    type: str
+    required: no
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   reverse_zones:
     description: The reverse DNS zones to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   http_cert_files:
     description:
       File containing the Apache Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_kra:
     description: Configure a dogtag KRA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_host_dns:
     description: Do not use DNS for hostname lookup during installation
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_hbac_allow:
     description: Don't install allow_all HBAC rule
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_ui_redirect:
     description: Do not automatically redirect to the Web UI
-    required: yes
+    type: bool
+    default: no
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   _subject_base:
     description: The installer _subject_base setting
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   _ca_subject:
     description: The installer _ca_subject setting
-    required: yes
+    type: str
+    required: no
   idstart:
     description: The starting value for the IDs range (default random)
-    required: no
+    type: int
+    required: yes
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: no
+    type: int
+    required: yes
   domainlevel:
     description: The domain level
-    required: yes
+    type: int
+    required: no
   dirsrv_config_file:
     description:
       The path to LDIF file that will be used to modify configuration of
       dse.ldif during installation of the directory server instance
-    required: yes
+    type: str
+    required: no
   dirsrv_cert_files:
     description:
       Files containing the Directory Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_reverse:
     description: Do not create new reverse DNS zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_forwarders:
     description: Use DNS forwarders configured in /etc/resolv.conf
-    required: yes
+    type: bool
+    default: no
+    required: no
   _dirsrv_pkcs12_info:
     description: The installer _dirsrv_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
   _http_pkcs12_info:
     description: The installer _http_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -150,7 +198,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     ansible_module_get_parsed_ip_addresses,
     api_Backend_ldap2, redirect_stdout, ds_init_info,
     krbinstance, httpinstance, ca, service, tasks
@@ -161,16 +209,19 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            master_password=dict(required=True, no_log=True),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=False),
-
-            ip_addresses=dict(required=False, type='list', default=[]),
-            reverse_zones=dict(required=False, type='list', default=[]),
-            http_cert_files=dict(required=False, type='list', default=[]),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            master_password=dict(required=True, type='str', no_log=True),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
+
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=[]),
+            reverse_zones=dict(required=False, type='list', elements='str',
+                               default=[]),
+            http_cert_files=dict(required=False, type='list', elements='str',
+                                 default=[]),
 
             setup_adtrust=dict(required=False, type='bool', default=False),
             setup_kra=dict(required=False, type='bool', default=False),
@@ -183,29 +234,34 @@ def main():
 
             no_ui_redirect=dict(required=False, type='bool', default=False),
 
-            external_cert_files=dict(required=False, type='list', default=[]),
-            subject_base=dict(required=False),
-            _subject_base=dict(required=False),
-            ca_subject=dict(required=False),
-            _ca_subject=dict(required=False),
+            external_cert_files=dict(required=False, type='list',
+                                     elements='str', default=[]),
+            subject_base=dict(required=False, type='str'),
+            _subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
+            _ca_subject=dict(required=False, type='str'),
 
             idstart=dict(required=True, type='int'),
             idmax=dict(required=True, type='int'),
             domainlevel=dict(required=False, type='int'),
             dirsrv_config_file=dict(required=False),
-            dirsrv_cert_files=dict(required=False, type='list', default=[]),
+            dirsrv_cert_files=dict(required=False, type='list', elements='str',
+                                   default=[]),
 
             no_reverse=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
 
             # _update_hosts_file=dict(required=False, type='bool',
             #                         default=False),
-            _dirsrv_pkcs12_info=dict(required=False, type='list'),
-            _http_pkcs12_info=dict(required=False, type='list'),
+            _dirsrv_pkcs12_info=dict(required=False, type='list',
+                                     elements='str'),
+            _http_pkcs12_info=dict(required=False, type='list',
+                                   elements='str'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_kra.py b/roles/ipaserver/library/ipaserver_setup_kra.py
index 78f1fe26de6cfbc8dc577980edfe44442bb99b95..9f05ef5a1da40f3a99c154cc60c8e36e09bdcf3a 100644
--- a/roles/ipaserver/library/ipaserver_setup_kra.py
+++ b/roles/ipaserver/library/ipaserver_setup_kra.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,24 +39,30 @@ description: Setup KRA
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: no
+    type: str
+    required: yes
   setup_ca:
     description: Configure a dogtag CA
-    required: no
+    type: bool
+    required: yes
   setup_kra:
     description: Configure a dogtag KRA
-    required: no
+    type: bool
+    required: yes
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   pki_config_override:
     description: Path to ini file with config overrides
-    required: yes
+    type: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -67,7 +73,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options,
+    check_imports, AnsibleModuleLog, setup_logging, options,
     api_Backend_ldap2, redirect_stdout, api, custodiainstance, kra
 )
 
@@ -76,16 +82,17 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            hostname=dict(required=True),
+            dm_password=dict(required=True, type='str', no_log=True),
+            hostname=dict(required=True, type='str'),
             setup_ca=dict(required=True, type='bool'),
             setup_kra=dict(required=True, type='bool'),
-            realm=dict(required=True),
-            pki_config_override=dict(required=False),
+            realm=dict(required=True, type='str'),
+            pki_config_override=dict(required=False, type='str'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_krb.py b/roles/ipaserver/library/ipaserver_setup_krb.py
index 70daab2528728a0aba279ad1dfac2e9b44ba5636..df37ed31a50f9845482a9d68dff808148b8761ff 100644
--- a/roles/ipaserver/library/ipaserver_setup_krb.py
+++ b/roles/ipaserver/library/ipaserver_setup_krb.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,79 +39,115 @@ description: Setup KRB
 options:
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: str
+    required: yes
   master_password:
     description: kerberos master password (normally autogenerated)
-    required: no
+    type: 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: yes
+    type: str
+    required: no
   ip_addresses:
     description: List of Master Server IP Addresses
-    required: yes
+    type: list
+    elements: str
+    required: no
   reverse_zones:
     description: The reverse DNS zones to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_kra:
     description: Configure a dogtag KRA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_host_dns:
     description: Do not use DNS for hostname lookup during installation
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   no_hbac_allow:
     description: Don't install allow_all HBAC rule
-    required: yes
+    type: bool
+    default: no
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   idstart:
     description: The starting value for the IDs range (default random)
-    required: no
+    type: int
+    required: yes
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: no
+    type: int
+    required: yes
   no_reverse:
     description: Do not create new reverse DNS zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_forwarders:
     description: Use DNS forwarders configured in /etc/resolv.conf
-    required: yes
+    type: bool
+    default: no
+    required: no
   _pkinit_pkcs12_info:
     description: The installer _pkinit_pkcs12_info setting
-    required: yes
+    type: list
+    elements: str
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -122,7 +158,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     ansible_module_get_parsed_ip_addresses,
     api_Backend_ldap2, redirect_stdout, krbinstance
 )
@@ -132,15 +168,17 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            master_password=dict(required=True, no_log=True),
-            domain=dict(required=True),
-            realm=dict(required=True),
-            hostname=dict(required=False),
-
-            ip_addresses=dict(required=False, type='list', default=[]),
-            reverse_zones=dict(required=False, type='list', default=[]),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            master_password=dict(required=True, type='str', no_log=True),
+            domain=dict(required=True, type='str'),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
+
+            ip_addresses=dict(required=False, type='list', elements='str',
+                              default=[]),
+            reverse_zones=dict(required=False, type='list', elements='str',
+                               default=[]),
 
             setup_adtrust=dict(required=False, type='bool', default=False),
             setup_kra=dict(required=False, type='bool', default=False),
@@ -151,9 +189,10 @@ def main():
             no_pkinit=dict(required=False, type='bool', default=False),
             no_hbac_allow=dict(required=False, type='bool', default=False),
 
-            external_cert_files=dict(required=False, type='list', default=[]),
-            subject_base=dict(required=False),
-            ca_subject=dict(required=False),
+            external_cert_files=dict(required=False, type='list',
+                                     elements='str', default=[]),
+            subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
 
             idstart=dict(required=True, type='int'),
             idmax=dict(required=True, type='int'),
@@ -161,11 +200,13 @@ def main():
             no_reverse=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
 
-            _pkinit_pkcs12_info=dict(required=False, type='list'),
+            _pkinit_pkcs12_info=dict(required=False, type='list',
+                                     elements='str'),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_ntp.py b/roles/ipaserver/library/ipaserver_setup_ntp.py
index 9efad2137ebf509102f83a7b98f9ee773b9695c9..eac722b5da03d923c6412e1e1589bcb63f3bb9a6 100644
--- a/roles/ipaserver/library/ipaserver_setup_ntp.py
+++ b/roles/ipaserver/library/ipaserver_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
@@ -39,12 +39,15 @@ description: Setup NTP
 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
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -55,7 +58,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options, sysrestore, paths,
+    check_imports, AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     redirect_stdout, time_service, sync_time, ntpinstance, timeconf,
     getargspec
 )
@@ -64,12 +67,14 @@ from ansible.module_utils.ansible_ipa_server import (
 def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
-            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),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_setup_otpd.py b/roles/ipaserver/library/ipaserver_setup_otpd.py
index ca1e06c4671362d57f9a7aa40247387a09a2b9b0..f89681184a8817b3db234040be62406ad91d95dc 100644
--- a/roles/ipaserver/library/ipaserver_setup_otpd.py
+++ b/roles/ipaserver/library/ipaserver_setup_otpd.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,15 +39,19 @@ description: Setup OTPD
 options:
   realm:
     description: Kerberos realm name of the IPA deployment
-    required: no
+    type: str
+    required: yes
   hostname:
     description: Fully qualified name of this host
-    required: yes
+    type: str
+    required: no
   setup_ca:
     description: Configure a dogtag CA
-    required: yes
+    type: bool
+    default: no
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -58,7 +62,7 @@ RETURN = '''
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_server import (
-    AnsibleModuleLog, setup_logging, options,
+    check_imports, AnsibleModuleLog, setup_logging, options,
     api_Backend_ldap2, redirect_stdout, otpdinstance, ipautil
 )
 
@@ -67,13 +71,14 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec=dict(
             # basic
-            realm=dict(required=True),
-            hostname=dict(required=False),
+            realm=dict(required=True, type='str'),
+            hostname=dict(required=False, type='str'),
             setup_ca=dict(required=False, type='bool', default=False),
         ),
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/library/ipaserver_test.py b/roles/ipaserver/library/ipaserver_test.py
index f830f37d8a3660815c1a3bc805c7bab23cffaab4..cf5b7c8f0f7f3eb3ee56bda383ae162ef41cefd2 100644
--- a/roles/ipaserver/library/ipaserver_test.py
+++ b/roles/ipaserver/library/ipaserver_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
@@ -39,169 +39,246 @@ description: IPA server test
 options:
   force:
     description: Installer force parameter
-    required: yes
+    type: bool
+    default: no
+    required: no
   dm_password:
     description: Directory Manager password
-    required: no
+    type: str
+    required: yes
   password:
     description: Admin user kerberos password
-    required: no
+    type: str
+    required: yes
   master_password:
     description: kerberos master password (normally autogenerated)
-    required: yes
+    type: str
+    required: no
   domain:
     description: Primary DNS domain of the IPA deployment
-    required: yes
+    type: 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
   ca_cert_files:
     description:
       List of files containing CA certificates for the service certificate
       files
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_host_dns:
     description: Do not use DNS for hostname lookup during installation
-    required: yes
+    type: bool
+    default: no
+    required: no
   pki_config_override:
     description: Path to ini file with config overrides
-    required: yes
+    type: str
+    required: no
   skip_mem_check:
     description: Skip checking for minimum required memory
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_adtrust:
     description: Configure AD trust capability
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_kra:
     description: Configure a dogtag KRA
-    required: yes
+    type: bool
+    default: no
+    required: no
   setup_dns:
     description: Configure bind with our zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   idstart:
     description: The starting value for the IDs range (default random)
-    required: yes
+    type: int
+    required: no
   idmax:
     description: The max value for the IDs range (default idstart+199999)
-    required: yes
+    type: int
+    required: no
   no_pkinit:
     description: Disable pkinit setup steps
-    required: yes
+    type: bool
+    default: no
+    required: no
   dirsrv_config_file:
     description:
       The path to LDIF file that will be used to modify configuration of
       dse.ldif during installation of the directory server instance
-    required: yes
+    type: str
+    required: no
   dirsrv_cert_files:
     description:
       Files containing the Directory Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   http_cert_files:
     description:
       File containing the Apache Server SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   pkinit_cert_files:
     description:
       File containing the Kerberos KDC SSL certificate and private key
-    required: yes
+    type: list
+    elements: str
+    required: no
   dirsrv_pin:
     description: The password to unlock the Directory Server private key
-    required: yes
+    type: str
+    required: no
   http_pin:
     description: The password to unlock the Apache Server private key
-    required: yes
+    type: str
+    required: no
   pkinit_pin:
     description: The password to unlock the Kerberos KDC private key
-    required: yes
+    type: str
+    required: no
   dirsrv_cert_name:
     description: Name of the Directory Server SSL certificate to install
-    required: yes
+    type: str
+    required: no
   http_cert_name:
     description: Name of the Apache Server SSL certificate to install
-    required: yes
+    type: str
+    required: no
   pkinit_cert_name:
     description: Name of the Kerberos KDC SSL certificate to install
-    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
+    default: no
+    required: no
   external_ca:
     description: External ca setting
-    required: yes
+    type: bool
+    default: no
+    required: no
   external_ca_type:
     description: Type of the external CA
-    required: yes
+    type: str
+    required: no
   external_ca_profile:
     description:
       Specify the certificate profile/template to use at the external CA
-    required: yes
+    type: str
+    required: no
   external_cert_files:
     description:
       File containing the IPA CA certificate and the external CA certificate
       chain
-    required: yes
+    type: list
+    elements: str
+    required: no
   subject_base:
     description:
       The certificate subject base (default O=<realm-name>).
       RDNs are in LDAP order (most specific RDN first).
-    required: yes
+    type: str
+    required: no
   ca_subject:
     description: The installer ca_subject setting
-    required: yes
+    type: str
+    required: no
   allow_zone_overlap:
     description: Create DNS zone even if it already exists
-    required: yes
+    type: bool
+    default: no
+    required: no
   reverse_zones:
     description: The reverse DNS zones to use
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_reverse:
     description: Do not create new reverse DNS zone
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_reverse:
     description: Create necessary reverse zones
-    required: yes
+    type: bool
+    default: no
+    required: no
   zonemgr:
     description: DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN
-    required: yes
+    type: str
+    required: no
   forwarders:
     description: Add DNS forwarders
-    required: yes
+    type: list
+    elements: str
+    required: no
   no_forwarders:
     description: Do not add any DNS forwarders, use root servers instead
-    required: yes
+    type: bool
+    default: no
+    required: no
   auto_forwarders:
     description: Use DNS forwarders configured in /etc/resolv.conf
-    required: yes
+    type: bool
+    default: no
+    required: no
   forward_policy:
     description: DNS forwarding policy for global forwarders
-    required: yes
+    type: str
+    choices: ['first', 'only']
+    required: no
   no_dnssec_validation:
     description: Disable DNSSEC validation
-    required: yes
+    type: bool
+    default: no
+    required: no
   enable_compat:
     description: Enable support for trusted domains for old clients
-    required: yes
+    type: bool
+    default: no
+    required: no
   netbios_name:
     description: NetBIOS name of the IPA domain
-    required: yes
+    type: str
+    required: no
   rid_base:
     description: Start value for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    default: 1000
+    required: no
   secondary_rid_base:
     description:
       Start value of the secondary range for mapping UIDs and GIDs to RIDs
-    required: yes
+    type: int
+    default: 100000000
+    required: no
 author:
-    - Thomas Woerner
+    - Thomas Woerner (@t-woerner)
 '''
 
 EXAMPLES = '''
@@ -218,6 +295,7 @@ from shutil import copyfile
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils._text import to_native
 from ansible.module_utils.ansible_ipa_server import (
+    check_imports,
     AnsibleModuleLog, setup_logging, options, adtrust_imported, kra_imported,
     PKIIniLoader, MIN_DOMAIN_LEVEL, MAX_DOMAIN_LEVEL, check_zone_overlap,
     redirect_stdout, validate_dm_password, validate_admin_password,
@@ -239,15 +317,16 @@ def main():
         argument_spec=dict(
             # basic
             force=dict(required=False, type='bool', default=False),
-            dm_password=dict(required=True, no_log=True),
-            password=dict(required=True, no_log=True),
-            master_password=dict(required=False, no_log=True),
-            domain=dict(required=False),
-            realm=dict(required=False),
-            hostname=dict(required=False),
-            ca_cert_files=dict(required=False, type='list', default=[]),
+            dm_password=dict(required=True, type='str', no_log=True),
+            password=dict(required=True, type='str', no_log=True),
+            master_password=dict(required=False, type='str', no_log=True),
+            domain=dict(required=False, type='str'),
+            realm=dict(required=False, type='str'),
+            hostname=dict(required=False, type='str'),
+            ca_cert_files=dict(required=False, type='list', elements='str',
+                               default=[]),
             no_host_dns=dict(required=False, type='bool', default=False),
-            pki_config_override=dict(required=False),
+            pki_config_override=dict(required=False, type='str'),
             skip_mem_check=dict(required=False, type='bool', default=False),
             # server
             setup_adtrust=dict(required=False, type='bool', default=False),
@@ -258,21 +337,25 @@ def main():
             # no_hbac_allow
             no_pkinit=dict(required=False, type='bool', default=False),
             # no_ui_redirect
-            dirsrv_config_file=dict(required=False),
+            dirsrv_config_file=dict(required=False, type='str'),
             # ssl certificate
-            dirsrv_cert_files=dict(required=False, type='list', default=None),
-            http_cert_files=dict(required=False, type='list', default=None),
-            pkinit_cert_files=dict(required=False, type='list', default=None),
-            dirsrv_pin=dict(required=False),
-            http_pin=dict(required=False),
-            pkinit_pin=dict(required=False),
-            dirsrv_cert_name=dict(required=False),
-            http_cert_name=dict(required=False),
-            pkinit_cert_name=dict(required=False),
+            dirsrv_cert_files=dict(required=False, type='list', elements='str',
+                                   default=None),
+            http_cert_files=dict(required=False, type='list', elements='str',
+                                 default=None),
+            pkinit_cert_files=dict(required=False, type='list', elements='str',
+                                   default=None),
+            dirsrv_pin=dict(required=False, type='str'),
+            http_pin=dict(required=False, type='str'),
+            pkinit_pin=dict(required=False, type='str'),
+            dirsrv_cert_name=dict(required=False, type='str'),
+            http_cert_name=dict(required=False, type='str'),
+            pkinit_cert_name=dict(required=False, type='str'),
             # client
             # mkhomedir
-            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),
             # ssh_trust_dns
             # no_ssh
@@ -280,38 +363,42 @@ def main():
             # no_dns_sshfp
             # certificate system
             external_ca=dict(required=False, type='bool', default=False),
-            external_ca_type=dict(required=False),
-            external_ca_profile=dict(required=False),
+            external_ca_type=dict(required=False, type='str'),
+            external_ca_profile=dict(required=False, type='str'),
             external_cert_files=dict(required=False, type='list',
-                                     default=None),
-            subject_base=dict(required=False),
-            ca_subject=dict(required=False),
+                                     elements='str', default=None),
+            subject_base=dict(required=False, type='str'),
+            ca_subject=dict(required=False, type='str'),
             # ca_signing_algorithm
             # dns
             allow_zone_overlap=dict(required=False, type='bool',
                                     default=False),
-            reverse_zones=dict(required=False, type='list', default=[]),
+            reverse_zones=dict(required=False, type='list', elements='str',
+                               default=[]),
             no_reverse=dict(required=False, type='bool', default=False),
             auto_reverse=dict(required=False, type='bool', default=False),
-            zonemgr=dict(required=False),
-            forwarders=dict(required=False, type='list', default=[]),
+            zonemgr=dict(required=False, type='str'),
+            forwarders=dict(required=False, type='list', elements='str',
+                            default=[]),
             no_forwarders=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
-            forward_policy=dict(default=None, choices=['first', 'only']),
+            forward_policy=dict(required=False, type='str',
+                                choices=['first', 'only'], default=None),
             no_dnssec_validation=dict(required=False, type='bool',
                                       default=False),
             # ad trust
             enable_compat=dict(required=False, type='bool', default=False),
-            netbios_name=dict(required=False),
+            netbios_name=dict(required=False, type='str'),
             rid_base=dict(required=False, type='int', default=1000),
             secondary_rid_base=dict(required=False, type='int',
                                     default=100000000),
             # additional
         ),
-        supports_check_mode=True,
+        supports_check_mode=False,
     )
 
     ansible_module._ansible_debug = True
+    check_imports(ansible_module)
     setup_logging()
     ansible_log = AnsibleModuleLog(ansible_module)
 
diff --git a/roles/ipaserver/module_utils/ansible_ipa_server.py b/roles/ipaserver/module_utils/ansible_ipa_server.py
index f1f4972b690b3fb44fd2f07a622a031088762916..6dec4bc210b1a2497f3c5accefae6cf3210d477e 100644
--- a/roles/ipaserver/module_utils/ansible_ipa_server.py
+++ b/roles/ipaserver/module_utils/ansible_ipa_server.py
@@ -3,9 +3,9 @@
 # Authors:
 #   Thomas Woerner <twoerner@redhat.com>
 #
-# Based on ipa-client-install code
+# Based on ipa-server-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
@@ -23,12 +23,12 @@
 
 from __future__ import (absolute_import, division, print_function)
 
-__metaclass__ = type
+__metaclass__ = type  # pylint: disable=invalid-name
 
 __all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
            "ipa_generate_password", "run", "ScriptError", "services",
            "tasks", "errors", "x509", "DOMAIN_LEVEL_0", "MIN_DOMAIN_LEVEL",
-           "validate_domain_name",
+           "MAX_DOMAIN_LEVEL", "validate_domain_name",
            "no_matching_interface_for_ip_address_warning",
            "check_zone_overlap", "timeconf", "ntpinstance", "adtrust",
            "bindinstance", "ca", "dns", "httpinstance", "installutils",
@@ -41,45 +41,42 @@ __all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
            "adtrustinstance", "IPAAPI_USER", "sync_time", "PKIIniLoader",
            "default_subject_base", "default_ca_subject_dn",
            "check_ldap_conf", "encode_certificate", "decode_certificate",
-           "check_available_memory", "getargspec", "get_min_idstart"]
+           "check_available_memory", "getargspec", "get_min_idstart",
+           "paths", "api", "ipautil", "adtrust_imported", "NUM_VERSION",
+           "time_service", "kra_imported", "dsinstance", "IPA_PYTHON_VERSION",
+           "NUM_VERSION"]
 
 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 logging
+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)
+
+
+try:
     from contextlib import contextmanager as contextlib_contextmanager
     from ansible.module_utils import six
     import base64
 
-    # 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.version import NUM_VERSION, VERSION
 
     if NUM_VERSION < 30201:
@@ -211,223 +208,249 @@ else:
 
         raise Exception("freeipa version '%s' is too old" % VERSION)
 
-    logger = logging.getLogger("ipa-server-install")
+except ImportError as _err:
+    ANSIBLE_IPA_SERVER_MODULE_IMPORT_ERROR = str(_err)
 
-    def setup_logging():
-        # logger.setLevel(logging.DEBUG)
-        standard_logging_setup(
-            paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
-            filemode='a', console_format='%(message)s')
+    for attr in __all__:
+        setattr(sys.modules[__name__], attr, None)
+else:
+    ANSIBLE_IPA_SERVER_MODULE_IMPORT_ERROR = None
 
-    @contextlib_contextmanager
-    def redirect_stdout(stream):
-        sys.stdout = stream
-        try:
-            yield stream
-        finally:
-            sys.stdout = sys.__stdout__
-
-    class AnsibleModuleLog():
-        def __init__(self, module):
-            self.module = module
-            _ansible_module_log = self
-
-            class AnsibleLoggingHandler(logging.Handler):
-                def emit(self, record):
-                    _ansible_module_log.write(self.format(record))
-
-            self.logging_handler = AnsibleLoggingHandler()
-            logger.setLevel(logging.DEBUG)
-            logger.root.addHandler(self.logging_handler)
-
-        def close(self):
-            self.flush()
-
-        def flush(self):
-            pass
-
-        def log(self, msg):
-            # self.write(msg+"\n")
-            self.write(msg)
-
-        def debug(self, msg):
-            self.module.debug(msg)
-
-        def info(self, msg):
-            self.module.debug(msg)
-
-        @staticmethod
-        def isatty():
-            return False
-
-        def write(self, msg):
-            self.module.debug(msg)
-            # self.module.warn(msg)
-
-    # pylint: disable=too-few-public-methods, useless-object-inheritance
-    # pylint: disable=too-many-instance-attributes
-    class options_obj(object):  # pylint: disable=invalid-name
-        def __init__(self):
-            self._replica_install = False
-            self.dnssec_master = False  # future unknown
-            self.disable_dnssec_master = False  # future unknown
-            self.domainlevel = MAX_DOMAIN_LEVEL  # deprecated
-            self.domain_level = self.domainlevel  # deprecated
-            self.interactive = False
-            self.unattended = not self.interactive
-
-        # def __getattribute__(self, attr):
-        #    logger.info(" <-- Accessing options.%s" % attr)
-        #    return super(options_obj, self).__getattribute__(attr)
-
-        # def __getattr__(self, attr):
-        #    logger.info(" --> Adding missing options.%s" % attr)
-        #    setattr(self, attr, None)
-        #    return getattr(self, attr)
-
-        def knobs(self):
-            for name in self.__dict__:
-                yield self, name
-
-    # pylint: enable=too-few-public-methods, useless-object-inheritance
-
-    # pylint: enable=too-many-instance-attributes
-    options = options_obj()
-    installer = options
-
-    # pylint: disable=attribute-defined-outside-init
-
-    # ServerMasterInstall
-    options.add_sids = True
-    options.add_agents = False
-
-    # Installable
-    options.uninstalling = False
-
-    # ServerInstallInterface
-    options.description = "Server"
-
-    options.kinit_attempts = 1
-    options.fixed_primary = True
-    options.permit = False
-    options.enable_dns_updates = False
-    options.no_krb5_offline_passwords = False
-    options.preserve_sssd = False
-    options.no_sssd = False
-
-    # ServerMasterInstall
-    options.force_join = False
-    options.servers = None
-    options.no_wait_for_dns = True
-    options.host_password = None
-    options.keytab = None
-    options.setup_ca = True
-    # always run sidgen task and do not allow adding agents on first master
-    options.add_sids = True
-    options.add_agents = False
-
-    # ADTrustInstallInterface
-    # no_msdcs is deprecated
-    options.no_msdcs = False
-
-    # For pylint
-    options.external_cert_files = None
-    options.dirsrv_cert_files = None
-
-    # Uninstall
-    options.ignore_topology_disconnect = False
-    options.ignore_last_of_role = False
-
-    # pylint: enable=attribute-defined-outside-init
-
-    # pylint: disable=invalid-name
-    def api_Backend_ldap2(host_name, setup_ca, connect=False):
-        # we are sure we have the configuration file ready.
-        cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True,
-                   host=host_name)
-        if setup_ca:
-            # we have an IPA-integrated CA
-            cfg['ca_host'] = host_name
-
-        api.bootstrap(**cfg)
-        api.finalize()
-        if connect:
-            api.Backend.ldap2.connect()
-
-    # pylint: enable=invalid-name
-
-    def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
-                     realm_name, host_name, domain_name, dm_password,
-                     idstart, idmax, subject_base, ca_subject,
-                     _no_hbac_allow, dirsrv_pkcs12_info, no_pkinit):
-
-        if not options.external_cert_files:
-            _ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel,
-                                        config_ldif=dirsrv_config_file)
-            _ds.set_output(ansible_log)
-
-            if options.dirsrv_cert_files:
-                _dirsrv_pkcs12_info = dirsrv_pkcs12_info
-            else:
-                _dirsrv_pkcs12_info = None
-
-            with redirect_stdout(ansible_log):
-                _ds.init_info(realm_name, host_name, domain_name, dm_password,
-                              subject_base, ca_subject, idstart, idmax,
-                              # hbac_allow=not no_hbac_allow,
-                              _dirsrv_pkcs12_info, setup_pkinit=not no_pkinit)
-        else:
-            _ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel)
-            _ds.set_output(ansible_log)
 
-            with redirect_stdout(ansible_log):
-                _ds.init_info(realm_name, host_name, domain_name, dm_password,
-                              subject_base, ca_subject, 1101, 1100, None,
-                              setup_pkinit=not no_pkinit)
+logger = logging.getLogger("ipa-server-install")
 
-        return _ds
 
-    def ansible_module_get_parsed_ip_addresses(ansible_module,
-                                               param='ip_addresses'):
-        ip_addrs = []
-        for _ip in ansible_module.params.get(param):
-            try:
-                ip_parsed = ipautil.CheckedIPAddress(_ip)
-            except Exception as err:
-                ansible_module.fail_json(
-                    msg="Invalid IP Address %s: %s" % (_ip, err))
-            ip_addrs.append(ip_parsed)
-        return ip_addrs
-
-    def encode_certificate(cert):
-        """
-        Encode a certificate using base64.
-
-        It also takes FreeIPA and Python versions into account.
-        """
-        if isinstance(cert, (str, bytes)):
-            encoded = base64.b64encode(cert)
-        else:
-            encoded = base64.b64encode(cert.public_bytes(Encoding.DER))
-        if not six.PY2:
-            encoded = encoded.decode('ascii')
-        return encoded
-
-    def decode_certificate(cert):
-        """
-        Decode a certificate using base64.
-
-        It also takes FreeIPA versions into account and returns a
-        IPACertificate for newer IPA versions.
-        """
-        if hasattr(x509, "IPACertificate"):
-            cert = cert.strip()
-            if not cert.startswith("-----BEGIN CERTIFICATE-----"):
-                cert = "-----BEGIN CERTIFICATE-----\n" + cert
-            if not cert.endswith("-----END CERTIFICATE-----"):
-                cert += "\n-----END CERTIFICATE-----"
-
-            cert = certificate_loader(cert.encode('utf-8'))
+def setup_logging():
+    # logger.setLevel(logging.DEBUG)
+    standard_logging_setup(
+        paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
+        filemode='a', console_format='%(message)s')
+
+
+@contextlib_contextmanager
+def redirect_stdout(stream):
+    sys.stdout = stream
+    try:
+        yield stream
+    finally:
+        sys.stdout = sys.__stdout__
+
+
+class AnsibleModuleLog():
+    def __init__(self, module):
+        self.module = module
+        _ansible_module_log = self
+
+        class AnsibleLoggingHandler(logging.Handler):
+            def emit(self, record):
+                _ansible_module_log.write(self.format(record))
+
+        self.logging_handler = AnsibleLoggingHandler()
+        logger.setLevel(logging.DEBUG)
+        logger.root.addHandler(self.logging_handler)
+
+    def close(self):
+        self.flush()
+
+    def flush(self):
+        pass
+
+    def log(self, msg):
+        # self.write(msg+"\n")
+        self.write(msg)
+
+    def debug(self, msg):
+        self.module.debug(msg)
+
+    def info(self, msg):
+        self.module.debug(msg)
+
+    @staticmethod
+    def isatty():
+        return False
+
+    def write(self, msg):
+        self.module.debug(msg)
+        # self.module.warn(msg)
+
+
+# pylint: disable=too-few-public-methods, useless-object-inheritance
+# pylint: disable=too-many-instance-attributes
+class options_obj(object):  # pylint: disable=invalid-name
+    def __init__(self):
+        self._replica_install = False
+        self.dnssec_master = False  # future unknown
+        self.disable_dnssec_master = False  # future unknown
+        self.domainlevel = MAX_DOMAIN_LEVEL  # deprecated
+        self.domain_level = self.domainlevel  # deprecated
+        self.interactive = False
+        self.unattended = not self.interactive
+
+    # def __getattribute__(self, attr):
+    #    logger.info(" <-- Accessing options.%s" % attr)
+    #    return super(options_obj, self).__getattribute__(attr)
+
+    # def __getattr__(self, attr):
+    #    logger.info(" --> Adding missing options.%s" % attr)
+    #    setattr(self, attr, None)
+    #    return getattr(self, attr)
+
+    def knobs(self):
+        for name in self.__dict__:
+            yield self, name
+
+
+# pylint: enable=too-few-public-methods, useless-object-inheritance
+
+
+# pylint: enable=too-many-instance-attributes
+options = options_obj()
+installer = options
+
+# pylint: disable=attribute-defined-outside-init
+
+# ServerMasterInstall
+options.add_sids = True
+options.add_agents = False
+
+# Installable
+options.uninstalling = False
+
+# ServerInstallInterface
+options.description = "Server"
+
+options.kinit_attempts = 1
+options.fixed_primary = True
+options.permit = False
+options.enable_dns_updates = False
+options.no_krb5_offline_passwords = False
+options.preserve_sssd = False
+options.no_sssd = False
+
+# ServerMasterInstall
+options.force_join = False
+options.servers = None
+options.no_wait_for_dns = True
+options.host_password = None
+options.keytab = None
+options.setup_ca = True
+# always run sidgen task and do not allow adding agents on first master
+options.add_sids = True
+options.add_agents = False
+
+# ADTrustInstallInterface
+# no_msdcs is deprecated
+options.no_msdcs = False
+
+# For pylint
+options.external_cert_files = None
+options.dirsrv_cert_files = None
+
+# Uninstall
+options.ignore_topology_disconnect = False
+options.ignore_last_of_role = False
+
+# pylint: enable=attribute-defined-outside-init
+
+
+# pylint: disable=invalid-name
+def api_Backend_ldap2(host_name, setup_ca, connect=False):
+    # we are sure we have the configuration file ready.
+    cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True,
+               host=host_name)
+    if setup_ca:
+        # we have an IPA-integrated CA
+        cfg['ca_host'] = host_name
+
+    api.bootstrap(**cfg)
+    api.finalize()
+    if connect:
+        api.Backend.ldap2.connect()
+
+
+# pylint: enable=invalid-name
+
+
+def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
+                 realm_name, host_name, domain_name, dm_password,
+                 idstart, idmax, subject_base, ca_subject,
+                 _no_hbac_allow, dirsrv_pkcs12_info, no_pkinit):
+
+    if not options.external_cert_files:
+        _ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel,
+                                    config_ldif=dirsrv_config_file)
+        _ds.set_output(ansible_log)
+
+        if options.dirsrv_cert_files:
+            _dirsrv_pkcs12_info = dirsrv_pkcs12_info
         else:
-            cert = base64.b64decode(cert)
-        return cert
+            _dirsrv_pkcs12_info = None
+
+        with redirect_stdout(ansible_log):
+            _ds.init_info(realm_name, host_name, domain_name, dm_password,
+                          subject_base, ca_subject, idstart, idmax,
+                          # hbac_allow=not no_hbac_allow,
+                          _dirsrv_pkcs12_info, setup_pkinit=not no_pkinit)
+    else:
+        _ds = dsinstance.DsInstance(fstore=fstore, domainlevel=domainlevel)
+        _ds.set_output(ansible_log)
+
+        with redirect_stdout(ansible_log):
+            _ds.init_info(realm_name, host_name, domain_name, dm_password,
+                          subject_base, ca_subject, 1101, 1100, None,
+                          setup_pkinit=not no_pkinit)
+
+    return _ds
+
+
+def ansible_module_get_parsed_ip_addresses(ansible_module,
+                                           param='ip_addresses'):
+    ip_addrs = []
+    for _ip in ansible_module.params.get(param):
+        try:
+            ip_parsed = ipautil.CheckedIPAddress(_ip)
+        except Exception as err:
+            ansible_module.fail_json(
+                msg="Invalid IP Address %s: %s" % (_ip, err))
+        ip_addrs.append(ip_parsed)
+    return ip_addrs
+
+
+def encode_certificate(cert):
+    """
+    Encode a certificate using base64.
+
+    It also takes FreeIPA and Python versions into account.
+    """
+    if isinstance(cert, (str, bytes)):
+        encoded = base64.b64encode(cert)
+    else:
+        encoded = base64.b64encode(cert.public_bytes(Encoding.DER))
+    if not six.PY2:
+        encoded = encoded.decode('ascii')
+    return encoded
+
+
+def decode_certificate(cert):
+    """
+    Decode a certificate using base64.
+
+    It also takes FreeIPA versions into account and returns a
+    IPACertificate for newer IPA versions.
+    """
+    if hasattr(x509, "IPACertificate"):
+        cert = cert.strip()
+        if not cert.startswith("-----BEGIN CERTIFICATE-----"):
+            cert = "-----BEGIN CERTIFICATE-----\n" + cert
+        if not cert.endswith("-----END CERTIFICATE-----"):
+            cert += "\n-----END CERTIFICATE-----"
+
+        cert = certificate_loader(cert.encode('utf-8'))
+    else:
+        cert = base64.b64decode(cert)
+    return cert
+
+
+def check_imports(module):
+    if ANSIBLE_IPA_SERVER_MODULE_IMPORT_ERROR is not None:
+        module.fail_json(msg=ANSIBLE_IPA_SERVER_MODULE_IMPORT_ERROR)