daemon: Add a startup service.
When enabled, the startup service ensures that other node services start in order (according to the service _startindex value) and that the prior service completes before the next service starts. It also captures any output from startup commands in a file named 'startup.log'.
This commit is contained in:
parent
2c8744f14e
commit
ac19cfa7ff
3 changed files with 51 additions and 7 deletions
|
@ -63,7 +63,8 @@ class CoreServices(ConfigurableManager):
|
||||||
for path in paths.split(','):
|
for path in paths.split(','):
|
||||||
path = path.strip()
|
path = path.strip()
|
||||||
self.importcustom(path)
|
self.importcustom(path)
|
||||||
|
self.isStartupService = startup.Startup.isStartupService
|
||||||
|
|
||||||
def importcustom(self, path):
|
def importcustom(self, path):
|
||||||
''' Import services from a myservices directory.
|
''' Import services from a myservices directory.
|
||||||
'''
|
'''
|
||||||
|
@ -217,24 +218,25 @@ class CoreServices(ConfigurableManager):
|
||||||
'''
|
'''
|
||||||
services = sorted(node.services,
|
services = sorted(node.services,
|
||||||
key=lambda service: service._startindex)
|
key=lambda service: service._startindex)
|
||||||
|
useStartupService = any(map(self.isStartupService, services))
|
||||||
for s in services:
|
for s in services:
|
||||||
if len(str(s._starttime)) > 0:
|
if len(str(s._starttime)) > 0:
|
||||||
try:
|
try:
|
||||||
t = float(s._starttime)
|
t = float(s._starttime)
|
||||||
if t > 0.0:
|
if t > 0.0:
|
||||||
fn = self.bootnodeservice
|
fn = self.bootnodeservice
|
||||||
self.session.evq.add_event(t, fn, node, s, services)
|
self.session.evq.add_event(t, fn, node, s, services, False)
|
||||||
continue
|
continue
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
self.bootnodeservice(node, s, services)
|
self.bootnodeservice(node, s, services, useStartupService)
|
||||||
|
|
||||||
def bootnodeservice(self, node, s, services):
|
def bootnodeservice(self, node, s, services, useStartupService):
|
||||||
''' Start a service on a node. Create private dirs, generate config
|
''' Start a service on a node. Create private dirs, generate config
|
||||||
files, and execute startup commands.
|
files, and execute startup commands.
|
||||||
'''
|
'''
|
||||||
if s._custom:
|
if s._custom:
|
||||||
self.bootnodecustomservice(node, s, services)
|
self.bootnodecustomservice(node, s, services, useStartupService)
|
||||||
return
|
return
|
||||||
if node.verbose:
|
if node.verbose:
|
||||||
node.info("starting service %s (%s)" % (s._name, s._startindex))
|
node.info("starting service %s (%s)" % (s._name, s._startindex))
|
||||||
|
@ -247,6 +249,8 @@ class CoreServices(ConfigurableManager):
|
||||||
for filename in s.getconfigfilenames(node.objid, services):
|
for filename in s.getconfigfilenames(node.objid, services):
|
||||||
cfg = s.generateconfig(node, filename, services)
|
cfg = s.generateconfig(node, filename, services)
|
||||||
node.nodefile(filename, cfg)
|
node.nodefile(filename, cfg)
|
||||||
|
if useStartupService and not self.isStartupService(s):
|
||||||
|
return
|
||||||
for cmd in s.getstartup(node, services):
|
for cmd in s.getstartup(node, services):
|
||||||
try:
|
try:
|
||||||
# NOTE: this wait=False can be problematic!
|
# NOTE: this wait=False can be problematic!
|
||||||
|
@ -254,7 +258,7 @@ class CoreServices(ConfigurableManager):
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
node.warn("error starting command %s: %s" % (cmd, e))
|
node.warn("error starting command %s: %s" % (cmd, e))
|
||||||
|
|
||||||
def bootnodecustomservice(self, node, s, services):
|
def bootnodecustomservice(self, node, s, services, useStartupService):
|
||||||
''' Start a custom service on a node. Create private dirs, use supplied
|
''' Start a custom service on a node. Create private dirs, use supplied
|
||||||
config files, and execute supplied startup commands.
|
config files, and execute supplied startup commands.
|
||||||
'''
|
'''
|
||||||
|
@ -284,6 +288,9 @@ class CoreServices(ConfigurableManager):
|
||||||
continue
|
continue
|
||||||
node.nodefile(filename, cfg)
|
node.nodefile(filename, cfg)
|
||||||
|
|
||||||
|
if useStartupService and not self.isStartupService(s):
|
||||||
|
return
|
||||||
|
|
||||||
for cmd in s._startup:
|
for cmd in s._startup:
|
||||||
try:
|
try:
|
||||||
# NOTE: this wait=False can be problematic!
|
# NOTE: this wait=False can be problematic!
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
Services available to nodes can be put in this directory. Everything listed in
|
Services available to nodes can be put in this directory. Everything listed in
|
||||||
__all__ is automatically loaded by the main core module.
|
__all__ is automatically loaded by the main core module.
|
||||||
"""
|
"""
|
||||||
__all__ = ["quagga", "nrl", "xorp", "bird", "utility", "security", "ucarp", "dockersvc"]
|
__all__ = ["quagga", "nrl", "xorp", "bird", "utility", "security", "ucarp", "dockersvc", 'startup']
|
||||||
|
|
37
daemon/core/services/startup.py
Normal file
37
daemon/core/services/startup.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from core.service import CoreService, addservice
|
||||||
|
from sys import maxint
|
||||||
|
from inspect import isclass
|
||||||
|
|
||||||
|
class Startup(CoreService):
|
||||||
|
'A CORE service to start other services in order, serially'
|
||||||
|
_name = 'startup'
|
||||||
|
_group = 'Utility'
|
||||||
|
_depends = ()
|
||||||
|
_dirs = ()
|
||||||
|
_configs = ('startup.sh', )
|
||||||
|
_startindex = maxint
|
||||||
|
_startup = ('sh startup.sh', )
|
||||||
|
_shutdown = ()
|
||||||
|
_validate = ()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def isStartupService(s):
|
||||||
|
return isinstance(s, Startup) or \
|
||||||
|
(isclass(s) and issubclass(s, Startup))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generateconfig(cls, node, filename, services):
|
||||||
|
if filename != cls._configs[0]:
|
||||||
|
return ''
|
||||||
|
script = '#!/bin/sh\n' \
|
||||||
|
'# auto-generated by Startup (startup.py)\n\n' \
|
||||||
|
'exec > startup.log 2>&1\n\n'
|
||||||
|
for s in sorted(services, key = lambda x: x._startindex):
|
||||||
|
if cls.isStartupService(s) or len(str(s._starttime)) > 0:
|
||||||
|
continue
|
||||||
|
start = '\n'.join(s.getstartup(node, services))
|
||||||
|
if start:
|
||||||
|
script += start + '\n'
|
||||||
|
return script
|
||||||
|
|
||||||
|
addservice(Startup)
|
Loading…
Reference in a new issue