def create_periodic_task(name, task, expires=None, args=None, kwargs=None, frequency=None, crontab_minute=None, crontab_hour=None, crontab_day_of_week=None, crontab_day_of_month=None, crontab_month_of_year=None): """ :return: """ task_data = { 'name': name, 'task': task, 'expires': expires, } if frequency is not None: task_data['interval'] = {'every': frequency, 'period': 'minutes'} crontab = {} if crontab_minute is not None: crontab['minute'] = crontab_minute if crontab_hour is not None: crontab['hour'] = crontab_hour if crontab_day_of_week is not None: crontab['day_of_week'] = crontab_day_of_week if crontab_day_of_month is not None: crontab['day_of_month'] = crontab_day_of_month if crontab_month_of_year is not None: crontab['month_of_year'] = crontab_month_of_year if len(crontab) != 0: task_data['crontab'] = crontab if args is not None: if isinstance(args, list): task_data['args'] = json.dumps(args) else: raise natrix_exception.ClassInsideException( message=u'periodic task args is not list') if kwargs is not None: if isinstance(kwargs, dict): task_data['kwargs'] = json.dumps(kwargs) else: raise natrix_exception.ClassInsideException( message=u'periodic task kwargs is not dict') serializer = PeriodicTaskSerializer(data=task_data) if serializer.is_valid(): serializer.save() else: raise natrix_exception.ClassInsideException(message=serializer.errors)
def store(self): if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') if not hasattr(self, 'is_store'): raise natrix_exceptions.ClassInsideException( message= 'Must call _get_message to generate message before store.') if self.is_store: logger.info('A message(response) can only store one time') res = store_message(type=self._message_type, data=self.message) logger.debug('store result : {}'.format(res))
def _get_message(self): """ :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') if not hasattr(self, 'is_store'): self.is_store = False message = {'errorcode': 1408, 'errorinfo': u'Terminal do not consume'} message['command_uuid'] = self._validated_data['uuid'] message['command_generate_time'] = int( self._validated_data['generate_timestamp'] * 1000) message['terminal'] = self._validated_data['terminal'] terminal_api = TerminalAPI(message['terminal']) message['organization_id'] = terminal_api.get_org_ids() message['organization_name'] = terminal_api.get_org_names() message['organization_isp'] = terminal_api.get_register_isp() message['province'] = terminal_api.get_register_province() message['city'] = terminal_api.get_register_city() message['command_response_process_time'] = int(time.time() * 1000) self.message = message
def summary_presentation(self, instance=None): """Summary info about organization :param instance: an instance of organization :return: """ org_instance = None if not (instance is None): org_instance = instance elif hasattr(self, 'instance'): org_instance = self.instance if not isinstance(org_instance, Organization): raise natrix_exception.ParameterInvalidException( parameter='instance') try: ret = OrderedDict() ret['id'] = org_instance.id ret['name'] = org_instance.name ret['full_name'] = org_instance.get_full_name() ret['addresses'] = map(lambda addr: str(addr), org_instance.get_addresses()) ret['networks'] = map(lambda n: str(n), org_instance.get_networks()) return ret except Exception as e: logger.error(e) raise natrix_exception.ClassInsideException( message='summary Organization error')
def _update_command_status(self): """更新command状态 :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') terminal_tag = self._validated_data['terminal'] command_uuid = str(self._validated_data['uuid']) timestamp = self._validated_data['generate_timestamp'] command_exist, record_exist = AdapterCommandStatus.remove_command_cache( command_uuid, timestamp, terminal_tag) if not command_exist: logger.error( 'There is not command instance for this dead message: {command_uuid}-{timestamp}' .format(command_uuid=command_uuid, timestamp=timestamp)) return command_exist if not record_exist: logger.error( 'There is not command record for this dead message: {command_uuid}-{timestamp}-{terminal}' .format(command_uuid=command_uuid, timestamp=timestamp, terminal=terminal_tag)) return record_exist return True
def _update_command_status(self): """Update command status in cache. Note: be same with CommandTerminal._update_command_status :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') command = self._validated_data['command'] command_uuid = str(command.get('uuid')) terminal_tag = command.get('terminal') timestamp = self._get_command_stamp() command_exist, record_exist = AdapterCommandStatus.remove_command_cache( command_uuid, timestamp, terminal_tag) if not command_exist: logger.error( 'There is not command instance for this response message: {command_uuid}-{timestamp}' .format(command_uuid=command_uuid, timestamp=timestamp)) return command_exist if not record_exist: logger.error( 'There is not command record for this dead message: {command_uuid}-{timestamp}-{terminal}' .format(command_uuid=command_uuid, timestamp=timestamp, terminal=terminal_tag)) return record_exist return True
def get(self, request, format=None): feedback = {'permission': True} try: id = request.GET.get('id') try: org_instance = Organization.objects.get(id=id) serializer = organization_serializer.OrganizationSerializer( instance=org_instance) feedback['data'] = { 'code': 200, 'message': u'Terminal device summary info!', 'info': serializer.summary_presentation() } except Organization.DoesNotExist: feedback['data'] = ErrorCode.parameter_invalid( 'id', reason=u'Organization record is not exist!') raise natrix_exception.ParameterInvalidException( parameter='id') except natrix_exception.BaseException as e: feedback['data'] = ErrorCode.sp_code_bug(e.get_log()) raise natrix_exception.ClassInsideException( message=e.get_log()) except natrix_exception.BaseException as e: logger.info(e.get_log()) return JsonResponse(data=feedback)
def init_request_queue(channel, tag): """初始化请求队列相关的信息 :param channel: :return: """ try: exchange_name = EXCHANGE_REQUEST_TEMPLATE.format(tag=tag) channel.exchange_declare(exchange=exchange_name, exchange_type='direct') channel.queue_declare(queue=exchange_name, durable=True, arguments={ 'x-message-ttl': 120000, 'x-dead-letter-exchange': EXCHANGE_COMMAND_DEAD, 'x-dead-letter-routing-key': 'dead_command' }) channel.queue_bind(exchange=exchange_name, queue=exchange_name, routing_key='command') except Exception as e: logger.error(e) raise natrix_exceptions.ClassInsideException(message=str(e))
def get(self, request): feedback = { 'permission': True } try: sn = request.GET.get('sn') if sn is None: feedback['data'] = ErrorCode.parameter_missing('sn') raise natrix_exception.ParameterMissingException(parameter='sn') try: device = TerminalDevice.objects.get(sn=sn) logger.debug('device info {}'.format(device)) except TerminalDevice.DoesNotExist: feedback['data'] = ErrorCode.parameter_invalid( parameter='sn', reason=u'The record is not exist') raise natrix_exception.ParameterInvalidException(parameter='sn') try: serializer = alive_serializer.AdavnceHardwareSerializer(instance=device) feedback['data'] = { 'code': 200, 'message': u'终端设备硬件信息', 'info': serializer.data } return JsonResponse(data=feedback) except natrix_exception.BaseException as e: feedback['data'] = ErrorCode.sp_db_fault(aspect=u'Terminal Hardware serializer error') raise natrix_exception.ClassInsideException(message=u'Terminal Hardware serializer error') except natrix_exception.BaseException as e: logger.info(e.get_log()) return JsonResponse(data=feedback)
def distribute_command(self): """命令分发 将command分发到不同的RabbitMQ队列中。 :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') with mqservice.MQService.get_purge_channel() as channel: try: terminals = [ t.get('mac') for t in self._validated_data['terminals'] ] command_timestamp = self._validated_data['timestamp'] command = self._validated_data['command'] publish_data = { 'uuid': str(command.get('command_uuid')), 'protocol': command.get('command_protocol'), 'destination': command.get('command_destination'), 'parameters': command.get('command_parameters'), 'generate_timestamp': command_timestamp, } # TODO: 思考如果取消重复声明、绑定(队列) for terminal_tag in terminals: AdapterMQSetting.init_request_queue(channel, terminal_tag) exchange_name = EXCHANGE_REQUEST_TEMPLATE.format( tag=terminal_tag) publish_data['terminal'] = terminal_tag channel.basic_publish( exchange=exchange_name, routing_key='command', body=json.dumps(publish_data), properties=pika.BasicProperties(delivery_mode=2)) except Exception as e: # TODO: 梳理pika的异常 logger.error(e) raise natrix_exceptions.ClassInsideException( message=u'Distribute command failed!')
def to_representation(self, instance): if not isinstance(instance, TerminalDevice): raise natrix_exception.ParameterInvalidException( parameter='instance') try: ret = OrderedDict() terminals = instance.terminal_set.all() total = 0 active = 0 alive = 0 for t in terminals: total += 1 if t.is_valid(): active += 1 if t.is_alive(): alive += 1 ret['sn'] = instance.sn ret['hostname'] = instance.hostname ret['type'] = instance.product ret['os_type'] = instance.os_type ret['os_version'] = '[{}]-[{}]'.format(instance.os_major_version, instance.os_minor_version) ret['client_version'] = instance.natrixclient_version ret['status'] = instance.status ret['update_time'] = instance.last_online_time ret['comment'] = instance.comment ret['device_alert'] = instance.device_alert ret['terminal_alert'] = instance.terminal_alert register = instance.register ret['reg_orgs'] = map( lambda item: { 'id': item.id, 'name': item.name, 'desc': item.get_full_name() }, register.organizations.all() if register else []) ret['detect_orgs'] = map( lambda item: { 'id': item.id, 'name': item.name, 'desc': item.get_full_name() }, instance.organizations.all()) segments = map(lambda t: t.get_segment(), instance.terminal_set.all()) ret['segments'] = [s for s in segments if s] ret['terminal_total'] = total ret['terminal_active'] = active ret['terminal_alive'] = alive return ret except Exception as e: logger.error('Serializer Terminal Device ERROR: {}'.format(e)) raise natrix_exception.ClassInsideException( message=u'{}'.format(e))
def notify(self, message): """send message :param message: :return: """ if not (self.valid_to(self.to) and self.to): raise natrix_exceptions.ClassInsideException( message= u'You must have a valid paremeter(to) before calling `.notify()`' )
def _get_command_stamp(self): """Get command timestamp (). :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') return self._validated_data['stamp'].get( 'server_request_generate_time')
def process(self): if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') try: # 下发command到终端 self.distribute_command() # 初始化command状态 self.init_command_status() except natrix_exceptions.BaseException as e: logger.error('Distribute command failed: {}'.format(e.get_log()))
def store(self, stage='dead'): """持久化存储 :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') if not hasattr(self, 'is_store'): raise natrix_exceptions.ClassInsideException( message= 'Must call _get_message to generate message before store.') if self.is_store: logger.info('A message(dead) can only store one time') return res = store_message(type='error', data=self.message) logger.info('store result : {}'.format(res))
def is_valid(self, model): if not issubclass(model, Model): raise natrix_exception.ClassInsideException(message=u'IDSerializer parameter error!') flag = super(IDSerializer, self).is_valid() if not flag: return flag try: self.instance = model.objects.get(id=self.validated_data.get('id')) except model.DoesNotExist: self._errors['id'] = u'不能检索到相应数据!' flag = False return flag
def _response_message_process(self): """ :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') status_res = self._update_command_status() if not status_res: logger.error( 'Update command status errro, drop this response message!') return self._get_message() self.store()
def get_event(self): if not hasattr(self, 'curr_alert_state'): logger.error('The event only exist after you call keep_alive ({}).'.format(self.pk)) raise natrix_exception.ClassInsideException(message=u'Call get_event before keep_alive.') if self.last_alert_state: if self.curr_alert_state: return 'aliving', 0 else: # first loss of communication return 'dead-first', self.state_info['update_time'] else: if self.curr_alert_state: return 'recovery', self.state_info['update_time'] else: return 'dead', self.state_info['timestamp'] - self.state_info['first_alert_time']
def init_command_status(self): """初始化command状态 :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') terminals = [t.get('mac') for t in self._validated_data['terminals']] command_uuid = self._validated_data.get('command').get('command_uuid') command_protocol = self._validated_data.get('command').get( 'command_protocol') timestamp = self._validated_data.get('timestamp') AdapterCommandStatus.add_command_cache(str(command_uuid), timestamp, terminals, command_protocol)
def status_change(self, status): if status in ('active', 'maintain'): terminal_status = status elif status in ('posting'): terminal_status = 'active' else: logger.error('Configure terminal deivce status with an error status ({})'.format(status)) raise natrix_exception.ClassInsideException( message='models.TerminalDevice.status_change with an error parameter(status={})'.format(status)) with transaction.atomic(): self.status = status terminals = self.terminal_set.all() for terminal in terminals: terminal.status = terminal_status terminal.save() self.save()
def _get_message(self): if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') if not hasattr(self, 'is_store'): self.is_store = False command = self._validated_data['command'] data = self._validated_data['data'] stamp = self._validated_data['stamp'] message = dict() # command info message['command_uuid'] = str(command.get('uuid')) message['command_generate_time'] = int(self._get_command_stamp() * 1000) # terminal info terminal = command.get('terminal') message.update(self._get_terminal_info(terminal)) # timestamp info: from second convert to millisecond message['response_process_time'] = int(time.time() * 1000) message['terminal_request_receive_time'] = int( stamp.get('terminal_request_receive_time') * 1000) message['terminal_request_send_time'] = int( stamp.get('terminal_request_send_time') * 1000) if stamp.get('terminal_response_receive_time'): response_receive_time = int( stamp.get('terminal_response_receive_time') * 1000) else: response_receive_time = None message['terminal_response_receive_time'] = response_receive_time if stamp.get('terminal_response_return_time'): response_return_time = int( stamp.get('terminal_response_return_time') * 1000) else: response_return_time = None message['terminal_response_return_time'] = response_return_time # response info message.update(data) self.message = message
def filter_available_terminals(type, filter_condition): filter_data = { 'type': type, 'is_classify': False, 'filter_condition': filter_condition } serializer = common_serializer.TerminalFilterSerializer( data=filter_data) if serializer.is_valid(): terminals = serializer.query_result()[0].get('terminals', []) return [TerminalInfo(pk=t['value']) for t in terminals] else: raise natrix_exceptions.ClassInsideException( message='Filter available terminals: {}'.format( serializer.format_errors()))
def process(self, stage='dead'): """ :param stage: :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') try: if stage == 'dead': self._dead_message_process() except natrix_exceptions.BaseException as e: # TODO: exception process logger.error()
def keep_alive(self, timeout=60): try: curr_time = time.time() last_alert_state = self.state_info.get('last_alert_state') curr_state = self.state_info.get('curr_state') update_time = self.state_info.get('update_time') if curr_time - update_time > timeout: self.curr_alert_state = False self.time_out() return self # continuous alive if curr_state and last_alert_state: self.curr_alert_state = True self.alive_continuous() return self # recovery if curr_state and not last_alert_state: self.curr_alert_state = True self.recovery() return self # poweroff if not curr_state and last_alert_state: self.curr_alert_state = False self.power_off() return self # dead continuous if not curr_state and not last_alert_state: self.curr_alert_state = False self.dead_continuous() return self except Exception as e: logger.error('Keep alive with error: {}'.format(e)) raise natrix_exception.ClassInsideException(message='keep alive failed: {}'.format(e))
def _dead_message_process(self): """Dead Message Process To process dead message, include: - process command status in cache - generate message (used to store) - store message :return: """ if not hasattr(self, '_validated_data'): raise natrix_exceptions.ClassInsideException( message=u'Must call is_valid before using this method') status_res = self._update_command_status() if not status_res: logger.error('Update command status error, drop this message!') return self._get_message() self.store()
def init_response_queue(channel): """初始化'超时未响应'command队列相关配置 :return: """ try: exchange_name = EXCHANGE_RESPONSE queue_name = QUEUE_RESPONSE routing_key = ROUTE_RESPONSE # channel.exchange_declare(exchange=exchange_name, exchange_type='direct') # channel.queue_declare(queue=queue_name, # durable=True) # channel.queue_bind(exchange=exchange_name, # queue=queue_name, # routing_key=routing_key) channel.queue_declare(queue=queue_name, durable=True) except Exception as e: logger.error(e) raise natrix_exceptions.ClassInsideException(message=str(e))
def init_dead_queue(channel): """初始化'超时未消费'command队列相关配置 :param channel: :return: """ try: exchange_name = EXCHANGE_COMMAND_DEAD queue_name = QUEUE_DEAD routing_key = ROUTE_DEAD channel.exchange_declare(exchange=exchange_name, exchange_type='direct') channel.queue_declare(queue=queue_name, durable=True) channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key=routing_key) except Exception as e: logger.error(e) raise natrix_exceptions.ClassInsideException(message=str(e))
def __init__(self, to=[]): if self.valid_to(to): self.to = to else: raise natrix_exceptions.ClassInsideException( message=u'Create Notify class with an error parameter')
def set_destination(self, to): if isinstance(to, (list, tuple)) and to: self.to = to else: raise natrix_exceptions.ClassInsideException( message=u'Create Notify class with an error parameter : to')
def get_curr_state(self): if not hasattr(self, 'curr_alert_state'): logger.error('The event only exist after you call keep_alive ({}).'.format(self.pk)) raise natrix_exception.ClassInsideException(message=u'Call get_event before keep_alive.') return self.curr_alert_state