Blob Blame History Raw
From ae9ab0545ff06b60df4b66c0ebccb7baa79b8898 Mon Sep 17 00:00:00 2001
From: Christian Heimes <cheimes@redhat.com>
Date: Mon, 25 Mar 2019 15:59:51 +0100
Subject: [PATCH] Improve config-show to show hidden servers

config-show only used to show enabled servers. Now also show hidden
servers on separate lines. Additionally include information about
KRA and DNS servers.

The augmented config-show output makes it easier to diagnose a cluster
and simplifies sanity checks.

Fixes: https://pagure.io/freeipa/issue/7892
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Thomas Woerner <twoerner@redhat.com>
Reviewed-By: Francois Cami <fcami@redhat.com>
---
 ipaserver/plugins/config.py                   | 56 +++++++++++++++++--
 ipaserver/plugins/serverroles.py              | 25 ++++++---
 ipaserver/servroles.py                        |  6 ++
 .../test_replica_promotion.py                 | 23 ++++++++
 4 files changed, 97 insertions(+), 13 deletions(-)

diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py
index fff58ac656f4fad3491dfa9f95c22b7d54a6da56..58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503 100644
--- a/ipaserver/plugins/config.py
+++ b/ipaserver/plugins/config.py
@@ -249,6 +249,18 @@ class config(LDAPObject):
             doc=_('List of all IPA masters'),
             flags={'virtual_attribute', 'no_create', 'no_update'}
         ),
+        Str(
+            'ipa_master_hidden_server*',
+            label=_('Hidden IPA masters'),
+            doc=_('List of all hidden IPA masters'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
+        Str(
+            'pkinit_server_server*',
+            label=_('IPA master capable of PKINIT'),
+            doc=_('IPA master which can process PKINIT requests'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
         Str(
             'ca_server_server*',
             label=_('IPA CA servers'),
@@ -261,6 +273,12 @@ class config(LDAPObject):
             doc=_('IPA servers with enabled NTP'),
             flags={'virtual_attribute', 'no_create', 'no_update'}
         ),
+        Str(
+            'ca_server_hidden_server*',
+            label=_('Hidden IPA CA servers'),
+            doc=_('Hidden IPA servers configured as certificate authority'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
         Str(
             'ca_renewal_master_server?',
             label=_('IPA CA renewal master'),
@@ -268,9 +286,15 @@ class config(LDAPObject):
             flags={'virtual_attribute', 'no_create'}
         ),
         Str(
-            'pkinit_server_server*',
-            label=_('IPA master capable of PKINIT'),
-            doc=_('IPA master which can process PKINIT requests'),
+            'kra_server_server*',
+            label=_('IPA KRA servers'),
+            doc=_('IPA servers configured as key recovery agent'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
+        Str(
+            'kra_server_hidden_server*',
+            label=_('Hidden IPA KRA servers'),
+            doc=_('Hidden IPA servers configured as key recovery agent'),
             flags={'virtual_attribute', 'no_create', 'no_update'}
         ),
         Str(
@@ -279,7 +303,25 @@ class config(LDAPObject):
             label=_('Domain resolution order'),
             doc=_('colon-separated list of domains used for short name'
                   ' qualification')
-        )
+        ),
+        Str(
+            'dns_server_server*',
+            label=_('IPA DNS servers'),
+            doc=_('IPA servers configured as domain name server'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
+        Str(
+            'dns_server_hidden_server*',
+            label=_('Hidden IPA DNS servers'),
+            doc=_('Hidden IPA servers configured as domain name server'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
+        Str(
+            'dnssec_key_master_server?',
+            label=_('IPA DNSSec key master'),
+            doc=_('DNSec key master'),
+            flags={'virtual_attribute', 'no_create', 'no_update'}
+        ),
     )
 
     def get_dn(self, *keys, **kwargs):
@@ -560,7 +602,8 @@ class config_mod(LDAPUpdate):
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         self.obj.show_servroles_attributes(
-            entry_attrs, "CA server", "IPA master", "NTP server", **options)
+            entry_attrs, "CA server", "KRA server", "IPA master",
+            "NTP server", "DNS server", **options)
         return dn
 
 
@@ -570,5 +613,6 @@ class config_show(LDAPRetrieve):
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
         self.obj.show_servroles_attributes(
-            entry_attrs, "CA server", "IPA master", "NTP server", **options)
+            entry_attrs, "CA server", "KRA server", "IPA master",
+            "NTP server", "DNS server", **options)
         return dn
diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py
index 0abf48ae5295be5f622bf8c90d32e7adff5e6cf7..5bba84972a5828b6c7230d0d0d858e6683e5986b 100644
--- a/ipaserver/plugins/serverroles.py
+++ b/ipaserver/plugins/serverroles.py
@@ -45,7 +45,9 @@ import six
 from ipalib import errors, _
 from ipalib.backend import Backend
 from ipalib.plugable import Registry
-from ipaserver.servroles import (attribute_instances, ENABLED, role_instances)
+from ipaserver.servroles import (
+    attribute_instances, ENABLED, HIDDEN, role_instances
+)
 from ipaserver.servroles import SingleValuedServerAttribute
 
 
@@ -81,17 +83,26 @@ class serverroles(Backend):
             raise errors.NotFound(
                 reason=_("{role}: role not found".format(role=role_name)))
 
-    def _get_enabled_masters(self, role_name):
+    def _get_masters(self, role_name, include_hidden):
         result = {}
         role = self._get_role(role_name)
+        role_states = role.status(self.api, server=None)
 
         enabled_masters = [
-            r[u'server_server'] for r in role.status(self.api, server=None) if
-            r[u'status'] == ENABLED]
-
+            r[u'server_server'] for r in role_states if
+            r[u'status'] == ENABLED
+        ]
         if enabled_masters:
             result.update({role.attr_name: enabled_masters})
 
+        if include_hidden and role.attr_name_hidden is not None:
+            hidden_masters = [
+                r[u'server_server'] for r in role_states if
+                r[u'status'] == HIDDEN
+            ]
+            if hidden_masters:
+                result.update({role.attr_name_hidden: hidden_masters})
+
         return result
 
     def _get_assoc_attributes(self, role_name):
@@ -131,8 +142,8 @@ class serverroles(Backend):
         return self._get_role(role_servrole).status(
             self.api, server=server_server)
 
-    def config_retrieve(self, servrole):
-        result = self._get_enabled_masters(servrole)
+    def config_retrieve(self, servrole, include_hidden=True):
+        result = self._get_masters(servrole, include_hidden=include_hidden)
 
         try:
             assoc_attributes = self._get_assoc_attributes(servrole)
diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
index 9c963be53527bb955ebf2b8cec7960f0d90717a4..0988cbdd7eac599ef26c89a015523b2d92e9502f 100644
--- a/ipaserver/servroles.py
+++ b/ipaserver/servroles.py
@@ -104,6 +104,12 @@ class LDAPBasedProperty(object):
     def __init__(self, attr_name, name):
         self.attr_name = attr_name
         self.name = name
+        # for hidden services, insert hidden before '_server' suffix
+        if attr_name.endswith(u'_server'):
+            parts = attr_name.rsplit(u'_', 1)
+            self.attr_name_hidden = u'{}_hidden_server'.format(parts[0])
+        else:
+            self.attr_name_hidden = None
 
 
 @six.add_metaclass(abc.ABCMeta)
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
index a4f3e402ce5d6f74af4bd6fed9376f0f039f297a..3be2ea95fa2325edfc74cbb902ce0a5966aa82d7 100644
--- a/ipatests/test_integration/test_replica_promotion.py
+++ b/ipatests/test_integration/test_replica_promotion.py
@@ -851,11 +851,32 @@ class TestHiddenReplicaPromotion(IntegrationTest):
             expected = 'Role status: {}'.format(status)
             assert expected in result.stdout_text
 
+    def _check_config(self, enabled=(), hidden=()):
+        enabled = {host.hostname for host in enabled}
+        hidden = {host.hostname for host in hidden}
+        services = [
+            'IPA masters', 'IPA CA servers', 'IPA KRA servers',
+            'IPA DNS servers'
+        ]
+
+        result = self.master.run_command(['ipa', 'config-show'])
+        values = {}
+        for line in result.stdout_text.split('\n'):
+            if ':' not in line:
+                continue
+            k, v = line.split(':', 1)
+            values[k.strip()] = {item.strip() for item in v.split(',')}
+
+        for service in services:
+            assert values[service] == enabled
+            assert values['Hidden {}'.format(service)] == hidden
+
     def test_hidden_replica_install(self):
         # TODO: check that all services are running on hidden replica
         self._check_server_role(self.master, 'enabled')
         self._check_server_role(self.replicas[0], 'hidden')
         self._check_dnsrecords([self.master], [self.replicas[0]])
+        self._check_config([self.master], [self.replicas[0]])
 
     def test_hidden_replica_promote(self):
         self.replicas[0].run_command([
@@ -864,6 +885,8 @@ class TestHiddenReplicaPromotion(IntegrationTest):
         ])
         self._check_server_role(self.replicas[0], 'enabled')
         self._check_dnsrecords([self.master, self.replicas[0]])
+        self._check_config([self.master, self.replicas[0]])
+
         result = self.replicas[0].run_command([
             'ipa', 'server-state',
             self.replicas[0].hostname, '--state=enabled'
-- 
2.20.1