added service executable check, added error message to gui for service load errors
This commit is contained in:
parent
e80736061f
commit
bf47e5fc0d
10 changed files with 90 additions and 39 deletions
|
@ -17,13 +17,13 @@ from core import logger
|
|||
from core.api import coreapi
|
||||
from core.api import dataconversion
|
||||
from core.conf import ConfigShim
|
||||
from core.data import ConfigData
|
||||
from core.data import ConfigData, ExceptionData
|
||||
from core.data import EventData
|
||||
from core.data import FileData
|
||||
from core.emulator.emudata import InterfaceData
|
||||
from core.emulator.emudata import LinkOptions
|
||||
from core.emulator.emudata import NodeOptions
|
||||
from core.enumerations import ConfigDataTypes
|
||||
from core.enumerations import ConfigDataTypes, ExceptionLevels
|
||||
from core.enumerations import ConfigFlags
|
||||
from core.enumerations import ConfigTlvs
|
||||
from core.enumerations import EventTlvs
|
||||
|
@ -551,6 +551,14 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
# set initial session state
|
||||
self.session.set_state(EventTypes.DEFINITION_STATE)
|
||||
|
||||
# send service errors, if present
|
||||
if self.coreemu.service_errors:
|
||||
self.send_exception(
|
||||
ExceptionLevels.ERROR,
|
||||
"ServiceManager.load()",
|
||||
"Failed to load services: %s" % " ".join(self.coreemu.service_errors)
|
||||
)
|
||||
|
||||
while True:
|
||||
try:
|
||||
message = self.receive_message()
|
||||
|
@ -579,6 +587,26 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.debug("BROADCAST TO OTHER CLIENT: %s", client)
|
||||
client.sendall(message.raw_message)
|
||||
|
||||
def send_exception(self, level, source, text, node=None):
|
||||
"""
|
||||
Sends an exception for display within the GUI.
|
||||
|
||||
:param core.enumerations.ExceptionLevel level: level for exception
|
||||
:param str source: source where exception came from
|
||||
:param str text: details about exception
|
||||
:param int node: node id, if related to a specific node
|
||||
:return:
|
||||
"""
|
||||
exception_data = ExceptionData(
|
||||
session=str(self.session.session_id),
|
||||
node=node,
|
||||
date=time.ctime(),
|
||||
level=level.value,
|
||||
source=source,
|
||||
text=text
|
||||
)
|
||||
self.handle_broadcast_exception(exception_data)
|
||||
|
||||
def add_session_handlers(self):
|
||||
logger.debug("adding session broadcast handlers")
|
||||
self.session.event_handlers.append(self.handle_broadcast_event)
|
||||
|
|
|
@ -15,6 +15,7 @@ from core.enumerations import LinkTypes
|
|||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodemaps
|
||||
from core.misc import nodeutils
|
||||
from core.service import ServiceManager
|
||||
from core.session import Session
|
||||
from core.xml.xmlparser import core_document_parser
|
||||
from core.xml.xmlwriter import core_document_writer
|
||||
|
@ -813,12 +814,26 @@ class CoreEmu(object):
|
|||
node_map = nodemaps.NODES
|
||||
nodeutils.set_node_map(node_map)
|
||||
|
||||
# load default services
|
||||
core.services.load()
|
||||
# load services
|
||||
self.service_errors = []
|
||||
self.load_services()
|
||||
|
||||
# catch exit event
|
||||
atexit.register(self.shutdown)
|
||||
|
||||
def load_services(self):
|
||||
# load default services
|
||||
self.service_errors = core.services.load()
|
||||
|
||||
# load custom services
|
||||
service_paths = self.config.get("custom_services_dir")
|
||||
logger.debug("custom service paths: %s", service_paths)
|
||||
if service_paths:
|
||||
for service_path in service_paths.split(','):
|
||||
service_path = service_path.strip()
|
||||
custom_service_errors = ServiceManager.add_services(service_path)
|
||||
self.service_errors.extend(custom_service_errors)
|
||||
|
||||
def update_nodes(self, node_map):
|
||||
"""
|
||||
Updates node map used by core.
|
||||
|
|
|
@ -7,6 +7,8 @@ a list of available services to the GUI and for configuring individual
|
|||
services.
|
||||
"""
|
||||
|
||||
from core.constants import which
|
||||
|
||||
from core import CoreCommandError
|
||||
from core import logger
|
||||
from core.data import FileData
|
||||
|
@ -126,8 +128,18 @@ class ServiceManager(object):
|
|||
"""
|
||||
logger.info("loading service: %s", service.__name__)
|
||||
name = service.name
|
||||
|
||||
# avoid duplicate services
|
||||
if name in cls.services:
|
||||
raise ValueError("duplicate service being added: %s" % name)
|
||||
|
||||
# validate dependent executables are present
|
||||
for executable in service.executables:
|
||||
if not which(executable):
|
||||
logger.error("service(%s) missing executable: %s", service.name, executable)
|
||||
raise ValueError("service(%s) missing executable: %s" % (service.name, executable))
|
||||
|
||||
# make service available
|
||||
cls.services[name] = service
|
||||
|
||||
@classmethod
|
||||
|
@ -147,15 +159,22 @@ class ServiceManager(object):
|
|||
Method for retrieving all CoreServices from a given path.
|
||||
|
||||
:param str path: path to retrieve services from
|
||||
:return: list of core services
|
||||
:rtype: list
|
||||
:return: list of core services that failed to load
|
||||
:rtype: list[str]
|
||||
"""
|
||||
service_errors = []
|
||||
services = utils.load_classes(path, CoreService)
|
||||
for service in services:
|
||||
if not service.name:
|
||||
continue
|
||||
service.on_load()
|
||||
|
||||
try:
|
||||
cls.add(service)
|
||||
except ValueError as e:
|
||||
service_errors.append(service.name)
|
||||
logger.error("failure loading service: %s", e.message)
|
||||
return service_errors
|
||||
|
||||
|
||||
class CoreServices(object):
|
||||
|
@ -623,6 +642,9 @@ class CoreService(object):
|
|||
# service name should not include spaces
|
||||
name = None
|
||||
|
||||
# executables that must exist for service to run
|
||||
executables = ()
|
||||
|
||||
# group string allows grouping services together
|
||||
group = None
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ def load():
|
|||
"""
|
||||
Loads all services from the modules that reside under core.services.
|
||||
|
||||
:return: nothing
|
||||
:return: list of services that failed to load
|
||||
:rtype: list[str]
|
||||
"""
|
||||
ServiceManager.add_services(_PATH)
|
||||
return ServiceManager.add_services(_PATH)
|
||||
|
|
|
@ -10,6 +10,7 @@ class Bird(CoreService):
|
|||
Bird router support
|
||||
"""
|
||||
name = "bird"
|
||||
executables = ("bird",)
|
||||
group = "BIRD"
|
||||
depends = ()
|
||||
dirs = ("/etc/bird",)
|
||||
|
@ -91,6 +92,7 @@ class BirdService(CoreService):
|
|||
"""
|
||||
|
||||
name = None
|
||||
executables = ("bird",)
|
||||
group = "BIRD"
|
||||
depends = ("bird",)
|
||||
dirs = ()
|
||||
|
|
|
@ -113,6 +113,7 @@ class DockerService(CoreService):
|
|||
node.
|
||||
"""
|
||||
name = "Docker"
|
||||
executables = ("docker",)
|
||||
group = "Docker"
|
||||
depends = ()
|
||||
dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',)
|
||||
|
|
|
@ -11,14 +11,8 @@ class SdnService(CoreService):
|
|||
"""
|
||||
Parent class for SDN services.
|
||||
"""
|
||||
name = None
|
||||
group = "SDN"
|
||||
depends = ()
|
||||
dirs = ()
|
||||
configs = ()
|
||||
startindex = 50
|
||||
startup = ()
|
||||
shutdown = ()
|
||||
|
||||
@classmethod
|
||||
def generateconfig(cls, node, filename, services):
|
||||
|
@ -27,6 +21,7 @@ class SdnService(CoreService):
|
|||
|
||||
class OvsService(SdnService):
|
||||
name = "OvsService"
|
||||
executables = ("ovs-ofctl", "ovs-vsctl")
|
||||
group = "SDN"
|
||||
depends = ()
|
||||
dirs = ("/etc/openvswitch", "/var/run/openvswitch", "/var/log/openvswitch")
|
||||
|
@ -101,6 +96,7 @@ class OvsService(SdnService):
|
|||
|
||||
class RyuService(SdnService):
|
||||
name = "ryuService"
|
||||
executables = ("ryu-manager",)
|
||||
group = "SDN"
|
||||
depends = ()
|
||||
dirs = ()
|
||||
|
|
|
@ -12,6 +12,7 @@ class XorpRtrmgr(CoreService):
|
|||
enabled XORP services, and launches necessary daemons upon startup.
|
||||
"""
|
||||
name = "xorp_rtrmgr"
|
||||
executables = ("xorp_rtrmgr",)
|
||||
group = "XORP"
|
||||
depends = ()
|
||||
dirs = ("/etc/xorp",)
|
||||
|
@ -75,6 +76,7 @@ class XorpService(CoreService):
|
|||
common to XORP's routing daemons.
|
||||
"""
|
||||
name = None
|
||||
executables = ("xorp_rtrmgr",)
|
||||
group = "XORP"
|
||||
depends = ("xorp_rtrmgr",)
|
||||
dirs = ()
|
||||
|
|
|
@ -4,7 +4,6 @@ Sample user-defined service.
|
|||
|
||||
from core.misc.ipaddress import Ipv4Prefix
|
||||
from core.service import CoreService
|
||||
from core.service import ServiceManager
|
||||
|
||||
|
||||
class MyService(CoreService):
|
||||
|
@ -12,22 +11,22 @@ class MyService(CoreService):
|
|||
This is a sample user-defined service.
|
||||
"""
|
||||
# a unique name is required, without spaces
|
||||
_name = "MyService"
|
||||
name = "MyService"
|
||||
# you can create your own group here
|
||||
_group = "Utility"
|
||||
group = "Utility"
|
||||
# list of other services this service depends on
|
||||
_depends = ()
|
||||
depends = ()
|
||||
# per-node directories
|
||||
_dirs = ()
|
||||
dirs = ()
|
||||
# generated files (without a full path this file goes in the node's dir,
|
||||
# e.g. /tmp/pycore.12345/n1.conf/)
|
||||
_configs = ('myservice.sh',)
|
||||
configs = ('myservice.sh',)
|
||||
# this controls the starting order vs other enabled services
|
||||
_startindex = 50
|
||||
startindex = 50
|
||||
# list of startup commands, also may be generated during startup
|
||||
_startup = ('sh myservice.sh',)
|
||||
startup = ('sh myservice.sh',)
|
||||
# list of shutdown commands
|
||||
_shutdown = ()
|
||||
shutdown = ()
|
||||
|
||||
@classmethod
|
||||
def generateconfig(cls, node, filename, services):
|
||||
|
@ -57,9 +56,3 @@ class MyService(CoreService):
|
|||
else:
|
||||
net = Ipv4Prefix(x)
|
||||
return 'echo " network %s"' % net
|
||||
|
||||
|
||||
# this is needed to load desired services when being integrated into core, otherwise this is not needed
|
||||
def load_services():
|
||||
# this line is required to add the above class to the list of available services
|
||||
ServiceManager.add(MyService)
|
||||
|
|
|
@ -16,7 +16,6 @@ from core import logger
|
|||
from core.corehandlers import CoreHandler
|
||||
from core.coreserver import CoreServer
|
||||
from core.misc.utils import close_onexec
|
||||
from core.service import ServiceManager
|
||||
|
||||
|
||||
def banner():
|
||||
|
@ -116,14 +115,6 @@ def main():
|
|||
for a in args:
|
||||
logger.error("ignoring command line argument: %s", a)
|
||||
|
||||
# attempt load custom services
|
||||
service_paths = cfg.get("custom_services_dir")
|
||||
logger.debug("custom service paths: %s", service_paths)
|
||||
if service_paths:
|
||||
for service_path in service_paths.split(','):
|
||||
service_path = service_path.strip()
|
||||
ServiceManager.add_services(service_path)
|
||||
|
||||
banner()
|
||||
|
||||
# check if ovs flag was provided
|
||||
|
|
Loading…
Reference in a new issue