Example #1
0
 def delete(self, req, agent_id, body=None):
     """call buy agent"""
     # if force is true
     # will not notify agent, just delete agent from database
     body = body or {}
     force = body.get('force', False)
     rpc = get_client()
     global_data = get_global()
     metadata = None
     with global_data.delete_agent(agent_id) as agent:
         if not force:
             metadata = BaseContorller.agent_metadata(agent.agent_id)
             if metadata is None:
                 raise RpcPrepareError('Can not delete offline agent, try force')
             agent_ipaddr = metadata.get('local_ip')
             secret = uuidutils.generate_uuid()
             # tell agent wait delete
             finishtime, timeout = rpcfinishtime()
             delete_agent_precommit = rpc.call(targetutils.target_agent(agent),
                                               ctxt={'finishtime': finishtime},
                                               msg={'method': 'delete_agent_precommit',
                                                    'args': {'agent_id': agent.agent_id,
                                                             'agent_type': agent.agent_type,
                                                             'host': agent.host,
                                                             'agent_ipaddr': agent_ipaddr,
                                                             'secret': secret}
                                                    }, timeout=timeout)
             if not delete_agent_precommit:
                 raise RpcResultError('delete_agent_precommit result is None')
             if delete_agent_precommit.get('resultcode') != manager_common.RESULT_SUCCESS:
                 return resultutils.results(result=delete_agent_precommit.get('result'),
                                            resultcode=manager_common.RESULT_ERROR)
     # if not force:
             # tell agent delete itself
             finishtime = rpcfinishtime()[0]
             LOG.info('Delete agent %s postcommit with secret %s' % (agent_ipaddr, secret))
             rpc.cast(targetutils.target_agent(agent),
                      ctxt={'finishtime': finishtime},
                      msg={'method': 'delete_agent_postcommit',
                           'args': {'agent_id': agent.agent_id,
                                    'agent_type': agent.agent_type,
                                    'host': agent.host,
                                    'agent_ipaddr': agent_ipaddr,
                                    'secret': secret}})
     def wapper():
         rpc.cast(targetutils.target_rpcserver(fanout=True),
                  msg={'method': 'deletesource',
                       'args': {'agent_id': agent_id}})
     threadpool.add_thread(safe_func_wrapper, wapper, LOG)
     result = resultutils.results(result='Delete agent success',
                                  data=[dict(agent_id=agent.agent_id,
                                             host=agent.host,
                                             status=agent.status,
                                             metadata=metadata,
                                             ports_range=jsonutils.safe_loads_as_bytes(agent.ports_range) or [])
                                        ])
     return result
Example #2
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 #3
0
 def notify_create(target, agent_id, entity, body, action='create'):
     rpc = get_client()
     body.setdefault('entity', entity)
     finishtime = body.pop('finishtime', None)
     if finishtime is None:
         finishtime, timeout = rpcfinishtime()
     else:
         timeout = finishtime - int(time.time()) + 1
     if timeout < 3:
         raise InvalidArgument('Timeout less then 3')
     create_ret = rpc.call(target,
                           ctxt={
                               'finishtime': finishtime,
                               'agents': [
                                   agent_id,
                               ],
                               'entitys': [
                                   entity,
                               ]
                           },
                           msg={
                               'method': '%s_entity' % action,
                               'args': body
                           },
                           timeout=timeout)
     return create_ret
Example #4
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 #5
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 #6
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 #7
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 #8
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 #9
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 #10
0
 def create_asyncrequest(body):
     """async request use this to create a new request
     argv in body
     request_time:  unix time in seconds that client send async request
     finishtime:  unix time in seconds that work shoud be finished after this time
     deadline:  unix time in seconds that work will igonre after this time
     expire: respone expire time
     """
     request_time = int(timeutils.realnow())
     expire = body.pop('expire', 0)
     if expire < 0:
         raise InvalidArgument('Async argv expire less thne 0')
     try:
         client_request_time = int(body.pop('request_time'))
     except KeyError:
         raise InvalidArgument('Async request need argument request_time')
     except TypeError:
         raise InvalidArgument(
             'request_time is not int of time or no request_time found')
     offset_time = request_time - client_request_time
     if abs(offset_time) > 5:
         raise InvalidArgument(
             'The offset time between send and receive is %d' % offset_time)
     finishtime = body.pop('finishtime', None)
     if finishtime:
         finishtime = int(finishtime) + offset_time
     else:
         finishtime = rpcfinishtime(request_time)[0]
     if finishtime - request_time < 3:
         raise InvalidArgument('Job can not be finished in 3 second')
     deadline = body.pop('deadline', None)
     if deadline:
         deadline = int(deadline) + offset_time - 1
     else:
         # deadline = rpcdeadline(finishtime)
         deadline = finishtime + 5
     if deadline - finishtime < 3:
         raise InvalidArgument(
             'Job deadline must at least 3 second after finishtime')
     request_id = uuidutils.generate_uuid()
     # req.environ[manager_common.ENV_REQUEST_ID] = request_id
     new_request = AsyncRequest(request_id=request_id,
                                request_time=request_time,
                                finishtime=finishtime,
                                deadline=deadline,
                                expire=expire)
     return new_request
Example #11
0
    def stop(self, req, group_id, objtype, entity, body=None):
        """
        kill 强制关闭
        notify 通过gm服务器通知区服关闭
        """
        body = body or {}
        kill = body.get('kill', False)
        notify = body.pop('notify', False)
        if objtype == common.GAMESERVER and notify and not kill:
            message = body.pop('message', '') or ''
            delay = body.pop('delay', 3)
            if delay:
                if not isinstance(delay, (int, long)) or delay < 3:
                    raise InvalidArgument('Delay value error')
                delay = min(delay, 60)
                finishtime = rpcfinishtime()[0] + delay + 5
                body.update({'finishtime': finishtime, 'delay': delay + 5})
            url = gmurl(req, group_id, interface='closegameserver')

            @contextlib.contextmanager
            def context(reqeust_id, entitys, agents):
                pre_run = {
                    'executer': 'http',
                    'ekwargs': {
                        'url':
                        url,
                        'method':
                        'POST',
                        'async':
                        False,
                        'json':
                        OrderedDict(RealSvrIds=list(entitys),
                                    Msg=message,
                                    DelayTime=delay)
                    }
                }
                body.update({'pre_run': pre_run})
                yield

        else:
            context = None
            body.pop('delay', None)

        return self._async_bluck_rpc('stop', group_id, objtype, entity, body,
                                     context)
Example #12
0
 def notify_delete(target, agent_id, entity, body, action='delete'):
     rpc = get_client()
     body.setdefault('entity', entity)
     token = body.get('token')
     finishtime = body.pop('finishtime', None)
     if finishtime is None:
         finishtime, timeout = rpcfinishtime()
     else:
         timeout = finishtime - int(time.time()) + 1
     if timeout < 3:
         raise InvalidArgument('Timeout less then 3')
     if token:
         # send a delete token
         rpc.cast(target,
                  ctxt={
                      'finishtime': finishtime,
                      'entitys': [
                          entity,
                      ]
                  },
                  msg={
                      'method': 'entity_token',
                      'args': {
                          'entity': entity,
                          'token': token
                      }
                  })
     delete_ret = rpc.call(target,
                           ctxt={
                               'finishtime': finishtime,
                               'agents': [
                                   agent_id,
                               ],
                               'entitys': [
                                   entity,
                               ]
                           },
                           msg={
                               'method': '%s_entity' % action,
                               'args': body
                           },
                           timeout=timeout)
     return delete_ret
Example #13
0
    def readlog(self, req, agent_id, body=None):
        """call by agent"""
        body = body or {}
        lines = body.get('lines', 10)
        rpc = get_client()
        metadata = BaseContorller.agent_metadata(agent_id)
        if metadata is None:
            raise RpcPrepareError('Can not get log from offline agent: %d' % agent_id)

        session = get_session()
        query = model_query(session, Agent, filter=Agent.agent_id == agent_id)
        agent = query.one()
        rpc_ret = rpc.call(targetutils.target_agent(agent),
                           ctxt={'finishtime': rpcfinishtime()[0]},
                           msg={'method': 'readlog', 'args': {'lines': lines}})
        if not rpc_ret:
            raise RpcResultError('Get log agent rpc result is None')
        if rpc_ret.get('resultcode') != manager_common.RESULT_SUCCESS:
            raise RpcResultError('Get log agent rpc result: ' + rpc_ret.get('result'))
        return resultutils.results(result=rpc_ret.get('result'), data=[rpc_ret.get('uri')])
Example #14
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 #15
0
 def active(self, req, agent_id, body=None):
     """call buy client"""
     body = body or {}
     status = body.get('status', manager_common.ACTIVE)
     if status not in (manager_common.ACTIVE, manager_common.UNACTIVE):
         raise InvalidArgument('Argument status not right')
     rpc = get_client()
     session = get_session()
     query = model_query(session, Agent,
                         filter=and_(Agent.agent_id == agent_id,
                                     Agent.status > manager_common.DELETED))
     agent = query.one()
     # make sure agent is online
     metadata = BaseContorller.agent_metadata(agent.agent_id)
     if metadata is None:
         raise RpcPrepareError('Can not active or unactive a offline agent: %d' % agent_id)
     agent_ipaddr = metadata.get('local_ip')
     with session.begin():
         agent.update({'status': status})
         active_agent = rpc.call(targetutils.target_agent(agent),
                                 ctxt={'finishtime': rpcfinishtime()[0]},
                                 msg={'method': 'active_agent',
                                      'args': {'agent_id': agent_id,
                                               'agent_ipaddr': agent_ipaddr,
                                               'status': status}
                                      })
         if not active_agent:
             raise RpcResultError('Active agent rpc result is None')
         if active_agent.pop('resultcode') != manager_common.RESULT_SUCCESS:
             raise RpcResultError('Call agent active or unactive fail: ' + active_agent.get('result'))
         result = resultutils.results(result=active_agent.pop('result'),
                                      data=[dict(agent_id=agent.agent_id,
                                                 host=agent.host,
                                                 agent_type=agent.agent_type,
                                                 metadata=metadata,
                                                 status=agent.status)
                                            ])
         return result
Example #16
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 #17
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 #18
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)
Example #19
0
    def create(self, req, group_id, objtype, body=None):
        body = body or {}
        group_id = int(group_id)
        jsonutils.schema_validate(body, self.CREATEAPPENTITY)
        if body.get('packages'):
            raise InvalidArgument('Package parameter is removed')
        # 找cross服务, gameserver专用
        cross_id = body.pop('cross_id', None)
        # 开服时间, gameserver专用
        opentime = body.pop('opentime', None)
        # 区服显示id, gameserver专用
        show_id = body.pop('show_id', None)
        # 区服显示民称, gameserver专用
        areaname = body.pop('areaname', None)
        # 平台类型
        platform = body.get('platform')

        include = set(body.pop('include', []))
        exclude = set(body.pop('exclude', []))
        if include and exclude:
            raise InvalidArgument('Both packages and exclude is forbidden')
        packages = []

        session = endpoint_session()
        if objtype == common.GAMESERVER:
            platform = common.PlatformTypeMap.get(platform)
            if not areaname or not opentime or not platform or not show_id:
                raise InvalidArgument(
                    '%s need opentime and areaname and platform and show_id' %
                    objtype)
        # 安装文件信息
        appfile = body.pop(common.APPFILE)
        LOG.debug('Try find agent and database for entity')
        # 选择实例运行服务器
        agent_id = body.get('agent_id') or self._agentselect(
            req, objtype, **body)
        # 选择实例运行数据库
        databases = self._dbselect(req, objtype, **body)
        # 校验数据库信息
        if not self._validate_databases(objtype, databases):
            raise InvalidArgument('Miss some database')
        LOG.info(
            'Find agent and database for entity success, to agent %d, to databse %s'
            % (agent_id, str(databases)))
        query = model_query(session, Group, filter=Group.group_id == group_id)
        joins = joinedload(Group.entitys, innerjoin=False)
        joins = joins.joinedload(AppEntity.databases, innerjoin=False)
        query = query.options(joins)
        _group = query.one()
        glock = get_gamelock()
        with glock.grouplock(group_id):
            if objtype == common.GAMESERVER:
                _pquery = model_query(session,
                                      Package,
                                      filter=Package.group_id == group_id)
                _packages = set([
                    p.package_id for p in _pquery.all()
                    if p.platform & platform
                ])

                if (include - _packages) or (exclude - _packages):
                    raise InvalidArgument(
                        'Package can not be found in include or exclude')
                if exclude:
                    packages = _packages - exclude
                elif include:
                    packages = include
                else:
                    packages = _packages

            typemap = {}
            for _entity in _group.entitys:
                # 跳过未激活的实体
                if _entity.status != common.OK:
                    continue
                try:
                    typemap[_entity.objtype].append(_entity)
                except KeyError:
                    typemap[_entity.objtype] = [
                        _entity,
                    ]
            # 前置实体
            chiefs = None
            # 相同类型的实例列表
            same_type_entitys = typemap.get(objtype, [])
            if objtype == common.GMSERVER:
                # GM服务不允许相同实例,必须clean掉所有同组GM服务器
                for _entity in _group.entitys:
                    if _entity.objtype == common.GMSERVER:
                        return resultutils.results(
                            result='create entity fail, %s duplicate in group'
                            % objtype,
                            resultcode=manager_common.RESULT_ERROR)
            else:
                # 非gm实体添加需要先找到同组的gm
                try:
                    gm = typemap[common.GMSERVER][0]
                    if gm.status <= common.DELETED:
                        return resultutils.results(
                            result='Create entity fail, gm mark deleted',
                            resultcode=manager_common.RESULT_ERROR)
                except KeyError as e:
                    return resultutils.results(
                        result='Create entity fail, can not find GMSERVER: %s'
                        % e.message,
                        resultcode=manager_common.RESULT_ERROR)
                if objtype == common.GAMESERVER:

                    if model_count_with_key(
                            session,
                            GameArea,
                            filter=and_(GameArea.group_id == group_id,
                                        GameArea.areaname == areaname)):
                        return resultutils.results(
                            result='Create entity fail, name exist',
                            resultcode=manager_common.RESULT_ERROR)
                    cross = None
                    # 游戏服务器需要在同组中找到cross实例
                    try:
                        crossservers = typemap[common.CROSSSERVER]
                    except KeyError as e:
                        return resultutils.results(
                            result=
                            'create entity fail, can not find my chief: %s' %
                            e.message,
                            resultcode=manager_common.RESULT_ERROR)
                    # 如果指定了cross实例id
                    if cross_id:
                        # 判断cross实例id是否在当前组中
                        for _cross in crossservers:
                            if cross_id == _cross.entity:
                                cross = _cross
                                break
                    else:
                        # 游戏服没有相同实例,直接使用第一个cross实例
                        if not same_type_entitys:
                            cross = crossservers[0]
                        else:
                            # 统计所有cross实例的引用次数
                            counted = set()
                            counter = dict()
                            for _cross in crossservers:
                                counter.setdefault(_cross.entity, 0)
                            # 查询当前组内所有entity对应的cross_id
                            for _entity in _group.entitys:
                                if _entity.objtype != common.GAMESERVER:
                                    continue
                                if _entity.cross_id in counted:
                                    continue
                                counter[_entity.cross_id] += 1
                            # 选取引用次数最少的cross_id
                            cross_id = sorted(
                                zip(counter.itervalues(),
                                    counter.iterkeys()))[0][1]
                            for _cross in crossservers:
                                if cross_id == _cross.entity:
                                    cross = _cross
                                    break
                    if not cross:
                        raise InvalidArgument(
                            'cross server can not be found or not active')
                    # 获取实体相关服务器信息(端口/ip)
                    maps = entity_controller.shows(
                        endpoint=common.NAME,
                        entitys=[gm.entity, cross.entity])
                    for v in six.itervalues(maps):
                        if v is None:
                            raise InvalidArgument(
                                'Get chiefs info error, agent not online?')
                    chiefs = dict()
                    # 战场与GM服务器信息
                    for chief in (cross, gm):
                        chiefmetadata = maps.get(chief.entity).get('metadata')
                        ports = maps.get(chief.entity).get('ports')
                        if not chiefmetadata:
                            raise InvalidArgument(
                                '%s.%d is offline' %
                                (chief.objtype, chief.entity))
                        need = common.POSTS_COUNT[chief.objtype]
                        if need and len(ports) != need:
                            raise InvalidArgument('%s.%d port count error, '
                                                  'find %d, need %d' %
                                                  (chief.objtype, chief.entity,
                                                   len(ports), need))
                        chiefs.setdefault(
                            chief.objtype,
                            dict(entity=chief.entity,
                                 ports=ports,
                                 local_ip=chiefmetadata.get('local_ip')))
                    cross_id = cross.entity
            # 完整的rpc数据包
            create_body = dict(objtype=objtype,
                               appfile=appfile,
                               databases=databases,
                               chiefs=chiefs,
                               entity=int(body.get('entity', 0)))

            with session.begin():
                body.setdefault('finishtime', rpcfinishtime()[0] + 5)
                try:
                    create_result = entity_controller.create(
                        req=req,
                        agent_id=agent_id,
                        endpoint=common.NAME,
                        body=create_body)['data'][0]
                except RpcResultError as e:
                    LOG.error('Create entity rpc call fail: %s' % e.message)
                    raise InvalidArgument(e.message)
                entity = create_result.get('entity')
                rpc_result = create_result.get('notify')
                LOG.info('Create new entity %d' % entity)
                LOG.debug('Entity controller create rpc result %s',
                          str(rpc_result))
                # 插入实体信息
                appentity = AppEntity(entity=entity,
                                      agent_id=agent_id,
                                      group_id=group_id,
                                      objtype=objtype,
                                      cross_id=cross_id,
                                      opentime=opentime,
                                      platform=platform)
                session.add(appentity)
                session.flush()
                if objtype == common.GAMESERVER:
                    areaname = areaname.decode('utf-8') if isinstance(
                        areaname, six.binary_type) else areaname
                    gamearea = GameArea(group_id=_group.group_id,
                                        show_id=show_id,
                                        areaname=areaname,
                                        gid=None,
                                        entity=appentity.entity)
                    session.add(gamearea)
                    session.flush()
                    # area id插入渠道包包含列表中,批量操作
                    if packages:
                        for package_id in packages:
                            session.add(
                                PackageArea(package_id=package_id,
                                            area_id=gamearea.area_id))
                            session.flush()
                # 插入数据库绑定信息
                if rpc_result.get('databases'):
                    self._bondto(session, entity, rpc_result.get('databases'))
                else:
                    LOG.error('New entity database miss')

            _result = dict(entity=entity,
                           objtype=objtype,
                           agent_id=agent_id,
                           connection=rpc_result.get('connection'),
                           ports=rpc_result.get('ports'),
                           databases=rpc_result.get('databases'))

            areas = []
            if objtype == common.GAMESERVER:
                areas = [
                    dict(area_id=gamearea.area_id,
                         gid=0,
                         areaname=areaname,
                         show_id=show_id)
                ]
                _result.setdefault('areas', areas)
                _result.setdefault('cross_id', cross_id)
                _result.setdefault('opentime', opentime)
                _result.setdefault('platform', platform)
                _result.setdefault('packages', sorted(packages))

        # 添加端口
        # threadpool.add_thread(port_controller.unsafe_create,
        #                       agent_id, common.NAME, entity, rpc_result.get('ports'))
        port_controller.unsafe_create(agent_id, common.NAME, entity,
                                      rpc_result.get('ports'))
        # agent 后续通知
        threadpool.add_thread(entity_controller.post_create_entity,
                              entity,
                              common.NAME,
                              objtype=objtype,
                              status=common.UNACTIVE,
                              opentime=opentime,
                              group_id=group_id,
                              areas=areas)
        return resultutils.results(result='create %s entity success' % objtype,
                                   data=[
                                       _result,
                                   ])
Example #20
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 #21
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 #22
0
    def merge(self, req, body=None):
        """合服接口,用于合服, 部分代码和create代码一直,未整合"""
        body = body or {}
        jsonutils.schema_validate(body, self.MERGEAPPENTITYS)

        group_id = body.pop('group_id')
        # 需要合并的实体
        entitys = list(set(body.pop('entitys')))
        entitys.sort()

        session = endpoint_session()

        # 安装文件信息
        appfile = body.pop(common.APPFILE)
        # 选择合并后实例运行服务器
        agent_id = body.get('agent_id') or self._agentselect(
            req, common.GAMESERVER, **body)
        # 选择合并后实体数据库
        databases = self._dbselect(req, common.GAMESERVER, **body)
        opentime = body.get('opentime')
        # 合服任务ID
        uuid = uuidutils.generate_uuid()

        # chiefs信息初始化
        query = model_query(session,
                            AppEntity,
                            filter=and_(
                                AppEntity.group_id == group_id,
                                AppEntity.objtype.in_(
                                    [common.GMSERVER, common.CROSSSERVER])))
        # 找到同组的gm和战场服
        gm = None
        cross = None
        crosss = []
        # 默认平台识标
        platform = None
        # 锁组
        glock = get_gamelock()
        with glock.grouplock(group_id):
            if model_count_with_key(session,
                                    MergeEntity,
                                    filter=MergeEntity.entity.in_(entitys)):
                raise InvalidArgument('Target entity merged or in mergeing')
            for appentity in query:
                if appentity.status != common.OK:
                    continue
                if appentity.objtype == common.GMSERVER:
                    gm = appentity
                else:
                    crosss.append(appentity)
            if not gm:
                raise InvalidArgument(
                    'Group not exist or gm not active/exist?')
            if not crosss:
                raise InvalidArgument('Group has no cross server?')
            if not body.get('cross_id'):
                cross = crosss[0]
            else:
                for appentity in crosss:
                    if appentity.entity == body.get('cross_id'):
                        cross = appentity
                        break
            if not cross:
                raise InvalidArgument('cross server can not be found?')
            # 获取实体相关服务器信息(端口/ip)
            maps = entity_controller.shows(endpoint=common.NAME,
                                           entitys=[gm.entity, cross.entity])
            chiefs = dict()
            # 战场与GM服务器信息
            for chief in (cross, gm):
                chiefmetadata = maps.get(chief.entity).get('metadata')
                ports = maps.get(chief.entity).get('ports')
                if not chiefmetadata:
                    raise InvalidArgument('%s.%d is offline' %
                                          (chief.objtype, chief.entity))
                need = common.POSTS_COUNT[chief.objtype]
                if need and len(ports) != need:
                    raise InvalidArgument(
                        '%s.%d port count error, '
                        'find %d, need %d' %
                        (chief.objtype, chief.entity, len(ports), need))
                chiefs.setdefault(
                    chief.objtype,
                    dict(entity=chief.entity,
                         ports=ports,
                         local_ip=chiefmetadata.get('local_ip')))

            # 需要合服的实体
            appentitys = []
            query = model_query(session,
                                AppEntity,
                                filter=and_(AppEntity.group_id == group_id,
                                            AppEntity.entity.in_(entitys)))
            query = query.options(joinedload(AppEntity.areas, innerjoin=False))
            with session.begin():
                for appentity in query:
                    if appentity.objtype != common.GAMESERVER:
                        raise InvalidArgument(
                            'Target entity %d is not %s' %
                            (appentity.entity, common.GAMESERVER))
                    if appentity.status != common.UNACTIVE:
                        raise InvalidArgument(
                            'Target entity %d is not unactive' %
                            appentity.entity)
                    if not appentity.areas:
                        raise InvalidArgument('Target entity %d has no area?' %
                                              appentity.entity)
                    if appentity.versions:
                        raise InvalidArgument(
                            'Traget entity %d version is not None' %
                            appentity.entity)
                    if platform is None:
                        platform = appentity.platform
                    else:
                        # 区服平台不相同, 位操作合并platform
                        platform = platform | appentity.platform
                    appentitys.append(appentity)
                    if not opentime:
                        opentime = appentity.opentime
                if len(appentitys) != len(entitys):
                    raise InvalidArgument('Can not match entitys count')
                # 完整的rpc数据包,准备发送合服命令到agent
                body = dict(appfile=appfile,
                            databases=databases,
                            opentime=opentime,
                            chiefs=chiefs,
                            uuid=uuid,
                            entitys=entitys)
                body.setdefault('finishtime', rpcfinishtime()[0] + 5)
                try:
                    create_result = entity_controller.create(
                        req=req,
                        agent_id=agent_id,
                        endpoint=common.NAME,
                        body=body,
                        action='merge')['data'][0]
                except RpcResultError as e:
                    LOG.error('Create entity rpc call fail: %s' % e.message)
                    raise InvalidArgument(e.message)
                mergetd_entity = create_result.get('entity')
                rpc_result = create_result.get('notify')
                LOG.info('Merge to entity %d, agent %d' %
                         (mergetd_entity, agent_id))
                LOG.debug('Entity controller merge rpc result %s' %
                          str(rpc_result))
                # 插入实体信息
                appentity = AppEntity(entity=mergetd_entity,
                                      agent_id=agent_id,
                                      group_id=group_id,
                                      objtype=common.GAMESERVER,
                                      cross_id=cross.entity,
                                      opentime=opentime,
                                      platform=platform)
                session.add(appentity)
                session.flush()
                # 插入数据库绑定信息
                if rpc_result.get('databases'):
                    self._bondto(session, mergetd_entity,
                                 rpc_result.get('databases'))
                else:
                    LOG.error('New entity database miss')
                # 插入合服记录
                mtask = MergeTask(uuid=uuid,
                                  entity=mergetd_entity,
                                  mergetime=int(time.time()))
                session.add(mtask)
                session.flush()
                for _appentity in appentitys:
                    session.add(
                        MergeEntity(entity=_appentity.entity, uuid=uuid))
                    session.flush()
                # 批量修改被合并服的状态
                query.update({'status': common.MERGEING},
                             synchronize_session=False)
                session.flush()
            port_controller.unsafe_create(agent_id, common.NAME,
                                          mergetd_entity,
                                          rpc_result.get('ports'))
            # agent 后续通知
            threadpool.add_thread(entity_controller.post_create_entity,
                                  appentity.entity,
                                  common.NAME,
                                  objtype=common.GAMESERVER,
                                  status=common.UNACTIVE,
                                  opentime=opentime,
                                  group_id=group_id,
                                  areas=[])
        # 添加端口
        # threadpool.add_thread(port_controller.unsafe_create,
        #                       agent_id, common.NAME, mergetd_entity, rpc_result.get('ports'))
        return resultutils.results(
            result='entitys is mergeing',
            data=[dict(uuid=uuid, entitys=entitys, entity=mergetd_entity)])