[seiscomp, scanloc] Install, add .gitignore
This commit is contained in:
386
lib/python/seiscomp/kernel.py
Normal file
386
lib/python/seiscomp/kernel.py
Normal file
@ -0,0 +1,386 @@
|
||||
############################################################################
|
||||
# Copyright (C) by gempa GmbH, GFZ Potsdam #
|
||||
# #
|
||||
# You can redistribute and/or modify this program under the #
|
||||
# terms of the SeisComP Public License. #
|
||||
# #
|
||||
# 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 #
|
||||
# SeisComP Public License for more details. #
|
||||
############################################################################
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import string
|
||||
import subprocess
|
||||
import seiscomp.config
|
||||
|
||||
|
||||
class Template(string.Template):
|
||||
idpattern = r'[_a-z][_a-z0-9.]*'
|
||||
|
||||
|
||||
class Environment(seiscomp.config.Config):
|
||||
def __init__(self, rootPath):
|
||||
seiscomp.config.Config.__init__(self)
|
||||
self.SEISCOMP_ROOT = rootPath
|
||||
try:
|
||||
self.home_dir = os.environ["HOME"]
|
||||
except:
|
||||
self.home_dir = "."
|
||||
|
||||
try:
|
||||
self.local_config_dir = os.environ["SEISCOMP_LOCAL_CONFIG"]
|
||||
except:
|
||||
self.local_config_dir = os.path.join(self.home_dir, ".seiscomp")
|
||||
|
||||
self.root = rootPath
|
||||
self.bin_dir = os.path.join(self.root, "bin")
|
||||
self.data_dir = os.path.join(self.root, "share")
|
||||
self.etc_dir = os.path.join(self.root, "etc")
|
||||
self.etc_defaults_dir = os.path.join(self.root, "etc", "defaults")
|
||||
self.descriptions_dir = os.path.join(self.root, "etc", "descriptions")
|
||||
self.key_dir = os.path.join(self.root, "etc", "key")
|
||||
self.var_dir = os.path.join(self.root, "var")
|
||||
self.log_dir = os.path.join(self.local_config_dir, "log")
|
||||
self.cwd = None
|
||||
self.last_template_file = None
|
||||
|
||||
self._csv = False
|
||||
self._readConfig()
|
||||
|
||||
os.environ["SEISCOMP_ROOT"] = self.SEISCOMP_ROOT
|
||||
|
||||
# Add LD_LIBRARY_PATH and PATH to OS environment
|
||||
LD_LIBRARY_PATH = os.path.join(self.SEISCOMP_ROOT, "lib")
|
||||
BIN_PATH = os.path.join(self.SEISCOMP_ROOT, "bin")
|
||||
SBIN_PATH = os.path.join(self.SEISCOMP_ROOT, "sbin")
|
||||
PATH = BIN_PATH + ":" + SBIN_PATH
|
||||
PYTHONPATH = os.path.join(self.SEISCOMP_ROOT, "lib", "python")
|
||||
try:
|
||||
LD_LIBRARY_PATH = os.environ["LD_LIBRARY_PATH"] + \
|
||||
":" + LD_LIBRARY_PATH
|
||||
except:
|
||||
pass
|
||||
os.environ["LD_LIBRARY_PATH"] = LD_LIBRARY_PATH
|
||||
try:
|
||||
PATH = PATH + ":" + os.environ["PATH"]
|
||||
except:
|
||||
pass
|
||||
os.environ["PATH"] = PATH
|
||||
try:
|
||||
PYTHONPATH = os.environ["PYTHONPATH"] + ":" + PYTHONPATH
|
||||
except:
|
||||
pass
|
||||
os.environ["PYTHONPATH"] = PYTHONPATH
|
||||
|
||||
# Create required directories
|
||||
try:
|
||||
os.makedirs(os.path.join(self.root, "var", "log"))
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.join(self.root, "var", "run"))
|
||||
except:
|
||||
pass
|
||||
|
||||
def _readConfig(self):
|
||||
self.syslog = False
|
||||
|
||||
# Read configuration file
|
||||
kernelCfg = os.path.join(self.root, "etc", "kernel.cfg")
|
||||
if self.readConfig(kernelCfg) == False:
|
||||
return
|
||||
|
||||
try:
|
||||
self.syslog = self.getBool("syslog")
|
||||
except:
|
||||
pass
|
||||
|
||||
# Changes into the SEISCOMP_ROOT directory
|
||||
def chroot(self):
|
||||
if self.root:
|
||||
# Remember current directory
|
||||
self.cwd = os.getcwd()
|
||||
os.chdir(self.SEISCOMP_ROOT)
|
||||
self.root = ""
|
||||
|
||||
# Changes back to the current workdir
|
||||
def chback(self):
|
||||
if self.cwd:
|
||||
os.chdir(self.cwd)
|
||||
self.cwd = None
|
||||
self.root = self.SEISCOMP_ROOT
|
||||
|
||||
def resolvePath(self, path):
|
||||
return path.replace("@LOGDIR@", self.log_dir)\
|
||||
.replace("@CONFIGDIR@", self.local_config_dir)\
|
||||
.replace("@DEFAULTCONFIGDIR@", self.etc_defaults_dir)\
|
||||
.replace("@SYSTEMCONFIGDIR@", self.etc_dir)\
|
||||
.replace("@ROOTDIR@", self.root)\
|
||||
.replace("@DATADIR@", self.data_dir)\
|
||||
.replace("@KEYDIR@", self.key_dir)\
|
||||
.replace("@HOMEDIR@", self.home_dir)
|
||||
|
||||
def setCSVOutput(self, csv):
|
||||
self._csv = csv
|
||||
|
||||
def enableModule(self, name):
|
||||
runFile = os.path.join(self.root, "etc", "init", name + ".auto")
|
||||
if os.path.exists(runFile):
|
||||
print("%s is already enabled" % name)
|
||||
return 0
|
||||
try:
|
||||
open(runFile, 'w').close()
|
||||
print("enabled %s" % name)
|
||||
return 0
|
||||
except Exception as exc:
|
||||
sys.stderr.write(str(exc) + "\n")
|
||||
sys.stderr.flush()
|
||||
return 0
|
||||
|
||||
def disableModule(self, name):
|
||||
runFile = os.path.join(self.root, "etc", "init", name + ".auto")
|
||||
if not os.path.exists(runFile):
|
||||
print("%s is not enabled" % name)
|
||||
return 0
|
||||
try:
|
||||
os.remove(runFile)
|
||||
print("disabled %s" % name)
|
||||
except Exception as exc:
|
||||
sys.stderr.write(str(exc) + "\n")
|
||||
sys.stderr.flush()
|
||||
return 0
|
||||
|
||||
def isModuleEnabled(self, name):
|
||||
runFile = os.path.join(self.root, "etc", "init", name + ".auto")
|
||||
return os.path.exists(runFile) == True
|
||||
|
||||
# Return the module name from a path
|
||||
def moduleName(self, path):
|
||||
return os.path.splitext(os.path.basename(path))[0]
|
||||
|
||||
# Returns a module's lockfile
|
||||
def lockFile(self, module):
|
||||
return os.path.join(self.root, "var", "run", module + ".pid")
|
||||
|
||||
# Returns a module's runfile
|
||||
def runFile(self, module):
|
||||
return os.path.join(self.root, "var", "run", module + ".run")
|
||||
|
||||
# Returns a module's logfile
|
||||
def logFile(self, module):
|
||||
return os.path.join(self.root, "var", "log", module + ".log")
|
||||
|
||||
# Returns the binary file path of a given module name
|
||||
def binaryFile(self, module):
|
||||
# return os.path.join(self.root, "bin/" + module)
|
||||
return module
|
||||
|
||||
def start(self, module, binary, params, nohup=False):
|
||||
cmd = binary + " " + params + " >" + self.logFile(module) + " 2>&1"
|
||||
if nohup:
|
||||
cmd = "nohup " + cmd + " &"
|
||||
return os.system(cmd)
|
||||
|
||||
def stop(self, module, timeout):
|
||||
return self.killWait(module, timeout)
|
||||
|
||||
def tryLock(self, module, timeout = None):
|
||||
if timeout is None:
|
||||
return subprocess.call("trylock " + self.lockFile(module), shell=True) == 0
|
||||
else:
|
||||
try:
|
||||
timeoutSeconds = int(timeout)
|
||||
except:
|
||||
print("Invalid timeout parameter, expected positive integer")
|
||||
raise
|
||||
return subprocess.call("waitlock %d \"%s\"" % (timeoutSeconds, self.lockFile(module)), shell=True) == 0
|
||||
|
||||
def killWait(self, module, timeout):
|
||||
lockfile = self.lockFile(module)
|
||||
|
||||
# Open pid file
|
||||
f = open(lockfile, "r")
|
||||
|
||||
# Try to read the pid
|
||||
try:
|
||||
pid = int(f.readline())
|
||||
except:
|
||||
f.close()
|
||||
raise
|
||||
|
||||
# Kill process with pid
|
||||
subprocess.call("kill %d" % pid, shell=True)
|
||||
if subprocess.call("waitlock %d \"%s\"" % (timeout, lockfile), shell=True) != 0:
|
||||
print("timeout exceeded")
|
||||
subprocess.call("kill -9 %d" % pid, shell=True)
|
||||
|
||||
# Remove pid file
|
||||
try:
|
||||
os.remove(lockfile)
|
||||
except:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
def processTemplate(self, templateFile, paths, params, printError=False):
|
||||
self.last_template_file = None
|
||||
|
||||
for tp in paths:
|
||||
if os.path.exists(os.path.join(tp, templateFile)):
|
||||
break
|
||||
|
||||
else:
|
||||
if printError:
|
||||
print("Error: template %s not found" % templateFile)
|
||||
return ""
|
||||
|
||||
filename = os.path.join(tp, templateFile)
|
||||
self.last_template_file = filename
|
||||
|
||||
try:
|
||||
t = Template(open(filename).read())
|
||||
except:
|
||||
if printError:
|
||||
print("Error: template %s not readable" % filename)
|
||||
return ""
|
||||
|
||||
params['date'] = time.ctime()
|
||||
params['template'] = filename
|
||||
|
||||
while True:
|
||||
try:
|
||||
return t.substitute(params)
|
||||
|
||||
except KeyError as e:
|
||||
print("warning: $%s is not defined in %s" % (e.args[0], filename))
|
||||
params[e.args[0]] = ""
|
||||
|
||||
except ValueError as e:
|
||||
raise ValueError("%s: %s" % (filename, str(e)))
|
||||
|
||||
def logStatus(self, name, isRunning, shouldRun, isEnabled):
|
||||
if self._csv == False:
|
||||
sys.stdout.write("%-20s is " % name)
|
||||
if not isRunning:
|
||||
sys.stdout.write("not ")
|
||||
sys.stdout.write("running")
|
||||
if not isRunning and shouldRun:
|
||||
sys.stdout.write(" [WARNING]")
|
||||
sys.stdout.write("\n")
|
||||
else:
|
||||
sys.stdout.write("%s;%d;%d;%d\n" % (
|
||||
name, int(isRunning), int(shouldRun), int(isEnabled)))
|
||||
sys.stdout.flush()
|
||||
|
||||
def log(self, line):
|
||||
sys.stdout.write(line + "\n")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
# The module interface which implementes the basic default operations.
|
||||
# Each script can define its own handlers to customize the behaviour.
|
||||
# Available handlers:
|
||||
# start()
|
||||
# stop()
|
||||
# check()
|
||||
# status(shouldRun)
|
||||
# setup(params = dict{name, values as []})
|
||||
# updateConfig()
|
||||
class Module:
|
||||
def __init__(self, env, name):
|
||||
self.env = env
|
||||
self.name = name
|
||||
# The start order
|
||||
self.order = 100
|
||||
# Defines if this is a kernel module or not.
|
||||
# Kernel modules are always started
|
||||
self.isKernelModule = False
|
||||
# Defines if this is a config only module
|
||||
self.isConfigModule = False
|
||||
# Set default timeout when stopping a module to 10 seconds before killing it
|
||||
self.killTimeout = 10
|
||||
# Set default timeout when reloading a module to 10 seconds
|
||||
self.reloadTimeout = 10
|
||||
|
||||
def _get_start_params(self):
|
||||
# Run as daemon
|
||||
params = "-D"
|
||||
|
||||
# Enable syslog if configured
|
||||
if self.env.syslog == True:
|
||||
params = params + "s"
|
||||
|
||||
params = params + " -l " + self.env.lockFile(self.name)
|
||||
return params
|
||||
|
||||
def _run(self):
|
||||
return self.env.start(self.name, self.env.binaryFile(self.name), self._get_start_params())
|
||||
|
||||
def isRunning(self):
|
||||
return self.env.tryLock(self.name) == False
|
||||
|
||||
def start(self):
|
||||
if self.isRunning():
|
||||
self.env.log("%s is already running" % self.name)
|
||||
return 1
|
||||
|
||||
self.env.log("starting %s" % self.name)
|
||||
return self._run()
|
||||
|
||||
def stop(self):
|
||||
if not self.isRunning():
|
||||
self.env.log("%s is not running" % self.name)
|
||||
return 1
|
||||
|
||||
self.env.log("shutting down %s" % self.name)
|
||||
# Default timeout to 10 seconds
|
||||
return self.env.stop(self.name, self.killTimeout)
|
||||
|
||||
def reload(self):
|
||||
self.env.log("reload not supported by %s" % self.name)
|
||||
return 1
|
||||
|
||||
# Check is the same as start. If a module should be checked
|
||||
# is decided by the control script which check the existence
|
||||
# of a corresponding run file.
|
||||
def check(self):
|
||||
return self.start()
|
||||
|
||||
def status(self, shouldRun):
|
||||
self.env.logStatus(self.name, self.isRunning(), shouldRun, self.env.isModuleEnabled(
|
||||
self.name) or isinstance(self, CoreModule))
|
||||
|
||||
def requiresKernelModules(self):
|
||||
# The default handler triggers a start of kernel modules before updating
|
||||
# its configuration
|
||||
return True
|
||||
|
||||
def updateConfigProxy(self):
|
||||
# This function must return either a string containing the module name
|
||||
# of the proxy module that should be configured as well or None.
|
||||
return None
|
||||
|
||||
def updateConfig(self):
|
||||
# This function must return a number indicating the error code where
|
||||
# 0 means no error. The default handler doesn't do anything.
|
||||
return 0
|
||||
|
||||
def printCrontab(self):
|
||||
# The default handler doesn't do anything
|
||||
return 0
|
||||
|
||||
def supportsAliases(self):
|
||||
# The default handler does not support aliases
|
||||
return False
|
||||
|
||||
|
||||
# Define a kernel core module which is started always
|
||||
class CoreModule(Module):
|
||||
def __init__(self, env, name):
|
||||
Module.__init__(self, env, name)
|
Reference in New Issue
Block a user