Fix/Improve startup/init.

Change-Id: Ia4b90c75a8cf89f4069bd8984a0e0c88f9ffa832
This commit is contained in:
Alexander Lenz
2016-08-08 11:12:19 +02:00
parent e0bf201b48
commit 2dae7649be
5 changed files with 153 additions and 77 deletions

View File

@ -48,15 +48,10 @@ def parseArgv(argv):
action='store_true', default=False)
loggroup.add_argument("-q", "--quiet", help="suppress non-error messages",
action='store_true', default=False)
parser.add_argument("action",
help="What to do: (re)start, status or stop",
choices=['start', 'status', 'stop', 'restart'],
default="status")
parser.add_argument("name",
type=str,
help="Name of the instance.\n"
" Uses etc/name.cfg for configuration\n"
"may be omitted to mean ALL (which are configured)",
nargs='?', default='')
" Uses etc/name.cfg for configuration\n",)
parser.add_argument('-d',
'--daemonize',
action='store_true',
@ -73,45 +68,16 @@ def main(argv=None):
loglevel = 'debug' if args.verbose else ('error' if args.quiet else 'info')
loggers.initLogging('secop', loglevel, path.join(log_path))
logger = loggers.log
srvNames = []
srv = Server(args.name, basepath)
if not args.name:
print('No name given, iterating over all specified servers')
for dirpath, dirs, files in os.walk(etc_path):
for fn in files:
if fn.endswith('.cfg'):
srvNames.append(fn[:-4])
else:
logger.debug('configfile with strange extension found: %r'
% path.basename(fn))
# ignore subdirs!
while (dirs):
dirs.pop()
if args.daemonize:
srv.start()
else:
srvNames = [args.name]
srvs = []
for entry in srvNames:
srv = Server(entry, basepath)
srvs.append(srv)
if args.action == "restart":
srv.stop()
srv.start()
elif args.action == "start":
if len(srvNames) > 1 or args.daemonize:
srv.start()
else:
srv.run()
elif args.action == "stop":
srv.stop()
elif args.action == "status":
if srv.isAlive():
logger.info("Server %s is running." % entry)
else:
logger.info("Server %s is DEAD!" % entry)
try:
srv.run()
except KeyboardInterrupt:
pass
if __name__ == '__main__':

124
etc/secop-server Executable file
View File

@ -0,0 +1,124 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
### BEGIN INIT INFO
# Provides: secop-server
# Required-Start: $local_fs $remote_fs $network $named $time
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Secop servers
### END INIT INFO
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Alexander Lenz <alexander.lenz@frm2.tum.de>
#
# *****************************************************************************
import sys
import argparse
import os.path
import glob
import signal
CFG_DIR='/etc/secop'
PID_DIR = '/var/run'
SRV_EXEC = 'secop-server'
inplace_basedir = os.path.join(os.path.dirname(__file__), '..')
if os.path.isfile(os.path.join(inplace_basedir, 'src', '__init__.py')):
CFG_DIR = os.path.join(inplace_basedir, 'etc')
PID_DIR = os.path.join(inplace_basedir, 'pid')
SRV_EXEC = os.path.join(inplace_basedir, 'bin/secop-server')
def parseArgv(argv):
parser = argparse.ArgumentParser(description='Manage a SECoP server')
parser.add_argument('action',
type=str,
choices=['start', 'stop', 'restart', 'status'],
help='What to do with the desired server', )
parser.add_argument('name',
nargs='*',
help='Name of the instance.\n'
' Uses etc/name.cfg for configuration\n',)
return parser.parse_args()
def getServerNames():
return sorted([os.path.basename(entry)[:-4]
for entry in glob.glob(os.path.join(CFG_DIR, '*.cfg'))])
def getSrvPid(name):
pidfile = os.path.join(PID_DIR, '%s.pid' % name)
if not os.path.isfile(pidfile):
return None
with open(pidfile) as f:
return int(f.read())
def startServer(name):
pid = getSrvPid(name)
if pid:
print('%s: already running (pid: %s)' % (name, pid))
else:
print('%s: starting ...' % name)
os.system('%s -d %s' % (SRV_EXEC, name))
def stopServer(name):
pid = getSrvPid(name)
if pid:
print('%s: stopping ...' % name)
os.kill(pid, signal.SIGTERM)
else:
print('%s: already stopped' % name)
def determineServerStatus(name):
pid = getSrvPid(name)
if pid:
print('%s: running (pid: %s)' % (name, pid))
else:
print('%s: dead' % name)
def main(argv=None):
if argv is None:
argv = sys.argv
args = parseArgv(argv[1:])
actionMap = {
'start' : startServer,
'stop': stopServer,
'status': determineServerStatus,
}
srvs = args.name
if not srvs:
srvs = getServerNames()
for entry in srvs:
actionMap[args.action](entry)
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@ -2,8 +2,7 @@
markdown>=2.6
# general stuff
psutil
# daemonizing not yet functional (logging problems)
#daemonize
python-daemon
# for zmq
#pyzmq>=13.1.0

View File

@ -87,6 +87,13 @@ class SecopLogger(Logger):
return child
def getLogfileStreams(self):
result = []
for entry in self._collectHandlers():
if isinstance(entry, LogfileHandler):
result.append(entry.stream)
return result
def _collectHandlers(self):
result = []

View File

@ -26,9 +26,8 @@ import os
import psutil
import ConfigParser
# apt install python-daemon !!!do not use pip install daemon <- wrong version!
import daemon
#from daemon import pidlockfile
from daemon import DaemonContext
from daemon.pidfile import TimeoutPIDLockFile
import loggers
from lib import read_pidfile, write_pidfile, get_class, check_pidfile
@ -54,39 +53,20 @@ class Server(object):
self._interface = None
def start(self):
pidfile = pidlockfile.TimeoutPIDLockFile(self._pidfile, 3)
piddir = os.path.dirname(self._pidfile)
if not os.path.isdir(piddir):
os.makedirs(piddir)
pidfile = TimeoutPIDLockFile(self._pidfile)
with daemon.DaemonContext(
# files_preserve=[logFileHandler.stream],
pidfile=pidfile,
):
try:
# write_pidfile(pidfilename, os.getpid())
self.run()
except Exception as e:
self.log.exception(e)
if pidfile.is_locked():
self.log.error('Pidfile already exists. Exiting')
def stop(self):
pid = read_pidfile(self._pidfile)
if pid is None:
# already dead/not started yet
return
# get process for this pid
for proc in psutil.process_iter():
if proc.pid == pid:
break
proc.terminate()
proc.wait(3)
proc.kill()
def isAlive(self):
if check_pidfile(self._pidfile):
return True
return False
with DaemonContext(working_directory=self._workdir,
pidfile=pidfile,
files_preserve=self.log.getLogfileStreams()):
self.run()
def run(self):
# write pidfile before doing actual things
write_pidfile(self._pidfile, os.getpid())
self._processCfg()
self.log.info('startup done, handling transport messages')