def _address(database_ids): IMPLMAP = {} NOT_CACHED = [] for database_id in database_ids: if database_id in MANAGERCACHE: try: IMPLMAP[MANAGERCACHE[database_id]].append(database_id) except KeyError: IMPLMAP[MANAGERCACHE[database_id]] = [ database_id, ] else: NOT_CACHED.append(database_id) if NOT_CACHED: session = endpoint_session(readonly=True) query = model_query(session, (GopDatabase.database_id, GopDatabase.impl), filter=GopDatabase.database_id.in_(NOT_CACHED)) for r in query: dbmanager = utils.impl_cls('wsgi', r[1]) try: IMPLMAP[dbmanager].append(r[0]) except KeyError: IMPLMAP[dbmanager] = [ r[0], ] session.close() maps = dict() for dbmanager in IMPLMAP: maps.update(dbmanager.address(IMPLMAP[dbmanager])) return maps
def rpc_unbond_entity(self, ctxt, entity, **kwargs): """从库收到解绑主库命令""" dbtype = self._dbtype(entity) dbinfo = self.konwn_database[entity] if dbinfo.get('slave') == 0: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, resultcode=manager_common.RESULT_ERROR, ctxt=ctxt, result= 'Can not unbond from master, database is master database?') dbmanager = utils.impl_cls('rpc', dbtype) cfgfile = self._db_conf(entity, dbtype) with self.lock(entity, timeout=3): p = self._entity_process(entity) if not p: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='unbond to master faile, slave db process not exist' ) dbmanager.unbond(cfgfile, postrun=None, timeout=None, **kwargs) return resultutils.AgentRpcResult(agent_id=self.manager.agent_id, ctxt=ctxt, result='unbond from master success')
def select(self, req, impl, body=None): body = body or {} kwargs = dict(req=req) kwargs.update(body) dbmanager = utils.impl_cls('wsgi', impl) dbresult = dbmanager.select_database(**kwargs) return resultutils.results(result='select database success', data=dbresult)
def agents(self, req, body=None): body = body or {} kwargs = dict(req=req) kwargs.update(body) dbtype = body.pop('dbtype', 'mysql') or 'mysql' dbmanager = utils.impl_cls('wsgi', 'local') dbresult = dbmanager.select_agents(dbtype, **kwargs) return resultutils.results(result='select database agents success', data=dbresult)
def rpc_stop_entity(self, ctxt, entity, **kwargs): dbtype = self._dbtype(entity) dbmanager = utils.impl_cls('rpc', dbtype) p = self._entity_process(entity) if p: cfgfile = self._db_conf(entity, dbtype) dbmanager.stop(cfgfile, postrun=None, timeout=None, process=p) return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='stop database entity success')
def rpc_slave_entity(self, ctxt, entity, **kwargs): """主库收到绑定从库命令""" bond = kwargs.pop('bond') dbtype = self._dbtype(entity) dbinfo = self.konwn_database[entity] port = self._get_port(entity) replication = privilegeutils.mysql_replprivileges( bond.get('database_id'), bond.get('host')) kwargs['replication'] = replication if dbinfo.get('slave') != 0: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, resultcode=manager_common.RESULT_ERROR, ctxt=ctxt, result='Can not bond a slave, database is not master database?' ) dbmanager = utils.impl_cls('rpc', dbtype) cfgfile = self._db_conf(entity, dbtype) with self.lock(entity, timeout=3): p = self._entity_process(entity) if not p: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, resultcode=manager_common.RESULT_ERROR, ctxt=ctxt, result='Cat not bond a slave, master db process not exist') def _bond_slave(_binlog, _scheams): LOG.debug('Try bond slave database') self.client.database_bond(database_id=bond.get('database_id'), body={ 'master': dbinfo.get('database_id'), 'host': self.manager.local_ip, 'port': port, 'passwd': replication.get('passwd'), 'file': _binlog.get('File'), 'position': _binlog.get('Position'), 'schemas': _scheams, }) dbmanager.bondslave(cfgfile, postrun=_bond_slave, timeout=None, dbinfo=dbinfo, **kwargs) return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='bond slave for master success')
def _impl(database_id): try: return MANAGERCACHE[database_id] except KeyError: session = endpoint_session(readonly=True) try: database = model_query( session, GopDatabase, GopDatabase.database_id == database_id).one() if database_id not in MANAGERCACHE: dbmanager = utils.impl_cls('wsgi', database.impl) MANAGERCACHE.setdefault(database_id, dbmanager) return MANAGERCACHE[database_id] finally: session.close()
def rpc_revoke_entity(self, ctxt, entity, **kwargs): dbtype = self._dbtype(entity) dbmanager = utils.impl_cls('rpc', dbtype) cfgfile = self._db_conf(entity, dbtype) with self.lock(entity, timeout=3): p = self._entity_process(entity) if not p: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='revoke entity fail, process not exist') dbmanager.revoke(cfgfile, postrun=None, timeout=None, **kwargs) return resultutils.AgentRpcResult(agent_id=self.manager.agent_id, ctxt=ctxt, result='revoke to master success')
def rpc_entity_replication_ready(self, ctxt, entity, **kwargs): dbtype = self._dbtype(entity) dbmanager = utils.impl_cls('rpc', dbtype) cfgfile = self._db_conf(entity, dbtype) with self.lock(entity, timeout=3): p = self._entity_process(entity) if not p: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='get replication status fail, process not exist') success, msg = dbmanager.replication_status(cfgfile, postrun=None, timeout=None, **kwargs) return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, resultcode=manager_common.RESULT_SUCCESS if success else manager_common.RESULT_ERROR, ctxt=ctxt, result=msg)
def rpc_start_entity(self, ctxt, entity, **kwargs): dbtype = self._dbtype(entity) dbmanager = utils.impl_cls('rpc', dbtype) cfgfile = self._db_conf(entity, dbtype) p = self._entity_process(entity) with self.lock(entity, timeout=3): if not p: dbmanager.start(cfgfile) eventlet.sleep(0.5) p = self._entity_process(entity) if not p: return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, resultcode=manager_common.RESULT_ERROR, ctxt=ctxt, result='start entity faile, process not exist after start') return resultutils.AgentRpcResult( agent_id=self.manager.agent_id, ctxt=ctxt, result='start entity success, runinng on pid %d' % p.info.get('pid'))
def create(self, req, body=None): body = body or {} jsonutils.schema_validate(body, self.CREATEDATABASE) impl = body.pop('impl') dbtype = body.pop('dbtype') user = body.pop('user') passwd = body.pop('passwd') dbversion = body.pop('dbversion', None) affinity = body.pop('affinity', 0) if body.get('slave'): if body.get('bond'): raise InvalidArgument( 'Slave database can not bond to another database ') affinity = 0 kwargs = dict(req=req) kwargs.update(body) dbmanager = utils.impl_cls('wsgi', impl) dbresult = dbmanager.create_database(user, passwd, dbtype, dbversion, affinity, **kwargs) return resultutils.results(result='create database success', data=[ dbresult, ])
def create_entity(self, entity, timeout, **kwargs): """ @param dbtype: string 数据库类型 @param configs: dict 数据库配置字典 @param auth: dict 远程管理员账号密码 @param bond: dict 需要绑定的从库(主库专用参数) """ dbtype = kwargs.pop('dbtype') configs = kwargs.pop('configs', {}) bond = kwargs.pop('bond', None) if bond: replication = privilegeutils.mysql_replprivileges( bond.get('database_id'), bond.get('host')) kwargs['replication'] = replication port = configs.pop('port', None) pidfile = os.path.join(self.entity_home(entity), '%s.pid' % dbtype) sockfile = os.path.join(self.entity_home(entity), '%s.sock' % dbtype) logfile = os.path.join(self.logpath(entity), '%s.log' % dbtype) install_log = os.path.join(self.logpath(entity), 'install.log') cfgfile = self._db_conf(entity, dbtype) LOG.info('Load database manager for %s' % dbtype) dbmanager = utils.impl_cls('rpc', dbtype) with self._prepare_entity_path(entity, apppath=False): with self._allocate_port(entity, port) as ports: port = ports[0] configs.setdefault('entity', entity) configs.setdefault('port', port) configs.setdefault('datadir', self.apppath(entity)) configs.setdefault('pidfile', pidfile) configs.setdefault('sockfile', sockfile) configs.setdefault('logfile', logfile) configs.setdefault('runuser', self.entity_user(entity)) dbmanager.save_conf(cfgfile, **configs) LOG.info('Prepare database config file success') def _notify_success(binlog): """notify database intance create success""" self.manager.change_performance() dbinfo = self.konwn_database.get(entity) if not dbinfo: LOG.warning( 'Can not find entity database id, active fail') return if bond: LOG.debug('Try bond slave database') self.client.database_bond( database_id=bond.get('database_id'), body={ 'master': dbinfo.get('database_id'), 'host': self.manager.local_ip, 'port': port, 'passwd': replication.get('passwd'), 'file': binlog.get('File'), 'position': binlog.get('Position'), 'schemas': [], }) if self._entity_process(entity): self.client.database_update( database_id=dbinfo.get('database_id'), body={'status': common.OK}) kwargs.update({'logfile': install_log}) threadpool.add_thread(dbmanager.install, cfgfile, _notify_success, timeout, **kwargs) # def _port_notify(): # """notify port bond""" # _timeout = timeout if timeout else 30 # overtime = int(time.time()) + _timeout # while entity not in self.konwn_database: # if int(time.time()) > overtime: # LOG.error('Fail allocate port %d for %s.%d' % (ports[0], common.DB, entity)) # return # eventlet.sleep(1) # self.client.ports_add(agent_id=self.manager.agent_id, # endpoint=common.DB, entity=entity, ports=ports) # threadpool.add_thread(_port_notify) return port