mirror of
https://github.com/r4sas/py-i2phosts
synced 2025-02-02 09:55:52 +00:00
d975295892
I don't remember why it was set to 077 initially, but now I see it causes problems. Exactly, py-i2phosts-builer called from master creates hosts.txt file with 600 permissions, so file is not readable by nginx for example. New umask fixes this problem.
168 lines
5.0 KiB
Python
Executable File
168 lines
5.0 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
import os
|
|
import sys
|
|
import pwd
|
|
import errno
|
|
import argparse
|
|
import time
|
|
import configobj
|
|
import validate
|
|
import subprocess
|
|
import threading
|
|
import daemon
|
|
# workaround for python-daemon >= 1.6
|
|
try:
|
|
import daemon.pidlockfile as pidfile
|
|
except ImportError:
|
|
import daemon.pidfile as pidfile
|
|
|
|
class Thread(threading.Thread):
|
|
|
|
def __init__(self):
|
|
threading.Thread.__init__(self)
|
|
self.setDaemon(True)
|
|
|
|
|
|
class FetcherThread(Thread):
|
|
""" Run py-i2phosts-fetcher periodically """
|
|
|
|
def run(self):
|
|
while True:
|
|
run_prog('py-i2phosts-fetcher')
|
|
time.sleep(float(config['fetch_interval']))
|
|
|
|
|
|
class CheckerThread(Thread):
|
|
""" Run py-i2phosts-checker, py-i2phosts-maint, py-i2phosts-builder periodically """
|
|
|
|
def run(self):
|
|
while True:
|
|
run_prog('py-i2phosts-checker')
|
|
run_prog('py-i2phosts-maint')
|
|
run_prog('py-i2phosts-builder')
|
|
time.sleep(float(config['check_interval']))
|
|
|
|
|
|
def run_prog(prog):
|
|
try:
|
|
log.info('starting: %s', prog)
|
|
sp_args = [prog]
|
|
if args.debug or args.verbose:
|
|
sp_args.append('-d')
|
|
p = subprocess.Popen(sp_args, shell=False)
|
|
except OSError, e:
|
|
log.error('failed to exec %s: %s', prog, e)
|
|
if e.errno == errno.ENOENT:
|
|
log.error(' maybe it isn\'t in PATH?')
|
|
else:
|
|
p.wait()
|
|
log.info('finished: %s', prog)
|
|
|
|
|
|
def main():
|
|
def run_fetcher():
|
|
fetcher = FetcherThread()
|
|
fetcher.start()
|
|
return fetcher
|
|
|
|
def run_checker():
|
|
checker = CheckerThread()
|
|
checker.start()
|
|
return checker
|
|
|
|
# if we're just started, wait while fetcher get some new hosts
|
|
fetcher = run_fetcher()
|
|
log.debug('just started, delaying checker run for 300 secs')
|
|
fetcher.join(300) # wait for 5 mins
|
|
# start checker and other
|
|
checker = run_checker()
|
|
|
|
while True:
|
|
log.debug('checking fetcher and checker threads status')
|
|
if fetcher.isAlive() == False:
|
|
log.warning('fetcher thread is dead, respawning...')
|
|
fetcher = run_fetcher()
|
|
else:
|
|
log.debug('fetcher thread: alive')
|
|
if checker.isAlive() == False:
|
|
log.warning('checker thread is dead, respawning...')
|
|
checker = run_checker()
|
|
else:
|
|
log.debug('checker thread: alive')
|
|
# do check every 30 mins
|
|
time.sleep(1800)
|
|
|
|
# parse command line options
|
|
parser = argparse.ArgumentParser(
|
|
description='Master daemon for py-i2phosts.',
|
|
epilog='Report bugs to http://zzz.i2p/topics/733')
|
|
parser.add_argument('-d', '--debug', action='store_true',
|
|
help='run in debug mode without detaching from terminal'),
|
|
parser.add_argument('-v', '--verbose', action='store_true',
|
|
help='run in verbose mode without detaching from terminal'),
|
|
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/master.conf', dest='config_file',
|
|
help='config file to use')
|
|
args = parser.parse_args()
|
|
|
|
# read and validate config
|
|
spec = '''
|
|
log_file = string(default='/var/log/py-i2phosts/master.log')
|
|
log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
|
|
pid_file = string(default='/var/run/py-i2phosts/master.pid')
|
|
runas = string(default='_pyi2phosts')
|
|
check_interval = integer(default=43200)
|
|
fetch_interval = integer(default=1800)
|
|
'''
|
|
spec = spec.split('\n')
|
|
config = configobj.ConfigObj(args.config_file, configspec=spec)
|
|
if 'include' in config:
|
|
config_included = configobj.ConfigObj(config['include'])
|
|
config.merge(config_included)
|
|
|
|
# django setup
|
|
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
|
|
if 'DJANGO_PROJECT_PATH' in config:
|
|
DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
|
|
else:
|
|
DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
|
|
sys.path.insert(1, DJANGO_PROJECT_PATH)
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
|
|
from pyi2phosts.lib.utils import get_logger
|
|
from pyi2phosts.lib.utils import validate_config
|
|
|
|
# validate config
|
|
validate_config(config)
|
|
|
|
# configure logger
|
|
if args.debug == True:
|
|
log_level = 'debug'
|
|
log_file = None
|
|
elif args.verbose == True:
|
|
log_level = 'info'
|
|
log_file = None
|
|
else:
|
|
log_level = config['log_level']
|
|
log_file = config['log_file']
|
|
|
|
if not args.debug and not args.verbose:
|
|
# get pid object for daemon
|
|
pid = pidfile.TimeoutPIDLockFile(config['pid_file'], 10)
|
|
# create daemon context
|
|
d = daemon.DaemonContext(pidfile=pid, umask=022)
|
|
# write stderr to logfile # FIXME: and how we will deal with log rotation?
|
|
logfile = open(config['log_file'], 'a')
|
|
d.stderr = logfile
|
|
d.stdout = logfile
|
|
# drop privileges when started as root
|
|
if os.getuid() == 0:
|
|
runas = config['runas']
|
|
pw_entry = pwd.getpwnam(runas)
|
|
d.uid = pw_entry[2]
|
|
d.gid = pw_entry[3]
|
|
os.chown(config['log_file'], d.uid, d.gid)
|
|
d.open() # become daemon
|
|
log = get_logger(filename=log_file, log_level=log_level)
|
|
log.info('started')
|
|
main()
|