Example #1
0
 def _start_database(self, database, **kwargs):
     req = kwargs.pop('req')
     entity = int(database.reflection_id)
     _entity = entity_controller.show(req=req,
                                      entity=entity,
                                      endpoint=common.DB,
                                      body={'ports': False})['data'][0]
     agent_id = _entity['agent_id']
     metadata = _entity['metadata']
     target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                 metadata.get('host'))
     target.namespace = common.DB
     rpc = get_client()
     finishtime, timeout = rpcfinishtime()
     rpc_ret = rpc.call(target,
                        ctxt={
                            'finishtime': finishtime,
                            'agents': [
                                agent_id,
                            ]
                        },
                        msg={
                            'method': 'start_entity',
                            'args': dict(entity=entity)
                        },
                        timeout=timeout)
     if not rpc_ret:
         raise RpcResultError('create entitys result is None')
     if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
         raise RpcResultError('create entity fail %s' %
                              rpc_ret.get('result'))
     return rpc_ret
Example #2
0
 def opentime(self, req, group_id, objtype, entity, body=None):
     """修改开服时间接口"""
     body = body or {}
     group_id = int(group_id)
     entity = int(entity)
     if objtype != common.GAMESERVER:
         raise InvalidArgument('Api just for %s' % common.GAMESERVER)
     opentime = int(body.pop('opentime'))
     if opentime < 0 or opentime >= int(time.time()) + 86400 * 15:
         raise InvalidArgument('opentime value error')
     session = endpoint_session()
     with session.begin():
         query = model_query(session, AppEntity, filter=AppEntity.entity == entity)
         _entity = query.one()
         if _entity.objtype != objtype:
             raise InvalidArgument('Entity is not %s' % objtype)
         if _entity.group_id != group_id:
             raise InvalidArgument('Entity group %d not match  %d' % (_entity.group_id, group_id))
         metadata, ports = self._entityinfo(req=req, entity=entity)
         target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                     metadata.get('host'))
         target.namespace = common.NAME
         rpc = get_client()
         finishtime, timeout = rpcfinishtime()
         # with session.begin():
         rpc_ret = rpc.call(target, ctxt={'finishtime': finishtime},
                            msg={'method': 'opentime_entity',
                                 'args': dict(entity=entity, opentime=opentime)},
                            timeout=timeout)
         query.update({'opentime': opentime})
         if not rpc_ret:
             raise RpcResultError('change entity opentime result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('change entity opentime fail %s' % rpc_ret.get('result'))
     return resultutils.results(result='change entity %d opentime success' % entity)
Example #3
0
 def _revoke_database_user(self, database, auth, **kwargs):
     req = kwargs.pop('req')
     entity = int(database.reflection_id)
     _entity = entity_controller.show(req=req,
                                      entity=entity,
                                      endpoint=common.DB,
                                      body={'ports': False})['data'][0]
     agent_id = _entity['agent_id']
     metadata = _entity['metadata']
     if not metadata:
         raise InvalidArgument('Traget database agent is offline')
     target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                 metadata.get('host'))
     target.namespace = common.DB
     rpc = get_client()
     finishtime, timeout = rpcfinishtime()
     rpc_ret = rpc.call(target,
                        ctxt={
                            'finishtime': finishtime,
                            'agents': [
                                agent_id,
                            ]
                        },
                        msg={
                            'method': 'revoke_entity',
                            'args': dict(entity=entity, auth=auth)
                        },
                        timeout=timeout)
     if not rpc_ret:
         raise RpcResultError('revoke grant from database result is None')
     if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
         raise RpcResultError('revoke grant from database fail %s' %
                              rpc_ret.get('result'))
     return rpc_ret
Example #4
0
 def _unbond_database(self, session, master, slave, relation, **kwargs):
     req = kwargs.pop('req')
     entity = int(slave.reflection_id)
     with session.begin(subtransactions=True):
         _entity = entity_controller.show(req=req,
                                          entity=entity,
                                          endpoint=common.DB,
                                          body={'ports': False})['data'][0]
         agent_id = _entity['agent_id']
         metadata = _entity['metadata']
         if not metadata:
             raise InvalidArgument('Traget database agent is offline')
         target = targetutils.target_agent_by_string(
             metadata.get('agent_type'), metadata.get('host'))
         target.namespace = common.DB
         rpc = get_client()
         finishtime, timeout = rpcfinishtime()
         # 发送master信息到从库所在agent
         rpc_ret = rpc.call(target,
                            ctxt={
                                'finishtime': finishtime + 3,
                                'agents': [
                                    agent_id,
                                ]
                            },
                            msg={
                                'method':
                                'unbond_entity',
                                'args':
                                dict(entity=entity,
                                     force=kwargs.get('force', False),
                                     master=dict(
                                         database_id=master.database_id,
                                         ready=relation.ready,
                                         schemas=[
                                             schema.schema
                                             for schema in master.schemas
                                         ],
                                     ))
                            },
                            timeout=timeout + 3)
         if not rpc_ret:
             raise RpcResultError('unbond database result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('unbond database fail %s' %
                                  rpc_ret.get('result'))
         # 绑定状态设置就绪
         session.delete(relation)
         session.flush()
         auth = privilegeutils.mysql_replprivileges(
             slave.database_id, metadata.get('local_ip'))
         auth['schema'] = '*'
         return self._revoke_database_user(master, auth, req=req)
Example #5
0
 def _slave_database(self, session, master, slave, **kwargs):
     req = kwargs.pop('req')
     with session.begin(subtransactions=True):
         # get slave host and port
         _host, _port = self._get_entity(req=req,
                                         entity=int(slave.reflection_id),
                                         raise_error=True)
         entity = int(master.reflection_id)
         _entity = entity_controller.show(req=req,
                                          entity=entity,
                                          endpoint=common.DB,
                                          body={'ports': False})['data'][0]
         agent_id = _entity['agent_id']
         metadata = _entity['metadata']
         if not metadata:
             raise InvalidArgument('Traget database agent is offline')
         target = targetutils.target_agent_by_string(
             metadata.get('agent_type'), metadata.get('host'))
         target.namespace = common.DB
         rpc = get_client()
         finishtime, timeout = rpcfinishtime()
         # 发送slave信息到主库所在agent
         rpc_ret = rpc.call(target,
                            ctxt={
                                'finishtime': finishtime + 5,
                                'agents': [
                                    agent_id,
                                ]
                            },
                            msg={
                                'method':
                                'slave_entity',
                                'args':
                                dict(entity=entity,
                                     schemas=kwargs.get('schemas'),
                                     file=kwargs.get('file'),
                                     position=kwargs.get('position'),
                                     bond=dict(
                                         database_id=slave.database_id,
                                         host=_host,
                                         port=_port))
                            },
                            timeout=timeout + 5)
         if not rpc_ret:
             raise RpcResultError(
                 'bond slave for master database result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('bond slave for master database fail %s' %
                                  rpc_ret.get('result'))
         return rpc_ret
Example #6
0
 def _bond_database(self, session, master, slave, relation, **kwargs):
     req = kwargs.pop('req')
     entity = int(slave.reflection_id)
     with session.begin(subtransactions=True):
         _entity = entity_controller.show(req=req,
                                          entity=entity,
                                          endpoint=common.DB,
                                          body={'ports': False})['data'][0]
         agent_id = _entity['agent_id']
         metadata = _entity['metadata']
         if not metadata:
             raise InvalidArgument('Traget database agent is offline')
         target = targetutils.target_agent_by_string(
             metadata.get('agent_type'), metadata.get('host'))
         target.namespace = common.DB
         rpc = get_client()
         finishtime, timeout = rpcfinishtime()
         # 发送master信息到从库所在agent
         rpc_ret = rpc.call(target,
                            ctxt={
                                'finishtime': finishtime + 5,
                                'agents': [
                                    agent_id,
                                ]
                            },
                            msg={
                                'method':
                                'bond_entity',
                                'args':
                                dict(entity=entity,
                                     force=kwargs.get('force', False),
                                     master=dict(
                                         database_id=master.database_id,
                                         host=kwargs.get('host'),
                                         port=kwargs.get('port'),
                                         passwd=kwargs.get('passwd'),
                                         file=kwargs.get('file'),
                                         position=kwargs.get('position'),
                                         schemas=kwargs.get('schemas')))
                            },
                            timeout=timeout + 5)
         if not rpc_ret:
             raise RpcResultError('bond database result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('bond database fail %s' %
                                  rpc_ret.get('result'))
         # 绑定状态设置就绪
         relation.ready = True if not kwargs.get('schemas') else False
         return rpc_ret
Example #7
0
 def _ready_relation(self, session, master, slave, relation, **kwargs):
     req = kwargs.pop('req')
     entity = int(slave.reflection_id)
     with session.begin(subtransactions=True):
         schemas = [schema.schema for schema in master.schemas]
         _host, _port = self._get_entity(req,
                                         int(master.reflection_id),
                                         raise_error=True)
         _entity = entity_controller.show(req=req,
                                          entity=entity,
                                          endpoint=common.DB,
                                          body={'ports': False})['data'][0]
         agent_id = _entity['agent_id']
         metadata = _entity['metadata']
         if not metadata:
             raise InvalidArgument('Traget database agent is offline')
         target = targetutils.target_agent_by_string(
             metadata.get('agent_type'), metadata.get('host'))
         target.namespace = common.DB
         rpc = get_client()
         finishtime, timeout = rpcfinishtime()
         # 发送master信息到从库所在agent
         rpc_ret = rpc.call(target,
                            ctxt={
                                'finishtime': finishtime,
                                'agents': [
                                    agent_id,
                                ]
                            },
                            msg={
                                'method':
                                'entity_replication_ready',
                                'args':
                                dict(entity=entity,
                                     master=dict(
                                         database_id=master.database_id,
                                         host=_host,
                                         port=_port,
                                         schemas=schemas))
                            },
                            timeout=timeout)
         if not rpc_ret:
             raise RpcResultError('get replication status result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('get replication status fail %s' %
                                  rpc_ret.get('result'))
         # 绑定状态设置就绪
         relation.ready = True
         return rpc_ret
Example #8
0
 def _check_file(agent_id, objtype, appfile):
     metadata = BaseContorller.agent_metadata(agent_id)
     if not metadata:
         return False
     target = targetutils.target_agent_by_string(metadata.get('agent_type'), metadata.get('host'))
     rpc = get_client()
     rpc_ret = rpc.call(target, ctxt={'agents': [agent_id, ]},
                        msg={'method': 'check_file',
                             'args': dict(objtype=objtype, appfile=appfile)})
     if not rpc_ret:
         LOG.error('Rpc call result is None')
         return False
     if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
         return False
     return True
Example #9
0
 def delete(self, req, endpoint, entity, body=None, action='delete'):
     body = body or {}
     notify = body.pop('notify', True)
     endpoint = validateutils.validate_endpoint(endpoint)
     entity = int(entity)
     session = get_session()
     glock = get_global().lock('entitys')
     result = 'delete entity success.'
     with glock(endpoint, [
             entity,
     ]) as agents:
         with session.begin():
             query = model_query(session,
                                 AgentEntity,
                                 filter=and_(
                                     AgentEntity.endpoint == endpoint,
                                     AgentEntity.entity == entity))
             if notify:
                 agent_id = agents.pop()
                 metadata = BaseContorller.agent_metadata(agent_id)
                 if not metadata:
                     raise InvalidArgument('Agent not online or not exist')
             _entity = query.one_or_none()
             if not _entity:
                 LOG.warning('Delete no entitys, but expect count 1')
             else:
                 query.delete()
             if notify:
                 target = targetutils.target_agent_by_string(
                     metadata.get('agent_type'), metadata.get('host'))
                 target.namespace = endpoint
                 delete_result = self.notify_delete(target, agent_id,
                                                    entity, body, action)
                 if not delete_result:
                     raise RpcResultError('delete entitys result is None')
                 if delete_result.get(
                         'resultcode') != manager_common.RESULT_SUCCESS:
                     raise RpcResultError('delete entity fail %s' %
                                          delete_result.get('result'))
                 result += delete_result.get('result')
                 notify = delete_result
     return resultutils.results(
         result=result,
         data=[dict(entity=entity, endpoint=endpoint, notify=notify)])
Example #10
0
 def continues(self, req, uuid, body=None):
     """中途失败的合服任务再次运行"""
     session = endpoint_session()
     query = model_query(session, MergeTask, filter=MergeTask.uuid == uuid)
     query = query.options(joinedload(MergeTask.entitys, innerjoin=False))
     etask = query.one()
     if etask.status == common.MERGEFINISH:
         raise InvalidArgument('Merge task has all ready finished')
     _query = model_query(session,
                          AppEntity,
                          filter=AppEntity.entity == etask.entity)
     _query = _query.options(
         joinedload(AppEntity.databases, innerjoin=False))
     appentity = _query.one_or_none()
     if not appentity or not appentity.databases or appentity.objtype != common.GAMESERVER:
         LOG.error('Etask entity can not be found or type/database error')
         raise exceptions.MergeException(
             'Etask entity can not be found or type/database error')
     databases = self._database_to_dict(appentity)
     rpc = get_client()
     metadata, ports = self._entityinfo(req=req, entity=appentity.entity)
     target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                 metadata.get('host'))
     target.namespace = common.NAME
     rpc_ret = rpc.call(target,
                        ctxt={'agents': [
                            appentity.agent_id,
                        ]},
                        msg={
                            'method':
                            'continue_merge',
                            'args':
                            dict(entity=etask.entity,
                                 uuid=uuid,
                                 databases=databases)
                        })
     if not rpc_ret:
         raise RpcResultError('continue entity result is None')
     if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
         raise RpcResultError('continue entity fail %s' %
                              rpc_ret.get('result'))
     return resultutils.results(
         result='continue merge task command has been send',
         data=[dict(uuid=etask.uuid, entity=etask.entity)])
Example #11
0
 def readlog(self, req, endpoint, entity, body=None):
     body = body or {}
     path = body.get('path')
     lines = body.get('lines', 10)
     if not path or '..' in path:
         raise InvalidArgument('Path value error')
     endpoint = validateutils.validate_endpoint(endpoint)
     entity = int(entity)
     session = get_session(readonly=True)
     query = model_query(session,
                         AgentEntity,
                         filter=and_(AgentEntity.endpoint == endpoint,
                                     AgentEntity.entity == entity))
     _entity = query.one_or_none()
     if not _entity:
         raise InvalidArgument('no entity found for %s' % endpoint)
     metadata = BaseContorller.agent_metadata(_entity.agent_id)
     if not metadata:
         raise InvalidArgument('Can not get log from off line agent')
     target = targetutils.target_agent_by_string(manager_common.APPLICATION,
                                                 metadata.get('host'))
     target.namespace = endpoint
     rpc = get_client()
     rpc_ret = rpc.call(target,
                        ctxt={'finishtime': rpcfinishtime()[0]},
                        msg={
                            'method': 'readlog',
                            'args': {
                                'entity': entity,
                                'path': path,
                                'lines': lines
                            }
                        })
     if not rpc_ret:
         raise RpcResultError('Get %s.%d log rpc result is None' %
                              (endpoint, entity))
     if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
         raise InvalidArgument(('Get %s.%d log agent rpc result: ' %
                                (endpoint, entity)) + rpc_ret.get('result'))
     return resultutils.results(result=rpc_ret.get('result'),
                                data=[rpc_ret.get('uri')])
Example #12
0
 def post_create_entity(self, entity, endpoint, **kwargs):
     entity = int(entity)
     endpoint = validateutils.validate_endpoint(endpoint)
     session = get_session(readonly=True)
     query = model_query(session,
                         AgentEntity,
                         filter=and_(AgentEntity.endpoint == endpoint,
                                     AgentEntity.entity == entity))
     _entity = query.one()
     metadata = BaseContorller.agent_metadata(_entity.agent_id)
     if not metadata:
         raise RpcPrepareError('Agent not online, can not sen post create')
     target = targetutils.target_agent_by_string(
         metadata.get('agent_type'),
         metadata.get('host'),
     )
     target.namespace = endpoint
     body = dict(entity=entity)
     body.update(kwargs)
     rpc = get_client()
     rpc.cast(target,
              ctxt={
                  'finishtime': body.pop('finishtime',
                                         rpcfinishtime()[0]),
                  'entitys': [
                      entity,
                  ]
              },
              msg={
                  'method': 'post_create_entity',
                  'args': body
              })
     return resultutils.results(result='notify post create success',
                                data=[
                                    dict(entity=entity,
                                         agent_id=_entity.agent_id,
                                         endpoint=endpoint)
                                ])
Example #13
0
    def reset(self, req, group_id, objtype, entity, body=None):
        """重置Entity程序以及配置"""
        body = body or {}
        group_id = int(group_id)
        entity = int(entity)
        # 重置程序文件,为空表示不需要重置程序文件
        appfile = body.pop(common.APPFILE, None)
        # 重置数据库信息
        databases = body.pop('databases', False)
        # 重置主服务器信息(gameserver专用)
        chiefs = body.pop('chiefs', False)
        # 查询entity信息
        session = endpoint_session()
        query = model_query(session, AppEntity, filter=AppEntity.entity == entity)
        query = query.options(joinedload(AppEntity.databases, innerjoin=False))
        _entity = query.one()
        if _entity.objtype != objtype:
            raise InvalidArgument('Entity is not %s' % objtype)
        if _entity.group_id != group_id:
            raise InvalidArgument('Entity group %d not match  %d' % (_entity.group_id, group_id))
        entityinfo = entity_controller.show(req=req, entity=entity,
                                            endpoint=common.NAME,
                                            body={'ports': False})['data'][0]
        agent_id = entityinfo['agent_id']
        metadata = entityinfo['metadata']
        if not metadata:
            raise InvalidArgument('Agent is off line, can not reset entity')
        # 需要更新数据库
        if databases:
            miss = []
            databases = {}
            # 从本地查询数据库信息
            for database in _entity.databases:
                subtype = database.subtype
                schema = '%s_%s_%s_%d' % (common.NAME, objtype, subtype, entity)
                databases[subtype] = dict(host=database.host,
                                          port=database.port,
                                          user=database.user,
                                          passwd=database.passwd,
                                          schema=schema,
                                          character_set=database.character_set)

            # 必要数据库信息
            NEEDED = common.DBAFFINITYS[objtype].keys()
            # 数据库信息不匹配,从gopdb接口反查数据库信息
            if set(NEEDED) != set(databases.keys()):
                LOG.warning('Database not match, try find schema info from gopdb')
                quotes = schema_controller.quotes(req, body=dict(entitys=[entity, ],
                                                                 endpoint=common.NAME))['data']
                for subtype in NEEDED:
                    if subtype not in databases:
                        # 从gopdb接口查询引用信息
                        schema = '%s_%s_%s_%d' % (common.NAME, objtype, subtype, entity)
                        for quote_detail in quotes:
                            # 确认引用不是从库且结构名称相等
                            if quote_detail['qdatabase_id'] == quote_detail['database_id'] \
                                    and quote_detail['schema'] == schema:
                                databases.setdefault(subtype,
                                                     dict(host=quote_detail['host'],
                                                          port=quote_detail['port'],
                                                          user=quote_detail['user'],
                                                          passwd=quote_detail['passwd'],
                                                          schema=schema,
                                                          character_set=quote_detail['character_set']))
                                miss.append(AreaDatabase(quote_id=quote_detail['quote_id'],
                                                         database_id=quote_detail['qdatabase_id'],
                                                         entity=entity,
                                                         subtype=subtype,
                                                         host=quote_detail['host'], port=quote_detail['port'],
                                                         user=quote_detail['user'], passwd=quote_detail['passwd'],
                                                         ro_user=quote_detail['ro_user'],
                                                         ro_passwd=quote_detail['ro_passwd'],
                                                         character_set=quote_detail['character_set'])
                                            )
                                quotes.remove(quote_detail)
                                break
                        if subtype not in databases:
                            LOG.critical('Miss database of %s' % schema)
                            # 数据库信息无法从gopdb中反查到
                            raise ValueError('Not %s.%s database found for %d' % (objtype, subtype, entity))
            self._validate_databases(objtype, databases)
            # 有数据库信息遗漏
            if miss:
                with session.begin():
                    for obj in miss:
                        session.add(obj)
                        session.flush()

        if objtype == common.GAMESERVER and chiefs:
            chiefs = {}
            cross_id = _entity.cross_id
            if cross_id is None:
                raise ValueError('%s.%d cross_id is None' % (objtype, entity))
            query = model_query(session, AppEntity,
                                filter=and_(AppEntity.group_id == group_id,
                                            or_(AppEntity.entity == cross_id,
                                                AppEntity.objtype == common.GMSERVER)))
            _chiefs = query.all()
            if len(_chiefs) != 2:
                raise ValueError('Try find %s.%d chiefs from local database error' % (objtype, entity))
            for chief in _chiefs:
                for _objtype in (common.GMSERVER, common.CROSSSERVER):
                    _metadata, ports = self._entityinfo(req, chief.entity)
                    if not _metadata:
                        raise InvalidArgument('Metadata of %s.%d is none' % (_objtype, chief.entity))
                    if chief.objtype == _objtype:
                        chiefs[_objtype] = dict(entity=chief.entity,
                                                ports=ports,
                                                local_ip=_metadata.get('local_ip'))
            if len(chiefs) != 2:
                raise ValueError('%s.%d chiefs error' % (objtype, entity))

        target = targetutils.target_agent_by_string(metadata.get('agent_type'), metadata.get('host'))
        target.namespace = common.NAME
        rpc = get_client()
        finishtime, timeout = rpcfinishtime()
        if appfile:
            finishtime += 30
            timeout += 35
        rpc_ret = rpc.call(target, ctxt={'finishtime': finishtime, 'agents': [agent_id, ]},
                           msg={'method': 'reset_entity',
                                'args': dict(entity=entity, appfile=appfile,
                                             opentime=_entity.opentime,
                                             databases=databases, chiefs=chiefs)},
                           timeout=timeout)
        if not rpc_ret:
            raise RpcResultError('reset entity result is None')
        if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
            raise RpcResultError('reset entity fail %s' % rpc_ret.get('result'))
        return resultutils.results(result='reset entity %d success' % entity)
Example #14
0
 def swallow(self, req, entity, body=None):
     """合服内部接口,一般由agent调用
     用于新实体吞噬旧实体的区服和数据库"""
     body = body or {}
     entity = int(entity)
     uuid = body.get('uuid')
     if not uuid:
         raise InvalidArgument('Merger uuid is None')
     session = endpoint_session()
     query = model_query(session, MergeTask, filter=MergeTask.uuid == uuid)
     query = query.options(joinedload(MergeTask.entitys, innerjoin=False))
     glock = get_gamelock()
     rpc = get_client()
     with session.begin():
         etask = query.one_or_none()
         if not etask:
             raise InvalidArgument('Not task exit with %s' % uuid)
         # 新实体不匹配
         if etask.entity != body.get('entity'):
             raise InvalidArgument('New entity not %d' % etask.entity)
         # 找到目标实体
         appentity = None
         for _entity in etask.entitys:
             if _entity.entity == entity:
                 if _entity.status != common.MERGEING:
                     if _entity.status != common.SWALLOWING:
                         raise InvalidArgument(
                             'Swallow entity find status error')
                     if not _entity.databases or not _entity.areas:
                         raise InvalidArgument(
                             'Entity is swallowing but database or ares is None'
                         )
                     LOG.warning('Entit is swallowing, return saved data')
                     return resultutils.results(
                         result='swallow entity is success',
                         data=[
                             dict(databases=jsonutils.loads_as_bytes(
                                 _entity.databases),
                                  areas=jsonutils.loads_as_bytes(
                                      _entity.areas))
                         ])
                 _query = model_query(session,
                                      AppEntity,
                                      filter=AppEntity.entity == entity)
                 _query = _query.options(
                     joinedload(AppEntity.databases, innerjoin=False))
                 appentity = _query.one_or_none()
                 break
         if not appentity:
             raise InvalidArgument('Can not find app entity?')
         if appentity.objtype != common.GAMESERVER:
             raise InvalidArgument('objtype error, entity not %s' %
                                   common.GAMESERVER)
         if appentity.status != common.MERGEING:
             raise InvalidArgument('find status error, when swallowing')
         databases = self._database_to_dict(appentity)
         areas = [area.to_dict() for area in appentity.areas]
         if not databases or not areas:
             LOG.error('Entity no areas or databases record')
             return resultutils.results(
                 result='swallow entity fail, '
                 'target entity can not found database or areas',
                 resultcode=manager_common.RESULT_ERROR)
         with glock.grouplock(group=appentity.group_id):
             # 发送吞噬命令到目标区服agent
             metadata, ports = self._entityinfo(req=req, entity=entity)
             target = targetutils.target_agent_by_string(
                 metadata.get('agent_type'), metadata.get('host'))
             target.namespace = common.NAME
             rpc_ret = rpc.call(target,
                                ctxt={'agents': [
                                    appentity.agent_id,
                                ]},
                                msg={
                                    'method': 'swallow_entity',
                                    'args': dict(entity=entity)
                                })
             if not rpc_ret:
                 raise RpcResultError('swallow entity result is None')
             if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
                 raise RpcResultError('swallow entity fail %s' %
                                      rpc_ret.get('result'))
         # 修改实体在合服任务中的状态,存储areas以及databases
         appentity.status = common.SWALLOWING
         _entity.status = common.SWALLOWING
         _entity.areas = jsonutils.dumps(areas)
         _entity.databases = jsonutils.dumps(databases)
         session.flush()
         return resultutils.results(
             result='swallow entity is success',
             data=[dict(databases=databases, areas=areas)])
Example #15
0
    def migrate_with_out_data(endpoint,
                              entity,
                              new,
                              body=None,
                              drop_ports=True):
        session = get_session()
        glock = get_global().lock('entitys')

        with glock(endpoint, [
                entity,
        ]) as agents:
            with session.begin():
                _query = model_query(session,
                                     AgentEndpoint,
                                     filter=and_(
                                         AgentEndpoint.agent_id == new,
                                         AgentEndpoint.endpoint == endpoint))
                _endpoint = _query.one_or_none()
                if not _endpoint:
                    raise InvalidArgument(
                        'New agent not exist or has not endpoint %s' %
                        endpoint)
                query = model_query(session,
                                    AgentEntity,
                                    filter=and_(
                                        AgentEntity.endpoint == endpoint,
                                        AgentEntity.entity == entity))
                agent_id = agents.pop()
                metadata = BaseContorller.agent_metadata(agent_id)
                if not metadata:
                    raise InvalidArgument('Agent not online or not exist')
                _agent_entity = query.one()
                if _agent_entity.agent_id != agent_id:
                    raise CacheStoneError('Agent id not the same')
                if agent_id == new:
                    raise InvalidArgument('Migrate agent is the same')
                ports_query = model_query(
                    session,
                    AllocatedPort,
                    filter=and_(AllocatedPort.entity == entity,
                                AllocatedPort.agent_id == agent_id))
                if drop_ports:
                    ports_query.delete()
                    session.flush()
                else:
                    for port in ports_query:
                        port.agent_id = new
                        port.endpoint_id = _endpoint.id
                    try:
                        session.flush()
                    except DBDuplicateEntry:
                        LOG.error('Migrate port fail, port duplicate')
                        raise InvalidArgument('Port duplicate')

                _agent_entity.agent_id = new
                _agent_entity.endpoint_id = _endpoint.id
                session.flush()

                target = targetutils.target_agent_by_string(
                    metadata.get('agent_type'), metadata.get('host'))
                target.namespace = endpoint
                LOG.debug(
                    'Migrate process call notify delete to source server')
                delete_result = EntityReuest.notify_delete(
                    target, agent_id, entity, body)
                if not delete_result:
                    raise RpcResultError('delete entitys result is None')
                if delete_result.get(
                        'resultcode') != manager_common.RESULT_SUCCESS:
                    raise RpcResultError('delete entity fail %s' %
                                         delete_result.get('result'))
                LOG.info('Migrate process call notify delete success')
            yield
Example #16
0
 def delete(self, req, group_id, objtype, entity, body=None):
     """标记删除entity"""
     body = body or {}
     force = body.get('force', False)
     group_id = int(group_id)
     entity = int(entity)
     session = endpoint_session()
     glock = get_gamelock()
     metadata, ports = self._entityinfo(req=req, entity=entity)
     if not metadata:
         raise InvalidArgument('Agent offline, can not delete entity')
     query = model_query(session,
                         AppEntity,
                         filter=AppEntity.entity == entity)
     if objtype == common.GAMESERVER:
         query = query.options(joinedload(AppEntity.areas, innerjoin=False))
     _entity = query.one()
     if _entity.status == common.DELETED:
         return resultutils.results(result='mark %s entity delete success' %
                                    objtype,
                                    data=[
                                        dict(entity=entity,
                                             objtype=objtype,
                                             ports=ports,
                                             metadata=metadata)
                                    ])
     if _entity.objtype != objtype:
         raise InvalidArgument('Objtype not match')
     if _entity.group_id != group_id:
         raise InvalidArgument('Group id not match')
     target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                 metadata.get('host'))
     target.namespace = common.NAME
     rpc = get_client()
     with glock.grouplock(group=group_id):
         if objtype == common.GMSERVER:
             if model_count_with_key(
                     session, AppEntity, filter=AppEntity.group_id
                     == group_id) > 1:
                 raise InvalidArgument(
                     'You must delete other objtype entity before delete gm'
                 )
             if model_count_with_key(
                     session, Package, filter=Package.group_id
                     == group_id) > 1:
                 raise InvalidArgument(
                     'You must delete other Package before delete gm')
         elif objtype == common.CROSSSERVER:
             if model_count_with_key(
                     session,
                     AppEntity,
                     filter=AppEntity.cross_id == _entity.entity):
                 raise InvalidArgument('Cross server are reflected')
         with session.begin():
             # 确认实体没有运行
             rpc_ret = rpc.call(target,
                                ctxt={'agents': [
                                    _entity.agent_id,
                                ]},
                                msg={
                                    'method': 'stoped',
                                    'args': dict(entity=entity)
                                })
             if not rpc_ret:
                 raise RpcResultError('check entity stoped result is None')
             if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
                 raise RpcResultError('check entity fail %s' %
                                      rpc_ret.get('result'))
             _entity.status = common.DELETED
             session.flush()
             if objtype == common.GAMESERVER:
                 # 删除所有资源版本引用
                 if _entity.versions:
                     for quote in six.itervalues(
                             jsonutils.loads_as_bytes(_entity.versions)):
                         threadpool.add_thread(cdnquote_controller.delete,
                                               req, quote.get('quote_id'))
                 _entity.versions = None
                 session.flush()
                 if _entity.areas:
                     if len(_entity.areas) > 1:
                         raise InvalidArgument('%s areas more then one' %
                                               objtype)
                     area = _entity.areas[0]
                     if not force:
                         if _entity.entity != model_max_with_key(
                                 session,
                                 AppEntity.entity,
                                 filter=and_(
                                     AppEntity.objtype == common.GAMESERVER,
                                     AppEntity.group_id == group_id)):
                             raise InvalidArgument(
                                 'entity %d is not the last gamesvr entity in group'
                                 % entity)
                     session.flush()
                     session.delete(area)
                     session.flush()
                     _query = model_query(
                         session,
                         PackageArea,
                         filter=PackageArea.area_id == area.area_id)
                     _query.delete()
                     session.flush()
             rpc.cast(target,
                      ctxt={'agents': [
                          _entity.agent_id,
                      ]},
                      msg={
                          'method': 'change_status',
                          'args': dict(entity=entity, status=common.DELETED)
                      })
     return resultutils.results(result='mark %s entity delete success' %
                                objtype,
                                data=[
                                    dict(entity=entity,
                                         objtype=objtype,
                                         ports=ports,
                                         metadata=metadata)
                                ])
Example #17
0
    def clean(self, req, group_id, objtype, entity, body=None):
        """彻底删除entity"""
        body = body or {}
        action = body.pop('clean', 'unquote')
        force = False
        ignores = body.pop('ignores', [])
        if action not in ('delete', 'unquote', 'force'):
            raise InvalidArgument('clean option value error')
        if action == 'force':
            action = 'delete'
            force = True
        group_id = int(group_id)
        entity = int(entity)
        session = endpoint_session()
        glock = get_gamelock()
        metadata, ports = self._entityinfo(req=req, entity=entity)
        if not metadata:
            raise InvalidArgument('Agent offline, can not delete entity')
        query = model_query(session, AppEntity, filter=AppEntity.entity == entity)
        query = query.options(joinedload(AppEntity.databases, innerjoin=False))
        _entity = query.one()

        rollbacks = []

        def _rollback():
            for back in rollbacks:
                __database_id = back.get('database_id')
                __schema = back.get('schema')
                __quote_id = back.get('quote_id')
                rbody = dict(quote_id=__quote_id, entity=entity)
                rbody.setdefault(dbcommon.ENDPOINTKEY, common.NAME)
                try:
                    schema_controller.bond(req, database_id=__database_id, schema=__schema, body=rbody)
                except Exception:
                    LOG.error('rollback entity %d quote %d.%s.%d fail' %
                              (entity, __database_id, schema, __quote_id))

        with glock.grouplock(group=group_id):
            target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                        metadata.get('host'))
            target.namespace = common.NAME
            rpc = get_client()
            finishtime, timeout = rpcfinishtime()
            LOG.warning('Clean entity %s.%d with action %s' % (objtype, entity, action))
            with session.begin():
                rpc_ret = rpc.call(target, ctxt={'finishtime': finishtime},
                                   msg={'method': 'stoped', 'args': dict(entity=entity)})
            if not rpc_ret:
                raise RpcResultError('check entity is stoped result is None')
            if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
                raise RpcResultError('check entity is stoped fail, running')

            with session.begin():
                if _entity.status != common.DELETED:
                    raise InvalidArgument('Entity status is not DELETED, '
                                          'mark status to DELETED before delete it')
                if _entity.objtype != objtype:
                    raise InvalidArgument('Objtype not match')
                if _entity.group_id != group_id:
                    raise InvalidArgument('Group id not match')
                # esure database delete
                if action == 'delete':
                    LOG.warning('Clean option is delete, can not rollback when fail')
                    if not force:
                        for _database in _entity.databases:
                            schema = '%s_%s_%s_%d' % (common.NAME, objtype, _database.subtype, entity)
                            schema_info = schema_controller.show(req=req, database_id=_database.database_id,
                                                                 schema=schema,
                                                                 body={'quotes': True})['data'][0]
                            quotes = {}
                            for _quote in schema_info['quotes']:
                                quotes[_quote.get('quote_id')] = _quote.get('desc')
                            if _database.quote_id not in quotes.keys():
                                # if set(quotes) != set([_database.quote_id]):
                                result = 'delete %s:%d fail' % (objtype, entity)
                                reason = ': database [%d].%s quote: %s' % (_database.database_id, schema, str(quotes))
                                return resultutils.results(result=(result + reason),
                                                           resultcode=manager_common.RESULT_ERROR)
                            quotes.pop(_database.quote_id)
                            for quote_id in quotes.keys():
                                if quotes[quote_id] in ignores:
                                    quotes.pop(quote_id, None)
                            if quotes:
                                if LOG.isEnabledFor(logging.DEBUG):
                                    LOG.debug('quotes not match for %d: %s' % (schema_info['schema_id'],
                                                                               schema))
                                    for quote_id in quotes.keys():
                                        LOG.debug('quote %d: %s exist' % (quote_id, quotes[quote_id]))
                                    LOG.debug('Can not delete schema before delete quotes')
                                return resultutils.results(result='Quotes not match',
                                                           resultcode=manager_common.RESULT_ERROR)
                            LOG.info('Databae quotes check success for %s' % schema)
                # clean database
                for _database in _entity.databases:
                    schema = '%s_%s_%s_%d' % (common.NAME, objtype, _database.subtype, entity)
                    if action == 'delete':
                        LOG.warning('Delete schema %s from %d' % (schema, _database.database_id))
                        try:
                            schema_controller.delete(req=req, database_id=_database.database_id,
                                                     schema=schema, body={'unquotes': [_database.quote_id],
                                                                          'ignores': ignores, 'force': force})
                        except GopdbError as e:
                            LOG.error('Delete schema:%s from %d fail, %s' % (schema, _database.database_id,
                                                                             e.message))
                            if not force:
                                raise e
                        except Exception:
                            LOG.exception('Delete schema:%s from %d fail' % (schema, _database.database_id))
                            if not force:
                                raise
                    elif action == 'unquote':
                        LOG.info('Try unquote %d' % _database.quote_id)
                        try:
                            quote = schema_controller.unquote(req=req, quote_id=_database.quote_id)['data'][0]
                            if quote.get('database_id') != _database.database_id:
                                LOG.critical('quote %d with database %d, not %d' % (_database.quote_id,
                                                                                    quote.get('database_id'),
                                                                                    _database.database_id))
                                raise RuntimeError('Data error, quote database not the same')
                            rollbacks.append(dict(database_id=_database.database_id,
                                                  quote_id=_database.quote_id, schema=schema))
                        except Exception as e:
                            LOG.error('Unquote %d fail, try rollback' % _database.quote_id)
                            if not force:
                                threadpool.add_thread(_rollback)
                                raise e
                token = uuidutils.generate_uuid()
                LOG.info('Send delete command with token %s' % token)
                session.delete(_entity)
                session.flush()
                try:
                    entity_controller.delete(req, common.NAME, entity=entity, body=dict(token=token))
                except Exception as e:
                    # roll back unquote
                    threadpool.add_thread(_rollback)
                    raise e
        return resultutils.results(result='delete %s:%d success' % (objtype, entity),
                                   data=[dict(entity=entity, objtype=objtype,
                                              ports=ports, metadata=metadata)])
Example #18
0
    def swallowed(self, req, entity, body=None):
        """
        合服内部接口,一般由agent调用
        用于新实体吞噬旧实体的区服完成后调用
        调用后将设置appentity为deleted状态
        """
        body = body or {}
        entity = int(entity)
        uuid = body.get('uuid')
        if not uuid:
            raise InvalidArgument('Merger uuid is None')
        session = endpoint_session()
        query = model_query(session, MergeTask, filter=MergeTask.uuid == uuid)
        query = query.options(joinedload(MergeTask.entitys, innerjoin=False))
        glock = get_gamelock()
        rpc = get_client()
        appentity = None
        with session.begin():
            etask = query.one_or_none()
            if not etask:
                raise InvalidArgument('Not task exit with %s' % uuid)
            # 新实体不匹配
            if etask.entity != body.get('entity'):
                raise InvalidArgument('New entity not %d' % etask.entity)
            for _entity in etask.entitys:
                if _entity.entity == entity:
                    if _entity.status != common.SWALLOWING:
                        raise InvalidArgument(
                            'Swallowed entity find status error')
                    _query = model_query(session,
                                         AppEntity,
                                         filter=AppEntity.entity == entity)
                    _query = _query.options(
                        joinedload(AppEntity.databases, innerjoin=False))
                    appentity = _query.one_or_none()
                    break
            if not appentity:
                raise InvalidArgument('Can not find app entity?')
            if appentity.objtype != common.GAMESERVER:
                raise InvalidArgument('objtype error, entity not %s' %
                                      common.GAMESERVER)
            if appentity.status != common.SWALLOWING:
                raise InvalidArgument('find status error, when swallowed')

            with glock.grouplock(group=appentity.group_id):
                # 发送吞噬完成命令到目标区服agent
                metadata, ports = self._entityinfo(req=req, entity=entity)
                target = targetutils.target_agent_by_string(
                    metadata.get('agent_type'), metadata.get('host'))
                target.namespace = common.NAME
                rpc_ret = rpc.call(target,
                                   ctxt={'agents': [
                                       appentity.agent_id,
                                   ]},
                                   msg={
                                       'method': 'swallowed_entity',
                                       'args': dict(entity=entity)
                                   })
                if not rpc_ret:
                    raise RpcResultError('swallowed entity result is None')
                if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
                    raise RpcResultError('swallowed entity fail %s' %
                                         rpc_ret.get('result'))
            # appentity状态修改为deleted
            appentity.status = common.DELETED
            # 修改实体在合服任务中的状态
            _entity.status = common.MERGEED
            session.flush()
            # area绑定新实体
            _query = model_query(session,
                                 GameArea,
                                 filter=GameArea.entity == entity)
            _query.update({'entity': etask.entity})
            session.flush()

        def _unquote():
            LOG.info('Swallowed %d finish, try unquote database' %
                     appentity.entity)
            for database in appentity.databases:
                try:
                    schema_controller.unquote(req, quote_id=database.quote_id)
                except Exception:
                    LOG.error('Delete database quote fail')

        eventlet.spawn_n(_unquote)

        return resultutils.results(
            result='swallowed entity is success',
            data=[
                dict(databases=jsonutils.loads_as_bytes(_entity.databases),
                     areas=jsonutils.loads_as_bytes(_entity.areas))
            ])
Example #19
0
 def area(self, req, group_id, body=None):
     """change entity area"""
     body = body or {}
     try:
         group_id = int(group_id)
     except (TypeError, ValueError):
         raise InvalidArgument('Group id value error')
     area_id = body.get('area_id')
     areaname = body.get('areaname')
     show_id = body.get('show_id')
     if not areaname and not show_id:
         raise InvalidArgument('No value change')
     rpc = get_client()
     session = endpoint_session()
     query = model_query(session,
                         GameArea,
                         filter=GameArea.area_id == area_id)
     with session.begin():
         area = query.one_or_none()
         if not area:
             raise InvalidArgument('No area found')
         if area.group_id != group_id:
             raise InvalidArgument('Area group not %d' % group_id)
         entityinfo = entity_controller.show(req=req,
                                             entity=area.entity,
                                             endpoint=common.NAME,
                                             body={'ports':
                                                   False})['data'][0]
         agent_id = entityinfo['agent_id']
         metadata = entityinfo['metadata']
         if not metadata:
             raise InvalidArgument(
                 'Agent is off line, can not reset entity')
         if areaname:
             if model_count_with_key(session,
                                     GameArea,
                                     filter=and_(
                                         GameArea.group_id == group_id,
                                         GameArea.areaname == areaname)):
                 raise InvalidArgument('Area name duplicate in group %d' %
                                       group_id)
             area.areaname = areaname
         if show_id:
             area.show_id = show_id
         target = targetutils.target_agent_by_string(
             metadata.get('agent_type'), metadata.get('host'))
         target.namespace = common.NAME
         finishtime, timeout = rpcfinishtime()
         rpc_ret = rpc.call(target,
                            ctxt={
                                'finishtime': finishtime,
                                'agents': [
                                    agent_id,
                                ]
                            },
                            msg={
                                'method':
                                'change_entity_area',
                                'args':
                                dict(entity=area.entity,
                                     area_id=area.area_id,
                                     show_id=area.show_id,
                                     areaname=area.areaname)
                            },
                            timeout=timeout)
         if not rpc_ret:
             raise RpcResultError('change entity area result is None')
         if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('change entity area fail %s' %
                                  rpc_ret.get('result'))
         session.flush()
     return resultutils.results(result='change group areas success')
Example #20
0
 def update(self, req, group_id, objtype, entity, body=None):
     body = body or {}
     group_id = int(group_id)
     entity = int(entity)
     status = body.get('status', common.OK)
     if status not in (common.UNACTIVE, common.OK):
         raise InvalidArgument('Status not in 0, 1, 2')
     session = endpoint_session()
     glock = get_gamelock()
     query = model_query(session,
                         AppEntity,
                         filter=AppEntity.entity == entity)
     if objtype == common.GAMESERVER:
         query = query.options(joinedload(AppEntity.areas, innerjoin=False))
     _entity = query.one()
     if status == _entity.status:
         return resultutils.results(result='%s entity status in same' %
                                    objtype)
     if _entity.status not in (common.OK, common.UNACTIVE):
         return resultutils.results(
             resultcode=manager_common.RESULT_ERROR,
             result='%s entity is not ok or unactive' % objtype)
     if _entity.objtype != objtype:
         raise InvalidArgument('Objtype not match')
     if _entity.group_id != group_id:
         raise InvalidArgument('Group id not match')
     entityinfo = entity_controller.show(req=req,
                                         entity=entity,
                                         endpoint=common.NAME,
                                         body={'ports': False})['data'][0]
     agent_id = entityinfo['agent_id']
     metadata = entityinfo['metadata']
     if not metadata:
         raise InvalidArgument('Agent is off line, can not reset entity')
     rpc = get_client()
     target = targetutils.target_agent_by_string(metadata.get('agent_type'),
                                                 metadata.get('host'))
     target.namespace = common.NAME
     if objtype == common.GAMESERVER:
         lock = functools.partial(
             glock.arealock,
             group=group_id,
             areas=[area.area_id for area in _entity.areas])
     else:
         lock = functools.partial(glock.grouplock, group=group_id)
     with lock():
         with session.begin():
             _entity.status = status
             session.flush()
             finishtime, timeout = rpcfinishtime()
             rpc_ret = rpc.call(target,
                                ctxt={
                                    'finishtime': finishtime,
                                    'agents': [
                                        agent_id,
                                    ]
                                },
                                msg={
                                    'method': 'change_status',
                                    'args': dict(entity=entity,
                                                 status=status)
                                },
                                timeout=timeout)
             if not rpc_ret:
                 raise RpcResultError('change entity sttus result is None')
             if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
                 raise RpcResultError('change entity status fail %s' %
                                      rpc_ret.get('result'))
     return resultutils.results(result='%s entity update success' % objtype)