Commit 1dd023c8 authored by Ad Schellevis's avatar Ad Schellevis

(configd) watch configd process for unexpected exit and restart if necessary.

parent 6d4953d2
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
Copyright (c) 2014 Ad Schellevis Copyright (c) 2014-2016 Ad Schellevis
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
...@@ -37,6 +37,7 @@ __author__ = 'Ad Schellevis' ...@@ -37,6 +37,7 @@ __author__ = 'Ad Schellevis'
import os import os
import sys import sys
import logging import logging
import subprocess
import modules.processhandler import modules.processhandler
import modules.csconfigparser import modules.csconfigparser
from modules.daemonize import Daemonize from modules.daemonize import Daemonize
...@@ -52,36 +53,58 @@ else: ...@@ -52,36 +53,58 @@ else:
sys.path.append(program_path) sys.path.append(program_path)
os.chdir(program_path) os.chdir(program_path)
# open configuration def get_config():
cnf = modules.csconfigparser.CSConfigParser() """ open configuration
cnf.read('conf/configd.conf') """
cnf = modules.csconfigparser.CSConfigParser()
# validate configuration, exit on missing item cnf.read('conf/configd.conf')
for config_item in ['socket_filename','pid_filename']: return cnf
if cnf.has_section('main') == False or cnf.has_option('main',config_item) == False:
print('configuration item main/%s not found in %s/conf/configd.conf'%(config_item,program_path)) def validate_config(cnf):
sys.exit(0) """ validate configuration, exit on missing item
"""
# setup configd environment to use for all configured actions for config_item in ['socket_filename','pid_filename']:
if not cnf.has_section('environment'): if cnf.has_section('main') == False or cnf.has_option('main',config_item) == False:
config_environment = os.environ.copy() print('configuration item main/%s not found in %s/conf/configd.conf'%(config_item,program_path))
else: sys.exit(0)
config_environment={}
for envKey in cnf.items('environment'): def main(cnf, simulate=False, single_threaded=False):
config_environment[envKey[0]] = envKey[1] """ configd startup
"""
# run process coordinator ( on console or as daemon ) # setup configd environment to use for all configured actions
# if command-line arguments contain "emulate", start in emulation mode if not cnf.has_section('environment'):
if len(sys.argv) > 1 and 'simulate' in sys.argv[1:]: config_environment = os.environ.copy()
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'), else:
config_path='%s/conf'%program_path, config_environment={}
config_environment=config_environment, for envKey in cnf.items('environment'):
simulation_mode=True) config_environment[envKey[0]] = envKey[1]
else:
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'), # run process coordinator ( on console or as daemon )
config_path='%s/conf'%program_path, # if command-line arguments contain "emulate", start in emulation mode
config_environment=config_environment) if simulate:
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'),
config_path='%s/conf'%program_path,
config_environment=config_environment,
simulation_mode=True)
else:
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'),
config_path='%s/conf'%program_path,
config_environment=config_environment)
proc_handler.single_threaded = single_threaded
proc_handler.run()
def run_watch():
""" start configd process and restart if it dies unexpected
"""
while True:
process = subprocess.Popen(['/usr/local/opnsense/service/configd.py', 'console'])
# optional dump process.pid into a pid file, but because the daemon is stopped by name
# this shouldn't be necessary
process.wait()
this_config = get_config()
validate_config(this_config)
if len(sys.argv) > 1 and 'console' in sys.argv[1:]: if len(sys.argv) > 1 and 'console' in sys.argv[1:]:
print('run %s in console mode'%sys.argv[0]) print('run %s in console mode'%sys.argv[0])
if 'profile' in sys.argv[1:]: if 'profile' in sys.argv[1:]:
...@@ -93,8 +116,11 @@ if len(sys.argv) > 1 and 'console' in sys.argv[1:]: ...@@ -93,8 +116,11 @@ if len(sys.argv) > 1 and 'console' in sys.argv[1:]:
profile = cProfile.Profile() profile = cProfile.Profile()
profile.enable(subcalls=True) profile.enable(subcalls=True)
try: try:
proc_handler.single_threaded = True if len(sys.argv) > 1 and 'simulate' in sys.argv[1:]:
proc_handler.run() print('simulate calls.')
main(cnf=this_config, simulate=True, single_threaded=True)
else:
main(cnf=this_config, single_threaded=True)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
except: except:
...@@ -102,8 +128,9 @@ if len(sys.argv) > 1 and 'console' in sys.argv[1:]: ...@@ -102,8 +128,9 @@ if len(sys.argv) > 1 and 'console' in sys.argv[1:]:
profile.disable() profile.disable()
profile.dump_stats('/tmp/configd.profile') profile.dump_stats('/tmp/configd.profile')
else: else:
proc_handler.run() main(cnf=this_config)
else: else:
# run as daemon, wrap the actual work process to enable automatic restart on sudden death
syslog_socket = "/var/run/log" syslog_socket = "/var/run/log"
if os.path.exists(syslog_socket): if os.path.exists(syslog_socket):
# bind log handle to syslog to catch messages from Daemonize() # bind log handle to syslog to catch messages from Daemonize()
...@@ -118,10 +145,9 @@ else: ...@@ -118,10 +145,9 @@ else:
loghandle = None loghandle = None
# daemonize process # daemonize process
daemon = Daemonize(app=__file__.split('/')[-1].split('.py')[0], daemon = Daemonize(app=__file__.split('/')[-1].split('.py')[0],
pid=cnf.get('main','pid_filename'), pid=this_config.get('main','pid_filename'),
action=proc_handler.run, action=run_watch,
logger=loghandle logger=loghandle
) )
daemon.start() daemon.start()
sys.exit(0) sys.exit(0)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment