86baa9
From ae9ab0545ff06b60df4b66c0ebccb7baa79b8898 Mon Sep 17 00:00:00 2001
86baa9
From: Christian Heimes <cheimes@redhat.com>
86baa9
Date: Mon, 25 Mar 2019 15:59:51 +0100
86baa9
Subject: [PATCH] Improve config-show to show hidden servers
86baa9
86baa9
config-show only used to show enabled servers. Now also show hidden
86baa9
servers on separate lines. Additionally include information about
86baa9
KRA and DNS servers.
86baa9
86baa9
The augmented config-show output makes it easier to diagnose a cluster
86baa9
and simplifies sanity checks.
86baa9
86baa9
Fixes: https://pagure.io/freeipa/issue/7892
86baa9
Signed-off-by: Christian Heimes <cheimes@redhat.com>
86baa9
Reviewed-By: Thomas Woerner <twoerner@redhat.com>
86baa9
Reviewed-By: Francois Cami <fcami@redhat.com>
86baa9
---
86baa9
 ipaserver/plugins/config.py                   | 56 +++++++++++++++++--
86baa9
 ipaserver/plugins/serverroles.py              | 25 ++++++---
86baa9
 ipaserver/servroles.py                        |  6 ++
86baa9
 .../test_replica_promotion.py                 | 23 ++++++++
86baa9
 4 files changed, 97 insertions(+), 13 deletions(-)
86baa9
86baa9
diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py
86baa9
index fff58ac656f4fad3491dfa9f95c22b7d54a6da56..58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503 100644
86baa9
--- a/ipaserver/plugins/config.py
86baa9
+++ b/ipaserver/plugins/config.py
86baa9
@@ -249,6 +249,18 @@ class config(LDAPObject):
86baa9
             doc=_('List of all IPA masters'),
86baa9
             flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
         ),
86baa9
+        Str(
86baa9
+            'ipa_master_hidden_server*',
86baa9
+            label=_('Hidden IPA masters'),
86baa9
+            doc=_('List of all hidden IPA masters'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
+        Str(
86baa9
+            'pkinit_server_server*',
86baa9
+            label=_('IPA master capable of PKINIT'),
86baa9
+            doc=_('IPA master which can process PKINIT requests'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
         Str(
86baa9
             'ca_server_server*',
86baa9
             label=_('IPA CA servers'),
86baa9
@@ -261,6 +273,12 @@ class config(LDAPObject):
86baa9
             doc=_('IPA servers with enabled NTP'),
86baa9
             flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
         ),
86baa9
+        Str(
86baa9
+            'ca_server_hidden_server*',
86baa9
+            label=_('Hidden IPA CA servers'),
86baa9
+            doc=_('Hidden IPA servers configured as certificate authority'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
         Str(
86baa9
             'ca_renewal_master_server?',
86baa9
             label=_('IPA CA renewal master'),
86baa9
@@ -268,9 +286,15 @@ class config(LDAPObject):
86baa9
             flags={'virtual_attribute', 'no_create'}
86baa9
         ),
86baa9
         Str(
86baa9
-            'pkinit_server_server*',
86baa9
-            label=_('IPA master capable of PKINIT'),
86baa9
-            doc=_('IPA master which can process PKINIT requests'),
86baa9
+            'kra_server_server*',
86baa9
+            label=_('IPA KRA servers'),
86baa9
+            doc=_('IPA servers configured as key recovery agent'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
+        Str(
86baa9
+            'kra_server_hidden_server*',
86baa9
+            label=_('Hidden IPA KRA servers'),
86baa9
+            doc=_('Hidden IPA servers configured as key recovery agent'),
86baa9
             flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
         ),
86baa9
         Str(
86baa9
@@ -279,7 +303,25 @@ class config(LDAPObject):
86baa9
             label=_('Domain resolution order'),
86baa9
             doc=_('colon-separated list of domains used for short name'
86baa9
                   ' qualification')
86baa9
-        )
86baa9
+        ),
86baa9
+        Str(
86baa9
+            'dns_server_server*',
86baa9
+            label=_('IPA DNS servers'),
86baa9
+            doc=_('IPA servers configured as domain name server'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
+        Str(
86baa9
+            'dns_server_hidden_server*',
86baa9
+            label=_('Hidden IPA DNS servers'),
86baa9
+            doc=_('Hidden IPA servers configured as domain name server'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
+        Str(
86baa9
+            'dnssec_key_master_server?',
86baa9
+            label=_('IPA DNSSec key master'),
86baa9
+            doc=_('DNSec key master'),
86baa9
+            flags={'virtual_attribute', 'no_create', 'no_update'}
86baa9
+        ),
86baa9
     )
86baa9
 
86baa9
     def get_dn(self, *keys, **kwargs):
86baa9
@@ -560,7 +602,8 @@ class config_mod(LDAPUpdate):
86baa9
 
86baa9
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
86baa9
         self.obj.show_servroles_attributes(
86baa9
-            entry_attrs, "CA server", "IPA master", "NTP server", **options)
86baa9
+            entry_attrs, "CA server", "KRA server", "IPA master",
86baa9
+            "NTP server", "DNS server", **options)
86baa9
         return dn
86baa9
 
86baa9
 
86baa9
@@ -570,5 +613,6 @@ class config_show(LDAPRetrieve):
86baa9
 
86baa9
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
86baa9
         self.obj.show_servroles_attributes(
86baa9
-            entry_attrs, "CA server", "IPA master", "NTP server", **options)
86baa9
+            entry_attrs, "CA server", "KRA server", "IPA master",
86baa9
+            "NTP server", "DNS server", **options)
86baa9
         return dn
86baa9
diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py
86baa9
index 0abf48ae5295be5f622bf8c90d32e7adff5e6cf7..5bba84972a5828b6c7230d0d0d858e6683e5986b 100644
86baa9
--- a/ipaserver/plugins/serverroles.py
86baa9
+++ b/ipaserver/plugins/serverroles.py
86baa9
@@ -45,7 +45,9 @@ import six
86baa9
 from ipalib import errors, _
86baa9
 from ipalib.backend import Backend
86baa9
 from ipalib.plugable import Registry
86baa9
-from ipaserver.servroles import (attribute_instances, ENABLED, role_instances)
86baa9
+from ipaserver.servroles import (
86baa9
+    attribute_instances, ENABLED, HIDDEN, role_instances
86baa9
+)
86baa9
 from ipaserver.servroles import SingleValuedServerAttribute
86baa9
 
86baa9
 
86baa9
@@ -81,17 +83,26 @@ class serverroles(Backend):
86baa9
             raise errors.NotFound(
86baa9
                 reason=_("{role}: role not found".format(role=role_name)))
86baa9
 
86baa9
-    def _get_enabled_masters(self, role_name):
86baa9
+    def _get_masters(self, role_name, include_hidden):
86baa9
         result = {}
86baa9
         role = self._get_role(role_name)
86baa9
+        role_states = role.status(self.api, server=None)
86baa9
 
86baa9
         enabled_masters = [
86baa9
-            r[u'server_server'] for r in role.status(self.api, server=None) if
86baa9
-            r[u'status'] == ENABLED]
86baa9
-
86baa9
+            r[u'server_server'] for r in role_states if
86baa9
+            r[u'status'] == ENABLED
86baa9
+        ]
86baa9
         if enabled_masters:
86baa9
             result.update({role.attr_name: enabled_masters})
86baa9
 
86baa9
+        if include_hidden and role.attr_name_hidden is not None:
86baa9
+            hidden_masters = [
86baa9
+                r[u'server_server'] for r in role_states if
86baa9
+                r[u'status'] == HIDDEN
86baa9
+            ]
86baa9
+            if hidden_masters:
86baa9
+                result.update({role.attr_name_hidden: hidden_masters})
86baa9
+
86baa9
         return result
86baa9
 
86baa9
     def _get_assoc_attributes(self, role_name):
86baa9
@@ -131,8 +142,8 @@ class serverroles(Backend):
86baa9
         return self._get_role(role_servrole).status(
86baa9
             self.api, server=server_server)
86baa9
 
86baa9
-    def config_retrieve(self, servrole):
86baa9
-        result = self._get_enabled_masters(servrole)
86baa9
+    def config_retrieve(self, servrole, include_hidden=True):
86baa9
+        result = self._get_masters(servrole, include_hidden=include_hidden)
86baa9
 
86baa9
         try:
86baa9
             assoc_attributes = self._get_assoc_attributes(servrole)
86baa9
diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
86baa9
index 9c963be53527bb955ebf2b8cec7960f0d90717a4..0988cbdd7eac599ef26c89a015523b2d92e9502f 100644
86baa9
--- a/ipaserver/servroles.py
86baa9
+++ b/ipaserver/servroles.py
86baa9
@@ -104,6 +104,12 @@ class LDAPBasedProperty(object):
86baa9
     def __init__(self, attr_name, name):
86baa9
         self.attr_name = attr_name
86baa9
         self.name = name
86baa9
+        # for hidden services, insert hidden before '_server' suffix
86baa9
+        if attr_name.endswith(u'_server'):
86baa9
+            parts = attr_name.rsplit(u'_', 1)
86baa9
+            self.attr_name_hidden = u'{}_hidden_server'.format(parts[0])
86baa9
+        else:
86baa9
+            self.attr_name_hidden = None
86baa9
 
86baa9
 
86baa9
 @six.add_metaclass(abc.ABCMeta)
86baa9
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
86baa9
index a4f3e402ce5d6f74af4bd6fed9376f0f039f297a..3be2ea95fa2325edfc74cbb902ce0a5966aa82d7 100644
86baa9
--- a/ipatests/test_integration/test_replica_promotion.py
86baa9
+++ b/ipatests/test_integration/test_replica_promotion.py
86baa9
@@ -851,11 +851,32 @@ class TestHiddenReplicaPromotion(IntegrationTest):
86baa9
             expected = 'Role status: {}'.format(status)
86baa9
             assert expected in result.stdout_text
86baa9
 
86baa9
+    def _check_config(self, enabled=(), hidden=()):
86baa9
+        enabled = {host.hostname for host in enabled}
86baa9
+        hidden = {host.hostname for host in hidden}
86baa9
+        services = [
86baa9
+            'IPA masters', 'IPA CA servers', 'IPA KRA servers',
86baa9
+            'IPA DNS servers'
86baa9
+        ]
86baa9
+
86baa9
+        result = self.master.run_command(['ipa', 'config-show'])
86baa9
+        values = {}
86baa9
+        for line in result.stdout_text.split('\n'):
86baa9
+            if ':' not in line:
86baa9
+                continue
86baa9
+            k, v = line.split(':', 1)
86baa9
+            values[k.strip()] = {item.strip() for item in v.split(',')}
86baa9
+
86baa9
+        for service in services:
86baa9
+            assert values[service] == enabled
86baa9
+            assert values['Hidden {}'.format(service)] == hidden
86baa9
+
86baa9
     def test_hidden_replica_install(self):
86baa9
         # TODO: check that all services are running on hidden replica
86baa9
         self._check_server_role(self.master, 'enabled')
86baa9
         self._check_server_role(self.replicas[0], 'hidden')
86baa9
         self._check_dnsrecords([self.master], [self.replicas[0]])
86baa9
+        self._check_config([self.master], [self.replicas[0]])
86baa9
 
86baa9
     def test_hidden_replica_promote(self):
86baa9
         self.replicas[0].run_command([
86baa9
@@ -864,6 +885,8 @@ class TestHiddenReplicaPromotion(IntegrationTest):
86baa9
         ])
86baa9
         self._check_server_role(self.replicas[0], 'enabled')
86baa9
         self._check_dnsrecords([self.master, self.replicas[0]])
86baa9
+        self._check_config([self.master, self.replicas[0]])
86baa9
+
86baa9
         result = self.replicas[0].run_command([
86baa9
             'ipa', 'server-state',
86baa9
             self.replicas[0].hostname, '--state=enabled'
86baa9
-- 
86baa9
2.20.1
86baa9