| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- # coding:utf-8
- import os
- import sys
- import fs
- import psutil
- import subprocess
- from crontab import CronTab
- local_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- if local_path not in sys.path:
- sys.path.append(local_path)
- from utils.comm_tools import shell_cmd, get_monitor_config
- class SupervisorTools:
- def __init__(self):
- supervisor_dir = "/data/supervisor"
- self.base_config_file = "/etc/supervisor/supervisord.conf"
- if supervisor_dir[-1] == '/':
- supervisor_dir = supervisor_dir[: -1]
- temp_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- utils_dir = os.path.join(temp_dir, 'utils')
- self.exception_warning_file = os.path.join(utils_dir, 'exception_warning.py')
- self.config_base = supervisor_dir
- self.python_bin = sys.executable
- self.bin_dir = os.path.dirname(self.python_bin)
- self.supervisord = os.path.join(self.bin_dir, 'supervisord')
- self.supervisorctl = os.path.join(self.bin_dir, 'supervisorctl')
- self.config_dir = os.path.join(self.config_base, 'config.d')
- self.log_dir = os.path.join(self.config_base, 'log')
- tmp_dir = os.path.dirname(self.base_config_file)
- if not os.path.isdir(tmp_dir):
- os.makedirs(tmp_dir)
- if not os.path.isdir(self.config_dir):
- os.makedirs(self.config_dir)
- if not os.path.isdir(self.log_dir):
- os.makedirs(self.log_dir)
- def _get_supervisor_app(self):
- '''获取supervisor所管理的程序'''
- status, app_name_list = False, []
- cmd = '{} status'.format(self.supervisorctl)
- code, stdout, stderr = shell_cmd(cmd)
- if code >= 0:
- for line in stdout.splitlines():
- tmp_line = line.split()
- if len(tmp_line) > 1:
- app_name = tmp_line[0].strip()
- app_name_list.append(app_name)
- status, msg = True, set(app_name_list)
- else:
- msg = '获取supervisor所管理的程序失败: {}'.format(stderr)
- return status, msg
- def _make_task_conf(self, app_name, dir_name, cmd, user):
- '''生成任务配置文件'''
- log_dir = os.path.join(self.log_dir, app_name)
- if not os.path.isdir(log_dir):
- os.makedirs(log_dir)
- conf_path = os.path.join(self.config_dir, '{}.conf'.format(app_name))
- log_file = os.path.join(log_dir, '{}.log'.format(app_name))
- conf_str = '''
- #程序唯一名称
- [program:{app_name}]
- #程序路径
- directory={dir_name}
- #运行程序的命令
- command={cmd}
- #标准日志输出位置
- stdout_logfile={log_file}
- autostart=true #supervisord启动后,同时启动此程序
- startsecs=5 #启动5秒后没有异常退出,就表示进程正常启动了,默认为1秒
- autorestart=true #程序退出后自动重启
- startretries=3 #启动失败自动重试次数,默认是3
- user={user} #用哪个用户启动进程,默认是root
- redirect_stderr=true #把stderr重定向到stdout标准输出,默认false
- stdout_logfile_maxbytes=50MB #stdout标准输出日志文件大小,日志文件备份数
- stdout_logfile_backups=10
- stopasgroup=true # 停止或终止进程时,同时结束进程包含的子进程
- killasgroup=true
- '''.format(app_name=app_name, dir_name=dir_name, cmd=cmd, log_file=log_file, user=user)
- with open(conf_path, 'w') as fw:
- fw.write(conf_str)
- def _make_supervisor_conf(self):
- cmd = '{} -u {}'.format(self.python_bin, self.exception_warning_file)
- conf = '''
- [unix_http_server]
- file={supervisor_dir}/supervisor.sock ; the path to the socket file
- ;chmod=0700 ; socket file mode (default 0700)
- ;chown=nobody:nogroup ; socket file uid:gid owner
- ;username=user ; default is no username (open server)
- ;password=123 ; default is no password (open server)
- [inet_http_server] ; inet (TCP) server disabled by default
- port=127.0.0.1:59001 ; ip_address:port specifier, *:port for all iface
- username=yunfei_yanfabu ; default is no username (open server)
- password=yanfabu6021 ; default is no password (open server)
- [supervisord]
- logfile={supervisor_dir}/supervisord.log ; main log file; default $CWD/supervisord.log
- logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
- logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
- loglevel=info ; log level; default info; others: debug,warn,trace
- pidfile={supervisor_dir}/supervisord.pid ; supervisord pidfile; default supervisord.pid
- nodaemon=false ; start in foreground if true; default false
- silent=false ; no logs to stdout if true; default false
- minfds=1024 ; min. avail startup file descriptors; default 1024
- minprocs=200 ; min. avail process descriptors;default 200
- ;umask=022 ; process file creation umask; default 022
- user=root ; setuid to this UNIX account at startup; recommended if root
- ;identifier=supervisor ; supervisord identifier, default is 'supervisor'
- ;directory=/tmp ; default is not to cd during start
- ;nocleanup=true ; don't clean up tempfiles at start; default false
- ;childlogdir=/tmp ; 'AUTO' child log dir, default $TEMP
- ;environment=KEY="value" ; key value pairs to add to environment
- ;strip_ansi=false ; strip ansi escape codes in logs; def. false
- [rpcinterface:supervisor]
- supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
- [supervisorctl]
- serverurl=unix://{supervisor_dir}/supervisor.sock
- ;username=chris ; should be same as in [*_http_server] if set
- ;password=123 ; should be same as in [*_http_server] if set
- ;prompt=mysupervisor ; cmd line prompt (default "supervisor")
- ;history_file=~/.sc_history ; use readline history if available
- [eventlistener:crash_warning]
- command={exception_warning_file}
- events=PROCESS_STATE
- redirect_stderr=false
- [include]
- files = {supervisor_dir}/config.d/*.conf
- '''.format(exception_warning_file=cmd, supervisor_dir=self.config_base)
- print(cmd)
- with open(self.base_config_file, 'w') as fw:
- fw.write(conf)
- def _update_task(self):
- '''启动添加的程序'''
- status, msg = True, 'supervisor管理器启动程序成功'
- cmd = '{} update all'.format(self.supervisorctl)
- code, stdout, stderr = shell_cmd(cmd)
- if code != 0:
- status, msg = False, 'supervisor管理器启动程序失败:{}\n{}'.format(stdout, stderr)
- return status, msg
- def make_task(self):
- '''创建supervisor任务并启动'''
- status, msg = self._get_supervisor_app()
- if not status:
- return status, msg
- app_name_set, app_name_list = msg, []
- monitor_config = get_monitor_config()
- with fs.open_fs('/') as root_fs:
- for script_dir, item in monitor_config.items():
- if not os.path.isdir(script_dir):
- continue
- file_filter, file_exclude = item['filter'], item.get('exclude', [])
- python_bin, env_name, cmd_user = item['executable'], item['name'], item['user']
- if not file_exclude:
- file_exclude = None
- if not file_filter:
- file_filter = None
- for path in root_fs.walk.files(script_dir, filter=file_filter, exclude=file_exclude, max_depth=1):
- dir_name, file_name = os.path.split(path)
- index = file_name.rfind('.')
- app_name = file_name[:index] if index != -1 else file_name
- app_name = "{}_{}".format(env_name, app_name)
- if app_name in app_name_set:
- continue
- cmd = '{} -u {}'.format(python_bin, path)
- self._make_task_conf(app_name=app_name, dir_name=dir_name, cmd=cmd, user=cmd_user)
- app_name_list.append(app_name)
- status, msg = True, 'supervisor管理器启动程序成功'
- if app_name_list:
- status, msg = self._update_task()
- return status, msg
- def _check_supervisord(self):
- ''' 检测supervisor管理器进程是否运行'''
- is_run = False
- for proc in psutil.process_iter():
- proc_name = proc.name().lower()
- if proc_name == 'supervisord':
- is_run = True
- break
- return is_run
- def start_supervisord(self):
- '''启动supervisor管理器'''
- msg = ''
- if not os.path.isfile(self.supervisord):
- msg = 'supervisor未安装,请先安装supervisor'
- else:
- is_run = self._check_supervisord()
- if not is_run:
- self._make_supervisor_conf()
- cmd = "{} -c {}".format(self.supervisord, self.base_config_file)
- result = subprocess.run(cmd, shell=True)
- if result.returncode == 0:
- is_run = True
- else:
- msg = '启动supervisor管理器失败, 请检查'
- if is_run:
- status, msg = self.make_task()
- return msg
- def _init_crond():
- cron = CronTab(user='root')
- python_bin = sys.executable
- main_file = os.path.abspath(__file__)
- cmd = "{} {}".format(python_bin, main_file)
- for job in cron:
- if job.command in cmd:
- break
- else:
- new_job = cron.new(cmd, comment="supervise监控脚本,禁止修改")
- new_job.minute.every(2)
- cron.write()
- if __name__ == '__main__':
- _init_crond()
- st = SupervisorTools()
- msg = st.start_supervisord()
- print(msg)
|