2021SC@SDUSC
task.py
OSSIM-agent源代码分析(五)
简述
OSSIM Agent的主要职责是收集网络上存在的各种设备发送的所有数据,然后按照一种标准方式(standardized way)有序的发送给OSSIM Server,Agent收集到数据后在发送给Server之前要对这些数据进行标准化处理,这样Server就可以依一种统一的方式来处理这些信息,并且也简化了Server的处理过程
其中对于各种数据的处理任务调度就是非常关键的一环,task.py完整的负责各种数据的具体处理和测试任务
相关代码
初始导包
import os
import signal
import sys
import time
忽略异常处理
class error(Exception):
pass
class _ready(Exception):
pass
在执行路径查找可执行文件。如果没有可执行文件被找到,返回None
def which(filename):
"""Find the file 'filename' in the execution path. If no executable
file is found, return None"""
for dir in os.environ['PATH'].split(os.pathsep):
fn=os.path.join(dir,filename)
if os.path.exists(fn):
if os.stat(fn)[0]&0111:
return fn
else:
return None
进程杀死函数
def Kill(self,signal=signal.SIGTERM):
if self.status is None:
return os.kill(self.pid,signal)
Task类:管理异步子流程任务。
但这和subproc类不同!
- subproc通过管道连接子进程
- task允许子进程自主运行。
- subproc是一个os.popen()
- task是一个os.system()
在开始任务后,我们可以:
1、问它是否完成了
2、等待直到它完成
3、在等待时执行一个“空闲”任务(例如Tkinter的主循环)
4、子流程终止
5、用特定的信号杀死子进程
6、询问exit code
包含错误处理和命令处理的构造函数
def __init__(self,command):
if type(command)==type(''):
self.cmd=command
self.words=command.split()
elif type(command)==type([]) or type(command)==type(()):
self.cmd="'"+"' '".join(command)+"'"
self.words=tuple(command)
else:
raise error("command must be tuple, list, or string")
self.pid=None
self.status=None
执行函数,只能执行一次
Usesh:如果为1,则执行’sh -c command’,如果为0,则拆分命令再运行它
如果usesh=1, Kill方法会杀死’sh’进程,而不是具体命令
detach:如果是1,执行’sh -c ‘command&’(无论“usesh”)。因为’sh’进程将立即执行,终止时,创建的任务将被继承init
如果detach=1, Kill(), Done()和Status()将会操作sh,但无法知道detached process
stdout:不为None要用作子进程的标准输出的文件名
如果为None,将使用父对象的标准输出。
stdin:不为None filename用于子进程的stdin
如果为None,将使用父对象的stdin
stderr:不为None filename用于子进程的stderr。
如果为None,将使用父节点的标准错误。
def Run(self,usesh=0,detach=0,stdout=None,stdin=None,stderr=None):
if self.pid!=None:
raise error("Second run on task forbidden")
self.pid=os.fork()
if not self.pid:
for fn in range(3,256):
try:
os.close(fn)
except os.error:
pass
if stdout:
os.close(1)
i=os.open(stdout,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
if i!=1:
sys.stderr.write("stdout not opened on 1!\n")
if stdin:
os.close(0)
i=os.open(stdin,os.O_RDONLY)
if i!=0:
sys.stderr.write("stdin not opened on 0!\n")
if stderr:
os.close(2)
i=os.open(stderr,os.O_CREAT|os.O_WRONLY|os.O_TRUNC,0666)
if i!=2:
sys.stdout.write("stderr not opened on 2!\n")
try:
if detach:
os.execv('/bin/sh',('sh','-c',self.cmd+'&'))
elif usesh:
os.execv('/bin/sh',('sh','-c',self.cmd))
elif self.words[0]=='/':
os.execv(self.words[0],self.words)
else:
os.execvp(self.words[0],self.words)
except:
print self.words
sys.stderr.write("Subprocess '%s' execution failed!\n"%self.cmd)
sys.exit(1)
else:
if detach:
self.Wait()
进程等待函数
def TextAbortableWait(self,text):
print text
try:
return self.Wait()
except KeyboardInterrupt:
print "Interrupted."
stat=self.Status()
if stat is None:
self.Kill(signal=2)
return self.Wait()
等待子进程终止函数。如果进程已经终止,该函数将返回而不引发错误
def AbortableWait(self,interval=0.1,master=None,text=None):
if master is None:
return self.TextAbortableWait(text)
import Pmw
d=Pmw.MessageDialog(master,
message_text=text,
title='Working...',
buttons=('Abort',),
command=self._buttonkill)
try:
from misc import config
d.configure(message_background=config.bgbusy)
except ImportError:
pass
d.component('message').pack(ipadx=15,ipady=15)
def doit(d=d,self=self,idlefunc=master.update,interval=interval):
d.update()
self.Wait(idlefunc=idlefunc,interval=interval)
raise _ready
d.configure(activatecommand=doit)
try:
try:
d.activate()
except _ready:
pass
finally:
d.deactivate()
d.destroy()
return self.status
等待子进程终止函数,idlefunc=None:一个可调用对象(函数,类,绑定方法)每0.1秒调用一次’interval’变量)要终止的子进程。这可以是Tkinter的“更新”程序,使GUI跑的时候不会死。如果设置为’None’,这个过程会等待。idlefunc应该不会花很长时间
def Wait(self,idlefunc=None,interval=0.1):
if self.status!=None:
return self.status
if callable(idlefunc):
while 1:
try:
pid,status=os.waitpid(self.pid,os.WNOHANG)
if pid==self.pid:
self.status=status
return status
else:
idlefunc()
time.sleep(interval)
except KeyboardInterrupt:
try:
self.Kill(signal=signal.SIGINT)
except OSError:
pass
except OSError:
print "WARNING: Unfindable process. Somebody else asked for my status!"
self.status=0
return 0
elif idlefunc:
raise error("Non-callable idle function")
else:
while 1:
try:
pid,status=os.waitpid(self.pid,0)
self.status=status
return status
except KeyboardInterrupt:
try:
self.Kill(signal=signal.SIGINT)
except OSError:
pass
except OSError:
print "WARNING: Unfindable process. Somebody else asked for my status!"
self.status=0
return 0
向正在运行的子进程发送信号函数
def Kill(self,signal=signal.SIGTERM):
if self.status is None:
return os.kill(self.pid,signal)
else:
print "DBG> trying to send signal to finished program"
询问该过程是否已经完成,Done函数
def Done(self):
if self.status!=None:
return 1
else:
pid,status=os.waitpid(self.pid,os.WNOHANG)
if pid==self.pid:
self.status=status
return 1
else:
return 0
询问任务的状态函数
def Status(self):
self.Done()
return self.status
Attach类,测试任务进程是否可正常进行类
class Attach:
def __init__(self,pid):
self.pid=pid
def Kill(self,signal=signal.SIGTERM):
return os.kill(self.pid,signal)
def Status(self):
try:
self.Kill(signal=0)
except OSError:
return 0
return None
if __name__=="__main__":
print "Testing simple program run"
done=0
t=Task('ls /tmp')
print t
t.Run()
print t
print "done,status=",t.Done(),t.Status()
time.sleep(2)
print "done,status=",t.Done(),t.Status()
print t
print "Superfluous wait=",t.Wait()
print "Testing interruption of task"
done=0
t=Task('sleep 10')
t.Run()
print "done,status=",t.Done(),t.Status()
t.Kill()
print "done,status=",t.Done(),t.Status()
t.Wait()
print "done,status=",t.Done(),t.Status()
print "Testing wait for simple program run"
done=0
t=Task('ls /tmp')
t.Run()
t.Wait()
print "done,status=",t.Done(),t.Status()