python编写agent_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 : 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值