#!/usr/bin/env python # -*- coding: utf-8 -*- # @CreateTime : 2018/3/6 # @Author : ***小君哥*** # @File : agent.py # @Software : agent # @since : 0.0.1 # @Desc : Agent # @license : Copyright (c) 2018, Inc. All rights reserved. # @Contact : zard@sz-chunyi.com import os import sys import time import atexit import signal import psutil import logging.config sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir)) #配置项和写log的方法,根据自己需要修改 config = Config() logging.config.fileConfig(config.logging_conf) logger = logging.getLogger("agent") class Agent: def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null',home_dir='/', umask=022, verbose=1): self.pidfile = pidfile self.stdin = stdin self.stdout = stdout self.stderr = stderr self.home_dir = home_dir self.verbose = verbose # 调试开关 self.umask = umask self.daemon_alive = True def init_agent(self): try: pid = os.fork() if pid > 0: sys.exit(0) except OSError as e: logger.error("fork #1 failed: {} ({})".format(e.errno, e.strerror)) sys.stderr.write("fork #1 failed: {} ({})".format(e.errno, e.strerror)) sys.exit(1) # decouple from parent environment os.chdir(self.home_dir) os.setsid() os.umask(self.umask) # do second fork try: pid = os.fork() if pid > 0: os._exit(0) except OSError as e: logger.error("fork #2 failed: {} ({})".format(e.errno, e.strerror)) sys.stderr.write("fork #2 failed: {} ({})".format(e.errno, e.strerror)) sys.exit(1) # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = file(self.stdin, 'r') so = file(self.stdout, 'a+') if self.stderr: se = file(self.stderr, 'a+', 0) else: se = so os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) def sig_handler(signum, frame): self.daemon_alive = False signal.signal(signal.SIGTERM, sig_handler) signal.signal(signal.SIGINT, sig_handler) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) logger.info("write pid : {} to pidfile : {}".format(pid, self.pidfile)) file(self.pidfile, 'w+').write('%s\n' % pid) # delete pid def delpid(self): if os.path.exists(self.pidfile): os.remove(self.pidfile) logger.info("do pid : {} os remove({})".format(str(os.getpid()), self.pidfile)) # start agent def start(self): # Check for a pidfile to see if the agnet already runs try: pf = file(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None try: if pid: message = "pidfile {} already exist. agent is running." sys.stdout.write(message.format(self.pidfile)) sys.exit(0) # Start the agent self.init_agent() self.run() except Exception as ex: logger.debug(ex) def stop(self): # stop the agent from the pidfile try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile {} does not exist. agnet is not running." sys.stdout.write(message.format(self.pidfile)) if os.path.exists(self.pidfile): os.remove(self.pidfile) return # not an error in a restart # Try killing the agent process try: nbocc = 0 while 1: logger.info("try to kill process: {}".format(str(pid))) os.kill(pid, signal.SIGTERM) time.sleep(0.1) nbocc = nbocc + 1 if nbocc % 5 == 0: os.kill(pid, signal.SIGHUP) except OSError as e: err = str(e) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) logger.info("pid : {} delete pidfile : {}".format(str(os.getpid()), self.pidfile)) else: print(str(err)) sys.exit(1) #restart agent def restart(self): self.stop() self.start() #status check def status(self): try: pf = open(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None sys.exit(2) except SystemExit: pid = None sys.exit() if psutil.pid_exists(pid): print("process is running, pid is %s" % str(pid)) sys.exit(0) else: print("no such process running") sys.exit(2) #agent run def run(self): """ You should override this method when you subclass agent. It will be called after the process has been InitAgent by start() or restart(). """
class SysUnitAgnet(Agent): def __init__(self, pidfile): Agent.__init__(self, pidfile) def run(self): #这里重载run函数实现你的具体操作 #if (psutil.__version__ < "1.2.1"): # logger.error("ERROR : update your psutil to a earlier version (> 1.2.1)") # print("ERROR : update your psutil to a earlier version (> 1.2.1)") # sys.exit(2) #sys.stdout.flush() #hostname = socket.getfqdn() #hostip = socket.gethostbyname(hostname) #logger.info("hostname is {}, ip is {}".format(hostname, hostip)) # my program do things
if __name__ == '__main__': #创建pid文件和log文件,确保文件存在,不存在就创建 util.ensure_dir(config.sys_agent_pfile) util.ensure_dir(config.agent_log_fname) #实例化一个agent sysagent = SysUnitAgnet(config.sys_agent_pfile) if len(sys.argv) == 3: if 'sys' == sys.argv[1]: if 'start' == sys.argv[2]: sysagent.start() elif 'stop' == sys.argv[2]: sysagent.stop() elif 'status' == sys.argv[2]: sysagent.status() elif 'restart' == sys.argv[2]: sysagent.restart() else: print("Unknown command") sys.exit(2) elif 'all' == sys.argv[1]: if 'start' == sys.argv[2]: tsy = Thread(target=sysagent.start) #多个agnet实例时可以依次添加 for t in [tsy]: t.start() elif 'stop' == sys.argv[2]: tsy = Thread(target=sysagent.stop) for t in [tsy]: t.start() elif 'status' == sys.argv[2]: tsy = Thread(target=sysagent.status) for t in [tsy]: t.start() elif 'restart' == sys.argv[2]: tsy = Thread(target=sysagent.restart) for t in [tsy]: t.start() else: print("Unknown command") sys.exit(2) else: print("Unknown command") sys.exit(2) else: print("usage: %s %s start|stop|restart|status" % (sys.argv[0],'sys|swift|task|all')) sys.exit(2) 保存后在命令行执行:python *.py sys start