Files
web2py/scripts/service/linux.py
mdipierro 5bc5d0496e R-2.9.12
2015-01-17 00:07:10 -06:00

221 lines
6.4 KiB
Python

from service import ServiceBase
import os, sys, time, subprocess, atexit
from signal import SIGTERM
class LinuxService(ServiceBase):
def __init__(self, name, label, stdout='/dev/null', stderr='/dev/null'):
ServiceBase.__init__(self, name, label, stdout, stderr)
self.pidfile = '/tmp/%s.pid' % name
self.config_file = '/etc/%s.conf' % name
def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
return
# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
return
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file('/dev/null', 'r')
so = file(self.stdout or '/dev/null', 'a+')
se = file(self.stderr or '/dev/null', 'a+')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
def getpid(self):
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
return pid
def status(self):
pid = self.getpid()
if pid:
return 'Service running with PID %s.' % pid
else:
return 'Service is not running.'
def check_permissions(self):
if not os.geteuid() == 0:
return (False, 'This script must be run with root permissions.')
else:
return (True, '')
def start(self):
"""
Start the daemon
"""
pid = self.getpid()
if pid:
message = "Service already running under PID %s\n"
sys.stderr.write(message % self.pidfile)
return
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""
Stop the daemon
"""
pid = self.getpid()
if not pid:
message = "Service is not running\n"
sys.stderr.write(message)
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.5)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
return
def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()
def run(self):
atexit.register(self.terminate)
args = self.load_configuration()[0]
stdout = open(self.stdout, 'a+')
stderr = open(self.stderr, 'a+')
process = subprocess.Popen(args, stdout=stdout, stderr=stderr)
file(self.pidfile,'w+').write("%s\n" % process.pid)
process.wait()
self.terminate()
def terminate(self):
try:
os.remove(self.pidfile)
except:
pass
def install(self):
env = self.detect_environment()
src_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'service.py')
# make sure this script is executable
self.run_command('chmod', '+x', src_path)
# link this daemon to the service directory
dest_path = env['rc.d-path'] + self.name
os.symlink(src_path, dest_path)
# start the service at boot
install_command = self.get_service_installer_command(env)
result = self.run_command(*install_command)
self.start()
def uninstall(self):
self.stop()
env = self.detect_environment()
# stop the service from autostarting
uninstall_command = self.get_service_uninstaller_command(env)
result = self.run_command(*uninstall_command)
# remove link to the script from the service directory
path = env['rc.d-path'] + self.name
os.remove(path)
def detect_environment(self):
"""
Returns a dictionary of command/path to the required command-line applications.
One key is 'dist' which will either be 'debian' or 'redhat', which is the best
guess as to which Linux distribution the current system is based on.
"""
check_for = [
'chkconfig',
'service',
'update-rc.d',
'rpm',
'dpkg',
]
env = dict()
for cmd in check_for:
result = self.run_command('which', cmd)
if result[0]:
env[cmd] = result[0].replace('\n', '')
if 'rpm' in env:
env['dist'] = 'redhat'
env['rc.d-path'] = '/etc/rc.d/init.d/'
elif 'dpkg' in env:
env['dist'] = 'debian'
env['rc.d-path'] = '/etc/init.d/'
else:
env['dist'] = 'unknown'
env['rc.d-path'] = '/dev/null/'
return env
def get_service_installer_command(self, env):
"""
Returns list of args required to set a service to run on boot.
"""
if env['dist'] == 'redhat':
cmd = env['chkconfig']
return [cmd, self.name, 'on']
else:
cmd = env['update-rc.d']
return [cmd, self.name, 'defaults']
def get_service_uninstaller_command(self, env):
"""
Returns list of arge required to stop a service from running at boot.
"""
if env['dist'] == 'redhat':
cmd = env['chkconfig']
return [cmd, self.name, 'off']
else:
cmd = env['update-rc.d']
return [cmd, self.name, 'remove']