Beispiel #1
0
 def _generate_err_taskbatchback(self, tb: IscoutBtaskBack):
     """返回控制端内部处理错误信息到中心"""
     try:
         tb._cmdrcvmsg = "内部错误:{}".format(tb._cmdrcvmsg)
         tb.cmdstatus = ECommandStatus.Failed
         if not OutputManagement.output(tb):
             self._logger.error(
                 "Generate error IscoutBtaskBack to center error:\ndata:{}\ntaskid:{}\nbatchid:{}\nerror:{}"
                 .format(tb.inputdata.name, tb._taskid, tb._batchid,
                         traceback.format_exc()))
     except Exception:
         self._logger.error(
             "Generate error IscoutBtaskBack to center error:\ndata:{}\ntaskid:{}\nbatchid:{}\nerror:{}"
             .format(tb.inputdata.name, tb._taskid, tb._batchid,
                     traceback.format_exc()))
Beispiel #2
0
 def write_iscouttaskback(
     self,
     iscouttask: IscoutTask,
     cmdstatus: ECommandStatus,
     scoutrecvmsg: str,
     currtime: str = None,
     elapsed: float = None,
 ):
     """
     通用方法编写iscantask的回馈
     update by judy 20201110
     编写这个任务的回馈因为需要登陆的插件需要这个回馈
     :param iscouttask:
     :param cmdstatus:
     :param scanrecvmsg:
     :param currtime:
     :param elapsed:
     :return:
     """
     if iscouttask is None:
         raise Exception("Write iscantaskback iscantask cannot be None")
     scanback = IscoutBtaskBack.create_from_task(iscouttask, cmdstatus,
                                                 scoutrecvmsg, currtime,
                                                 elapsed)
     OutputManagement.output(scanback)
     return
Beispiel #3
0
    def _output_batch_task_back(self, scouttask: IscoutTask,
                                status: ECommandStatus, msg: str):
        if not isinstance(scouttask, IscoutTask):
            self._logger.error(
                "Invalid IscoutTask object for output ScanTaskBack: {}".format(
                    type(scouttask)))
            return

        scouttask: IscoutTask = scouttask
        scouttask: IscoutBtaskBack = IscoutBtaskBack.create_from_task(
            scouttask, status, msg)
        if not OutputManagement.output(scouttask):
            self._logger.error(
                "Output IscoutBTaskBack failed:\ntaskid={}\ndata={}".format(
                    scouttask.taskid, scouttask.inputdata._source))
Beispiel #4
0
    def _save_task_to_db(self, task: IscoutTask, client: Client) -> bool:
        """存储新任务,来的肯定是子任务\n
        task: 任务对象\n
        client: 任务被分配到的采集端对象"""
        res: bool = True
        try:
            ############
            # 1. 不同任务下发多次
            # 2. 同一批次任务反复测试(同一个批处理任务需要反复测了10次那种)

            #
            # 任务必有taskid+batchid

            # 所有任务来了都存入3张表
            with self._dbmanager.get_automic_locker(
                    EDBAutomic.ReduplicateIScoutTask):
                res = self._dbmanager.save_new_iscouttask(task, client)
            if res:
                self._logger.debug(
                    "Save IScoutTask OK: {} {} {} {} -> {} {}".format(
                        task.taskid, task.batchid, task._objecttype.name,
                        task._object, client._statusbasic._clientid,
                        client._statusbasic.ip))
            else:
                # 如果存入失败了,
                # 对于当前子任务来说,需要返回一个子任务回馈文件
                # 对于总任务,需要判断是否其所有子任务都失败了,并返回回馈数据
                self._logger.debug(
                    "Save IScoutTask Failed: {} {} {} {} -> {} {}".format(
                        task.taskid, task.batchid, task._objecttype.name,
                        task._object, client._statusbasic._clientid,
                        client._statusbasic.ip))

                ## 返回回馈数据
                taskbatchback: IscoutBtaskBack = IscoutBtaskBack.create_from_task(
                    task, ECommandStatus.Failed, '内部错误:任务分配采集端失败,存入本地数据库失败')
                if not OutputManagement.output(taskbatchback):
                    self._logger.error(
                        'Output TaskBatchBack failed:\ntaskid={}\nbatchid={}'.
                        format(task.taskid, task.batchid))

        except Exception:
            res = False
            self._logger.error(
                "save new task to db error:\ntaskid:{}\nerror:{}".format(
                    task.taskid, traceback.format_exc()))

        return res
Beispiel #5
0
 def write_iscoutback(
     iscouttask: IscoutTask,
     cmdstatus: ECommandStatus,
     scoutrecvmsg: str,
     currtime: str = None,
 ):
     """
     通用方法编写iscantask的回馈
     :param iscouttask:
     :param cmdstatus:
     :param scanrecvmsg:
     :param currtime:
     :return:
     """
     if iscouttask is None:
         raise Exception("Write iscantaskback iscantask cannot be None")
     scanback = IscoutBtaskBack.create_from_task(iscouttask, cmdstatus,
                                                 scoutrecvmsg)
     OutputManagement.output(scanback)
     return
Beispiel #6
0
 def write_iscoutback_dict(
     iscouttask: dict,
     cmdstatus: ECommandStatus,
     scoutrecvmsg: str,
     currtime: str = None,
 ):
     """
     通用方法编写iscantask的回馈
     :param iscouttask:
     :param cmdstatus:
     :param scanrecvmsg:
     :param currtime:
     :return:
     """
     # 为了兼容以前的方法,所以在这里添加字段create by judy 20200327
     iscouttask["state"] = cmdstatus.value
     iscouttask["recvmsg"] = scoutrecvmsg
     platform = iscouttask.get("platform")
     if iscouttask is None:
         raise Exception("Write iscantaskback iscantask cannot be None")
     scanback = IscoutBtaskBack.create_from_dict(iscouttask,
                                                 platform=platform)
     OutputManagement.output(scanback)
     return
Beispiel #7
0
    def _parse_data_back(self, data: InputData) -> iter:
        """解析数据,并返回每个数据段对应的 TaskBatchBack 结构"""
        try:

            for seg in DataParser.parse_standard_data(data.stream):
                seg: DataSeg = seg
                try:
                    tb: IscoutBtaskBack = IscoutBtaskBack.create_from_dataseg(
                        seg, data._platform)
                    tb.inputdata = data
                    yield tb

                except Exception:
                    self._logger.error(
                        "Parse one data segment error:\ndata:{}\nsegindex:{}\nerror:{}"
                        .format(data._source, seg.segindex,
                                traceback.format_exc()))
                    # 解析数据时,只要出错一个数据段,就算作错误数据
                    data.on_complete(False)

        except Exception:
            self._logger.error(
                "Parse TaskBatchBack data error:\ndata:{}\nerror:{}".format(
                    data._source, traceback.format_exc()))
Beispiel #8
0
    def _deal_data_back(self, tb: IscoutBtaskBack) -> bool:
        """处理TaskBatchBack数据"""
        # ==================
        # 更新指定的子任务的cmdstatus命令状态等字段
        # 综合判断总任务是否完成或结束,
        # 返回总任务完成进度或总任务最终结果

        # 当总任务下的所有子任务的命令状态均为以下枚举值时
        # Failed/Succeed/Cancelled/Timeout
        # 判定为总任务已结束

        # 子任务状态为 NeedSmsCode 时,需要在数据库添加
        # 标记,以确认中心是否收到消息并下发了验证码,若长时间
        # 未收到中心的验证码,且也未收到来自采集端的任务超时错误,
        # 需要控制端进行超时处理(此时认为采集端的此条任务挂了?)
        # ==================

        res: bool = False

        # 更新数据库子任务状态
        currperiodnum = tb.periodnum
        with self._dbmanager.get_automic_locker(
                EDBAutomic.ReduplicateIScoutTask):
            task: IscoutTask = self._dbmanager.get_iscout_batch_task(
                tb._platform, tb._taskid, tb._batchid)
            if task is None:  # 没查到,就是竟然凭空来了一个back
                self._logger.warn(
                    "No task find for IscoutTaskBack: taskid={}, batchid={}".
                    format(tb._taskid, tb._batchid))
                return res

        if tb.periodnum < task.periodnum:
            # self._logger.error(
            #     "IScoutBTaskBack periodnum({}) < task.periodnum({}) in db:\ntaskid:{}\nbatchid:{}"
            #         .format(tb.periodnum, task.periodnum, task.taskid,
            #                 task.batchid))
            # return res
            # 容错处理,更正client返回的taskback里的周期数periodnom
            self._logger.warn(
                "IScoutBTaskBack periodnum({}) < task.periodnum({}) in db, corrected it:\ntaskid:{}\nbatchid:{}"
                .format(tb.periodnum, task.periodnum, task.taskid,
                        task.batchid))
            tb.periodnum = task.periodnum

        # 只有当back的sequence>task的sequence才去更新
        if tb._sequence > task._sequence:
            if not self._deal_equal_period(tb, task):
                return res

        # 置回当前周期数
        tb.periodnum = currperiodnum
        # 回传子任务回馈文件
        if not OutputManagement.output(tb):
            tb._cmdrcvmsg = "输出IScoutTask子任务回馈数据失败"
            self._logger.error(
                "Output IScoutBatchTaskBack file to center failed:\ndata:{}\ntaskid:{}\nbatchid:{}"
                .format(tb.inputdata.name, tb._taskid, tb._batchid))
            return res

        # 计算当前子任务的 elapsed
        task.elapsed += tb.elapsed

        # 顺利跑到这里,子任务处理就是成功的了
        tb.ok = True
        self._logger.info(
            "IScoutBatchTaskBack dealt [{} {}]:\ndata:{}\ntaskid:{}\nbatchid:{}\nperiodnum:{}"
            .format(tb.cmdstatus.name, tb.progress, tb.inputdata.name,
                    tb._taskid, tb._batchid, currperiodnum))

        self._tbqueue.put(task)
        res = True
        return res
Beispiel #9
0
    def _deal_equal_period(self, tb: IscoutBtaskBack,
                           task: IscoutTask) -> bool:
        res: bool = False
        try:
            # 查询对应的总任务对象
            # 子任务是这些状态,那么总任务的 batchcompletecount+=1
            # 把当前IScouTBatchTask子任务查出来
            if tb._cmdstatus == ECommandStatus.Failed or \
                    tb._cmdstatus == ECommandStatus.Succeed or \
                    tb._cmdstatus == ECommandStatus.Timeout or \
                    tb._cmdstatus == ECommandStatus.Cancelled:
                tb.progress = 1
                if not self._dbmanager.is_iscoutbtask_batchcompletecount_increaced(
                        tb._platform, tb._taskid, tb._batchid):
                    if not self._dbmanager.increace_iscouttask_batch_complete_count(
                            tb._platform, tb._taskid, tb._batchid):
                        tb._cmdrcvmsg = "IScout子任务完成数量增加到数据库失败"
                        self._logger.error(
                            "Increace IScoutTask batch complete count failed:\ndata:{}\ntaskid={}\nbatchid={}\nperiodnum={}\nbatchtask_cmdstatus={}"
                            .format(tb.inputdata.name, tb._taskid, tb._batchid,
                                    tb.periodnum, tb._cmdstatus.name))
                        return res
                    elif not task.isbatchcompletecountincreased:
                        task.batchcompletecount += 1
                        task.isbatchcompletecountincreased = True
                # 周期数+1
                # if task._is_period:
                #     tb.periodnum += 1
                #     task.periodnum += 1
                # PeriodNum=?,
                # Status=?,
                # Progress=?,
                # CmdRcvMsg=?,
                # Sequence=?,
                # UpdateTime=?
                if not self._dbmanager.update_iscoutbtask(
                        tb._platform,
                        tb._taskid,
                        tb._batchid,
                        updatefields={
                            'PeriodNum': tb.periodnum,
                            'Status': tb.cmdstatus.value,
                            'Progress': 1,
                            'Elapsed': tb.elapsed,
                            'CmdRcvMsg': tb.cmdrcvmsg,
                            'Sequence': tb._sequence,
                            'UpdateTime': tb.time,
                            'LastEndTime': helper_time.ts_since_1970_tz(),
                        }):
                    tb._cmdrcvmsg = "更新IScout子任务状态到本地数据库失败"
                    self._logger.error(
                        "Update IScoutBatchTask to db failed:\ndata:{}\ntaskid:{}\nbatchid:{}"
                        .format(tb.inputdata.name, tb._taskid, tb._batchid))
                    return res

            res = True
        except Exception:
            self._logger.error(
                "Deal first period task back error:\ntaskid:{}\nbatchid:{}\nclientid:{}\nerror:{}"
                .format(task.taskid, task.batchid, task._clientid,
                        traceback.format_exc()))
        return res
Beispiel #10
0
    def _update_to_db(self, task: IscoutTask, targetclient: Client,
                      succ: bool):
        """同步任务下发状态到数据库。这里来的永远是子任务"""
        try:
            task.laststarttime = helper_time.ts_since_1970_tz()
            updatefields: dict = {}
            updatefields["PeriodNum"] = task.periodnum
            if not succ:
                # 失败,返回回馈数据
                task.lastendtime = helper_time.ts_since_1970_tz()
                updatefields["LastEndTime"] = task.lastendtime

                task.cmdstatus = ECommandStatus.Failed
                task.cmdrcvmsg = "发送任务到采集端失败"
                tb: IscoutBtaskBack = IscoutBtaskBack.create_from_task(
                    task, cmdstatus=task.cmdstatus, recvmsg=task.cmdrcvmsg)
                if not OutputManagement.output(tb):
                    self._logger.error(
                        "Write IscoutBtaskBack failed:\ntaskid:{}".format(
                            task.taskid))
                if isinstance(task.cmd, IdownCmd):
                    task.cmd.cmdstatus = ECommandStatus.Failed
                    task.cmd.cmdrcvmsg = task.cmdrcvmsg
                    cmdback: CmdFeedBack = CmdFeedBack.create_from_cmd(
                        task.cmd, task.cmd.cmdstatus, task.cmd.cmdrcvmsg)
                    if not OutputManagement.output(cmdback):
                        self._logger.error(
                            "Write IDownCmdBack failed:\nplatform:{}\ncmdid:{}"
                            .format(task._platform, task.cmd_id))
            else:
                # 成功
                task.cmdstatus = ECommandStatus.Dealing
                if isinstance(task.cmd, IdownCmd):
                    task.cmd.cmdstatus = ECommandStatus.Dealing
                # 返回 子任务开始回馈
                task.cmdstatus = ECommandStatus.Dealing
                task.cmdrcvmsg = "任务开始执行"
                if task.periodnum > 1:
                    task.cmdrcvmsg += ",周期{}".format(task.periodnum)
                tb: IscoutBtaskBack = IscoutBtaskBack.create_from_task(
                    task, cmdstatus=task.cmdstatus, recvmsg=task.cmdrcvmsg)
                if not OutputManagement.output(tb):
                    self._logger.error(
                        "Write IscoutBtaskBack failed:\ntaskid:{}".format(
                            task.taskid))
                self._logger.info(
                    "Send IScoutTask succeed [{}: {}]:\ntaskid:{}\nbatchid:{}\nperiod:{}\nclient:{}\t{}"
                    .format(
                        task._objecttype.name,
                        task._object,
                        task.taskid,
                        task.batchid,
                        task.periodnum,
                        task._clientid,
                        targetclient._statusbasic.ip,
                    ))

            with self._dbmanager.get_automic_locker(
                    EDBAutomic.ReduplicateIScoutTask):
                # 总任务batchcompletecount -1
                # 子任务isbatchcompletecountincreaced 置0
                self._dbmanager.decreace_iscouttask_batch_complete_count(
                    task._platform, task.taskid, task.batchid)
                task.batchcompletecount -= 1
                # 更新数据库当前子任务状态
                updatefields["Status"] = task.cmdstatus.value
                updatefields["LastStartTime"] = task.laststarttime
                if not self._dbmanager.update_iscoutbtask(
                        task._platform, task.taskid, task.batchid,
                        updatefields):
                    # 这里如果更新数据库状态失败了,那发送线程可能会重新发送当前子任务。
                    # 此时需要采集端支持 冥等性(任务去重,保证多次收到同一条任务只会处理一条)
                    self._logger.error(
                        "Update IScoutBatchTask cmdstatus failed:\ntaskid:{}\ncmdstatus:{}"
                        .format(task.taskid, task.cmdstatus.name))
                # 更新总任务开始时间
                if not self._dbmanager.update_iscout_task(
                        task._platform,
                        task.taskid,
                        updatefields={
                            "LastStartTime": helper_time.ts_since_1970_tz(),
                            "PeriodNum": task.periodnum,
                        },
                ):
                    self._logger.error(
                        "Update IScouttask LastStartTime failed:\ntaskid:{}\ncmdstatus:{}"
                        .format(task.taskid, task.cmdstatus.name))
                # 如果带cmd,更新cmd状态
                if isinstance(
                        task.cmd,
                        IdownCmd) and not self._dbmanager.update_cmd_status(
                            task.cmd.platform,
                            task.cmd.cmd_id,
                            targetclient._statusbasic._clientid
                            if not targetclient is None else task._clientid,
                            task.cmd.cmdstatus,
                        ):
                    self._logger.error(
                        "Update cmd cmdstatus failed:\ntaskid:{}\ncmdstatus:{}"
                        .format(task.taskid, task.cmdstatus.name))

                # 返回 总任务开始回馈
                task.cmdstatus = ECommandStatus.Dealing
                task.cmdrcvmsg = "任务开始执行,周期{}".format(task.periodnum)
                tb: IscoutTaskBack = IscoutTaskBack.create_from_task(
                    task,
                    cmdstatus=task.cmdstatus,
                    recvmsg=task.cmdrcvmsg,
                    batchcompletecount=task.batchcompletecount,
                    periodnum=task.periodnum,
                )
                if not OutputManagement.output(tb):
                    self._logger.error(
                        "Write IscoutBtaskBack failed:\ntaskid:{}".format(
                            task.taskid))
        except Exception:
            self._logger.error("Update task cmdstatus to db error: {}".format(
                traceback.format_exc()))
            self._dbmanager.update_iscouttask_status(task._platform,
                                                     task.taskid,
                                                     ECommandStatus.Failed)
            if isinstance(task.cmd, IdownCmd):
                self._dbmanager.update_cmd_status(
                    task._platform,
                    task.cmd_id,
                    task.cmd._clientid,
                    ECommandStatus.Failed,
                )