From 5057b3cfe0d3a79562afaac1486505eefb83cb7f Mon Sep 17 00:00:00 2001
From: Thomas Woerner <twoerner@redhat.com>
Date: Fri, 31 May 2019 18:05:02 +0200
Subject: [PATCH] ipareplica: Add support for hidden replica

The hidden replica support introduced some incompatible changes to replica
deployment. The methods find_providing_server and find_providing_serves
have been moved from ipaserver.install.service to ipaserver.masters.
Additionally the host_name argument for find_providing_server is a list
now. This breaks existing ipareplica Ansible modules ipareplica_prepare
and ipareplica_enable_ipa.
---
 roles/ipareplica/defaults/main.yml            |  1 +
 .../library/ipareplica_enable_ipa.py          | 16 ++++++---
 .../ipareplica/library/ipareplica_prepare.py  | 34 +++++++++++++++----
 roles/ipareplica/library/ipareplica_test.py   |  6 ++++
 .../module_utils/ansible_ipa_replica.py       |  9 +++++
 roles/ipareplica/tasks/install.yml            |  3 ++
 6 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/roles/ipareplica/defaults/main.yml b/roles/ipareplica/defaults/main.yml
index 5fe168fa..5eca5909 100644
--- a/roles/ipareplica/defaults/main.yml
+++ b/roles/ipareplica/defaults/main.yml
@@ -4,6 +4,7 @@
 ### basic ###
 ipareplica_no_host_dns: no
 ipareplica_skip_conncheck: no
+ipareplica_hidden_replica: no
 ### server ###
 ipareplica_setup_adtrust: no
 ipareplica_setup_ca: no
diff --git a/roles/ipareplica/library/ipareplica_enable_ipa.py b/roles/ipareplica/library/ipareplica_enable_ipa.py
index 20893176..35b288f2 100644
--- a/roles/ipareplica/library/ipareplica_enable_ipa.py
+++ b/roles/ipareplica/library/ipareplica_enable_ipa.py
@@ -69,6 +69,7 @@ def main():
     ansible_module = AnsibleModule(
         argument_spec = dict(
             hostname=dict(required=False),
+            hidden_replica=dict(required=False, type='bool', default=False),
             ### server ###
             ### certificate system ###
             subject_base=dict(required=True),
@@ -88,6 +89,7 @@ def main():
 
     options = installer
     options.host_name = ansible_module.params.get('hostname')
+    options.hidden_replica = ansible_module.params.get('hidden_replica')
     ### server ###
     ### certificate system ###
     options.subject_base = ansible_module.params.get('subject_base')
@@ -112,6 +114,7 @@ def main():
     env = gen_env_boostrap_finalize_core(paths.ETC_IPA,
                                          constants.DEFAULT_CONFIG)
     api_bootstrap_finalize(env)
+    config = gen_ReplicaConfig()
 
     remote_api = gen_remote_api(config_master_host_name, paths.ETC_IPA)
     installer._remote_api = remote_api
@@ -122,11 +125,16 @@ def main():
     api.Backend.ldap2.connect()
 
     with redirect_stdout(ansible_log):
-        # Enable configured services and update DNS SRV records
-        service.enable_services(options.host_name)
+        if options.hidden_replica:
+            # Set services to hidden
+            service.hide_services(config.host_name)
+        else:
+            # Enable configured services
+            service.enable_services(config.host_name)
+        # update DNS SRV records. Although it's only really necessary in
+        # enabled-service case, also perform update in hidden replica case.
         api.Command.dns_update_system_records()
-        ca_servers = service.find_providing_servers('CA', api.Backend.ldap2,
-                                                    api)
+        ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api)
         api.Backend.ldap2.disconnect()
 
         # Everything installed properly, activate ipa service.
diff --git a/roles/ipareplica/library/ipareplica_prepare.py b/roles/ipareplica/library/ipareplica_prepare.py
index 9c417269..55994d2b 100644
--- a/roles/ipareplica/library/ipareplica_prepare.py
+++ b/roles/ipareplica/library/ipareplica_prepare.py
@@ -293,10 +293,14 @@ def main():
 
     # pylint: disable=no-member
     xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host))
+    if hasattr(ipaldap, "realm_to_ldapi_uri"):
+        realm_to_ldapi_uri = ipaldap.realm_to_ldapi_uri
+    else:
+        realm_to_ldapi_uri = installutils.realm_to_ldapi_uri
     api.bootstrap(in_server=True,
                   context='installer',
                   confdir=paths.ETC_IPA,
-                  ldap_uri=installutils.realm_to_ldapi_uri(env.realm),
+                  ldap_uri=realm_to_ldapi_uri(env.realm),
                   xmlrpc_uri=xmlrpc_uri)
     # pylint: enable=no-member
     api.finalize()
@@ -308,13 +312,19 @@ def main():
     config.host_name = api.env.host
     config.domain_name = api.env.domain
     config.master_host_name = api.env.server
-    config.ca_host_name = api.env.ca_host
+    if not api.env.ca_host or api.env.ca_host == api.env.host:
+        # ca_host has not been configured explicitly, prefer source master
+        config.ca_host_name = api.env.server
+    else:
+        # default to ca_host from IPA config
+        config.ca_host_name = api.env.ca_host
     config.kra_host_name = config.ca_host_name
     config.ca_ds_port = 389
     config.setup_ca = options.setup_ca
     config.setup_kra = options.setup_kra
     config.dir = installer._top_dir
     config.basedn = api.env.basedn
+    #config.hidden_replica = options.hidden_replica
 
     # load and check certificates #
 
@@ -550,8 +560,11 @@ def main():
         ansible_log.debug("-- SEARCH FOR CA --")
 
         # Find if any server has a CA
-        ca_host = service.find_providing_server(
-                'CA', conn, config.ca_host_name)
+        if not hasattr(service, "find_providing_server"):
+            _host = [config.ca_host_name]
+        else:
+            _host = config.ca_host_name
+        ca_host = find_providing_server('CA', conn, _host)
         if ca_host is not None:
             config.ca_host_name = ca_host
             ca_enabled = True
@@ -574,14 +587,17 @@ def main():
 
         ansible_log.debug("-- SEARCH FOR KRA --")
 
-        kra_host = service.find_providing_server(
-                'KRA', conn, config.kra_host_name)
+        if not hasattr(service, "find_providing_server"):
+            _host = [config.kra_host_name]
+        else:
+            _host = config.kra_host_name
+        kra_host = find_providing_server('KRA', conn, _host)
         if kra_host is not None:
             config.kra_host_name = kra_host
             kra_enabled = True
         else:
             if options.setup_kra:
-                logger.error("There is no KRA server in the domain, "
+                logger.error("There is no active KRA server in the domain, "
                              "can't setup a KRA clone")
                 raise ScriptError(rval=3)
             kra_enabled = False
@@ -673,6 +689,10 @@ def main():
             if add_to_ipaservers:
                 os.environ['KRB5CCNAME'] = ccache
 
+    if hasattr(tasks, "configure_pkcs11_modules"):
+        if tasks.configure_pkcs11_modules(fstore):
+            ansible_log.info("Disabled p11-kit-proxy")
+
     installer._ca_enabled = ca_enabled
     installer._kra_enabled = kra_enabled
     installer._ca_file = cafile
diff --git a/roles/ipareplica/library/ipareplica_test.py b/roles/ipareplica/library/ipareplica_test.py
index 7687e59a..41975c05 100644
--- a/roles/ipareplica/library/ipareplica_test.py
+++ b/roles/ipareplica/library/ipareplica_test.py
@@ -64,6 +64,7 @@ def main():
             realm=dict(required=False),
             hostname=dict(required=False),
             ca_cert_files=dict(required=False, type='list', default=[]),
+            hidden_replica=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),
@@ -106,6 +107,7 @@ def main():
     options.realm_name = ansible_module.params.get('realm')
     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')
     ### server ###
     options.setup_adtrust = ansible_module.params.get('setup_adtrust')
     options.setup_kra = ansible_module.params.get('setup_kra')
@@ -173,6 +175,10 @@ def main():
     #    #  options.setup_kra = False
     #    #  ansible_module.warn(msg="kra is not supported, disabling")
 
+    if options.hidden_replica and not hasattr(service, "hide_services"):
+        ansible_module.fail_json(
+            msg="Hidden replica is not supported in this version.")
+
     # From ipa installer classes
 
     # pkinit is not supported on DL0, don't allow related options
diff --git a/roles/ipareplica/module_utils/ansible_ipa_replica.py b/roles/ipareplica/module_utils/ansible_ipa_replica.py
index 92bf1cda..fb14da1f 100644
--- a/roles/ipareplica/module_utils/ansible_ipa_replica.py
+++ b/roles/ipareplica/module_utils/ansible_ipa_replica.py
@@ -79,6 +79,12 @@ if NUM_VERSION >= 40600:
         adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance,
         installutils, kra, krbinstance,
         otpdinstance, custodiainstance, service, upgradeinstance)
+    try:
+        from ipaserver.masters import (
+            find_providing_servers, find_providing_server)
+    except ImportError:
+        from ipaserver.install.service import (
+            find_providing_servers, find_providing_server)
     from ipaserver.install.installutils import (
         ReplicaConfig, load_pkcs12, is_ipa_configured)
     from ipaserver.install.replication import (
@@ -162,6 +168,9 @@ class AnsibleModuleLog():
     def debug(self, msg):
         self.module.debug(msg)
 
+    def info(self, msg):
+        self.module.debug(msg)
+
     def write(self, msg):
         self.module.debug(msg)
         #self.module.warn(msg)
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
index 72f45223..a2a0621a 100644
--- a/roles/ipareplica/tasks/install.yml
+++ b/roles/ipareplica/tasks/install.yml
@@ -46,6 +46,7 @@
     realm: "{{ ipareplica_realm | default(omit) }}"
     hostname: "{{ ipareplica_hostname | default(ansible_fqdn) }}"
     ca_cert_files: "{{ ipareplica_ca_cert_files | default([]) }}"
+    hidden_replica: "{{ ipareplica_hidden_replica }}"
     ### server ###
     setup_adtrust: "{{ ipareplica_setup_adtrust }}"
     setup_kra: "{{ ipareplica_setup_kra }}"
@@ -637,6 +638,8 @@
   - name: Install - Enable IPA
     ipareplica_enable_ipa:
       hostname: "{{ result_ipareplica_test.hostname }}"
+      hidden_replica: "{{ ipareplica_hidden_replica }}"
+      ### server ###
       ### certificate system ###
       subject_base: "{{ result_ipareplica_prepare.subject_base }}"
       ### additional ###
-- 
GitLab