diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bc8a9e86c87a000eb08fbb29e2d8e10c0923ab7a..f4b27c6cd65692daefd12ca0ec80fd4c6bfd9b8b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -132,6 +132,7 @@ set (common_sources
      lua/slab.m
      lua/uuid.m
      lua/lua_ipc.m
+     lua/space.m
 )
 
 if (ENABLE_TRACE)
diff --git a/src/box/box.lua b/src/box/box.lua
index 2f68c47aa841c94a1b694fe96d50c675ffb4f146..238aee1925e61f03b217b8755964a74989895dd1 100644
--- a/src/box/box.lua
+++ b/src/box/box.lua
@@ -173,7 +173,7 @@ function box.counter.dec(space, ...)
     end
 end
 
-function box.on_reload_configuration()
+function box.bless_space(space)
     local index_mt = {}
     -- __len and __index
     index_mt.len = function(index) return #index.idx end
@@ -254,18 +254,20 @@ function box.on_reload_configuration()
     end
     space_mt.pairs = function(space) return space.index[0]:pairs() end
     space_mt.__index = space_mt
-    for i, space in pairs(box.space) do
-        rawset(space, 'n', i)
-        setmetatable(space, space_mt)
-        if type(space.index) == 'table' and space.enabled then
-            for j, index in pairs(space.index) do
-                rawset(index, 'idx', box.index.new(i, j))
-                setmetatable(index, index_mt)
-            end
+    
+    setmetatable(space, space_mt)
+    if type(space.index) == 'table' and space.enabled then
+        for j, index in pairs(space.index) do
+            rawset(index, 'idx', box.index.new(space.n, j))
+            setmetatable(index, index_mt)
         end
     end
 end
 
+-- User can redefine the hook
+function box.on_reload_configuration()
+end
+
 require("bit")
 
 -- vim: set et ts=4 sts
diff --git a/src/box/index.h b/src/box/index.h
index f77bb465ddc068f81a889943b050c567d3bf4f88..fae5231dc7981f489c0f5799739388d49706476c 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -77,6 +77,7 @@ struct key_def {
 	 */
 	int max_fieldno;
 	bool is_unique;
+	enum index_type type;
 };
 
 /** Descriptor of index features. */
diff --git a/src/box/space.m b/src/box/space.m
index 5a08e1b2e9dd0865504896bd644f8ced17ad5f55..5903926f2c6a44100e89321dbeba8790ad5a7cc3 100644
--- a/src/box/space.m
+++ b/src/box/space.m
@@ -216,6 +216,12 @@ key_init(struct key_def *def, struct tarantool_cfg_space_index *cfg_index)
 {
 	def->max_fieldno = 0;
 	def->part_count = 0;
+	if (strcmp(cfg_index->type, "HASH") == 0)
+		def->type = HASH;
+	else if (strcmp(cfg_index->type, "TREE") == 0)
+		def->type = TREE;
+	else
+		panic("Wrong index type: %s", cfg_index->type);
 
 	/* Calculate key part count and maximal field number. */
 	for (int k = 0; cfg_index->key_field[k] != NULL; ++k) {
diff --git a/src/lua/init.m b/src/lua/init.m
index 527c67ce984a7ac9c82261af88eef413fb7b93c9..e1b7beae3e0255247e80861562f5da2ea87eee59 100644
--- a/src/lua/init.m
+++ b/src/lua/init.m
@@ -48,6 +48,7 @@
 #include "lua/slab.h"
 #include "lua/stat.h"
 #include "lua/uuid.h"
+#include "space.h"
 
 #include TARANTOOL_CONFIG
 
@@ -1374,14 +1375,13 @@ tarantool_lua_load_cfg(struct lua_State *L, struct tarantool_cfg *cfg)
 	luaL_addstring(&b,
 		       "box.cfg = {}\n"
 		       "setmetatable(box.cfg, {})\n"
-		       "box.space = {}\n"
-		       "setmetatable(box.space, getmetatable(box.cfg))\n"
-		       "getmetatable(box.space).__index = "
+		       "getmetatable(box.cfg).__index = "
 		       "function(table, index)\n"
 		       "  table[index] = {}\n"
 		       "  setmetatable(table[index], getmetatable(table))\n"
 		       "  return rawget(table, index)\n"
-		       "end\n");
+		       "end\n"
+	);
 	while ((key = tarantool_cfg_iterator_next(i, cfg, &value)) != NULL) {
 		if (value == NULL)
 			continue;
@@ -1390,44 +1390,33 @@ tarantool_lua_load_cfg(struct lua_State *L, struct tarantool_cfg *cfg)
 			lua_pushfstring(L, "box.cfg.%s = %s%s%s\n",
 					key, quote, value, quote);
 			luaL_addvalue(&b);
-		} else if (strncmp(key, "space", strlen("space")) == 0) {
-			lua_pushfstring(L, "box.%s = %s%s%s\n",
-					key, quote, value, quote);
-			luaL_addvalue(&b);
 		}
 		free(value);
 	}
-	if (cfg->memcached_port) {
-		lua_pushfstring(L,
-		"box.space[%d].enabled = true\n"
-		"box.space[%d].cardinality = 4\n"
-		"box.space[%d].estimated_rows = 0\n"
-		"box.space[%d].index[0].unique = true\n"
-		"box.space[%d].index[0].type = 'HASH'\n"
-		"box.space[%d].index[0].key_field[0].field_no = 0\n"
-		"box.space[%d].index[0].key_field[0].field_type = 'STRING'\n",
-		cfg->memcached_space, cfg->memcached_space,
-		cfg->memcached_space, cfg->memcached_space,
-		cfg->memcached_space, cfg->memcached_space,
-		cfg->memcached_space);
-		luaL_addvalue(&b);
-	}
+
 	luaL_addstring(&b,
 		       "getmetatable(box.cfg).__newindex = "
 		       "function(table, index)\n"
 		       "  error('Attempt to modify a read-only table')\n"
 		       "end\n"
 		       "getmetatable(box.cfg).__index = nil\n"
-		       "if type(box.on_reload_configuration) == 'function' "
-		       "then\n"
-		       "  box.on_reload_configuration()\n"
-		       "end\n");
+	);
 	luaL_pushresult(&b);
 	if (luaL_loadstring(L, lua_tostring(L, -1)) != 0 ||
 	    lua_pcall(L, 0, 0, 0) != 0) {
 		panic("%s", lua_tostring(L, -1));
 	}
-	lua_pop(L, 1);
+	lua_pop(L, 1);	/* cleanup stack */
+
+	lbox_space_init(L);
+
+	/* on_reload_configuration hook */
+	lua_getfield(L, LUA_GLOBALSINDEX, "box");
+	lua_pushstring(L, "on_reload_configuration");
+	lua_gettable(L, -2);
+	if (lua_isfunction(L, -1))
+		lua_call(L, 0, 0);
+	lua_pop(L, 1);	/* cleanup stack */
 }
 
 /**
diff --git a/src/lua/space.h b/src/lua/space.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6ee38d2a449cb8aaa658b3ebe2f4ff106c4653e
--- /dev/null
+++ b/src/lua/space.h
@@ -0,0 +1,40 @@
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef INCLUDES_TARANTOOL_LUA_SPACE_H
+#define INCLUDES_TARANTOOL_LUA_SPACE_H
+
+
+struct lua_State;
+struct space;
+
+int lbox_pushspace(struct lua_State *L, struct space *space);
+void lbox_space_init(struct lua_State *L);
+
+#endif /* INCLUDES_TARANTOOL_LUA_SPACE_H */
diff --git a/src/lua/space.m b/src/lua/space.m
new file mode 100644
index 0000000000000000000000000000000000000000..c3526535c759e263de0935e665fae7213ee1fcd9
--- /dev/null
+++ b/src/lua/space.m
@@ -0,0 +1,166 @@
+/*
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "space.h"
+#include "../box/space.h"
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include <say.h>
+
+
+int
+lbox_pushspace(struct lua_State *L, struct space *space)
+{
+	lua_newtable(L);
+
+	/* space.cardinality */
+	lua_pushstring(L, "cardinality");
+	lua_pushnumber(L, space->arity);
+	lua_settable(L, -3);
+
+	/* space.n */
+	lua_pushstring(L, "n");
+	lua_pushnumber(L, space->no);
+	lua_settable(L, -3);
+
+	/* all exists spaces are enabled */
+	lua_pushstring(L, "enabled");
+	lua_pushboolean(L, 1);
+	lua_settable(L, -3);
+
+	/* legacy field */
+	lua_pushstring(L, "estimated_rows");
+	lua_pushnumber(L, 0);
+	lua_settable(L, -3);
+
+	/* space.index */
+	lua_pushstring(L, "index");
+	lua_newtable(L);
+
+
+	for(int i = 0; i < space->key_count; i++) {
+		lua_pushnumber(L, i);
+		lua_newtable(L);		/* space.index[i] */
+
+		lua_pushstring(L, "idx");
+		lua_pushfstring(L, "index %d in space %d", i, space->no);
+		lua_settable(L, -3);
+
+		lua_pushstring(L, "unique");
+		lua_pushboolean(L, space->key_defs[i].is_unique);
+		lua_settable(L, -3);
+
+		lua_pushstring(L, "type");
+		switch(space->key_defs[i].type) {
+			case HASH:
+				lua_pushstring(L, "HASH");
+				break;
+			case TREE:
+				lua_pushstring(L, "TREE");
+				break;
+			default:
+				panic("unknown index type %d",
+					space->key_defs[i].parts[0].type);
+		}
+		lua_settable(L, -3);
+
+		lua_pushstring(L, "key_field");
+		lua_newtable(L);
+
+		for (int j = 0; j < space->key_defs[i].part_count; j++) {
+			lua_pushnumber(L, j);
+			lua_newtable(L);
+
+			lua_pushstring(L, "type");
+			switch(space->key_defs[i].parts[j].type) {
+				case NUM:
+					lua_pushstring(L, "NUM");
+					break;
+				case NUM64:
+					lua_pushstring(L, "NUM64");
+					break;
+				case STRING:
+					lua_pushstring(L, "STR");
+					break;
+				default:
+					lua_pushstring(L, "UNKNOWN");
+					break;
+			}
+			lua_settable(L, -3);
+
+			lua_pushstring(L, "fieldno");
+			lua_pushnumber(L, space->key_defs[i].parts[j].fieldno);
+			lua_settable(L, -3);
+
+			lua_settable(L, -3);
+		}
+
+		lua_settable(L, -3);	/* space[i].key_field */
+
+		lua_settable(L, -3);	/* space[i] */
+	}
+
+	lua_settable(L, -3);	/* push space.index */
+
+
+	/* on_reload_configuration hook */
+	lua_getfield(L, LUA_GLOBALSINDEX, "box");
+	lua_pushstring(L, "bless_space");
+	lua_gettable(L, -2);
+
+	if (!lua_isfunction(L, -1))
+		panic("box.bless_space isn't a function");
+
+	lua_pushvalue(L, -3);			/* box, bless, space */
+	lua_call(L, 1, 0);
+	lua_pop(L, 1);	/* cleanup stack */
+
+	return 1;
+}
+
+static void
+lbox_add_space(struct space *space, struct lua_State *L)
+{
+	lua_pushnumber(L, space->no);
+	lbox_pushspace(L, space);
+	lua_settable(L, -3);
+}
+
+void
+lbox_space_init(struct lua_State *L)
+{
+	lua_getfield(L, LUA_GLOBALSINDEX, "box");
+	lua_pushstring(L, "space");
+	lua_newtable(L);
+	space_foreach((void *)lbox_add_space, L);	/* fill box.space */
+	lua_settable(L, -3);
+	lua_pop(L, 1);
+	assert(lua_gettop(L) == 0);
+}
diff --git a/src/memcached.m b/src/memcached.m
index 166148745d9c6f355aa50fe26c1de3e66b7e2bfa..0c77fdecef937bd4234c282e26c6622515d71630 100644
--- a/src/memcached.m
+++ b/src/memcached.m
@@ -469,6 +469,7 @@ memcached_space_init()
 	struct key_def *key_def = malloc(sizeof(struct key_def));
 	key_def->part_count = 1;
 	key_def->is_unique = true;
+	key_def->type = HASH;
 
 	key_def->parts = malloc(sizeof(struct key_part));
 	key_def->cmp_order = malloc(sizeof(u32));
diff --git a/src/tarantool.m b/src/tarantool.m
index e04d82251f490b4b90118ad236146c42ead3c5a6..c0ee8387ccf07b49f2576c71e856c21e9ae4078a 100644
--- a/src/tarantool.m
+++ b/src/tarantool.m
@@ -860,8 +860,8 @@ main(int argc, char **argv)
 	@try {
 		tarantool_L = tarantool_lua_init();
 		mod_init();
-		tarantool_lua_load_cfg(tarantool_L, &cfg);
 		memcached_init(cfg.bind_ipaddr, cfg.memcached_port);
+		tarantool_lua_load_cfg(tarantool_L, &cfg);
 		/*
 		 * init iproto before admin and after memcached:
 		 * recovery is finished on bind to the primary port,
diff --git a/test/box/admin.test b/test/box/admin.test
index b1877799ffc2bc744f81e69ee0a54690c9408a76..eb9f210869e20a0aea46a57d111b29da685e667b 100644
--- a/test/box/admin.test
+++ b/test/box/admin.test
@@ -25,4 +25,5 @@ exec admin "show fiber"
 exec admin "show slab"
 exec admin "show palloc"
 sys.stdout.clear_all_filters()
+
 # vim: syntax=python
diff --git a/test/box/lua.result b/test/box/lua.result
index e57c46d84d83a338f3194d038f052c2da151955d..4e07b733394e67fba4f128c75fa68ca443c1924a 100644
--- a/test/box/lua.result
+++ b/test/box/lua.result
@@ -20,9 +20,10 @@ lua for n in pairs(box) do print('  - box.', n) end
   - box.replace
   - box.space
   - box.cfg
+  - box.on_reload_configuration
   - box.select_range
   - box.insert
-  - box.on_reload_configuration
+  - box.bless_space
   - box.counter
   - box.info
   - box.auto_increment
@@ -401,8 +402,8 @@ lua for k,v in pairs(box.space[0]) do if type(v) ~= 'table' then print(' - ', k,
 ---
  - cardinality: -1
  - estimated_rows: 0
- - enabled: true
  - n: 0
+ - enabled: true
 ...
 reload configuration
 ---
@@ -449,16 +450,15 @@ lua for k,v in pairs(box.space[0]) do if type(v) ~= 'table' then print(' - ', k,
 ---
  - cardinality: -1
  - estimated_rows: 0
- - enabled: true
  - n: 0
+ - enabled: true
 ...
 lua box.cfg.nosuchoption = 1
 ---
-error: '[string "box.cfg = {}..."]:52: Attempt to modify a read-only table'
+error: '[string "box.cfg = {}..."]:43: Attempt to modify a read-only table'
 ...
 lua box.space[300] = 1
 ---
-error: '[string "box.cfg = {}..."]:52: Attempt to modify a read-only table'
 ...
 lua box.index.new('abc', 'cde')
 ---
@@ -699,12 +699,11 @@ lua box.fiber.resume(f, 'hello', 'world')
 ...
 lua box.fiber.resume(f, 'wide')
 ---
- - world
- - wide
+error: 'fiber.resume(): the fiber is dead'
 ...
 lua box.fiber.resume(f)
 ---
- - true
+error: 'fiber.resume(): the fiber is dead'
 ...
 lua function y() print('started') box.fiber.detach() while true do box.replace(0, 'test', os.time()) box.fiber.sleep(0.001) end end
 ---
diff --git a/test/box/space.result b/test/box/space.result
new file mode 100644
index 0000000000000000000000000000000000000000..4d48f37e129d6f7a4a64187a4f186a7952535470
--- /dev/null
+++ b/test/box/space.result
@@ -0,0 +1,17 @@
+lua type(box)
+---
+ - table
+...
+lua type(box.space)
+---
+ - table
+...
+lua box.cfg.memcached_space
+---
+ - 23
+...
+lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end
+---
+type: NUM
+fieldno: 0
+...
diff --git a/test/box/space.test b/test/box/space.test
new file mode 100644
index 0000000000000000000000000000000000000000..a421d2685268a19bfd5d8c34231f3bd7a7512afb
--- /dev/null
+++ b/test/box/space.test
@@ -0,0 +1,5 @@
+# encoding: tarantool
+exec admin "lua type(box)"
+exec admin "lua type(box.space)"
+exec admin "lua box.cfg.memcached_space"
+exec admin "lua for i, v in pairs(box.space[0].index[0].key_field[0]) do print(i, ': ', v) end"
diff --git a/test/run b/test/run
deleted file mode 120000
index 68f68dd76759c0c540d91e2d612c5458f09a06d5..0000000000000000000000000000000000000000
--- a/test/run
+++ /dev/null
@@ -1 +0,0 @@
-./run.sh
\ No newline at end of file
diff --git a/test/run b/test/run
new file mode 100755
index 0000000000000000000000000000000000000000..351474a9b40d24ae694e79c1b824330164d0140b
--- /dev/null
+++ b/test/run
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+/usr/bin/env python <<__EOB__
+import sys
+if sys.hexversion < 0x02060000 or sys.hexversion >= 0x03000000:
+    sys.stderr.write("ERROR: test harness must use python >= 2.6 but not 3.x\n")
+    sys.exit(1)
+else:
+    sys.exit(0)
+__EOB__
+
+[ $? -eq 0 ] && ./test-run.py $*
+
diff --git a/test/tarantool b/test/tarantool
deleted file mode 120000
index eb4a53a7491315cdba3dd460a8b76de5e57f39d7..0000000000000000000000000000000000000000
--- a/test/tarantool
+++ /dev/null
@@ -1 +0,0 @@
-../client/tarantool/tarantool
\ No newline at end of file