python实现Agent守护进程

#!/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 : [email protected]

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

猜你喜欢

转载自www.cnblogs.com/chmyee/p/9205102.html