mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
Verify replication topology for a suffix
Checks done: 1. check if the topology is not disconnected. In other words if there are replication paths between all servers. 2. check if servers don't have more than a recommended number of replication agreements(4) https://fedorahosted.org/freeipa/ticket/4302 Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
parent
659b88b820
commit
5397150979
5
API.txt
5
API.txt
@ -4911,6 +4911,11 @@ option: Str('version?', exclude='webui')
|
|||||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||||
output: PrimaryKey('value', None, None)
|
output: PrimaryKey('value', None, None)
|
||||||
|
command: topologysuffix_verify
|
||||||
|
args: 1,1,1
|
||||||
|
arg: Str('cn', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True)
|
||||||
|
option: Str('version?', exclude='webui')
|
||||||
|
output: Output('result', None, None)
|
||||||
command: trust_add
|
command: trust_add
|
||||||
args: 1,13,3
|
args: 1,13,3
|
||||||
arg: Str('cn', attribute=True, cli_name='realm', multivalue=False, primary_key=True, required=True)
|
arg: Str('cn', attribute=True, cli_name='realm', multivalue=False, primary_key=True, required=True)
|
||||||
|
4
VERSION
4
VERSION
@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
|
|||||||
# #
|
# #
|
||||||
########################################################
|
########################################################
|
||||||
IPA_API_VERSION_MAJOR=2
|
IPA_API_VERSION_MAJOR=2
|
||||||
IPA_API_VERSION_MINOR=135
|
IPA_API_VERSION_MINOR=136
|
||||||
# Last change: jcholast - User life cycle: Make user-del flags CLI-specific
|
# Last change: pvoborni: add topologysuffix-verify command
|
||||||
|
@ -170,6 +170,10 @@ DEFAULT_CONFIG = (
|
|||||||
# KRA plugin
|
# KRA plugin
|
||||||
('kra_host', FQDN), # Set in Env._finalize_core()
|
('kra_host', FQDN), # Set in Env._finalize_core()
|
||||||
|
|
||||||
|
# Topology plugin
|
||||||
|
('recommended_max_agmts', 4), # Recommended maximum number of replication
|
||||||
|
# agreements
|
||||||
|
|
||||||
# Special CLI:
|
# Special CLI:
|
||||||
('prompt_all', False),
|
('prompt_all', False),
|
||||||
('interactive', True),
|
('interactive', True),
|
||||||
|
@ -10,6 +10,7 @@ from ipalib.plugins.baseldap import (
|
|||||||
LDAPRetrieve)
|
LDAPRetrieve)
|
||||||
from ipalib import _, ngettext
|
from ipalib import _, ngettext
|
||||||
from ipalib import output
|
from ipalib import output
|
||||||
|
from ipalib.util import create_topology_graph, get_topology_connection_errors
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
|
|
||||||
|
|
||||||
@ -401,3 +402,85 @@ class topologysuffix_mod(LDAPUpdate):
|
|||||||
@register()
|
@register()
|
||||||
class topologysuffix_show(LDAPRetrieve):
|
class topologysuffix_show(LDAPRetrieve):
|
||||||
__doc__ = _('Show managed suffix.')
|
__doc__ = _('Show managed suffix.')
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
class topologysuffix_verify(LDAPQuery):
|
||||||
|
__doc__ = _('''
|
||||||
|
Verify replication topology for suffix.
|
||||||
|
|
||||||
|
Checks done:
|
||||||
|
1. check if a topology is not disconnected. In other words if there are
|
||||||
|
replication paths between all servers.
|
||||||
|
2. check if servers don't have more than the recommended number of
|
||||||
|
replication agreements
|
||||||
|
''')
|
||||||
|
|
||||||
|
def execute(self, *keys, **options):
|
||||||
|
|
||||||
|
validate_domain_level(self.api)
|
||||||
|
|
||||||
|
masters = self.api.Command.server_find('', sizelimit=0)['result']
|
||||||
|
segments = self.api.Command.topologysegment_find(
|
||||||
|
keys[0], sizelimit=0)['result']
|
||||||
|
graph = create_topology_graph(masters, segments)
|
||||||
|
master_cns = [m['cn'][0] for m in masters]
|
||||||
|
master_cns.sort()
|
||||||
|
|
||||||
|
# check if each master can contact others
|
||||||
|
connect_errors = get_topology_connection_errors(graph)
|
||||||
|
|
||||||
|
# check if suggested maximum number of agreements per replica
|
||||||
|
max_agmts_errors = []
|
||||||
|
for m in master_cns:
|
||||||
|
# chosen direction doesn't matter much given that 'both' is the
|
||||||
|
# only allowed direction
|
||||||
|
suppliers = graph.get_tails(m)
|
||||||
|
if len(suppliers) > self.api.env.recommended_max_agmts:
|
||||||
|
max_agmts_errors.append((m, suppliers))
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
result={
|
||||||
|
'in_order': not connect_errors and not max_agmts_errors,
|
||||||
|
'connect_errors': connect_errors,
|
||||||
|
'max_agmts_errors': max_agmts_errors,
|
||||||
|
'max_agmts': self.api.env.recommended_max_agmts
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def output_for_cli(self, textui, output, *args, **options):
|
||||||
|
|
||||||
|
in_order = output['result']['in_order']
|
||||||
|
connect_errors = output['result']['connect_errors']
|
||||||
|
max_agmts_errors = output['result']['max_agmts_errors']
|
||||||
|
|
||||||
|
if in_order:
|
||||||
|
header = _('Replication topology of suffix "%(suffix)s" '
|
||||||
|
'is in order.')
|
||||||
|
else:
|
||||||
|
header = _('Replication topology of suffix "%(suffix)s" contains '
|
||||||
|
'errors.')
|
||||||
|
textui.print_h1(header % {'suffix': args[0]})
|
||||||
|
|
||||||
|
if connect_errors:
|
||||||
|
textui.print_dashed(unicode(_('Topology is disconnected')))
|
||||||
|
for err in connect_errors:
|
||||||
|
msg = _("Server %(srv)s can't contact servers: %(replicas)s")
|
||||||
|
msg = msg % {'srv': err[0], 'replicas': ', '.join(err[2])}
|
||||||
|
textui.print_indented(msg)
|
||||||
|
|
||||||
|
if max_agmts_errors:
|
||||||
|
textui.print_dashed(unicode(_('Recommended maximum number of '
|
||||||
|
'agreements per replica exceeded')))
|
||||||
|
textui.print_attribute(
|
||||||
|
unicode(_("Maximum number of agreements per replica")),
|
||||||
|
[output['result']['max_agmts']]
|
||||||
|
)
|
||||||
|
for err in max_agmts_errors:
|
||||||
|
msg = _('Server "%(srv)s" has %(n)d agreements with servers:')
|
||||||
|
msg = msg % {'srv': err[0], 'n': len(err[1])}
|
||||||
|
textui.print_indented(msg)
|
||||||
|
for replica in err[1]:
|
||||||
|
textui.print_indented(replica, 2)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
Loading…
Reference in New Issue
Block a user