def configure(self, config): def get_option(config, section, key): if not config.has_option(section, key): return None value = config.get(section, key) if value.isdigit(): value = int(value) return value self.config = os.path.abspath(config) # now read the server config, we need some properties from it with open(self.config) as fp: dummy_section_name = "tarantool" config = ConfigParser.ConfigParser() config.readfp(TarantoolConfigFile(fp, dummy_section_name)) self.pidfile = get_option(config, dummy_section_name, "pid_file") self.primary_port = get_option(config, dummy_section_name, "primary_port") self.admin_port = get_option(config, dummy_section_name, "admin_port") self.memcached_port = get_option(config, dummy_section_name, "memcached_port") self.port = self.admin_port self.admin = AdminConnection("localhost", self.admin_port) self.sql = BoxConnection("localhost", self.primary_port) if self.memcached_port != 0: # Run memcached client self.memcached = MemcachedConnection('localhost', self.memcached_port)
def _sql(self, port): try: port = int(port) except ValueError as e: raise ValueError("Bad port number: '%s'" % port) if hasattr(self, 'sql'): del self.sql self.sql = BoxConnection('localhost', port)
def _iproto(self, port): try: port = int(port) except ValueError as e: raise ValueError("Bad port number: '%s'" % port) if hasattr(self, 'iproto'): del self.iproto self.iproto = BoxConnection('localhost', port)
def _sql(self, port): try: port = int(port) except ValueError as e: raise ValueError("Bad port number: '%s'" % port) if not hasattr(self, 'sql') or self.sql is None: self.sql = BoxConnection('localhost', port) return if self.sql.port != port: self.sql.port = port self.sql.reconnect()
con1("active_connections") con2 = AdminConnection('localhost', server.admin_port) con2("active_connections") con1.disconnect() con2.disconnect() admin("type(box.session.on_connect(nil))") admin("type(box.session.on_disconnect(nil))") # write audit trail of connect/disconnect into a space admin("box.session.on_connect(function() box.insert(0, box.session.id()) end)") admin("box.session.on_disconnect(function() box.delete(0, box.session.id()) end)") con1("box.unpack('i', box.select(0, 0, box.session.id())[0]) == box.session.id()") con1.disconnect() # if on_connect() trigger raises an exception, the connection is dropped admin("type(box.session.on_connect(function() nosuchfunction() end))") con1 = BoxConnection('localhost', server.primary_port) try: con1.execute("select * from t0 where k0=0") con1.execute("select * from t0 where k0=0") except Exception as e: print "disconnected" # cleanup admin("type(box.session.on_connect(nil))") admin("type(box.session.on_disconnect(nil))") admin("active_connections") # vim: syntax=python
class TarantoolServer(Server): default_tarantool = { "bin": "tarantool_box", "config": "tarantool.cfg", "logfile": "tarantool.log", "init": "init.lua", "pidfile": "box.pid", "name": "default"} generate_ports = [ 'primary_port', 'admin_port', ] generated_props = [ 'replication_source' ] #----------------------------------PROPERTIES----------------------------------# @property def debug(self): return self.test_debug() @property def name(self): if not hasattr(self, '_name') or not self._name: return self.default_tarantool["name"] return self._name @name.setter def name(self, val): self._name = val @property def logfile(self): if not hasattr(self, '_logfile') or not self._logfile: return os.path.join(self.vardir, self.default_tarantool["logfile"]) return self._logfile @logfile.setter def logfile(self, val): self._logfile = os.path.join(self.vardir, val) @property def pidfile(self): if not hasattr(self, '_pidfile') or not self._pidfile: return os.path.join(self.vardir, self.default_tarantool["pidfile"]) return self._pidfile @pidfile.setter def pidfile(self, val): self._pidfile = os.path.join(self.vardir, val) @property def cfgfile(self): if not hasattr(self, '_cfgfile') or not self._cfgfile: return os.path.join(self.vardir, self.default_tarantool["config"]) return self._cfgfile @cfgfile.setter def cfgfile(self, val): self._cfgfile = os.path.join(self.vardir, val) @property def cfgfile_source(self): if not hasattr(self, '_cfgfile_source'): raise ValueError("No config-file is specified") return self._cfgfile_source @cfgfile_source.setter def cfgfile_source(self, path): if path == None: if hasattr(self, '_cfgfile_source'): delattr(self, '_cfgfile_source') return self._cfgfile_source = os.path.abspath(path) @property def init_lua_source(self): if not hasattr(self, '_init_lua_source'): self._init_lua_source = None return self._init_lua_source @init_lua_source.setter def init_lua_source(self, val): if val is None: return self._init_lua_source = os.path.abspath(val) @property def builddir(self): if not hasattr(self, '_builddir'): raise ValueError("No build-dir is specified") return self._builddir @builddir.setter def builddir(self, val): if val is None: return self._builddir = os.path.abspath(val) @property def init_lua(self): return os.path.join(self.vardir, self.default_tarantool['init']) @property def logfile_pos(self): if not hasattr(self, '_logfile_pos'): self._logfile_pos = None return self._logfile_pos @logfile_pos.setter def logfile_pos(self, val): self._logfile_pos = TarantoolLog(val) self._logfile_pos.positioning() @property def shebang(self): if not hasattr(self, '_shebang'): self._shebang = None return self._shebang @shebang.setter def shebang(self, val): if val is None: if hasattr(self, '_shebang'): delattr(self, '_shebang') return self._shebang = os.path.abspath(val) @property def _admin(self): if not hasattr(self, 'admin'): self.admin = None return self.admin @_admin.setter def _admin(self, port): try: int(port) except ValueError as e: raise ValueError("Bad port number: '%s'" % port) if not hasattr(self, 'admin') or self.admin is None: self.admin = AdminConnection('localhost', port) return if self.admin.port != port: self.admin.port = port self.admin.reconnect() @property def _sql(self): if not hasattr(self, 'sql'): self.sql = None return self.sql @_sql.setter def _sql(self, port): try: port = int(port) except ValueError as e: raise ValueError("Bad port number: '%s'" % port) if not hasattr(self, 'sql') or self.sql is None: self.sql = BoxConnection('localhost', port) return if self.sql.port != port: self.sql.port = port self.sql.reconnect() @property def log_des(self): if not hasattr(self, '_log_des'): self._log_des = open(self.logfile, 'a') return self._log_des @log_des.deleter def log_des(self): if not hasattr(self, '_log_des'): return if not self._log_des.closed: self._log_des.closed() delattr(self, _log_des) @property def rpl_master(self): if not hasattr(self, '_rpl_master'): self._rpl_master = None return self._rpl_master @rpl_master.setter def rpl_master(self, val): if not isinstance(self, (TarantoolServer, None)): raise ValueError('Replication master must be Tarantool' ' Server class, his derivation or None') self._rpl_master = val @property def hot_master(self): if not hasattr(self, '_hot_master'): self._hot_master = None return self._hot_master @hot_master.setter def hot_master(self, val): if not isinstance(self, (TarantoolServer, None)): raise ValueError('Hot-standby master must be Tarantool' ' Server class, his derivation or None') self._hot_master = val #------------------------------------------------------------------------------# def __new__(cls, ini=None): if ini is None: ini = {'core': 'tarantool'} if ('valgrind' in ini and ini['valgrind']) and ('gdb' in ini and ini['gdb']): raise OSError('Can\'t run under valgrind and gdb simultaniously') if 'valgrind' in ini and ini['valgrind']: cls = type('ValgrindTarantooServer', (ValgrindMixin, TarantoolServer), {}) elif 'gdb' in ini and ini['gdb']: cls = type('GdbTarantoolServer', (GdbMixin, TarantoolServer), {}) return super(TarantoolServer, cls).__new__(cls) def __init__(self, _ini=None): if _ini is None: _ini = {} ini = { 'config': None, 'core': 'tarantool', 'gdb': False, 'init_lua': None, 'lua_libs': [], 'random_ports': True, 'valgrind': False, 'vardir': None, 'start_and_exit': False }; ini.update(_ini) Server.__init__(self, ini) self.generated_fields = self.generate_ports + self.generated_props self.testdir = os.path.abspath(os.curdir) self.re_vardir_cleanup += [ "*.snap", "*.xlog", "*.inprogress", "*.cfg", "*.sup", "*.lua", "*.pid"] self.name = "default" self.conf = {} self.status = None #-----InitBasicVars-----# self.cfgfile_source = ini['config'] self.core = ini['core'] self.gdb = ini['gdb'] self.init_lua_source = ini['init_lua'] self.lua_libs = ini['lua_libs'] self.random_ports = ini['random_ports'] self.valgrind = ini['valgrind'] self._start_and_exit = ini['start_and_exit'] def __del__(self): self.stop() @classmethod def find_exe(cls, builddir, silent=True): cls.builddir = os.path.abspath(builddir) builddir = os.path.join(builddir, "src/box") path = builddir + os.pathsep + os.environ["PATH"] if not silent: color_stdout("Looking for server binary in ", schema='serv_text') color_stdout(path + ' ...\n', schema='path') for _dir in path.split(os.pathsep): exe = os.path.join(_dir, cls.default_tarantool["bin"]) if os.access(exe, os.X_OK): cls.binary = os.path.abspath(exe) return exe raise RuntimeError("Can't find server executable in " + path) def install(self, silent=True): if not silent: color_stdout('Installing the server ...\n', schema='serv_text') color_stdout(' Found executable at ', schema='serv_text') color_stdout(self.binary + '\n', schema='path') color_stdout(' Creating and populating working directory in ', schema='serv_text') color_stdout(self.vardir + ' ...\n', schema='path') if not os.path.exists(self.vardir): os.makedirs(self.vardir) else: if not silent: color_stdout(' Found old vardir, deleting ...\n', schema='serv_text') self.kill_old_server() self.cleanup() self.copy_files() self.configure() return def deploy(self, silent=True): self.install(silent) if not self._start_and_exit: self.start(silent) else: self.start_and_exit() def configure(self, config=None): self.copy_config(config) self.port = self.conf['admin_port'] self._sql = self.conf['primary_port'] self._admin = self.conf['admin_port'] def reconfigure(self, config, silent=False, override=['all']): if config == None: os.unlink(self.cfgfile) else: self.cfgfile_source = config self.copy_config(override=override) self.admin.execute("box.cfg.reload()", silent=silent) def copy_config(self, rand=True, override = ['all']): override_all = (True if 'all' in override else False) port = random.randrange(3300, 9999) for t in self.generate_ports: if not t in self.conf: self.conf[t] = find_port(port) port += 1 if not self.hot_master is None: self.conf['primary_port'] = self.hot_master.sql.port if not self.rpl_master is None and 'replication_source' in self.generated_fields: self.conf['replication_source'] = \ '127.0.0.1:'+str(self.rpl_master.conf['primary_port']) basic = TarantoolConfig(self.cfgfile_source).parse() addit = {} for key in self.generated_fields: if key in basic and (override_all or key in override) and key in self.conf: addit[key] = str(self.conf[key]) basic.update(addit) TarantoolConfig(self.cfgfile).generate(basic) def copy_files(self): if self.shebang: shutil.copy(self.shebang, self.init_lua) os.chmod(self.init_lua, 0777) elif self.init_lua_source: shutil.copy(self.init_lua_source, self.init_lua) if self.lua_libs: for i in self.lua_libs: source = os.path.join(self.testdir, i) shutil.copy(source, self.vardir) def prepare_args(self): return shlex.split(self.init_lua if self.shebang else self.binary) def start_and_exit(self): color_stdout('Starting the server {0} on ports {1} ...\n'.format( os.path.basename(self.binary) if not self.shebang else self.shebang, ', '.join([': '.join([str(j) for j in i]) for i in self.conf.items() if i[0].find('port') != -1]) ), schema='serv_text') with daemon.DaemonContext(): self.start() self.process.wait() def start(self, silent=True): if self.status == 'started': if not silent: color_stdout('The server is already started.\n', schema='lerror') return if not silent or self._start_and_exit: color_stdout("Starting the server ...\n", schema='serv_text') color_stdout("Starting ", schema='serv_text') color_stdout((os.path.basename(self.binary) if not self.shebang else self.shebang) + " \n", schema='path') color_stdout(self.version() + "\n", schema='version') check_port(self.conf['admin_port']) args = self.prepare_args() self.logfile_pos = self.logfile self.process = subprocess.Popen(args, cwd = self.vardir, stdout=self.log_des, stderr=self.log_des) self.wait_until_started() self.status = 'started' def wait_stop(self): self.process.wait() def stop(self, silent=True): if self.status != 'started': if not silent: color_stdout('The server is not started.\n', schema='lerror') return if not silent: color_stdout('Stopping the server ...\n', schema='serv_text') self.process.terminate() self.wait_stop() self.status = None def restart(self): self.stop() self.start() def kill_old_server(self, silent=True): pid = self.read_pidfile() if pid == -1: return False if not silent: color_stdout(' Found old server, pid {0}, killing ...'.format(pid), schema='info') try: os.kill(pid, signal.SIGTERM) except OSError: pass self.wait_until_stopped(pid) return True def wait_until_started(self): """ Wait until server is started. Server consists of two parts: 1) wait until server is listening on sockets 2) wait until server tells us his status """ self.logfile_pos.seek_from('entering the event loop\n', self.process if not self.gdb else None) while True: try: temp = AdminConnection('localhost', self.conf['admin_port']) ans = yaml.load(temp.execute('box.info.status'))[0] if ans in ('primary', 'hot_standby', 'orphan') or ans.startswith('replica'): return True else: raise Exception("Strange output for `box.info.status`: %s" % (ans)) except socket.error as e: if e.errno == errno.ECONNREFUSED: time.sleep(0.1) continue raise def wait_until_stopped(self, pid): while True: try: time.sleep(0.01) os.kill(pid, 0) continue except OSError as err: break def read_pidfile(self): pid = -1 if os.path.exists(self.pidfile): try: with open(self.pidfile) as f: pid = int(f.read()) except: pass return pid def print_log(self, lines): color_stdout("\nLast {0} lines of Tarantool Log file:\n".format(lines), schema='error') with open(self.logfile, 'r') as log: return log.readlines()[-lines:] def test_option_get(self, option_list_str, silent=False): args = [self.binary] + shlex.split(option_list_str) if not silent: print " ".join([os.path.basename(self.binary)] + args[1:]) output = subprocess.Popen(args, cwd = self.vardir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.read() return output def test_option(self, option_list_str): print self.test_option_get(option_list_str) def test_debug(self): if self.test_option_get("-V", True).find("-Debug"): return True return False def find_tests(self, test_suite, suite_path): def patterned(test, patterns): return [test for i in patterns if test.name.find(i) != -1] tests = [PythonTest(k, test_suite.args, test_suite.ini) \ for k in sorted(glob.glob(os.path.join(suite_path, "*.test.py" )))] tests += [LuaTest(k, test_suite.args, test_suite.ini) \ for k in sorted(glob.glob(os.path.join(suite_path, "*.test.lua")))] test_suite.tests = sum(map((lambda x: patterned(x, test_suite.args.tests)), tests), []) def get_param(self, param = None): if not param is None: return yaml.load(self.admin("box.info." + param, silent=True))[0] return yaml.load(self.admin("box.info", silent=True)) def wait_lsn(self, lsn): while (int(self.get_param("lsn")) < lsn): time.sleep(0.01) def version(self): p = subprocess.Popen([self.binary, "--version"], cwd = self.vardir, stdout = subprocess.PIPE) version = p.stdout.read().rstrip() p.wait() return version
def _iproto(self, port): if hasattr(self, 'iproto'): del self.iproto self.iproto = BoxConnection('localhost', port)
from lib.box_connection import BoxConnection print """ # # if on_connect() trigger raises an exception, the connection is dropped # """ admin("function f1() nosuchfunction() end") admin("box.session.on_connect(f1)") con1 = BoxConnection('localhost', sql.port) con1("select * from t0 where k0=0") if not con1.check_connection(): print "Connection is dead.\n" else: print "Connection is alive.\n" # Clean-up admin("box.session.on_connect(nil, f1)")
from lib.box_connection import BoxConnection print """ # # if on_connect() trigger raises an exception, the connection is dropped # """ admin("type(box.session.on_connect(function() nosuchfunction() end))") con1 = BoxConnection('localhost', server.primary_port) con1("select * from t0 where k0=0") if not con1.check_connection(): print "Connection is dead.\n" else: print "Connection is alive.\n" # Clean-up admin("type(box.session.on_connect(nil))")