From 691715b516289994a7218818fa5551eea7936a98 Mon Sep 17 00:00:00 2001
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Date: Tue, 5 Nov 2019 15:38:02 +0300
Subject: [PATCH] replication: show errno in replication info

Box.info.replication shows applier/relay's latest error message.
But it didn't include errno description for system errors, even
though it was included in the logs. Now box.info shows the errno
description as well, when possible.

Closes #4402

Conflicts:
	test/replication/suite.cfg
---
 src/box/lua/info.c                           | 29 +++++----
 test/replication/gh-4402-info-errno.result   | 63 ++++++++++++++++++++
 test/replication/gh-4402-info-errno.test.lua | 25 ++++++++
 test/replication/suite.cfg                   |  1 +
 4 files changed, 108 insertions(+), 10 deletions(-)
 create mode 100644 test/replication/gh-4402-info-errno.result
 create mode 100644 test/replication/gh-4402-info-errno.test.lua

diff --git a/src/box/lua/info.c b/src/box/lua/info.c
index 55382fd774..e029e0e174 100644
--- a/src/box/lua/info.c
+++ b/src/box/lua/info.c
@@ -50,6 +50,7 @@
 #include "box/box.h"
 #include "lua/utils.h"
 #include "fiber.h"
+#include "tt_static.h"
 
 static void
 lbox_pushvclock(struct lua_State *L, const struct vclock *vclock)
@@ -65,6 +66,20 @@ lbox_pushvclock(struct lua_State *L, const struct vclock *vclock)
 	luaL_setmaphint(L, -1); /* compact flow */
 }
 
+static inline void
+lbox_push_replication_error_message(struct lua_State *L, struct error *e,
+				    int idx)
+{
+	lua_pushstring(L, "message");
+	lua_pushstring(L, e->errmsg);
+	lua_settable(L, idx - 2);
+	if (e->saved_errno == 0)
+		return;
+	lua_pushstring(L, "system_message");
+	lua_pushstring(L, strerror(e->saved_errno));
+	lua_settable(L, idx - 2);
+}
+
 static void
 lbox_pushapplier(lua_State *L, struct applier *applier)
 {
@@ -103,11 +118,8 @@ lbox_pushapplier(lua_State *L, struct applier *applier)
 		lua_settable(L, -3);
 
 		struct error *e = diag_last_error(&applier->reader->diag);
-		if (e != NULL) {
-			lua_pushstring(L, "message");
-			lua_pushstring(L, e->errmsg);
-			lua_settable(L, -3);
-		}
+		if (e != NULL)
+			lbox_push_replication_error_message(L, e, -1);
 	}
 }
 
@@ -135,11 +147,8 @@ lbox_pushrelay(lua_State *L, struct relay *relay)
 		lua_settable(L, -3);
 
 		struct error *e = diag_last_error(relay_get_diag(relay));
-		if (e != NULL) {
-			lua_pushstring(L, "message");
-			lua_pushstring(L, e->errmsg);
-			lua_settable(L, -3);
-		}
+		if (e != NULL)
+			lbox_push_replication_error_message(L, e, -1);
 		break;
 	}
 	default: unreachable();
diff --git a/test/replication/gh-4402-info-errno.result b/test/replication/gh-4402-info-errno.result
new file mode 100644
index 0000000000..661eea38bf
--- /dev/null
+++ b/test/replication/gh-4402-info-errno.result
@@ -0,0 +1,63 @@
+-- test-run result file version 2
+test_run = require('test_run').new()
+ | ---
+ | ...
+
+--
+-- gh-4402: replication info table should contain not only
+-- Tarantool's error, but also a system error (errno's message)
+-- when possible.
+--
+
+box.schema.user.grant('guest', 'replication')
+ | ---
+ | ...
+
+test_run:cmd('create server replica with rpl_master=default, script="replication/replica.lua"')
+ | ---
+ | - true
+ | ...
+test_run:cmd('start server replica')
+ | ---
+ | - true
+ | ...
+i = box.info
+ | ---
+ | ...
+replica_id = i.id % 2 + 1
+ | ---
+ | ...
+d = i.replication[replica_id].downstream
+ | ---
+ | ...
+d ~= nil and d.status == 'follow' or i
+ | ---
+ | - true
+ | ...
+
+test_run:cmd('stop server replica')
+ | ---
+ | - true
+ | ...
+test_run:cmd("cleanup server replica")
+ | ---
+ | - true
+ | ...
+test_run:cmd("delete server replica")
+ | ---
+ | - true
+ | ...
+i = box.info
+ | ---
+ | ...
+d = i.replication[replica_id].downstream
+ | ---
+ | ...
+d ~= nil and d.system_message ~= nil and d.message ~= nil or i
+ | ---
+ | - true
+ | ...
+
+box.schema.user.revoke('guest', 'replication')
+ | ---
+ | ...
diff --git a/test/replication/gh-4402-info-errno.test.lua b/test/replication/gh-4402-info-errno.test.lua
new file mode 100644
index 0000000000..1b2d9d8148
--- /dev/null
+++ b/test/replication/gh-4402-info-errno.test.lua
@@ -0,0 +1,25 @@
+test_run = require('test_run').new()
+
+--
+-- gh-4402: replication info table should contain not only
+-- Tarantool's error, but also a system error (errno's message)
+-- when possible.
+--
+
+box.schema.user.grant('guest', 'replication')
+
+test_run:cmd('create server replica with rpl_master=default, script="replication/replica.lua"')
+test_run:cmd('start server replica')
+i = box.info
+replica_id = i.id % 2 + 1
+d = i.replication[replica_id].downstream
+d ~= nil and d.status == 'follow' or i
+
+test_run:cmd('stop server replica')
+test_run:cmd("cleanup server replica")
+test_run:cmd("delete server replica")
+i = box.info
+d = i.replication[replica_id].downstream
+d ~= nil and d.system_message ~= nil and d.message ~= nil or i
+
+box.schema.user.revoke('guest', 'replication')
diff --git a/test/replication/suite.cfg b/test/replication/suite.cfg
index 13b9131cc8..0848eecd61 100644
--- a/test/replication/suite.cfg
+++ b/test/replication/suite.cfg
@@ -11,6 +11,7 @@
     "on_schema_init.test.lua": {},
     "long_row_timeout.test.lua": {},
     "join_without_snap.test.lua": {},
+    "gh-4402-info-errno.test.lua": {},
     "gh-4606-admin-creds.test.lua": {},
     "*": {
         "memtx": {"engine": "memtx"},
-- 
GitLab