zrhoffman / rpms / 389-ds-base

Forked from rpms/389-ds-base 3 years ago
Clone

Blame SOURCES/0000-Issue-49602-Revise-replication-status-messages.patch

232633
From 45f4abd6befa50b129fc49b331b42c280f37199a Mon Sep 17 00:00:00 2001
232633
From: Mark Reynolds <mreynolds@redhat.com>
232633
Date: Thu, 13 Jun 2019 13:01:35 -0400
232633
Subject: [PATCH] Issue 49602 - Revise replication status messages
232633
232633
Bug Description: All agreement status messages start with "Error (##)" followed
232633
                 by a text string.  Even success states start with "Error", and
232633
                 this is confusing.
232633
232633
                 Added new attributes to display the status in a JSON format
232633
                 for easier parsing for applications:
232633
232633
                     replicaLastUpdateStatusJSON
232633
                     replicaLastInitStatusJSON
232633
232633
Design Doc:  https://www.port389.org/docs/389ds/design/repl-agmt-status-design.html
232633
232633
https://pagure.io/389-ds-base/issue/49602
232633
232633
Reviewed by: firstyear(Thanks!)
232633
---
232633
 .../suites/replication/single_master_test.py  | 19 +++--
232633
 ldap/schema/01core389.ldif                    |  2 +
232633
 ldap/servers/plugins/replication/repl5_agmt.c | 84 ++++++++++++++++---
232633
 .../plugins/replication/repl5_protocol_util.c | 13 +--
232633
 4 files changed, 96 insertions(+), 22 deletions(-)
232633
232633
diff --git a/dirsrvtests/tests/suites/replication/single_master_test.py b/dirsrvtests/tests/suites/replication/single_master_test.py
232633
index 5b73e23ae..78f849da7 100644
232633
--- a/dirsrvtests/tests/suites/replication/single_master_test.py
232633
+++ b/dirsrvtests/tests/suites/replication/single_master_test.py
232633
@@ -23,6 +23,7 @@ from lib389._constants import (ReplicaRole, DEFAULT_SUFFIX, REPLICAID_MASTER_1,
232633
                                 REPLICATION_BIND_METHOD, REPLICATION_TRANSPORT, DEFAULT_BACKUPDIR,
232633
                                 RA_NAME, RA_BINDDN, RA_BINDPW, RA_METHOD, RA_TRANSPORT_PROT,
232633
                                 defaultProperties)
232633
+import json
232633
 
232633
 pytestmark = pytest.mark.tier1
232633
 
232633
@@ -95,7 +96,7 @@ def test_mail_attr_repl(topo_r):
232633
     consumer.start()
232633
 
232633
     log.info("Make a search for mail attribute in attempt to crash server")
232633
-    consumer.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(mail=testuser@redhat.com)", ["mail"])
232633
+    c_user.get_attr_val("mail")
232633
 
232633
     log.info("Make sure that server hasn't crashed")
232633
     repl.test_replication(master, consumer)
232633
@@ -111,11 +112,13 @@ def test_lastupdate_attr_before_init(topo_nr):
232633
         1. Check nsds5replicaLastUpdateStart value
232633
         2. Check nsds5replicaLastUpdateEnd value
232633
         3. Check nsds5replicaLastUpdateStatus value
232633
+        4. Check nsds5replicaLastUpdateStatusJSON is parsable
232633
     :expectedresults:
232633
         1. nsds5replicaLastUpdateStart should be equal to 0
232633
         2. nsds5replicaLastUpdateEnd should be equal to 0
232633
         3. nsds5replicaLastUpdateStatus should not be equal
232633
-           to "0 Replica acquired successfully: Incremental update started"
232633
+           to "Replica acquired successfully: Incremental update started"
232633
+        4. Success
232633
     """
232633
 
232633
     master = topo_nr.ins["standalone1"]
232633
@@ -139,11 +142,15 @@ def test_lastupdate_attr_before_init(topo_nr):
232633
     with pytest.raises(Exception):
232633
         repl.wait_for_replication(master, consumer, timeout=5)
232633
 
232633
-    assert agmt.get_attr_val_bytes('nsds5replicaLastUpdateStart') == b"19700101000000Z"
232633
-    assert agmt.get_attr_val_bytes("nsds5replicaLastUpdateEnd") == b"19700101000000Z"
232633
-    assert b"Replica acquired successfully" not in agmt.get_attr_val_bytes("nsds5replicaLastUpdateStatus")
232633
-
232633
+    assert agmt.get_attr_val_utf8('nsds5replicaLastUpdateStart') == "19700101000000Z"
232633
+    assert agmt.get_attr_val_utf8("nsds5replicaLastUpdateEnd") == "19700101000000Z"
232633
+    assert "replica acquired successfully" not in agmt.get_attr_val_utf8_l("nsds5replicaLastUpdateStatus")
232633
 
232633
+    # make sure the JSON attribute is parsable
232633
+    json_status = agmt.get_attr_val_utf8("nsds5replicaLastUpdateStatusJSON")
232633
+    if json_status is not None:
232633
+        json_obj = json.loads(json_status)
232633
+        log.debug("JSON status message: {}".format(json_obj))
232633
 
232633
 if __name__ == '__main__':
232633
     # Run isolated
232633
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
232633
index 993fa4a6d..7bf4acc5b 100644
232633
--- a/ldap/schema/01core389.ldif
232633
+++ b/ldap/schema/01core389.ldif
232633
@@ -312,6 +312,8 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2341 NAME 'nsslapd-changelogmaxentries'
232633
 attributeTypes: ( 2.16.840.1.113730.3.1.2344 NAME 'nsslapd-tls-check-crl' DESC 'Check CRL when opening outbound TLS connections. Valid options are none, peer, all.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
232633
 attributeTypes: ( 2.16.840.1.113730.3.1.2353 NAME 'nsslapd-encryptionalgorithm' DESC 'The encryption algorithm used to encrypt the changelog' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
232633
 attributeTypes: ( 2.16.840.1.113730.3.1.2084 NAME 'nsSymmetricKey' DESC 'A symmetric key - currently used by attribute encryption' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'attribute encryption' )
232633
+attributeTypes: ( 2.16.840.1.113730.3.1.2364 NAME 'nsds5replicaLastInitStatusJSON' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
232633
+attributeTypes: ( 2.16.840.1.113730.3.1.2365 NAME 'nsds5replicaLastUpdateStatusJSON' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
232633
 #
232633
 # objectclasses
232633
 #
232633
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
232633
index 53e6708c8..8e4586d8b 100644
232633
--- a/ldap/servers/plugins/replication/repl5_agmt.c
232633
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
232633
@@ -60,7 +60,11 @@
232633
 #define DEFAULT_TIMEOUT 120             /* (seconds) default outbound LDAP connection */
232633
 #define DEFAULT_FLOWCONTROL_WINDOW 1000 /* #entries sent without acknowledgment */
232633
 #define DEFAULT_FLOWCONTROL_PAUSE 2000  /* msec of pause when #entries sent witout acknowledgment */
232633
-#define STATUS_LEN 1024
232633
+#define STATUS_LEN 2048
232633
+#define STATUS_GOOD "green"
232633
+#define STATUS_WARNING "amber"
232633
+#define STATUS_BAD "red"
232633
+
232633
 
232633
 struct changecounter
232633
 {
232633
@@ -93,11 +97,13 @@ typedef struct repl5agmt
232633
     time_t last_update_start_time;       /* Local start time of last update session */
232633
     time_t last_update_end_time;         /* Local end time of last update session */
232633
     char last_update_status[STATUS_LEN]; /* Status of last update. Format = numeric code <space> textual description */
232633
+    char last_update_status_json[STATUS_LEN];
232633
     PRBool update_in_progress;
232633
     PRBool is_enabled;
232633
     time_t last_init_start_time;       /* Local start time of last total init */
232633
     time_t last_init_end_time;         /* Local end time of last total init */
232633
     char last_init_status[STATUS_LEN]; /* Status of last total init. Format = numeric code <space> textual description */
232633
+    char last_init_status_json[STATUS_LEN];
232633
     PRLock *lock;
232633
     Object *consumerRUV;     /* last RUV received from the consumer - used for changelog purging */
232633
     CSN *consumerSchemaCSN;  /* last schema CSN received from the consumer */
232633
@@ -2443,6 +2449,21 @@ agmt_set_last_init_end(Repl_Agmt *ra, time_t end_time)
232633
     }
232633
 }
232633
 
232633
+static void
232633
+agmt_set_last_update_status_json(Repl_Agmt *ra, char *state, int ldaprc, int replrc)
232633
+{
232633
+    char ts[SLAPI_TIMESTAMP_BUFSIZE];
232633
+    time_t now;
232633
+
232633
+    time(&now;;
232633
+    strftime(ts, sizeof ts, "%FT%TZ", gmtime(&now));
232633
+    PR_snprintf(ra->last_update_status_json, STATUS_LEN,
232633
+            "{\"state\": \"%s\", \"ldap_rc\": \"%d\", \"ldap_rc_text\": \"%s\", "
232633
+            "\"repl_rc\": \"%d\", \"repl_rc_text\": \"%s\", \"date\": \"%s\", \"message\": \"%s\"}",
232633
+            state, ldaprc, ldap_err2string(ldaprc), replrc, protocol_response2string(replrc),
232633
+            ts, ra->last_update_status);
232633
+}
232633
+
232633
 void
232633
 agmt_set_last_update_status(Repl_Agmt *ra, int ldaprc, int replrc, const char *message)
232633
 {
232633
@@ -2463,19 +2484,29 @@ agmt_set_last_update_status(Repl_Agmt *ra, int ldaprc, int replrc, const char *m
232633
             PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (%d) %s%s - LDAP error: %s%s%s%s",
232633
                         ldaprc, message ? message : "", message ? "" : " - ",
232633
                         slapi_err2string(ldaprc), replmsg ? " (" : "", replmsg ? replmsg : "", replmsg ? ")" : "");
232633
+            agmt_set_last_update_status_json(ra, STATUS_BAD, ldaprc, replrc);
232633
         }
232633
         /* ldaprc == LDAP_SUCCESS */
232633
         else if (replrc != 0) {
232633
             if (replrc == NSDS50_REPL_REPLICA_BUSY) {
232633
                 PR_snprintf(ra->last_update_status, STATUS_LEN,
232633
-                            "Error (%d) Can't acquire busy replica", replrc);
232633
+                            "Error (%d) Can't acquire busy replica (%s)",
232633
+                            replrc, message ? message : "");
232633
+                agmt_set_last_update_status_json(ra, STATUS_WARNING, ldaprc, replrc);
232633
+            } else if (replrc == NSDS50_REPL_TRANSIENT_ERROR  || replrc == NSDS50_REPL_BACKOFF) {
232633
+                PR_snprintf(ra->last_update_status, STATUS_LEN,
232633
+                            "Error (%d) Can't acquire replica (%s)",
232633
+                            replrc, message ? message : "");
232633
+                agmt_set_last_update_status_json(ra, STATUS_WARNING, ldaprc, replrc);
232633
             } else if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED) {
232633
                 PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (0) Replication session successful");
232633
+                agmt_set_last_update_status_json(ra, STATUS_GOOD, ldaprc, replrc);
232633
             } else if (replrc == NSDS50_REPL_DISABLED) {
232633
                 PR_snprintf(ra->last_update_status, STATUS_LEN, "Error (%d) Incremental update aborted: "
232633
                                                                 "Replication agreement for %s\n can not be updated while the replica is disabled.\n"
232633
                                                                 "(If the suffix is disabled you must enable it then restart the server for replication to take place).",
232633
                             replrc, ra->long_name ? ra->long_name : "a replica");
232633
+                agmt_set_last_update_status_json(ra, STATUS_BAD, ldaprc, replrc);
232633
                 /* Log into the errors log, as "ra->long_name" is not accessible from the caller */
232633
                 slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
232633
                               "Incremental update aborted: Replication agreement for \"%s\" "
232633
@@ -2487,17 +2518,35 @@ agmt_set_last_update_status(Repl_Agmt *ra, int ldaprc, int replrc, const char *m
232633
                 PR_snprintf(ra->last_update_status, STATUS_LEN,
232633
                             "Error (%d) Replication error acquiring replica: %s%s(%s)",
232633
                             replrc, message ? message : "", message ? " " : "", protocol_response2string(replrc));
232633
+                agmt_set_last_update_status_json(ra, STATUS_BAD, ldaprc, replrc);
232633
             }
232633
         } else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
232633
         {
232633
             PR_snprintf(ra->last_update_status, STATUS_LEN,
232633
                         "Error (0) Replica acquired successfully: %s", message);
232633
+            agmt_set_last_update_status_json(ra, STATUS_GOOD, ldaprc, replrc);
232633
         } else { /* agmt_set_last_update_status(0,0,NULL) to reset agmt */
232633
             ra->last_update_status[0] = '\0';
232633
+            ra->last_update_status_json[0] = '\0';
232633
         }
232633
     }
232633
 }
232633
 
232633
+static void
232633
+agmt_set_last_init_status_json(Repl_Agmt *ra, char *state, int ldaprc, int replrc, int connrc)
232633
+{
232633
+    char ts[SLAPI_TIMESTAMP_BUFSIZE];
232633
+    time_t now;
232633
+
232633
+    time(&now;;
232633
+    strftime(ts, sizeof ts, "%FT%TZ", gmtime(&now));
232633
+    PR_snprintf(ra->last_init_status_json, STATUS_LEN,
232633
+            "{\"state\": \"%s\", \"ldap_rc\": \"%d\", \"ldap_rc_text\": \"%s\", \"repl_rc\": \"%d\", \"repl_rc_text\": \"%s\", "
232633
+            "\"conn_rc\": \"%d\", \"conn_rc_text\": \"%s\", \"date\": \"%s\", \"message\": \"%s\"}",
232633
+            state, ldaprc, ldap_err2string(ldaprc), replrc, protocol_response2string(replrc),
232633
+            connrc, conn_result2string(connrc), ts, ra->last_init_status);
232633
+}
232633
+
232633
 void
232633
 agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, const char *message)
232633
 {
232633
@@ -2523,16 +2572,16 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
232633
                     replmsg = NULL;
232633
                 }
232633
             }
232633
-            PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) %s%sLDAP error: %s%s%s%s%s",
232633
+            PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d)%s%sLDAP error: %s%s%s%s%s",
232633
                         ldaprc, message ? message : "", message ? "" : " - ",
232633
                         slapi_err2string(ldaprc), replmsg ? " - " : "", replmsg ? replmsg : "",
232633
                         connrc ? " - " : "", connrc ? connmsg : "");
232633
+            agmt_set_last_init_status_json(ra, STATUS_BAD, ldaprc, replrc, connrc);
232633
         }
232633
         /* ldaprc == LDAP_SUCCESS */
232633
         else if (replrc != 0) {
232633
             if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED) {
232633
-                PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) %s",
232633
-                            ldaprc, "Replication session successful");
232633
+                PR_snprintf(ra->last_init_status, STATUS_LEN, "Replication session successful");
232633
             } else if (replrc == NSDS50_REPL_DISABLED) {
232633
                 if (agmt_is_enabled(ra)) {
232633
                     slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Total update aborted: "
232633
@@ -2543,6 +2592,7 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
232633
                                                                   "Replication agreement for \"%s\" can not be updated while the suffix is disabled.\n"
232633
                                                                   "You must enable it then restart the server for replication to take place).",
232633
                                 replrc, ra->long_name ? ra->long_name : "a replica");
232633
+                    agmt_set_last_init_status_json(ra, STATUS_BAD, ldaprc, replrc, connrc);
232633
                 } else {
232633
                     /* You do not need to restart the server after enabling the agreement */
232633
                     slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Total update aborted: "
232633
@@ -2551,6 +2601,7 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
232633
                     PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d) Total update aborted: "
232633
                                                                   "Replication agreement for \"%s\" can not be updated while the agreement is disabled.",
232633
                                 replrc, ra->long_name ? ra->long_name : "a replica");
232633
+                    agmt_set_last_init_status_json(ra, STATUS_BAD, ldaprc, replrc, connrc);
232633
                 }
232633
             } else {
232633
                 PR_snprintf(ra->last_init_status, STATUS_LEN,
232633
@@ -2558,19 +2609,21 @@ agmt_set_last_init_status(Repl_Agmt *ra, int ldaprc, int replrc, int connrc, con
232633
                             replrc, protocol_response2string(replrc),
232633
                             message ? " - " : "", message ? message : "",
232633
                             connrc ? " - " : "", connrc ? connmsg : "");
232633
+                agmt_set_last_init_status_json(ra, STATUS_BAD, ldaprc, replrc, connrc);
232633
             }
232633
         } else if (connrc != CONN_OPERATION_SUCCESS) {
232633
             PR_snprintf(ra->last_init_status, STATUS_LEN,
232633
                         "Error (%d) connection error: %s%s%s",
232633
                         connrc, connmsg,
232633
                         message ? " - " : "", message ? message : "");
232633
-        } else if (message != NULL) /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
232633
-        {
232633
+            agmt_set_last_init_status_json(ra, STATUS_BAD, ldaprc, replrc, connrc);
232633
+        } else if (message != NULL) { /* replrc == NSDS50_REPL_REPLICA_READY == 0 */
232633
             PR_snprintf(ra->last_init_status, STATUS_LEN,
232633
-                        "Error (%d) %s",
232633
-                        ldaprc, message);
232633
+                        "Error (%d) %s", ldaprc, message);
232633
+            agmt_set_last_init_status_json(ra, STATUS_GOOD, ldaprc, replrc, connrc);
232633
         } else { /* agmt_set_last_init_status(0,0,NULL) to reset agmt */
232633
-            PR_snprintf(ra->last_init_status, STATUS_LEN, "Error (%d)", ldaprc);
232633
+            ra->last_init_status[0] = '\0';
232633
+            ra->last_init_status_json[0] = '\0';
232633
         }
232633
     }
232633
 }
232633
@@ -2705,10 +2758,20 @@ get_agmt_status(Slapi_PBlock *pb __attribute__((unused)),
232633
         agmt_get_changecount_string(ra, changecount_string, sizeof(changecount_string));
232633
         slapi_entry_add_string(e, "nsds5replicaChangesSentSinceStartup", changecount_string);
232633
         if (ra->last_update_status[0] == '\0') {
232633
+            char status_msg[STATUS_LEN];
232633
+            char ts[SLAPI_TIMESTAMP_BUFSIZE];
232633
+            time_t now;
232633
+            time(&now;;
232633
+            strftime(ts, sizeof ts, "%FT%TZ", gmtime(&now));
232633
             slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus",
232633
                                    "Error (0) No replication sessions started since server startup");
232633
+            PR_snprintf(status_msg, STATUS_LEN,
232633
+                    "{\"state\": \"green\", \"ldap_rc\": \"0\", \"ldap_rc_text\": \"success\", \"repl_rc\": \"0\", \"repl_rc_text\": \"replica acquired\", "
232633
+                    "\"date\": \"%s\", \"message\": \"Error (0) No replication sessions started since server startup\"}", ts);
232633
+            slapi_entry_add_string(e, "nsds5replicaLastUpdateStatusJSON", status_msg);
232633
         } else {
232633
             slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", ra->last_update_status);
232633
+            slapi_entry_add_string(e, "nsds5replicaLastUpdateStatusJSON", ra->last_update_status_json);
232633
         }
232633
         slapi_entry_add_string(e, "nsds5replicaUpdateInProgress", ra->update_in_progress ? "TRUE" : "FALSE");
232633
 
232633
@@ -2724,6 +2787,7 @@ get_agmt_status(Slapi_PBlock *pb __attribute__((unused)),
232633
 
232633
         if (ra->last_init_status[0] != '\0') {
232633
             slapi_entry_add_string(e, "nsds5replicaLastInitStatus", ra->last_init_status);
232633
+            slapi_entry_add_string(e, "nsds5replicaLastInitStatusJSON", ra->last_init_status_json);
232633
         }
232633
     }
232633
 bail:
232633
diff --git a/ldap/servers/plugins/replication/repl5_protocol_util.c b/ldap/servers/plugins/replication/repl5_protocol_util.c
232633
index a48d4d02a..bb9f9e7e1 100644
232633
--- a/ldap/servers/plugins/replication/repl5_protocol_util.c
232633
+++ b/ldap/servers/plugins/replication/repl5_protocol_util.c
232633
@@ -374,13 +374,13 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
232633
                                       "has the same Replica ID as this one. "
232633
                                       "Replication is aborting.\n",
232633
                                       agmt_get_long_name(prp->agmt));
232633
-                        agmt_set_last_update_status(prp->agmt, 0, 0,
232633
-                                                    "Unable to aquire replica: the replica has the same "
232633
+                        agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_REPLICAID_ERROR,
232633
+                                                    "Unable to acquire replica: the replica has the same "
232633
                                                     "Replica ID as this one. Replication is aborting.");
232633
                         return_value = ACQUIRE_FATAL_ERROR;
232633
                         break;
232633
                     case NSDS50_REPL_BACKOFF:
232633
-                        /* A replication sesssion hook on the replica
232633
+                        /* A replication session hook on the replica
232633
                          * wants us to go into backoff mode. */
232633
                         slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
232633
                                       "acquire_replica - "
232633
@@ -487,9 +487,8 @@ acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
232633
                           "%s: Unable to obtain current CSN. "
232633
                           "Replication is aborting.\n",
232633
                           agmt_get_long_name(prp->agmt));
232633
-            agmt_set_last_update_status(prp->agmt, 0, 0,
232633
-                                        "Unable to obtain current CSN. "
232633
-                                        "Replication is aborting.");
232633
+            agmt_set_last_update_status(prp->agmt, 0, NSDS50_REPL_INTERNAL_ERROR,
232633
+                                        "Unable to obtain current CSN. Replication is aborting.");
232633
             return_value = ACQUIRE_FATAL_ERROR;
232633
         }
232633
     }
232633
@@ -665,6 +664,8 @@ protocol_response2string(int response)
232633
         return "transient warning";
232633
     case NSDS50_REPL_RUV_ERROR:
232633
         return "RUV error";
232633
+    case NSDS50_REPL_REPLICA_NO_RESPONSE:
232633
+        return "no response received";
232633
     default:
232633
         return "unknown error";
232633
     }
232633
-- 
232633
2.21.0
232633