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

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