From 5acab7b3dcda8aa3c8ea55e4eb5ca419f7d6ec4b Mon Sep 17 00:00:00 2001
From: Thomas Woerner <twoerner@redhat.com>
Date: Wed, 25 Nov 2020 11:01:07 +0100
Subject: [PATCH] ipa[server,replica]: Support memory check from command line
 installers

The common_check function in the replica installer code has been changed
for the new memory checker code. With this the server and replica command
line installers got the option --skip-mem-check.

The server and replica role now also support the memory cheker and there
are new variables for server and replica:

    ipaserver_mem_check - for ipaserver
    ipareplica_mem_check - for ipaserver

These bool values default to yes and can be turned off in the inventory
or playbook if needed.

Related to freeipa PR https://pagure.io/freeipa/issue/8404 (Detect and
fail if not enough memory is available for installation)

Fixes: #450 (IPA Replica Installation Fails)
---
 roles/ipareplica/README.md                      |  1 +
 roles/ipareplica/defaults/main.yml              |  1 +
 roles/ipareplica/library/ipareplica_test.py     | 17 ++++++++++++++++-
 roles/ipareplica/tasks/install.yml              |  2 ++
 roles/ipaserver/README.md                       |  1 +
 roles/ipaserver/defaults/main.yml               |  1 +
 roles/ipaserver/library/ipaserver_test.py       | 13 +++++++++++--
 .../module_utils/ansible_ipa_server.py          |  7 ++++++-
 roles/ipaserver/tasks/install.yml               |  1 +
 9 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/roles/ipareplica/README.md b/roles/ipareplica/README.md
index d50d33d4..18ed1cc4 100644
--- a/roles/ipareplica/README.md
+++ b/roles/ipareplica/README.md
@@ -153,6 +153,7 @@ Variable | Description | Required
 `ipareplica_no_host_dns` | Do not use DNS for hostname lookup during installation. (bool, default: false) | no
 `ipareplica_skip_conncheck` | Skip connection check to remote master. (bool, default: false) | no
 `ipareplica_pki_config_override` | Path to ini file with config overrides. This is only usable with recent FreeIPA versions. (string) | no
+`ipareplica_mem_check` | Checking for minimum required memory for the deployment.  This is only usable with recent FreeIPA versions (4.8.10+) else ignored. (bool, default: yes) | no
 
 Server Vaiables
 ---------------
diff --git a/roles/ipareplica/defaults/main.yml b/roles/ipareplica/defaults/main.yml
index 5eca5909..01afc442 100644
--- a/roles/ipareplica/defaults/main.yml
+++ b/roles/ipareplica/defaults/main.yml
@@ -5,6 +5,7 @@
 ipareplica_no_host_dns: no
 ipareplica_skip_conncheck: no
 ipareplica_hidden_replica: no
+ipareplica_mem_check: yes
 ### server ###
 ipareplica_setup_adtrust: no
 ipareplica_setup_ca: no
diff --git a/roles/ipareplica/library/ipareplica_test.py b/roles/ipareplica/library/ipareplica_test.py
index ebb1163f..217e29c8 100644
--- a/roles/ipareplica/library/ipareplica_test.py
+++ b/roles/ipareplica/library/ipareplica_test.py
@@ -57,9 +57,15 @@ options:
   hidden_replica:
     description: Install a hidden replica
     required: yes
+  skip_mem_check:
+    description: Skip checking for minimum required memory
+    required: yes
   setup_adtrust:
     description: Configure AD trust capability
     required: yes
+  setup_ca:
+    description: Configure a dogtag CA
+    required: yes
   setup_kra:
     description: Configure a dogtag KRA
     required: yes
@@ -152,8 +158,10 @@ def main():
             hostname=dict(required=False),
             ca_cert_files=dict(required=False, type='list', default=[]),
             hidden_replica=dict(required=False, type='bool', default=False),
+            skip_mem_check=dict(required=False, type='bool', default=False),
             # server
             setup_adtrust=dict(required=False, type='bool', default=False),
+            setup_ca=dict(required=False, type='bool'),
             setup_kra=dict(required=False, type='bool', default=False),
             setup_dns=dict(required=False, type='bool', default=False),
             no_pkinit=dict(required=False, type='bool', default=False),
@@ -196,8 +204,10 @@ def main():
     options.host_name = ansible_module.params.get('hostname')
     options.ca_cert_files = ansible_module.params.get('ca_cert_files')
     options.hidden_replica = ansible_module.params.get('hidden_replica')
+    options.skip_mem_check = ansible_module.params.get('skip_mem_check')
     # server
     options.setup_adtrust = ansible_module.params.get('setup_adtrust')
+    options.setup_ca = ansible_module.params.get('setup_ca')
     options.setup_kra = ansible_module.params.get('setup_kra')
     options.setup_dns = ansible_module.params.get('setup_dns')
     options.no_pkinit = ansible_module.params.get('no_pkinit')
@@ -404,7 +414,12 @@ def main():
     # check selinux status, http and DS ports, NTP conflicting services
     try:
         with redirect_stdout(ansible_log):
-            common_check(options.no_ntp)
+            argspec = inspect.getargspec(common_check)
+            if "skip_mem_check" in argspec.args:
+                common_check(options.no_ntp, options.skip_mem_check,
+                             options.setup_ca)
+            else:
+                common_check(options.no_ntp)
     except Exception as msg:  # ScriptError as msg:
         _msg = str(msg)
         if "server is already configured" in _msg:
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
index 45af06a9..bae12531 100644
--- a/roles/ipareplica/tasks/install.yml
+++ b/roles/ipareplica/tasks/install.yml
@@ -75,8 +75,10 @@
     hostname: "{{ ipareplica_hostname | default(ansible_fqdn) }}"
     ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}"
     hidden_replica: "{{ ipareplica_hidden_replica }}"
+    skip_mem_check: "{{ not ipareplica_mem_check }}"
     ### server ###
     setup_adtrust: "{{ ipareplica_setup_adtrust }}"
+    setup_ca: "{{ ipareplica_setup_ca }}"
     setup_kra: "{{ ipareplica_setup_kra }}"
     setup_dns: "{{ ipareplica_setup_dns }}"
     no_pkinit: "{{ ipareplica_no_pkinit }}"
diff --git a/roles/ipaserver/README.md b/roles/ipaserver/README.md
index 8c1177c9..828f5562 100644
--- a/roles/ipaserver/README.md
+++ b/roles/ipaserver/README.md
@@ -205,6 +205,7 @@ Variable | Description | Required
 `ipaserver_realm` | The Kerberos realm of an existing IPA deployment. (string) | no
 `ipaserver_hostname` | Fully qualified name of the server. (string) | no
 `ipaserver_no_host_dns` | Do not use DNS for hostname lookup during installation. (bool, default: false) | no
+`ipaserver_mem_check` | Checking for minimum required memory for the deployment. This is only usable with recent FreeIPA versions (4.8.10+) else ignored. (bool, default: yes) | no
 
 Server Variables
 ----------------
diff --git a/roles/ipaserver/defaults/main.yml b/roles/ipaserver/defaults/main.yml
index ed1364b7..6abcb796 100644
--- a/roles/ipaserver/defaults/main.yml
+++ b/roles/ipaserver/defaults/main.yml
@@ -10,6 +10,7 @@ ipaserver_setup_dns: no
 ipaserver_no_hbac_allow: no
 ipaserver_no_pkinit: no
 ipaserver_no_ui_redirect: no
+ipaserver_mem_check: yes
 ### ssl certificate ###
 ### client ###
 ipaclient_mkhomedir: no
diff --git a/roles/ipaserver/library/ipaserver_test.py b/roles/ipaserver/library/ipaserver_test.py
index 4ac100c9..175a1e03 100644
--- a/roles/ipaserver/library/ipaserver_test.py
+++ b/roles/ipaserver/library/ipaserver_test.py
@@ -66,6 +66,9 @@ options:
   pki_config_override:
     description: Path to ini file with config overrides
     required: yes
+  skip_mem_check:
+    description: Skip checking for minimum required memory
+    required: yes
   setup_adtrust:
     description: Configure AD trust capability
     required: yes
@@ -221,7 +224,7 @@ from ansible.module_utils.ansible_ipa_server import (
     read_cache, ca, tasks, check_ldap_conf, timeconf, httpinstance,
     check_dirsrv, ScriptError, get_fqdn, verify_fqdn, BadHostError,
     validate_domain_name, load_pkcs12, IPA_PYTHON_VERSION,
-    encode_certificate
+    encode_certificate, check_available_memory
 )
 
 if six.PY3:
@@ -242,6 +245,7 @@ def main():
             ca_cert_files=dict(required=False, type='list', default=[]),
             no_host_dns=dict(required=False, type='bool', default=False),
             pki_config_override=dict(required=False),
+            skip_mem_check=dict(required=False, type='bool', default=False),
             # server
             setup_adtrust=dict(required=False, type='bool', default=False),
             setup_kra=dict(required=False, type='bool', default=False),
@@ -322,6 +326,7 @@ def main():
     options.no_host_dns = ansible_module.params.get('no_host_dns')
     options.pki_config_override = ansible_module.params.get(
         'pki_config_override')
+    options.skip_mem_check = ansible_module.params.get('skip_mem_check')
     # server
     options.setup_adtrust = ansible_module.params.get('setup_adtrust')
     options.setup_dns = ansible_module.params.get('setup_dns')
@@ -855,8 +860,12 @@ def main():
     if options.ca_subject:
         ca.subject_validator(ca.VALID_SUBJECT_ATTRS, options.ca_subject)
 
-    # IPv6 and SELinux check
+    # Memory check
+    if not options.skip_mem_check and check_available_memory is not None:
+        check_available_memory(ca=options.dirsrv_cert_files and
+                               len(options.dirsrv_cert_files) > 0)
 
+    # IPv6 and SELinux check
     tasks.check_ipv6_stack_enabled()
     tasks.check_selinux_status()
     if check_ldap_conf is not None:
diff --git a/roles/ipaserver/module_utils/ansible_ipa_server.py b/roles/ipaserver/module_utils/ansible_ipa_server.py
index 8447c048..fcecd0df 100644
--- a/roles/ipaserver/module_utils/ansible_ipa_server.py
+++ b/roles/ipaserver/module_utils/ansible_ipa_server.py
@@ -37,7 +37,8 @@ __all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
            "validate_dm_password", "read_cache", "write_cache",
            "adtrustinstance", "IPAAPI_USER", "sync_time", "PKIIniLoader",
            "default_subject_base", "default_ca_subject_dn",
-           "check_ldap_conf", "encode_certificate", "decode_certificate"]
+           "check_ldap_conf", "encode_certificate", "decode_certificate",
+           "check_available_memory"]
 
 import sys
 import logging
@@ -139,6 +140,10 @@ if NUM_VERSION >= 40500:
     except ImportError:
         def default_ca_subject_dn(subject_base):
             return DN(('CN', 'Certificate Authority'), subject_base)
+    try:
+        from ipaserver.install.installutils import check_available_memory
+    except ImportError:
+        check_available_memory = None
 
     try:
         from ipaserver.install import adtrustinstance
diff --git a/roles/ipaserver/tasks/install.yml b/roles/ipaserver/tasks/install.yml
index c1e3a95a..d34bc125 100644
--- a/roles/ipaserver/tasks/install.yml
+++ b/roles/ipaserver/tasks/install.yml
@@ -69,6 +69,7 @@
     ca_cert_files: "{{ ipaserver_ca_cert_files | default(omit) }}"
     no_host_dns: "{{ ipaserver_no_host_dns }}"
     pki_config_override: "{{ ipaserver_pki_config_override | default(omit) }}"
+    skip_mem_check: "{{ not ipaserver_mem_check }}"
     ### server ###
     setup_adtrust: "{{ ipaserver_setup_adtrust }}"
     setup_kra: "{{ ipaserver_setup_kra }}"
-- 
GitLab