Blame SOURCES/0010-Issue-4449-dsconf-replication-monitor-fails-to-retri.patch

3280a9
From 2a2773d4bf8553ba64b396d567fe05506b22c94c Mon Sep 17 00:00:00 2001
3280a9
From: progier389 <72748589+progier389@users.noreply.github.com>
3280a9
Date: Tue, 24 Nov 2020 19:22:49 +0100
3280a9
Subject: [PATCH] Issue 4449 - dsconf replication monitor fails to retrieve
3280a9
 database RUV - consumer (Unavailable) (#4451)
3280a9
3280a9
Bug Description:
3280a9
3280a9
"dsconf replication monitor" fails to retrieve database RUV entry from consumer and this
3280a9
appears into the Cockpit web UI too.
3280a9
The problem is that the bind credentials are not rightly propagated when trying to get
3280a9
the consumers agreement status.  Then supplier credntials are used instead  and RUV
3280a9
is searched anonymously because there is no bind dn in ldapi case.
3280a9
3280a9
Fix Description:
3280a9
3280a9
- Propagates the bind credentials when computing agreement status
3280a9
- Add a credential cache because now a replica password could get asked several times:
3280a9
    when discovering the topology and
3280a9
    when getting the agreement maxcsn
3280a9
- No testcase in 1.4.3 branch as the file modfied in master does not exists
3280a9
3280a9
- Add a comment about nonlocal keyword
3280a9
3280a9
Relates: #4449
3280a9
3280a9
Reviewers:
3280a9
  firstyear
3280a9
  droideck
3280a9
  mreynolds
3280a9
3280a9
Issue 4449: Add a comment about nonlocal keyword
3280a9
3280a9
(cherry picked from commit 73ee04fa12cd1de3a5e47c109e79e31c1aaaa2ab)
3280a9
---
3280a9
 src/lib389/lib389/cli_conf/replication.py | 13 +++++++++++--
3280a9
 src/lib389/lib389/replica.py              | 16 ++++++++++++----
3280a9
 2 files changed, 23 insertions(+), 6 deletions(-)
3280a9
3280a9
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
3280a9
index 9dbaa320a..248972cba 100644
3280a9
--- a/src/lib389/lib389/cli_conf/replication.py
3280a9
+++ b/src/lib389/lib389/cli_conf/replication.py
3280a9
@@ -369,9 +369,16 @@ def set_repl_config(inst, basedn, log, args):
3280a9
 
3280a9
 def get_repl_monitor_info(inst, basedn, log, args):
3280a9
     connection_data = dsrc_to_repl_monitor(DSRC_HOME, log)
3280a9
+    credentials_cache = {}
3280a9
 
3280a9
     # Additional details for the connections to the topology
3280a9
     def get_credentials(host, port):
3280a9
+        # credentials_cache is nonlocal to refer to the instance
3280a9
+        # from enclosing function (get_repl_monitor_info)`
3280a9
+        nonlocal credentials_cache
3280a9
+        key = f'{host}:{port}'
3280a9
+        if key in credentials_cache:
3280a9
+            return credentials_cache[key]
3280a9
         found = False
3280a9
         if args.connections:
3280a9
             connections = args.connections
3280a9
@@ -406,8 +413,10 @@ def get_repl_monitor_info(inst, basedn, log, args):
3280a9
             binddn = input(f'\nEnter a bind DN for {host}:{port}: ').rstrip()
3280a9
             bindpw = getpass(f"Enter a password for {binddn} on {host}:{port}: ").rstrip()
3280a9
 
3280a9
-        return {"binddn": binddn,
3280a9
-                "bindpw": bindpw}
3280a9
+        credentials = {"binddn": binddn,
3280a9
+                       "bindpw": bindpw}
3280a9
+        credentials_cache[key] = credentials
3280a9
+        return credentials
3280a9
 
3280a9
     repl_monitor = ReplicationMonitor(inst)
3280a9
     report_dict = repl_monitor.generate_report(get_credentials, args.json)
3280a9
diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py
3280a9
index c2ad2104d..3d89e61fb 100644
3280a9
--- a/src/lib389/lib389/replica.py
3280a9
+++ b/src/lib389/lib389/replica.py
3280a9
@@ -2487,9 +2487,10 @@ class ReplicationMonitor(object):
3280a9
         else:
3280a9
             self._log = logging.getLogger(__name__)
3280a9
 
3280a9
-    def _get_replica_status(self, instance, report_data, use_json):
3280a9
+    def _get_replica_status(self, instance, report_data, use_json, get_credentials=None):
3280a9
         """Load all of the status data to report
3280a9
         and add new hostname:port pairs for future processing
3280a9
+        :type get_credentials: function
3280a9
         """
3280a9
 
3280a9
         replicas_status = []
3280a9
@@ -2503,6 +2504,13 @@ class ReplicationMonitor(object):
3280a9
             for agmt in agmts.list():
3280a9
                 host = agmt.get_attr_val_utf8_l("nsds5replicahost")
3280a9
                 port = agmt.get_attr_val_utf8_l("nsds5replicaport")
3280a9
+                if get_credentials is not None:
3280a9
+                    credentials = get_credentials(host, port)
3280a9
+                    binddn = credentials["binddn"]
3280a9
+                    bindpw = credentials["bindpw"]
3280a9
+                else:
3280a9
+                    binddn = instance.binddn
3280a9
+                    bindpw = instance.bindpw
3280a9
                 protocol = agmt.get_attr_val_utf8_l('nsds5replicatransportinfo')
3280a9
                 # Supply protocol here because we need it only for connection
3280a9
                 # and agreement status is already preformatted for the user output
3280a9
@@ -2510,9 +2518,9 @@ class ReplicationMonitor(object):
3280a9
                 if consumer not in report_data:
3280a9
                     report_data[f"{consumer}:{protocol}"] = None
3280a9
                 if use_json:
3280a9
-                    agmts_status.append(json.loads(agmt.status(use_json=True)))
3280a9
+                    agmts_status.append(json.loads(agmt.status(use_json=True, binddn=binddn, bindpw=bindpw)))
3280a9
                 else:
3280a9
-                    agmts_status.append(agmt.status())
3280a9
+                    agmts_status.append(agmt.status(binddn=binddn, bindpw=bindpw))
3280a9
             replicas_status.append({"replica_id": replica_id,
3280a9
                                     "replica_root": replica_root,
3280a9
                                     "replica_status": "Available",
3280a9
@@ -2535,7 +2543,7 @@ class ReplicationMonitor(object):
3280a9
         initial_inst_key = f"{self._instance.config.get_attr_val_utf8_l('nsslapd-localhost')}:{self._instance.config.get_attr_val_utf8_l('nsslapd-port')}"
3280a9
         # Do this on an initial instance to get the agreements to other instances
3280a9
         try:
3280a9
-            report_data[initial_inst_key] = self._get_replica_status(self._instance, report_data, use_json)
3280a9
+            report_data[initial_inst_key] = self._get_replica_status(self._instance, report_data, use_json, get_credentials)
3280a9
         except ldap.LDAPError as e:
3280a9
             self._log.debug(f"Connection to consumer ({supplier_hostname}:{supplier_port}) failed, error: {e}")
3280a9
             report_data[initial_inst_key] = [{"replica_status": f"Unavailable - {e.args[0]['desc']}"}]
3280a9
-- 
3280a9
2.26.2
3280a9