From 70addce9a1347e2fd14aebf5e7e326bc6c24f66c Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Mon, 28 Dec 2015 12:42:29 +0300
Subject: [PATCH] Fix #1230: Assertion on attempt to JOIN read-only master

A prerequisite for #1219 test case.
---
 src/box/box.cc                      |  9 ++++++++-
 test/replication-py/cluster.result  |  4 ++++
 test/replication-py/cluster.test.py | 17 +++++++++++++++++
 test/replication-py/failed.lua      |  9 +++++++++
 4 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 test/replication-py/failed.lua

diff --git a/src/box/box.cc b/src/box/box.cc
index c43982f5ef..67cf1d363b 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -649,6 +649,9 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple,
 static void
 box_on_cluster_join(const tt_uuid *server_uuid)
 {
+	if (is_ro)
+		tnt_raise(LoggedError, ER_READONLY);
+
 	/** Find the largest existing server id. */
 	struct space *space = space_cache_find(BOX_CLUSTER_ID);
 	class MemtxIndex *index = index_find_system(space, 0);
@@ -669,11 +672,15 @@ box_on_cluster_join(const tt_uuid *server_uuid)
 void
 box_process_join(int fd, struct xrow_header *header)
 {
+	assert(header->type == IPROTO_JOIN);
+
 	/* Check permissions */
 	access_check_universe(PRIV_R);
 	access_check_space(space_cache_find(BOX_CLUSTER_ID), PRIV_W);
 
-	assert(header->type == IPROTO_JOIN);
+	/* Check that we actually can register a new replica */
+	if (is_ro)
+		tnt_raise(LoggedError, ER_READONLY);
 
 	/* Process JOIN request via a replication relay */
 	relay_join(fd, header, recovery->server_id,
diff --git a/test/replication-py/cluster.result b/test/replication-py/cluster.result
index 8f0de85a59..c84116802a 100644
--- a/test/replication-py/cluster.result
+++ b/test/replication-py/cluster.result
@@ -263,6 +263,10 @@ box.info.vclock[10] == nil
 - true
 ...
 -------------------------------------------------------------
+JOIN replica to read-only master
+-------------------------------------------------------------
+'ER_READONLY' exists in server log
+-------------------------------------------------------------
 Cleanup
 -------------------------------------------------------------
 box.schema.user.revoke('guest', 'replication')
diff --git a/test/replication-py/cluster.test.py b/test/replication-py/cluster.test.py
index 86c7a494df..73ced6b822 100644
--- a/test/replication-py/cluster.test.py
+++ b/test/replication-py/cluster.test.py
@@ -242,6 +242,23 @@ replica.admin('box.info.server.ro')
 replica.admin('box.info.server.lsn == -1')
 replica.admin('box.info.vclock[%d] == nil' % replica_id2)
 
+print '-------------------------------------------------------------'
+print 'JOIN replica to read-only master'
+print '-------------------------------------------------------------'
+
+#gh-1230 Assertion vclock_has on attempt to JOIN read-only master
+failed = TarantoolServer(server.ini)
+failed.script = 'replication-py/failed.lua'
+failed.vardir = server.vardir
+failed.rpl_master = replica
+failed.name = "failed"
+try:
+    failed.deploy()
+except Exception as e:
+    line = "ER_READONLY"
+    if failed.logfile_pos.seek_once(line) >= 0:
+        print "'%s' exists in server log" % line
+
 print '-------------------------------------------------------------'
 print 'Cleanup'
 print '-------------------------------------------------------------'
diff --git a/test/replication-py/failed.lua b/test/replication-py/failed.lua
new file mode 100644
index 0000000000..3a08208e06
--- /dev/null
+++ b/test/replication-py/failed.lua
@@ -0,0 +1,9 @@
+#!/usr/bin/env tarantool
+
+box.cfg({
+    listen              = os.getenv("LISTEN"),
+    replication_source  = os.getenv("MASTER"),
+    slab_alloc_arena    = 0.1,
+})
+
+require('console').listen(os.getenv('ADMIN'))
-- 
GitLab