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
def validate_config(cnf):
""" validate configuration, exit on missing item
"""
for config_item in ['socket_filename','pid_filename']:
if cnf.has_section('main') == False or cnf.has_option('main',config_item) == False: 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)) print('configuration item main/%s not found in %s/conf/configd.conf'%(config_item,program_path))
sys.exit(0) sys.exit(0)
# setup configd environment to use for all configured actions def main(cnf, simulate=False, single_threaded=False):
if not cnf.has_section('environment'): """ configd startup
"""
# setup configd environment to use for all configured actions
if not cnf.has_section('environment'):
config_environment = os.environ.copy() config_environment = os.environ.copy()
else: else:
config_environment={} config_environment={}
for envKey in cnf.items('environment'): for envKey in cnf.items('environment'):
config_environment[envKey[0]] = envKey[1] config_environment[envKey[0]] = envKey[1]
# run process coordinator ( on console or as daemon ) # run process coordinator ( on console or as daemon )
# if command-line arguments contain "emulate", start in emulation mode # if command-line arguments contain "emulate", start in emulation mode
if len(sys.argv) > 1 and 'simulate' in sys.argv[1:]: if simulate:
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'), proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'),
config_path='%s/conf'%program_path, config_path='%s/conf'%program_path,
config_environment=config_environment, config_environment=config_environment,
simulation_mode=True) simulation_mode=True)
else: else:
proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'), proc_handler = modules.processhandler.Handler(socket_filename=cnf.get('main','socket_filename'),
config_path='%s/conf'%program_path, config_path='%s/conf'%program_path,
config_environment=config_environment) 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