refactored service interaction use names with a _, and cleanup up some of the CoreServices methods
This commit is contained in:
parent
0bf9c99910
commit
e80736061f
27 changed files with 958 additions and 885 deletions
|
@ -42,8 +42,8 @@ from core.enumerations import SessionTlvs
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.misc import structutils
|
from core.misc import structutils
|
||||||
from core.misc import utils
|
from core.misc import utils
|
||||||
from core.service import CoreService
|
|
||||||
from core.service import ServiceManager
|
from core.service import ServiceManager
|
||||||
|
from core.service import ServiceShim
|
||||||
|
|
||||||
|
|
||||||
class CoreHandler(SocketServer.BaseRequestHandler):
|
class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
|
@ -1072,10 +1072,10 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
# sort groups by name and map services to groups
|
# sort groups by name and map services to groups
|
||||||
groups = set()
|
groups = set()
|
||||||
group_map = {}
|
group_map = {}
|
||||||
for service in ServiceManager.services.itervalues():
|
for service_name in ServiceManager.services.itervalues():
|
||||||
group = service._group
|
group = service_name.group
|
||||||
groups.add(group)
|
groups.add(group)
|
||||||
group_map.setdefault(group, []).append(service)
|
group_map.setdefault(group, []).append(service_name)
|
||||||
groups = sorted(groups, key=lambda x: x.lower())
|
groups = sorted(groups, key=lambda x: x.lower())
|
||||||
|
|
||||||
# define tlv values in proper order
|
# define tlv values in proper order
|
||||||
|
@ -1086,15 +1086,15 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
start_index = 1
|
start_index = 1
|
||||||
logger.info("sorted groups: %s", groups)
|
logger.info("sorted groups: %s", groups)
|
||||||
for group in groups:
|
for group in groups:
|
||||||
services = sorted(group_map[group], key=lambda x: x._name.lower())
|
services = sorted(group_map[group], key=lambda x: x.name.lower())
|
||||||
logger.info("sorted services for group(%s): %s", group, services)
|
logger.info("sorted services for group(%s): %s", group, services)
|
||||||
end_index = start_index + len(services) - 1
|
end_index = start_index + len(services) - 1
|
||||||
group_strings.append("%s:%s-%s" % (group, start_index, end_index))
|
group_strings.append("%s:%s-%s" % (group, start_index, end_index))
|
||||||
start_index = start_index + len(services)
|
start_index += len(services)
|
||||||
for service in services:
|
for service_name in services:
|
||||||
captions.append(service._name)
|
captions.append(service_name.name)
|
||||||
values.append("0")
|
values.append("0")
|
||||||
if service._custom_needed:
|
if service_name.custom_needed:
|
||||||
possible_values.append("1")
|
possible_values.append("1")
|
||||||
else:
|
else:
|
||||||
possible_values.append("")
|
possible_values.append("")
|
||||||
|
@ -1111,30 +1111,31 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
|
|
||||||
node = self.session.get_object(node_id)
|
node = self.session.get_object(node_id)
|
||||||
if node is None:
|
if node is None:
|
||||||
logger.warn("Request to configure service for unknown node %s", node_id)
|
logger.warn("request to configure service for unknown node %s", node_id)
|
||||||
return replies
|
return replies
|
||||||
servicesstring = opaque.split(':')
|
|
||||||
services, unknown = self.session.services.servicesfromopaque(opaque, node.objid)
|
|
||||||
for u in unknown:
|
|
||||||
logger.warn("Request for unknown service '%s'" % u)
|
|
||||||
|
|
||||||
|
services = ServiceShim.servicesfromopaque(opaque)
|
||||||
if not services:
|
if not services:
|
||||||
return replies
|
return replies
|
||||||
|
|
||||||
|
servicesstring = opaque.split(":")
|
||||||
if len(servicesstring) == 3:
|
if len(servicesstring) == 3:
|
||||||
# a file request: e.g. "service:zebra:quagga.conf"
|
# a file request: e.g. "service:zebra:quagga.conf"
|
||||||
file_data = self.session.services.getservicefile(services, node, servicesstring[2])
|
file_name = servicesstring[2]
|
||||||
|
service_name = services[0]
|
||||||
|
file_data = self.session.services.getservicefile(service_name, node, file_name, services)
|
||||||
self.session.broadcast_file(file_data)
|
self.session.broadcast_file(file_data)
|
||||||
# short circuit this request early to avoid returning response below
|
# short circuit this request early to avoid returning response below
|
||||||
return replies
|
return replies
|
||||||
|
|
||||||
# the first service in the list is the one being configured
|
# the first service in the list is the one being configured
|
||||||
svc = services[0]
|
service_name = services[0]
|
||||||
# send back:
|
# send back:
|
||||||
# dirs, configs, startindex, startup, shutdown, metadata, config
|
# dirs, configs, startindex, startup, shutdown, metadata, config
|
||||||
type_flag = ConfigFlags.UPDATE.value
|
type_flag = ConfigFlags.UPDATE.value
|
||||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(svc.keys)))
|
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(ServiceShim.keys)))
|
||||||
values = svc.tovaluelist(node, services)
|
service = self.session.services.getcustomservice(node_id, service_name, default_service=True)
|
||||||
|
values = ServiceShim.tovaluelist(service, node, services)
|
||||||
captions = None
|
captions = None
|
||||||
possible_values = None
|
possible_values = None
|
||||||
groups = None
|
groups = None
|
||||||
|
@ -1173,15 +1174,21 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
self.session.services.defaultservices[key] = values
|
self.session.services.defaultservices[key] = values
|
||||||
logger.debug("default services for type %s set to %s", key, values)
|
logger.debug("default services for type %s set to %s", key, values)
|
||||||
elif node_id:
|
elif node_id:
|
||||||
# store service customized config in self.customservices[]
|
services = ServiceShim.servicesfromopaque(opaque)
|
||||||
services, unknown = self.session.services.servicesfromopaque(opaque, node_id)
|
|
||||||
for u in unknown:
|
|
||||||
logger.warn("request for unknown service: %s", u)
|
|
||||||
|
|
||||||
if services:
|
if services:
|
||||||
svc = services[0]
|
service_name = services[0]
|
||||||
|
|
||||||
|
# set custom service for node
|
||||||
|
self.session.services.setcustomservice(node_id, service_name)
|
||||||
|
|
||||||
|
# set custom values for custom service
|
||||||
|
service = self.session.services.getcustomservice(node_id, service_name)
|
||||||
|
if not service:
|
||||||
|
raise ValueError("custom service(%s) for node(%s) does not exist", service_name, node_id)
|
||||||
|
|
||||||
values = ConfigShim.str_to_dict(values)
|
values = ConfigShim.str_to_dict(values)
|
||||||
self.session.services.setcustomservice(node_id, svc, values)
|
for name, value in values.iteritems():
|
||||||
|
ServiceShim.setvalue(service, name, value)
|
||||||
|
|
||||||
return replies
|
return replies
|
||||||
|
|
||||||
|
@ -1324,7 +1331,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
if file_type is not None:
|
if file_type is not None:
|
||||||
if file_type.startswith("service:"):
|
if file_type.startswith("service:"):
|
||||||
_, service_name = file_type.split(':')[:2]
|
_, service_name = file_type.split(':')[:2]
|
||||||
self.session.add_node_service_file(node_num, service_name, file_name, source_name, data)
|
self.session.services.setservicefile(node_num, service_name, file_name, data)
|
||||||
return ()
|
return ()
|
||||||
elif file_type.startswith("hook:"):
|
elif file_type.startswith("hook:"):
|
||||||
_, state = file_type.split(':')[:2]
|
_, state = file_type.split(':')[:2]
|
||||||
|
@ -1430,7 +1437,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
# TODO: register system for event message handlers,
|
# TODO: register system for event message handlers,
|
||||||
# like confobjs
|
# like confobjs
|
||||||
if name.startswith("service:"):
|
if name.startswith("service:"):
|
||||||
self.session.services_event(event_data)
|
self.handle_service_event(event_data)
|
||||||
handled = True
|
handled = True
|
||||||
elif name.startswith("mobility:"):
|
elif name.startswith("mobility:"):
|
||||||
self.session.mobility_event(event_data)
|
self.session.mobility_event(event_data)
|
||||||
|
@ -1463,6 +1470,72 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
|
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
|
def handle_service_event(self, event_data):
|
||||||
|
"""
|
||||||
|
Handle an Event Message used to start, stop, restart, or validate
|
||||||
|
a service on a given node.
|
||||||
|
|
||||||
|
:param EventData event_data: event data to handle
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
event_type = event_data.event_type
|
||||||
|
node_id = event_data.node
|
||||||
|
name = event_data.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
node = self.session.get_object(node_id)
|
||||||
|
except KeyError:
|
||||||
|
logger.warn("ignoring event for service '%s', unknown node '%s'", name, node_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
fail = ""
|
||||||
|
unknown = []
|
||||||
|
services = ServiceShim.servicesfromopaque(name)
|
||||||
|
for service_name in services:
|
||||||
|
service = self.session.services.getcustomservice(node_id, service_name, default_service=True)
|
||||||
|
if not service:
|
||||||
|
unknown.append(service_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if event_type == EventTypes.STOP.value or event_type == EventTypes.RESTART.value:
|
||||||
|
status = self.session.services.stopnodeservice(node, service)
|
||||||
|
if status != "0":
|
||||||
|
fail += "Stop %s," % service.name
|
||||||
|
if event_type == EventTypes.START.value or event_type == EventTypes.RESTART.value:
|
||||||
|
status = self.session.services.node_service_startup(node, service, services)
|
||||||
|
if status != "0":
|
||||||
|
fail += "Start %s(%s)," % service.name
|
||||||
|
if event_type == EventTypes.PAUSE.value:
|
||||||
|
status = self.session.services.validatenodeservice(node, service, services)
|
||||||
|
if status != 0:
|
||||||
|
fail += "%s," % service.name
|
||||||
|
if event_type == EventTypes.RECONFIGURE.value:
|
||||||
|
self.session.services.node_service_reconfigure(node, service, services)
|
||||||
|
|
||||||
|
fail_data = ""
|
||||||
|
if len(fail) > 0:
|
||||||
|
fail_data += "Fail:" + fail
|
||||||
|
unknown_data = ""
|
||||||
|
num = len(unknown)
|
||||||
|
if num > 0:
|
||||||
|
for u in unknown:
|
||||||
|
unknown_data += u
|
||||||
|
if num > 1:
|
||||||
|
unknown_data += ", "
|
||||||
|
num -= 1
|
||||||
|
logger.warn("Event requested for unknown service(s): %s", unknown_data)
|
||||||
|
unknown_data = "Unknown:" + unknown_data
|
||||||
|
|
||||||
|
event_data = EventData(
|
||||||
|
node=node_id,
|
||||||
|
event_type=event_type,
|
||||||
|
name=name,
|
||||||
|
data=fail_data + ";" + unknown_data,
|
||||||
|
time="%s" % time.time()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.session.broadcast_event(event_data)
|
||||||
|
|
||||||
def handle_session_message(self, message):
|
def handle_session_message(self, message):
|
||||||
"""
|
"""
|
||||||
Session Message handler
|
Session Message handler
|
||||||
|
@ -1620,10 +1693,10 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
||||||
# service customizations
|
# service customizations
|
||||||
service_configs = self.session.services.getallconfigs()
|
service_configs = self.session.services.getallconfigs()
|
||||||
for node_id, service in service_configs:
|
for node_id, service in service_configs:
|
||||||
opaque = "service:%s" % service._name
|
opaque = "service:%s" % service.name
|
||||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(CoreService.keys)))
|
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(ServiceShim.keys)))
|
||||||
node = self.session.get_object(node_id)
|
node = self.session.get_object(node_id)
|
||||||
values = CoreService.tovaluelist(node, node.services)
|
values = ServiceShim.tovaluelist(service, node, node.services)
|
||||||
config_data = ConfigData(
|
config_data = ConfigData(
|
||||||
message_type=0,
|
message_type=0,
|
||||||
node=node_id,
|
node=node_id,
|
||||||
|
|
|
@ -218,7 +218,7 @@ class PyCoreObj(object):
|
||||||
if hasattr(self, "services") and len(self.services) != 0:
|
if hasattr(self, "services") and len(self.services) != 0:
|
||||||
nodeservices = []
|
nodeservices = []
|
||||||
for s in self.services:
|
for s in self.services:
|
||||||
nodeservices.append(s._name)
|
nodeservices.append(s.name)
|
||||||
services = "|".join(nodeservices)
|
services = "|".join(nodeservices)
|
||||||
|
|
||||||
node_data = NodeData(
|
node_data = NodeData(
|
||||||
|
|
|
@ -507,8 +507,7 @@ class EmuSession(Session):
|
||||||
if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]:
|
if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]:
|
||||||
node.type = node_options.model
|
node.type = node_options.model
|
||||||
logger.debug("set node type: %s", node.type)
|
logger.debug("set node type: %s", node.type)
|
||||||
services = "|".join(node_options.services) or None
|
self.services.addservicestonode(node, node.type, node_options.services)
|
||||||
self.services.addservicestonode(node, node.type, services)
|
|
||||||
|
|
||||||
# boot nodes if created after runtime, LcxNodes, Physical, and RJ45 are all PyCoreNodes
|
# boot nodes if created after runtime, LcxNodes, Physical, and RJ45 are all PyCoreNodes
|
||||||
is_boot_node = isinstance(node, PyCoreNode) and not nodeutils.is_node(node, NodeTypes.RJ45)
|
is_boot_node = isinstance(node, PyCoreNode) and not nodeutils.is_node(node, NodeTypes.RJ45)
|
||||||
|
@ -697,21 +696,6 @@ class EmuSession(Session):
|
||||||
state = ":%s" % state
|
state = ":%s" % state
|
||||||
self.set_hook(state, file_name, source_name, data)
|
self.set_hook(state, file_name, source_name, data)
|
||||||
|
|
||||||
def add_node_service_file(self, node_id, service_name, file_name, source_name, data):
|
|
||||||
"""
|
|
||||||
Add a service file for a node.
|
|
||||||
|
|
||||||
:param int node_id: node to add service file to
|
|
||||||
:param str service_name: service file to add
|
|
||||||
:param str file_name: file name to use
|
|
||||||
:param str source_name: source file
|
|
||||||
:param str data: file data to save
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
# hack to conform with old logic until updated
|
|
||||||
service_name = ":%s" % service_name
|
|
||||||
self.services.setservicefile(node_id, service_name, file_name, source_name, data)
|
|
||||||
|
|
||||||
def add_node_file(self, node_id, source_name, file_name, data):
|
def add_node_file(self, node_id, source_name, file_name, data):
|
||||||
"""
|
"""
|
||||||
Add a file to a node.
|
Add a file to a node.
|
||||||
|
@ -749,15 +733,6 @@ class EmuSession(Session):
|
||||||
"""
|
"""
|
||||||
self.event_loop.run()
|
self.event_loop.run()
|
||||||
|
|
||||||
def services_event(self, event_data):
|
|
||||||
"""
|
|
||||||
Handle a service event.
|
|
||||||
|
|
||||||
:param core.data.EventData event_data: event data to handle
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.services.handleevent(event_data)
|
|
||||||
|
|
||||||
def mobility_event(self, event_data):
|
def mobility_event(self, event_data):
|
||||||
"""
|
"""
|
||||||
Handle a mobility event.
|
Handle a mobility event.
|
||||||
|
|
|
@ -6,18 +6,110 @@ The CoreServices class handles configuration messages for sending
|
||||||
a list of available services to the GUI and for configuring individual
|
a list of available services to the GUI and for configuring individual
|
||||||
services.
|
services.
|
||||||
"""
|
"""
|
||||||
import time
|
|
||||||
|
|
||||||
from core import CoreCommandError
|
from core import CoreCommandError
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.data import EventData
|
|
||||||
from core.data import FileData
|
from core.data import FileData
|
||||||
from core.enumerations import EventTypes
|
|
||||||
from core.enumerations import MessageFlags
|
from core.enumerations import MessageFlags
|
||||||
from core.enumerations import RegisterTlvs
|
from core.enumerations import RegisterTlvs
|
||||||
from core.misc import utils
|
from core.misc import utils
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceShim(object):
|
||||||
|
keys = ["dirs", "files", "startidx", "cmdup", "cmddown", "cmdval", "meta", "starttime"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tovaluelist(cls, service, node, services):
|
||||||
|
"""
|
||||||
|
Convert service properties into a string list of key=value pairs,
|
||||||
|
separated by "|".
|
||||||
|
|
||||||
|
:param CoreService service: service to get value list for
|
||||||
|
:param core.netns.nodes.CoreNode node: node to get value list for
|
||||||
|
:param list[CoreService] services: services for node
|
||||||
|
:return: value list string
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
valmap = [service.dirs, service.configs, service.startindex, service.startup,
|
||||||
|
service.shutdown, service.validate, service.meta, service.starttime]
|
||||||
|
if not service.custom:
|
||||||
|
# this is always reached due to classmethod
|
||||||
|
valmap[valmap.index(service.configs)] = service.getconfigfilenames(node.objid, services)
|
||||||
|
valmap[valmap.index(service.startup)] = service.getstartup(node, services)
|
||||||
|
vals = map(lambda a, b: "%s=%s" % (a, str(b)), cls.keys, valmap)
|
||||||
|
return "|".join(vals)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromvaluelist(cls, service, values):
|
||||||
|
"""
|
||||||
|
Convert list of values into properties for this instantiated
|
||||||
|
(customized) service.
|
||||||
|
|
||||||
|
:param CoreService service: service to get value list for
|
||||||
|
:param dict values: value list to set properties from
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
# TODO: support empty value? e.g. override default meta with ''
|
||||||
|
for key in cls.keys:
|
||||||
|
try:
|
||||||
|
cls.setvalue(service, key, values[cls.keys.index(key)])
|
||||||
|
except IndexError:
|
||||||
|
# old config does not need to have new keys
|
||||||
|
logger.exception("error indexing into key")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setvalue(cls, service, key, value):
|
||||||
|
"""
|
||||||
|
Set values for this service.
|
||||||
|
|
||||||
|
:param CoreService service: service to get value list for
|
||||||
|
:param str key: key to set value for
|
||||||
|
:param value: value of key to set
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
if key not in cls.keys:
|
||||||
|
raise ValueError('key `%s` not in `%s`' % (key, cls.keys))
|
||||||
|
# this handles data conversion to int, string, and tuples
|
||||||
|
if value:
|
||||||
|
if key == "startidx":
|
||||||
|
value = int(value)
|
||||||
|
elif key == "meta":
|
||||||
|
value = str(value)
|
||||||
|
else:
|
||||||
|
value = utils.make_tuple_fromstr(value, str)
|
||||||
|
|
||||||
|
if key == "dirs":
|
||||||
|
service.dirs = value
|
||||||
|
elif key == "files":
|
||||||
|
service.configs = value
|
||||||
|
elif key == "startidx":
|
||||||
|
service.startindex = value
|
||||||
|
elif key == "cmdup":
|
||||||
|
service.startup = value
|
||||||
|
elif key == "cmddown":
|
||||||
|
service.shutdown = value
|
||||||
|
elif key == "cmdval":
|
||||||
|
service.validate = value
|
||||||
|
elif key == "meta":
|
||||||
|
service.meta = value
|
||||||
|
elif key == "starttime":
|
||||||
|
service.starttime = value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def servicesfromopaque(self, opaque):
|
||||||
|
"""
|
||||||
|
Build a list of services from an opaque data string.
|
||||||
|
|
||||||
|
:param str opaque: opaque data string
|
||||||
|
:return: services
|
||||||
|
:rtype: list
|
||||||
|
"""
|
||||||
|
servicesstring = opaque.split(':')
|
||||||
|
if servicesstring[0] != "service":
|
||||||
|
return []
|
||||||
|
return servicesstring[1].split(',')
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager(object):
|
class ServiceManager(object):
|
||||||
"""
|
"""
|
||||||
Manages services available for CORE nodes to use.
|
Manages services available for CORE nodes to use.
|
||||||
|
@ -33,7 +125,7 @@ class ServiceManager(object):
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
logger.info("loading service: %s", service.__name__)
|
logger.info("loading service: %s", service.__name__)
|
||||||
name = service._name
|
name = service.name
|
||||||
if name in cls.services:
|
if name in cls.services:
|
||||||
raise ValueError("duplicate service being added: %s" % name)
|
raise ValueError("duplicate service being added: %s" % name)
|
||||||
cls.services[name] = service
|
cls.services[name] = service
|
||||||
|
@ -45,7 +137,7 @@ class ServiceManager(object):
|
||||||
|
|
||||||
:param str name: name of the service to retrieve
|
:param str name: name of the service to retrieve
|
||||||
:return: service if it exists, None otherwise
|
:return: service if it exists, None otherwise
|
||||||
:rtype: CoreService
|
:rtype: CoreService.class
|
||||||
"""
|
"""
|
||||||
return cls.services.get(name)
|
return cls.services.get(name)
|
||||||
|
|
||||||
|
@ -60,7 +152,7 @@ class ServiceManager(object):
|
||||||
"""
|
"""
|
||||||
services = utils.load_classes(path, CoreService)
|
services = utils.load_classes(path, CoreService)
|
||||||
for service in services:
|
for service in services:
|
||||||
if not service._name:
|
if not service.name:
|
||||||
continue
|
continue
|
||||||
service.on_load()
|
service.on_load()
|
||||||
cls.add(service)
|
cls.add(service)
|
||||||
|
@ -76,7 +168,6 @@ class CoreServices(object):
|
||||||
"""
|
"""
|
||||||
name = "services"
|
name = "services"
|
||||||
config_type = RegisterTlvs.UTILITY.value
|
config_type = RegisterTlvs.UTILITY.value
|
||||||
_invalid_custom_names = ("core", "api", "emane", "misc", "netns", "phys", "services")
|
|
||||||
|
|
||||||
def __init__(self, session):
|
def __init__(self, session):
|
||||||
"""
|
"""
|
||||||
|
@ -84,7 +175,6 @@ class CoreServices(object):
|
||||||
|
|
||||||
:param core.session.Session session: session this manager is tied to
|
:param core.session.Session session: session this manager is tied to
|
||||||
"""
|
"""
|
||||||
# ConfigurableManager.__init__(self)
|
|
||||||
self.session = session
|
self.session = session
|
||||||
# dict of default services tuples, key is node type
|
# dict of default services tuples, key is node type
|
||||||
self.defaultservices = {}
|
self.defaultservices = {}
|
||||||
|
@ -109,99 +199,79 @@ class CoreServices(object):
|
||||||
|
|
||||||
:param service_type: service type to get default services for
|
:param service_type: service type to get default services for
|
||||||
:return: default services
|
:return: default services
|
||||||
:rtype: list
|
:rtype: list[CoreService]
|
||||||
"""
|
"""
|
||||||
logger.debug("getting default services for type: %s", service_type)
|
logger.debug("getting default services for type: %s", service_type)
|
||||||
results = []
|
results = []
|
||||||
if service_type in self.defaultservices:
|
defaults = self.defaultservices.get(service_type, [])
|
||||||
defaults = self.defaultservices[service_type]
|
for name in defaults:
|
||||||
for name in defaults:
|
logger.debug("checking for service with service manager: %s", name)
|
||||||
logger.debug("checking for service with service manager: %s", name)
|
service = ServiceManager.get(name)
|
||||||
service = ServiceManager.get(name)
|
if not service:
|
||||||
if not service:
|
logger.warn("default service %s is unknown", name)
|
||||||
logger.warn("default service %s is unknown", name)
|
else:
|
||||||
else:
|
results.append(service)
|
||||||
results.append(service)
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def getcustomservice(self, object_id, service):
|
def getcustomservice(self, node_id, service_name, default_service=False):
|
||||||
"""
|
"""
|
||||||
Get any custom service configured for the given node that matches the specified service name.
|
Get any custom service configured for the given node that matches the specified service name.
|
||||||
If no custom service is found, return the specified service.
|
If no custom service is found, return the specified service.
|
||||||
|
|
||||||
:param int object_id: object id to get service from
|
:param int node_id: object id to get service from
|
||||||
:param CoreService service: custom service to retrieve
|
:param str service_name: name of service to retrieve
|
||||||
|
:param bool default_service: True to return default service when custom does not exist, False returns None
|
||||||
:return: custom service from the node
|
:return: custom service from the node
|
||||||
:rtype: CoreService
|
:rtype: CoreService
|
||||||
"""
|
"""
|
||||||
if object_id in self.customservices:
|
node_services = self.customservices.setdefault(node_id, {})
|
||||||
for s in self.customservices[object_id]:
|
default = None
|
||||||
if s._name == service._name:
|
if default_service:
|
||||||
return s
|
default = ServiceManager.get(service_name)
|
||||||
return service
|
return node_services.get(service_name, default)
|
||||||
|
|
||||||
def setcustomservice(self, object_id, service, config):
|
def setcustomservice(self, node_id, service_name):
|
||||||
"""
|
"""
|
||||||
Store service customizations in an instantiated service object
|
Store service customizations in an instantiated service object
|
||||||
using a list of values that came from a config message.
|
using a list of values that came from a config message.
|
||||||
|
|
||||||
:param int object_id: object id to set custom service for
|
:param int node_id: object id to set custom service for
|
||||||
:param class service: service to set
|
:param str service_name: name of service to set
|
||||||
:param dict config: values to
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
logger.debug("setting custom service(%s) for node(%s): %s", object_id, service, config)
|
|
||||||
if service._custom:
|
|
||||||
s = service
|
|
||||||
else:
|
|
||||||
# instantiate the class, for storing config customization
|
|
||||||
s = service()
|
|
||||||
|
|
||||||
# set custom service configuration
|
|
||||||
for name, value in config.iteritems():
|
|
||||||
s.setvalue(name, value)
|
|
||||||
|
|
||||||
# assume custom service already in dict
|
|
||||||
if service._custom:
|
|
||||||
return
|
|
||||||
|
|
||||||
# add the custom service to dict
|
|
||||||
if object_id in self.customservices:
|
|
||||||
self.customservices[object_id] += (s,)
|
|
||||||
else:
|
|
||||||
self.customservices[object_id] = (s,)
|
|
||||||
|
|
||||||
def addservicestonode(self, node, nodetype, services_str):
|
|
||||||
"""
|
|
||||||
Populate the node.service list using (1) the list of services
|
|
||||||
requested from the services TLV, (2) using any custom service
|
|
||||||
configuration, or (3) using the default services for this node type.
|
|
||||||
|
|
||||||
:param core.coreobj.PyCoreNode node: node to add services to
|
|
||||||
:param str nodetype: node type to add services to
|
|
||||||
:param str services_str: string formatted service list
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if services_str is not None:
|
logger.debug("setting custom service(%s) for node: %s", node_id, service_name)
|
||||||
logger.info("setting custom services for node(%s)", node.name)
|
service = self.getcustomservice(node_id, service_name)
|
||||||
services = services_str.split("|")
|
if not service:
|
||||||
for name in services:
|
service_class = ServiceManager.get(service_name)
|
||||||
s = ServiceManager.get(name)
|
service = service_class()
|
||||||
if s is None:
|
|
||||||
logger.warn("configured service %s for node %s is unknown", name, node.name)
|
|
||||||
continue
|
|
||||||
logger.info("adding service to node(%s): %s", node.name, s._name)
|
|
||||||
s = self.getcustomservice(node.objid, s)
|
|
||||||
node.addservice(s)
|
|
||||||
else:
|
|
||||||
logger.info("setting default services for node(%s) type (%s)", node.name, nodetype)
|
|
||||||
services = self.getdefaultservices(nodetype)
|
|
||||||
for s in services:
|
|
||||||
logger.info("adding service to node(%s): %s", node.name, s._name)
|
|
||||||
s = self.getcustomservice(node.objid, s)
|
|
||||||
node.addservice(s)
|
|
||||||
|
|
||||||
def getallconfigs(self, use_clsmap=True):
|
# add the custom service to dict
|
||||||
|
node_services = self.customservices.setdefault(node_id, {})
|
||||||
|
node_services[service.name] = service
|
||||||
|
|
||||||
|
def addservicestonode(self, node, node_type, services=None):
|
||||||
|
"""
|
||||||
|
Add services to a node.
|
||||||
|
|
||||||
|
:param core.coreobj.PyCoreNode node: node to add services to
|
||||||
|
:param str node_type: node type to add services to
|
||||||
|
:param list[str] services: services to add to node
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
if not services:
|
||||||
|
logger.info("using default services for node(%s) type(%s)", node.name, node_type)
|
||||||
|
services = self.defaultservices.get(node_type, [])
|
||||||
|
|
||||||
|
logger.info("setting services for node(%s): %s", node.name, services)
|
||||||
|
for service_name in services:
|
||||||
|
service = self.getcustomservice(node.objid, service_name, default_service=True)
|
||||||
|
if not service:
|
||||||
|
logger.warn("unknown service(%s) for node(%s)", service_name, node.name)
|
||||||
|
continue
|
||||||
|
logger.info("adding service to node(%s): %s", node.name, service_name)
|
||||||
|
node.addservice(service)
|
||||||
|
|
||||||
|
def getallconfigs(self):
|
||||||
"""
|
"""
|
||||||
Return (nodenum, service) tuples for all stored configs. Used when reconnecting to a
|
Return (nodenum, service) tuples for all stored configs. Used when reconnecting to a
|
||||||
session or opening XML.
|
session or opening XML.
|
||||||
|
@ -211,9 +281,9 @@ class CoreServices(object):
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
configs = []
|
configs = []
|
||||||
for nodenum in self.customservices:
|
for node_id in self.customservices.iterkeys():
|
||||||
for service in self.customservices[nodenum]:
|
for service in self.customservices[node_id].itervalues():
|
||||||
configs.append((nodenum, service))
|
configs.append((node_id, service))
|
||||||
return configs
|
return configs
|
||||||
|
|
||||||
def getallfiles(self, service):
|
def getallfiles(self, service):
|
||||||
|
@ -226,11 +296,11 @@ class CoreServices(object):
|
||||||
"""
|
"""
|
||||||
files = []
|
files = []
|
||||||
|
|
||||||
if not service._custom:
|
if not service.custom:
|
||||||
return files
|
return files
|
||||||
|
|
||||||
for filename in service._configs:
|
for filename in service.configs:
|
||||||
data = self.getservicefiledata(service, filename)
|
data = service.configtxt.get(filename)
|
||||||
if data is None:
|
if data is None:
|
||||||
continue
|
continue
|
||||||
files.append((filename, data))
|
files.append((filename, data))
|
||||||
|
@ -244,19 +314,19 @@ class CoreServices(object):
|
||||||
:param core.netns.vnode.LxcNode node: node to start services on
|
:param core.netns.vnode.LxcNode node: node to start services on
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
services = sorted(node.services, key=lambda service: service._startindex)
|
services = sorted(node.services, key=lambda x: x.startindex)
|
||||||
use_startup_service = any(map(self.is_startup_service, services))
|
use_startup_service = any(map(self.is_startup_service, services))
|
||||||
for s in services:
|
for service in services:
|
||||||
if len(str(s._starttime)) > 0:
|
if len(str(service.starttime)) > 0:
|
||||||
try:
|
try:
|
||||||
t = float(s._starttime)
|
starttime = float(service.starttime)
|
||||||
if t > 0.0:
|
if starttime > 0.0:
|
||||||
fn = self.bootnodeservice
|
fn = self.bootnodeservice
|
||||||
self.session.event_loop.add_event(t, fn, node, s, services, False)
|
self.session.event_loop.add_event(starttime, fn, node, service, services, False)
|
||||||
continue
|
continue
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception("error converting start time to float")
|
logger.exception("error converting start time to float")
|
||||||
self.bootnodeservice(node, s, services, use_startup_service)
|
self.bootnodeservice(node, service, services, use_startup_service)
|
||||||
|
|
||||||
def bootnodeservice(self, node, service, services, use_startup_service):
|
def bootnodeservice(self, node, service, services, use_startup_service):
|
||||||
"""
|
"""
|
||||||
|
@ -269,12 +339,12 @@ class CoreServices(object):
|
||||||
:param bool use_startup_service: flag to use startup services or not
|
:param bool use_startup_service: flag to use startup services or not
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if service._custom:
|
if service.custom:
|
||||||
self.bootnodecustomservice(node, service, services, use_startup_service)
|
self.bootnodecustomservice(node, service, services, use_startup_service)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info("starting node(%s) service: %s (%s)", node.name, service._name, service._startindex)
|
logger.info("starting node(%s) service: %s (%s)", node.name, service.name, service.startindex)
|
||||||
for directory in service._dirs:
|
for directory in service.dirs:
|
||||||
node.privatedir(directory)
|
node.privatedir(directory)
|
||||||
|
|
||||||
for filename in service.getconfigfilenames(node.objid, services):
|
for filename in service.getconfigfilenames(node.objid, services):
|
||||||
|
@ -299,18 +369,17 @@ class CoreServices(object):
|
||||||
:param bool use_startup_service: flag to use startup services or not
|
:param bool use_startup_service: flag to use startup services or not
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
logger.info("starting service(%s) %s (%s)(custom)", service, service._name, service._startindex)
|
logger.info("starting node(%s) service(custom): %s (%s)", node.name, service.name, service.startindex)
|
||||||
for directory in service._dirs:
|
for directory in service.dirs:
|
||||||
node.privatedir(directory)
|
node.privatedir(directory)
|
||||||
|
|
||||||
logger.info("service configurations: %s", service._configs)
|
logger.info("service configurations: %s", service.configs)
|
||||||
for i, filename in enumerate(service._configs):
|
for filename in service.configs:
|
||||||
logger.info("generating service config: %s", filename)
|
logger.info("generating service config: %s", filename)
|
||||||
if len(filename) == 0:
|
cfg = service.configtxt.get(filename)
|
||||||
continue
|
|
||||||
cfg = self.getservicefiledata(service, filename)
|
|
||||||
if cfg is None:
|
if cfg is None:
|
||||||
cfg = service.generateconfig(node, filename, services)
|
cfg = service.generateconfig(node, filename, services)
|
||||||
|
|
||||||
# cfg may have a file:/// url for copying from a file
|
# cfg may have a file:/// url for copying from a file
|
||||||
try:
|
try:
|
||||||
if self.copyservicefile(node, filename, cfg):
|
if self.copyservicefile(node, filename, cfg):
|
||||||
|
@ -323,7 +392,7 @@ class CoreServices(object):
|
||||||
if use_startup_service and not self.is_startup_service(service):
|
if use_startup_service and not self.is_startup_service(service):
|
||||||
return
|
return
|
||||||
|
|
||||||
for args in service._startup:
|
for args in service.startup:
|
||||||
# TODO: this wait=False can be problematic!
|
# TODO: this wait=False can be problematic!
|
||||||
node.cmd(args, wait=False)
|
node.cmd(args, wait=False)
|
||||||
|
|
||||||
|
@ -355,9 +424,9 @@ class CoreServices(object):
|
||||||
:param core.netns.vnode.LxcNode node: node to validate services for
|
:param core.netns.vnode.LxcNode node: node to validate services for
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
services = sorted(node.services, key=lambda service: service._startindex)
|
services = sorted(node.services, key=lambda service: service.startindex)
|
||||||
for s in services:
|
for service in services:
|
||||||
self.validatenodeservice(node, s, services)
|
self.validatenodeservice(node, service, services)
|
||||||
|
|
||||||
def validatenodeservice(self, node, service, services):
|
def validatenodeservice(self, node, service, services):
|
||||||
"""
|
"""
|
||||||
|
@ -369,22 +438,20 @@ class CoreServices(object):
|
||||||
:return: service validation status
|
:return: service validation status
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
logger.info("validating service for node (%s): %s (%s)", node.name, service._name, service._startindex)
|
logger.info("validating service for node (%s): %s (%s)", node.name, service.name, service.startindex)
|
||||||
if service._custom:
|
if service.custom:
|
||||||
validate_cmds = service._validate
|
validate_cmds = service.validate
|
||||||
else:
|
else:
|
||||||
validate_cmds = service.getvalidate(node, services)
|
validate_cmds = service.getvalidate(node, services)
|
||||||
|
|
||||||
status = 0
|
status = 0
|
||||||
# has validate commands
|
for args in validate_cmds:
|
||||||
if validate_cmds:
|
logger.info("validating service %s using: %s", service.name, args)
|
||||||
for args in validate_cmds:
|
try:
|
||||||
logger.info("validating service %s using: %s", service._name, args)
|
node.check_cmd(args)
|
||||||
try:
|
except CoreCommandError:
|
||||||
node.check_cmd(args)
|
logger.exception("validate command failed")
|
||||||
except CoreCommandError:
|
status = -1
|
||||||
logger.exception("validate command failed")
|
|
||||||
status = -1
|
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
@ -395,9 +462,9 @@ class CoreServices(object):
|
||||||
:param core.netns.nodes.CoreNode node: node to stop services on
|
:param core.netns.nodes.CoreNode node: node to stop services on
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
services = sorted(node.services, key=lambda service: service._startindex)
|
services = sorted(node.services, key=lambda x: x.startindex)
|
||||||
for s in services:
|
for service in services:
|
||||||
self.stopnodeservice(node, s)
|
self.stopnodeservice(node, service)
|
||||||
|
|
||||||
def stopnodeservice(self, node, service):
|
def stopnodeservice(self, node, service):
|
||||||
"""
|
"""
|
||||||
|
@ -409,68 +476,57 @@ class CoreServices(object):
|
||||||
:rtype: str
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
status = "0"
|
status = "0"
|
||||||
if service._shutdown:
|
for args in service.shutdown:
|
||||||
for args in service._shutdown:
|
try:
|
||||||
try:
|
node.check_cmd(args)
|
||||||
node.check_cmd(args)
|
except CoreCommandError:
|
||||||
except CoreCommandError:
|
logger.exception("error running stop command %s", args)
|
||||||
logger.exception("error running stop command %s", args)
|
# TODO: determine if its ok to just return the bad exit status
|
||||||
# TODO: determine if its ok to just return the bad exit status
|
status = "-1"
|
||||||
status = "-1"
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def servicesfromopaque(self, opaque, object_id):
|
def getservicefile(self, service_name, node, filename, services):
|
||||||
"""
|
|
||||||
Build a list of services from an opaque data string.
|
|
||||||
|
|
||||||
:param str opaque: opaque data string
|
|
||||||
:param int object_id: object id
|
|
||||||
:return: services and unknown services lists tuple
|
|
||||||
:rtype: tuple
|
|
||||||
"""
|
|
||||||
services = []
|
|
||||||
unknown = []
|
|
||||||
servicesstring = opaque.split(':')
|
|
||||||
if servicesstring[0] != "service":
|
|
||||||
return []
|
|
||||||
servicenames = servicesstring[1].split(',')
|
|
||||||
for name in servicenames:
|
|
||||||
s = ServiceManager.get(name)
|
|
||||||
s = self.getcustomservice(object_id, s)
|
|
||||||
if s is None:
|
|
||||||
unknown.append(name)
|
|
||||||
else:
|
|
||||||
services.append(s)
|
|
||||||
return services, unknown
|
|
||||||
|
|
||||||
def getservicefile(self, services, node, filename):
|
|
||||||
"""
|
"""
|
||||||
Send a File Message when the GUI has requested a service file.
|
Send a File Message when the GUI has requested a service file.
|
||||||
The file data is either auto-generated or comes from an existing config.
|
The file data is either auto-generated or comes from an existing config.
|
||||||
|
|
||||||
:param list services: service list
|
:param str service_name: service to get file from
|
||||||
:param core.netns.vnode.LxcNode node: node to get service file from
|
:param core.netns.vnode.LxcNode node: node to get service file from
|
||||||
:param str filename: file name to retrieve
|
:param str filename: file name to retrieve
|
||||||
|
:param list[str] services: list of services associated with node
|
||||||
:return: file message for node
|
:return: file message for node
|
||||||
"""
|
"""
|
||||||
svc = services[0]
|
# get service to get file from
|
||||||
# get the filename and determine the config file index
|
service = self.getcustomservice(node.objid, service_name, default_service=True)
|
||||||
if svc._custom:
|
if not service:
|
||||||
cfgfiles = svc._configs
|
raise ValueError("invalid service: %s", service_name)
|
||||||
|
|
||||||
|
# get service for node
|
||||||
|
node_services = []
|
||||||
|
for service_name in services:
|
||||||
|
node_service = self.getcustomservice(node.objid, service_name, default_service=True)
|
||||||
|
if not node_service:
|
||||||
|
logger.warn("unknown service: %s", service)
|
||||||
|
continue
|
||||||
|
node_services.append(node_service)
|
||||||
|
|
||||||
|
# retrieve config files for default/custom service
|
||||||
|
if service.custom:
|
||||||
|
config_files = service.configs
|
||||||
else:
|
else:
|
||||||
cfgfiles = svc.getconfigfilenames(node.objid, services)
|
config_files = service.getconfigfilenames(node.objid, node_services)
|
||||||
if filename not in cfgfiles:
|
|
||||||
logger.warn("Request for unknown file '%s' for service '%s'" % (filename, services[0]))
|
if filename not in config_files:
|
||||||
return None
|
raise ValueError("unknown service(%s) config file: %s", service_name, filename)
|
||||||
|
|
||||||
# get the file data
|
# get the file data
|
||||||
data = self.getservicefiledata(svc, filename)
|
data = service.configtxt.get(filename)
|
||||||
if data is None:
|
if data is None:
|
||||||
data = "%s" % svc.generateconfig(node, filename, services)
|
data = "%s" % service.generateconfig(node, filename, services)
|
||||||
else:
|
else:
|
||||||
data = "%s" % data
|
data = "%s" % data
|
||||||
filetypestr = "service:%s" % svc._name
|
|
||||||
|
|
||||||
|
filetypestr = "service:%s" % service.name
|
||||||
return FileData(
|
return FileData(
|
||||||
message_type=MessageFlags.ADD.value,
|
message_type=MessageFlags.ADD.value,
|
||||||
node=node.objid,
|
node=node.objid,
|
||||||
|
@ -479,141 +535,85 @@ class CoreServices(object):
|
||||||
data=data
|
data=data
|
||||||
)
|
)
|
||||||
|
|
||||||
def getservicefiledata(self, service, filename):
|
def setservicefile(self, node_id, service_name, filename, data):
|
||||||
"""
|
|
||||||
Get the customized file data associated with a service. Return None
|
|
||||||
for invalid filenames or missing file data.
|
|
||||||
|
|
||||||
:param CoreService service: service to get file data from
|
|
||||||
:param str filename: file name to get data from
|
|
||||||
:return: file data
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
i = service._configs.index(filename)
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
if i >= len(service._configtxt) or service._configtxt[i] is None:
|
|
||||||
return None
|
|
||||||
return service._configtxt[i]
|
|
||||||
|
|
||||||
def setservicefile(self, nodenum, type, filename, srcname, data):
|
|
||||||
"""
|
"""
|
||||||
Receive a File Message from the GUI and store the customized file
|
Receive a File Message from the GUI and store the customized file
|
||||||
in the service config. The filename must match one from the list of
|
in the service config. The filename must match one from the list of
|
||||||
config files in the service.
|
config files in the service.
|
||||||
|
|
||||||
:param int nodenum: node id to set service file
|
:param int node_id: node id to set service file
|
||||||
:param str type: file type to set
|
:param str service_name: service name to set file for
|
||||||
:param str filename: file name to set
|
:param str filename: file name to set
|
||||||
:param str srcname: source name of file to set
|
|
||||||
:param data: data for file to set
|
:param data: data for file to set
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
if len(type.split(':')) < 2:
|
# attempt to set custom service, if needed
|
||||||
logger.warn("Received file type did not contain service info.")
|
self.setcustomservice(node_id, service_name)
|
||||||
return
|
|
||||||
if srcname is not None:
|
# retrieve custom service
|
||||||
raise NotImplementedError
|
svc = self.getcustomservice(node_id, service_name)
|
||||||
svcid, svcname = type.split(':')[:2]
|
|
||||||
svc = ServiceManager.get(svcname)
|
|
||||||
svc = self.getcustomservice(nodenum, svc)
|
|
||||||
if svc is None:
|
if svc is None:
|
||||||
logger.warn("Received filename for unknown service '%s'" % svcname)
|
logger.warn("received filename for unknown service: %s", service_name)
|
||||||
return
|
return
|
||||||
cfgfiles = svc._configs
|
|
||||||
|
# validate file being set is valid
|
||||||
|
cfgfiles = svc.configs
|
||||||
if filename not in cfgfiles:
|
if filename not in cfgfiles:
|
||||||
logger.warn("Received unknown file '%s' for service '%s'" % (filename, svcname))
|
logger.warn("received unknown file '%s' for service '%s'", filename, service_name)
|
||||||
return
|
return
|
||||||
i = cfgfiles.index(filename)
|
|
||||||
configtxtlist = list(svc._configtxt)
|
|
||||||
numitems = len(configtxtlist)
|
|
||||||
if numitems < i + 1:
|
|
||||||
# add empty elements to list to support index assignment
|
|
||||||
for j in range(1, (i + 2) - numitems):
|
|
||||||
configtxtlist += None,
|
|
||||||
configtxtlist[i] = data
|
|
||||||
svc._configtxt = configtxtlist
|
|
||||||
|
|
||||||
def handleevent(self, event_data):
|
# set custom service file data
|
||||||
|
svc.configtxt[filename] = data
|
||||||
|
|
||||||
|
def node_service_startup(self, node, service, services):
|
||||||
"""
|
"""
|
||||||
Handle an Event Message used to start, stop, restart, or validate
|
Startup a node service.
|
||||||
a service on a given node.
|
|
||||||
|
|
||||||
:param EventData event_data: event data to handle
|
:param PyCoreNode node: node to reconfigure service for
|
||||||
|
:param CoreService service: service to reconfigure
|
||||||
|
:param list[CoreService] services: node services
|
||||||
|
:return: status of startup
|
||||||
|
:rtype: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
if service.custom:
|
||||||
|
cmds = service.startup
|
||||||
|
else:
|
||||||
|
cmds = service.getstartup(node, services)
|
||||||
|
|
||||||
|
status = "0"
|
||||||
|
for args in cmds:
|
||||||
|
try:
|
||||||
|
node.check_cmd(args)
|
||||||
|
except CoreCommandError:
|
||||||
|
logger.exception("error starting command")
|
||||||
|
status = "-1"
|
||||||
|
return status
|
||||||
|
|
||||||
|
def node_service_reconfigure(self, node, service, services):
|
||||||
|
"""
|
||||||
|
Reconfigure a node service.
|
||||||
|
|
||||||
|
:param PyCoreNode node: node to reconfigure service for
|
||||||
|
:param CoreService service: service to reconfigure
|
||||||
|
:param list[CoreService] services: node services
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
event_type = event_data.event_type
|
if service.custom:
|
||||||
node_id = event_data.node
|
cfgfiles = service.configs
|
||||||
name = event_data.name
|
else:
|
||||||
|
cfgfiles = service.getconfigfilenames(node.objid, services)
|
||||||
|
|
||||||
try:
|
for filename in cfgfiles:
|
||||||
node = self.session.get_object(node_id)
|
if filename[:7] == "file:///":
|
||||||
except KeyError:
|
# TODO: implement this
|
||||||
logger.warn("Ignoring event for service '%s', unknown node '%s'", name, node_id)
|
raise NotImplementedError
|
||||||
return
|
|
||||||
|
|
||||||
fail = ""
|
cfg = service.configtxt.get(filename)
|
||||||
services, unknown = self.servicesfromopaque(name, node_id)
|
if cfg is None:
|
||||||
for s in services:
|
cfg = service.generateconfig(node, filename, services)
|
||||||
if event_type == EventTypes.STOP.value or event_type == EventTypes.RESTART.value:
|
|
||||||
status = self.stopnodeservice(node, s)
|
|
||||||
if status != "0":
|
|
||||||
fail += "Stop %s," % s._name
|
|
||||||
if event_type == EventTypes.START.value or event_type == EventTypes.RESTART.value:
|
|
||||||
if s._custom:
|
|
||||||
cmds = s._startup
|
|
||||||
else:
|
|
||||||
cmds = s.getstartup(node, services)
|
|
||||||
if len(cmds) > 0:
|
|
||||||
for args in cmds:
|
|
||||||
try:
|
|
||||||
node.check_cmd(args)
|
|
||||||
except CoreCommandError:
|
|
||||||
logger.exception("error starting command")
|
|
||||||
fail += "Start %s(%s)," % (s._name, args)
|
|
||||||
if event_type == EventTypes.PAUSE.value:
|
|
||||||
status = self.validatenodeservice(node, s, services)
|
|
||||||
if status != 0:
|
|
||||||
fail += "%s," % s._name
|
|
||||||
if event_type == EventTypes.RECONFIGURE.value:
|
|
||||||
if s._custom:
|
|
||||||
cfgfiles = s._configs
|
|
||||||
else:
|
|
||||||
cfgfiles = s.getconfigfilenames(node.objid, services)
|
|
||||||
if len(cfgfiles) > 0:
|
|
||||||
for filename in cfgfiles:
|
|
||||||
if filename[:7] == "file:///":
|
|
||||||
# TODO: implement this
|
|
||||||
raise NotImplementedError
|
|
||||||
cfg = self.getservicefiledata(s, filename)
|
|
||||||
if cfg is None:
|
|
||||||
cfg = s.generateconfig(node, filename, services)
|
|
||||||
|
|
||||||
node.nodefile(filename, cfg)
|
node.nodefile(filename, cfg)
|
||||||
|
|
||||||
fail_data = ""
|
|
||||||
if len(fail) > 0:
|
|
||||||
fail_data += "Fail:" + fail
|
|
||||||
unknown_data = ""
|
|
||||||
num = len(unknown)
|
|
||||||
if num > 0:
|
|
||||||
for u in unknown:
|
|
||||||
unknown_data += u
|
|
||||||
if num > 1:
|
|
||||||
unknown_data += ", "
|
|
||||||
num -= 1
|
|
||||||
logger.warn("Event requested for unknown service(s): %s", unknown_data)
|
|
||||||
unknown_data = "Unknown:" + unknown_data
|
|
||||||
|
|
||||||
event_data = EventData(
|
|
||||||
node=node_id,
|
|
||||||
event_type=event_type,
|
|
||||||
name=name,
|
|
||||||
data=fail_data + ";" + unknown_data,
|
|
||||||
time="%s" % time.time()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.session.broadcast_event(event_data)
|
|
||||||
|
|
||||||
|
|
||||||
class CoreService(object):
|
class CoreService(object):
|
||||||
|
@ -621,45 +621,42 @@ class CoreService(object):
|
||||||
Parent class used for defining services.
|
Parent class used for defining services.
|
||||||
"""
|
"""
|
||||||
# service name should not include spaces
|
# service name should not include spaces
|
||||||
_name = ""
|
name = None
|
||||||
|
|
||||||
# group string allows grouping services together
|
# group string allows grouping services together
|
||||||
_group = ""
|
group = None
|
||||||
|
|
||||||
# list name(s) of services that this service depends upon
|
# list name(s) of services that this service depends upon
|
||||||
_depends = ()
|
depends = ()
|
||||||
keys = ["dirs", "files", "startidx", "cmdup", "cmddown", "cmdval", "meta", "starttime"]
|
|
||||||
|
|
||||||
# private, per-node directories required by this service
|
# private, per-node directories required by this service
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
|
|
||||||
# config files written by this service
|
# config files written by this service
|
||||||
_configs = ()
|
configs = ()
|
||||||
# configs = []
|
|
||||||
|
|
||||||
# index used to determine start order with other services
|
# index used to determine start order with other services
|
||||||
_startindex = 0
|
startindex = 0
|
||||||
|
|
||||||
# time in seconds after runtime to run startup commands
|
# time in seconds after runtime to run startup commands
|
||||||
_starttime = ""
|
starttime = 0
|
||||||
|
|
||||||
# list of startup commands
|
# list of startup commands
|
||||||
_startup = ()
|
startup = ()
|
||||||
# startup = []
|
|
||||||
|
|
||||||
# list of shutdown commands
|
# list of shutdown commands
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
||||||
# list of validate commands
|
# list of validate commands
|
||||||
_validate = ()
|
validate = ()
|
||||||
|
|
||||||
# metadata associated with this service
|
# metadata associated with this service
|
||||||
_meta = ""
|
meta = None
|
||||||
|
|
||||||
# custom configuration text
|
# custom configuration text
|
||||||
_configtxt = ()
|
configtxt = {}
|
||||||
_custom = False
|
custom = False
|
||||||
_custom_needed = False
|
custom_needed = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
|
@ -667,7 +664,16 @@ class CoreService(object):
|
||||||
against their config. Services are instantiated when a custom
|
against their config. Services are instantiated when a custom
|
||||||
configuration is used to override their default parameters.
|
configuration is used to override their default parameters.
|
||||||
"""
|
"""
|
||||||
self._custom = True
|
self.custom = True
|
||||||
|
self.dirs = self.__class__.dirs
|
||||||
|
self.configs = self.__class__.configs
|
||||||
|
self.startindex = self.__class__.startindex
|
||||||
|
self.startup = self.__class__.startup
|
||||||
|
self.shutdown = self.__class__.shutdown
|
||||||
|
self.validate = self.__class__.validate
|
||||||
|
self.meta = self.__class__.meta
|
||||||
|
self.starttime = self.__class__.starttime
|
||||||
|
self.configtxt = self.__class__.configtxt
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def on_load(cls):
|
def on_load(cls):
|
||||||
|
@ -685,7 +691,7 @@ class CoreService(object):
|
||||||
:return: class configuration files
|
:return: class configuration files
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
return cls._configs
|
return cls.configs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -716,7 +722,7 @@ class CoreService(object):
|
||||||
:return: startup commands
|
:return: startup commands
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
return cls._startup
|
return cls.startup
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getvalidate(cls, node, services):
|
def getvalidate(cls, node, services):
|
||||||
|
@ -731,76 +737,4 @@ class CoreService(object):
|
||||||
:return: validation commands
|
:return: validation commands
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
return cls._validate
|
return cls.validate
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tovaluelist(cls, node, services):
|
|
||||||
"""
|
|
||||||
Convert service properties into a string list of key=value pairs,
|
|
||||||
separated by "|".
|
|
||||||
|
|
||||||
:param core.netns.nodes.CoreNode node: node to get value list for
|
|
||||||
:param list services: services for node
|
|
||||||
:return: value list string
|
|
||||||
:rtype: str
|
|
||||||
"""
|
|
||||||
valmap = [cls._dirs, cls._configs, cls._startindex, cls._startup,
|
|
||||||
cls._shutdown, cls._validate, cls._meta, cls._starttime]
|
|
||||||
if not cls._custom:
|
|
||||||
# this is always reached due to classmethod
|
|
||||||
valmap[valmap.index(cls._configs)] = cls.getconfigfilenames(node.objid, services)
|
|
||||||
valmap[valmap.index(cls._startup)] = cls.getstartup(node, services)
|
|
||||||
vals = map(lambda a, b: "%s=%s" % (a, str(b)), cls.keys, valmap)
|
|
||||||
return "|".join(vals)
|
|
||||||
|
|
||||||
def fromvaluelist(self, values):
|
|
||||||
"""
|
|
||||||
Convert list of values into properties for this instantiated
|
|
||||||
(customized) service.
|
|
||||||
|
|
||||||
:param list values: value list to set properties from
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
# TODO: support empty value? e.g. override default meta with ''
|
|
||||||
for key in self.keys:
|
|
||||||
try:
|
|
||||||
self.setvalue(key, values[self.keys.index(key)])
|
|
||||||
except IndexError:
|
|
||||||
# old config does not need to have new keys
|
|
||||||
logger.exception("error indexing into key")
|
|
||||||
|
|
||||||
def setvalue(self, key, value):
|
|
||||||
"""
|
|
||||||
Set values for this service.
|
|
||||||
|
|
||||||
:param str key: key to set value for
|
|
||||||
:param value: value of key to set
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
if key not in self.keys:
|
|
||||||
raise ValueError('key `%s` not in `%s`' % (key, self.keys))
|
|
||||||
# this handles data conversion to int, string, and tuples
|
|
||||||
if value:
|
|
||||||
if key == "startidx":
|
|
||||||
value = int(value)
|
|
||||||
elif key == "meta":
|
|
||||||
value = str(value)
|
|
||||||
else:
|
|
||||||
value = utils.make_tuple_fromstr(value, str)
|
|
||||||
|
|
||||||
if key == "dirs":
|
|
||||||
self._dirs = value
|
|
||||||
elif key == "files":
|
|
||||||
self._configs = value
|
|
||||||
elif key == "startidx":
|
|
||||||
self._startindex = value
|
|
||||||
elif key == "cmdup":
|
|
||||||
self._startup = value
|
|
||||||
elif key == "cmddown":
|
|
||||||
self._shutdown = value
|
|
||||||
elif key == "cmdval":
|
|
||||||
self._validate = value
|
|
||||||
elif key == "meta":
|
|
||||||
self._meta = value
|
|
||||||
elif key == "starttime":
|
|
||||||
self._starttime = value
|
|
||||||
|
|
|
@ -9,22 +9,22 @@ class Bird(CoreService):
|
||||||
"""
|
"""
|
||||||
Bird router support
|
Bird router support
|
||||||
"""
|
"""
|
||||||
_name = "bird"
|
name = "bird"
|
||||||
_group = "BIRD"
|
group = "BIRD"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ("/etc/bird",)
|
dirs = ("/etc/bird",)
|
||||||
_configs = ("/etc/bird/bird.conf",)
|
configs = ("/etc/bird/bird.conf",)
|
||||||
_startindex = 35
|
startindex = 35
|
||||||
_startup = ("bird -c %s" % (_configs[0]),)
|
startup = ("bird -c %s" % (configs[0]),)
|
||||||
_shutdown = ("killall bird",)
|
shutdown = ("killall bird",)
|
||||||
_validate = ("pidof bird",)
|
validate = ("pidof bird",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
"""
|
"""
|
||||||
Return the bird.conf file contents.
|
Return the bird.conf file contents.
|
||||||
"""
|
"""
|
||||||
if filename == cls._configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateBirdConf(node, services)
|
return cls.generateBirdConf(node, services)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
@ -35,7 +35,7 @@ class Bird(CoreService):
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
for a in ifc.addrlist:
|
for a in ifc.addrlist:
|
||||||
if a.find(".") >= 0:
|
if a.find(".") >= 0:
|
||||||
|
@ -73,11 +73,11 @@ protocol device {
|
||||||
scan time 10; # Scan interfaces every 10 seconds
|
scan time 10; # Scan interfaces every 10 seconds
|
||||||
}
|
}
|
||||||
|
|
||||||
""" % (cls._name, cls.routerid(node))
|
""" % (cls.name, cls.routerid(node))
|
||||||
|
|
||||||
# Generate protocol specific configurations
|
# Generate protocol specific configurations
|
||||||
for s in services:
|
for s in services:
|
||||||
if cls._name not in s._depends:
|
if cls.name not in s.depends:
|
||||||
continue
|
continue
|
||||||
cfg += s.generatebirdconfig(node)
|
cfg += s.generatebirdconfig(node)
|
||||||
|
|
||||||
|
@ -90,15 +90,15 @@ class BirdService(CoreService):
|
||||||
common to Bird's routing daemons.
|
common to Bird's routing daemons.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = None
|
name = None
|
||||||
_group = "BIRD"
|
group = "BIRD"
|
||||||
_depends = ("bird",)
|
depends = ("bird",)
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 40
|
startindex = 40
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
_meta = "The config file for this service can be found in the bird service."
|
meta = "The config file for this service can be found in the bird service."
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
@ -106,14 +106,15 @@ class BirdService(CoreService):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdifcconfig(cls, node):
|
def generatebirdifcconfig(cls, node):
|
||||||
''' Use only bare interfaces descriptions in generated protocol
|
"""
|
||||||
|
Use only bare interfaces descriptions in generated protocol
|
||||||
configurations. This has the slight advantage of being the same
|
configurations. This has the slight advantage of being the same
|
||||||
everywhere.
|
everywhere.
|
||||||
'''
|
"""
|
||||||
cfg = ""
|
cfg = ""
|
||||||
|
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
cfg += ' interface "%s";\n' % ifc.name
|
cfg += ' interface "%s";\n' % ifc.name
|
||||||
|
|
||||||
|
@ -125,8 +126,8 @@ class BirdBgp(BirdService):
|
||||||
BGP BIRD Service (configuration generation)
|
BGP BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "BIRD_BGP"
|
name = "BIRD_BGP"
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
@ -156,7 +157,7 @@ class BirdOspf(BirdService):
|
||||||
OSPF BIRD Service (configuration generation)
|
OSPF BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "BIRD_OSPFv2"
|
name = "BIRD_OSPFv2"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
@ -181,7 +182,7 @@ class BirdRadv(BirdService):
|
||||||
RADV BIRD Service (configuration generation)
|
RADV BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "BIRD_RADV"
|
name = "BIRD_RADV"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
@ -209,7 +210,7 @@ class BirdRip(BirdService):
|
||||||
RIP BIRD Service (configuration generation)
|
RIP BIRD Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "BIRD_RIP"
|
name = "BIRD_RIP"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
@ -231,8 +232,8 @@ class BirdStatic(BirdService):
|
||||||
Static Bird Service (configuration generation)
|
Static Bird Service (configuration generation)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "BIRD_static"
|
name = "BIRD_static"
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatebirdconfig(cls, node):
|
def generatebirdconfig(cls, node):
|
||||||
|
|
|
@ -112,16 +112,16 @@ class DockerService(CoreService):
|
||||||
This is a service which will allow running docker containers in a CORE
|
This is a service which will allow running docker containers in a CORE
|
||||||
node.
|
node.
|
||||||
"""
|
"""
|
||||||
_name = "Docker"
|
name = "Docker"
|
||||||
_group = "Docker"
|
group = "Docker"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',)
|
dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',)
|
||||||
_configs = ('docker.sh',)
|
configs = ('docker.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh docker.sh',)
|
startup = ('sh docker.sh',)
|
||||||
_shutdown = ('service docker stop',)
|
shutdown = ('service docker stop',)
|
||||||
# Container image to start
|
# Container image to start
|
||||||
_image = ""
|
image = ""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -139,7 +139,7 @@ class DockerService(CoreService):
|
||||||
# distros may just be docker
|
# distros may just be docker
|
||||||
cfg += 'service docker start\n'
|
cfg += 'service docker start\n'
|
||||||
cfg += "# you could add a command to start a image here eg:\n"
|
cfg += "# you could add a command to start a image here eg:\n"
|
||||||
if not cls._image:
|
if not cls.image:
|
||||||
cfg += "# docker run -d --net host --name coreDock <imagename>\n"
|
cfg += "# docker run -d --net host --name coreDock <imagename>\n"
|
||||||
else:
|
else:
|
||||||
cfg += """\
|
cfg += """\
|
||||||
|
@ -150,7 +150,7 @@ until [ $result -eq 0 ]; do
|
||||||
# this is to alleviate contention to docker's SQLite database
|
# this is to alleviate contention to docker's SQLite database
|
||||||
sleep 0.3
|
sleep 0.3
|
||||||
done
|
done
|
||||||
""" % (cls._image,)
|
""" % (cls.image,)
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -13,14 +13,14 @@ class NrlService(CoreService):
|
||||||
Parent class for NRL services. Defines properties and methods
|
Parent class for NRL services. Defines properties and methods
|
||||||
common to NRL's routing daemons.
|
common to NRL's routing daemons.
|
||||||
"""""
|
"""""
|
||||||
_name = None
|
name = None
|
||||||
_group = "ProtoSvc"
|
group = "ProtoSvc"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 45
|
startindex = 45
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -34,7 +34,7 @@ class NrlService(CoreService):
|
||||||
interface's prefix length, so e.g. '/32' can turn into '/24'.
|
interface's prefix length, so e.g. '/32' can turn into '/24'.
|
||||||
"""
|
"""
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
for a in ifc.addrlist:
|
for a in ifc.addrlist:
|
||||||
if a.find(".") >= 0:
|
if a.find(".") >= 0:
|
||||||
|
@ -46,12 +46,12 @@ class NrlService(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class MgenSinkService(NrlService):
|
class MgenSinkService(NrlService):
|
||||||
_name = "MGEN_Sink"
|
name = "MGEN_Sink"
|
||||||
_configs = ("sink.mgen",)
|
configs = ("sink.mgen",)
|
||||||
_startindex = 5
|
startindex = 5
|
||||||
_startup = ("mgen input sink.mgen",)
|
startup = ("mgen input sink.mgen",)
|
||||||
_validate = ("pidof mgen",)
|
validate = ("pidof mgen",)
|
||||||
_shutdown = ("killall mgen",)
|
shutdown = ("killall mgen",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -63,7 +63,7 @@ class MgenSinkService(NrlService):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getstartup(cls, node, services):
|
def getstartup(cls, node, services):
|
||||||
cmd = cls._startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " output /tmp/mgen_%s.log" % node.name
|
cmd += " output /tmp/mgen_%s.log" % node.name
|
||||||
return cmd,
|
return cmd,
|
||||||
|
|
||||||
|
@ -72,27 +72,26 @@ class NrlNhdp(NrlService):
|
||||||
"""
|
"""
|
||||||
NeighborHood Discovery Protocol for MANET networks.
|
NeighborHood Discovery Protocol for MANET networks.
|
||||||
"""
|
"""
|
||||||
_name = "NHDP"
|
name = "NHDP"
|
||||||
_startup = ("nrlnhdp",)
|
startup = ("nrlnhdp",)
|
||||||
_shutdown = ("killall nrlnhdp",)
|
shutdown = ("killall nrlnhdp",)
|
||||||
_validate = ("pidof nrlnhdp",)
|
validate = ("pidof nrlnhdp",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getstartup(cls, node, services):
|
def getstartup(cls, node, services):
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls._startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " -l /var/log/nrlnhdp.log"
|
cmd += " -l /var/log/nrlnhdp.log"
|
||||||
cmd += " -rpipe %s_nhdp" % node.name
|
cmd += " -rpipe %s_nhdp" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x._name, services)
|
servicenames = map(lambda x: x.name, services)
|
||||||
if "SMF" in servicenames:
|
if "SMF" in servicenames:
|
||||||
cmd += " -flooding ecds"
|
cmd += " -flooding ecds"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
|
|
||||||
netifs = filter(lambda x: not getattr(x, 'control', False), \
|
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
||||||
node.netifs())
|
|
||||||
if len(netifs) > 0:
|
if len(netifs) > 0:
|
||||||
interfacenames = map(lambda x: x.name, netifs)
|
interfacenames = map(lambda x: x.name, netifs)
|
||||||
cmd += " -i "
|
cmd += " -i "
|
||||||
|
@ -105,11 +104,11 @@ class NrlSmf(NrlService):
|
||||||
"""
|
"""
|
||||||
Simplified Multicast Forwarding for MANET networks.
|
Simplified Multicast Forwarding for MANET networks.
|
||||||
"""
|
"""
|
||||||
_name = "SMF"
|
name = "SMF"
|
||||||
_startup = ("sh startsmf.sh",)
|
startup = ("sh startsmf.sh",)
|
||||||
_shutdown = ("killall nrlsmf",)
|
shutdown = ("killall nrlsmf",)
|
||||||
_validate = ("pidof nrlsmf",)
|
validate = ("pidof nrlsmf",)
|
||||||
_configs = ("startsmf.sh",)
|
configs = ("startsmf.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -123,7 +122,7 @@ class NrlSmf(NrlService):
|
||||||
comments = ""
|
comments = ""
|
||||||
cmd = "nrlsmf instance %s_smf" % node.name
|
cmd = "nrlsmf instance %s_smf" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x._name, services)
|
servicenames = map(lambda x: x.name, services)
|
||||||
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
||||||
if len(netifs) == 0:
|
if len(netifs) == 0:
|
||||||
return ""
|
return ""
|
||||||
|
@ -156,17 +155,17 @@ class NrlOlsr(NrlService):
|
||||||
"""
|
"""
|
||||||
Optimized Link State Routing protocol for MANET networks.
|
Optimized Link State Routing protocol for MANET networks.
|
||||||
"""
|
"""
|
||||||
_name = "OLSR"
|
name = "OLSR"
|
||||||
_startup = ("nrlolsrd",)
|
startup = ("nrlolsrd",)
|
||||||
_shutdown = ("killall nrlolsrd",)
|
shutdown = ("killall nrlolsrd",)
|
||||||
_validate = ("pidof nrlolsrd",)
|
validate = ("pidof nrlolsrd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getstartup(cls, node, services):
|
def getstartup(cls, node, services):
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls._startup[0]
|
cmd = cls.startup[0]
|
||||||
# are multiple interfaces supported? No.
|
# are multiple interfaces supported? No.
|
||||||
netifs = list(node.netifs())
|
netifs = list(node.netifs())
|
||||||
if len(netifs) > 0:
|
if len(netifs) > 0:
|
||||||
|
@ -175,7 +174,7 @@ class NrlOlsr(NrlService):
|
||||||
cmd += " -l /var/log/nrlolsrd.log"
|
cmd += " -l /var/log/nrlolsrd.log"
|
||||||
cmd += " -rpipe %s_olsr" % node.name
|
cmd += " -rpipe %s_olsr" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x._name, services)
|
servicenames = map(lambda x: x.name, services)
|
||||||
if "SMF" in servicenames and not "NHDP" in servicenames:
|
if "SMF" in servicenames and not "NHDP" in servicenames:
|
||||||
cmd += " -flooding s-mpr"
|
cmd += " -flooding s-mpr"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
|
@ -189,21 +188,21 @@ class NrlOlsrv2(NrlService):
|
||||||
"""
|
"""
|
||||||
Optimized Link State Routing protocol version 2 for MANET networks.
|
Optimized Link State Routing protocol version 2 for MANET networks.
|
||||||
"""
|
"""
|
||||||
_name = "OLSRv2"
|
name = "OLSRv2"
|
||||||
_startup = ("nrlolsrv2",)
|
startup = ("nrlolsrv2",)
|
||||||
_shutdown = ("killall nrlolsrv2",)
|
shutdown = ("killall nrlolsrv2",)
|
||||||
_validate = ("pidof nrlolsrv2",)
|
validate = ("pidof nrlolsrv2",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getstartup(cls, node, services):
|
def getstartup(cls, node, services):
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls._startup[0]
|
cmd = cls.startup[0]
|
||||||
cmd += " -l /var/log/nrlolsrv2.log"
|
cmd += " -l /var/log/nrlolsrv2.log"
|
||||||
cmd += " -rpipe %s_olsrv2" % node.name
|
cmd += " -rpipe %s_olsrv2" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x._name, services)
|
servicenames = map(lambda x: x.name, services)
|
||||||
if "SMF" in servicenames:
|
if "SMF" in servicenames:
|
||||||
cmd += " -flooding ecds"
|
cmd += " -flooding ecds"
|
||||||
cmd += " -smfClient %s_smf" % node.name
|
cmd += " -smfClient %s_smf" % node.name
|
||||||
|
@ -223,19 +222,19 @@ class OlsrOrg(NrlService):
|
||||||
"""
|
"""
|
||||||
Optimized Link State Routing protocol from olsr.org for MANET networks.
|
Optimized Link State Routing protocol from olsr.org for MANET networks.
|
||||||
"""
|
"""
|
||||||
_name = "OLSRORG"
|
name = "OLSRORG"
|
||||||
_configs = ("/etc/olsrd/olsrd.conf",)
|
configs = ("/etc/olsrd/olsrd.conf",)
|
||||||
_dirs = ("/etc/olsrd",)
|
dirs = ("/etc/olsrd",)
|
||||||
_startup = ("olsrd",)
|
startup = ("olsrd",)
|
||||||
_shutdown = ("killall olsrd",)
|
shutdown = ("killall olsrd",)
|
||||||
_validate = ("pidof olsrd",)
|
validate = ("pidof olsrd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def getstartup(cls, node, services):
|
def getstartup(cls, node, services):
|
||||||
"""
|
"""
|
||||||
Generate the appropriate command-line based on node interfaces.
|
Generate the appropriate command-line based on node interfaces.
|
||||||
"""
|
"""
|
||||||
cmd = cls._startup[0]
|
cmd = cls.startup[0]
|
||||||
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
||||||
if len(netifs) > 0:
|
if len(netifs) > 0:
|
||||||
interfacenames = map(lambda x: x.name, netifs)
|
interfacenames = map(lambda x: x.name, netifs)
|
||||||
|
@ -572,24 +571,24 @@ class MgenActor(NrlService):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# a unique name is required, without spaces
|
# a unique name is required, without spaces
|
||||||
_name = "MgenActor"
|
name = "MgenActor"
|
||||||
# you can create your own group here
|
# you can create your own group here
|
||||||
_group = "ProtoSvc"
|
group = "ProtoSvc"
|
||||||
# list of other services this service depends on
|
# list of other services this service depends on
|
||||||
_depends = ()
|
depends = ()
|
||||||
# per-node directories
|
# per-node directories
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
# generated files (without a full path this file goes in the node's dir,
|
# generated files (without a full path this file goes in the node's dir,
|
||||||
# e.g. /tmp/pycore.12345/n1.conf/)
|
# e.g. /tmp/pycore.12345/n1.conf/)
|
||||||
_configs = ('start_mgen_actor.sh',)
|
configs = ('start_mgen_actor.sh',)
|
||||||
# this controls the starting order vs other enabled services
|
# this controls the starting order vs other enabled services
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
# list of startup commands, also may be generated during startup
|
# list of startup commands, also may be generated during startup
|
||||||
_startup = ("sh start_mgen_actor.sh",)
|
startup = ("sh start_mgen_actor.sh",)
|
||||||
# list of validation commands
|
# list of validation commands
|
||||||
_validate = ("pidof mgen",)
|
validate = ("pidof mgen",)
|
||||||
# list of shutdown commands
|
# list of shutdown commands
|
||||||
_shutdown = ("killall mgen",)
|
shutdown = ("killall mgen",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -603,7 +602,7 @@ class MgenActor(NrlService):
|
||||||
comments = ""
|
comments = ""
|
||||||
cmd = "mgenBasicActor.py -n %s -a 0.0.0.0" % node.name
|
cmd = "mgenBasicActor.py -n %s -a 0.0.0.0" % node.name
|
||||||
|
|
||||||
servicenames = map(lambda x: x._name, services)
|
servicenames = map(lambda x: x.name, services)
|
||||||
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
||||||
if len(netifs) == 0:
|
if len(netifs) == 0:
|
||||||
return ""
|
return ""
|
||||||
|
@ -616,12 +615,12 @@ class Arouted(NrlService):
|
||||||
"""
|
"""
|
||||||
Adaptive Routing
|
Adaptive Routing
|
||||||
"""
|
"""
|
||||||
_name = "arouted"
|
name = "arouted"
|
||||||
_configs = ("startarouted.sh",)
|
configs = ("startarouted.sh",)
|
||||||
_startindex = NrlService._startindex + 10
|
startindex = NrlService.startindex + 10
|
||||||
_startup = ("sh startarouted.sh",)
|
startup = ("sh startarouted.sh",)
|
||||||
_shutdown = ("pkill arouted",)
|
shutdown = ("pkill arouted",)
|
||||||
_validate = ("pidof arouted",)
|
validate = ("pidof arouted",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
|
|
@ -10,33 +10,33 @@ from core.service import CoreService
|
||||||
|
|
||||||
|
|
||||||
class Zebra(CoreService):
|
class Zebra(CoreService):
|
||||||
_name = "zebra"
|
name = "zebra"
|
||||||
_group = "Quagga"
|
group = "Quagga"
|
||||||
_dirs = ("/usr/local/etc/quagga", "/var/run/quagga")
|
dirs = ("/usr/local/etc/quagga", "/var/run/quagga")
|
||||||
_configs = (
|
configs = (
|
||||||
"/usr/local/etc/quagga/Quagga.conf",
|
"/usr/local/etc/quagga/Quagga.conf",
|
||||||
"quaggaboot.sh",
|
"quaggaboot.sh",
|
||||||
"/usr/local/etc/quagga/vtysh.conf"
|
"/usr/local/etc/quagga/vtysh.conf"
|
||||||
)
|
)
|
||||||
_startindex = 35
|
startindex = 35
|
||||||
_startup = ("sh quaggaboot.sh zebra",)
|
startup = ("sh quaggaboot.sh zebra",)
|
||||||
_shutdown = ("killall zebra",)
|
shutdown = ("killall zebra",)
|
||||||
_validate = ("pidof zebra",)
|
validate = ("pidof zebra",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
"""
|
"""
|
||||||
Return the Quagga.conf or quaggaboot.sh file contents.
|
Return the Quagga.conf or quaggaboot.sh file contents.
|
||||||
"""
|
"""
|
||||||
if filename == cls._configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateQuaggaConf(node, services)
|
return cls.generateQuaggaConf(node, services)
|
||||||
elif filename == cls._configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateQuaggaBoot(node, services)
|
return cls.generateQuaggaBoot(node, services)
|
||||||
elif filename == cls._configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generateVtyshConf(node, services)
|
return cls.generateVtyshConf(node, services)
|
||||||
else:
|
else:
|
||||||
raise ValueError("file name (%s) is not a known configuration: %s",
|
raise ValueError("file name (%s) is not a known configuration: %s",
|
||||||
filename, cls._configs)
|
filename, cls.configs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateVtyshConf(cls, node, services):
|
def generateVtyshConf(cls, node, services):
|
||||||
|
@ -67,12 +67,12 @@ class Zebra(CoreService):
|
||||||
want_ipv4 = False
|
want_ipv4 = False
|
||||||
want_ipv6 = False
|
want_ipv6 = False
|
||||||
for s in services:
|
for s in services:
|
||||||
if cls._name not in s._depends:
|
if cls.name not in s.depends:
|
||||||
continue
|
continue
|
||||||
ifccfg = s.generatequaggaifcconfig(node, ifc)
|
ifccfg = s.generatequaggaifcconfig(node, ifc)
|
||||||
if s._ipv4_routing:
|
if s.ipv4_routing:
|
||||||
want_ipv4 = True
|
want_ipv4 = True
|
||||||
if s._ipv6_routing:
|
if s.ipv6_routing:
|
||||||
want_ipv6 = True
|
want_ipv6 = True
|
||||||
cfgv6 += ifccfg
|
cfgv6 += ifccfg
|
||||||
else:
|
else:
|
||||||
|
@ -93,7 +93,7 @@ class Zebra(CoreService):
|
||||||
cfg += "!\n"
|
cfg += "!\n"
|
||||||
|
|
||||||
for s in services:
|
for s in services:
|
||||||
if cls._name not in s._depends:
|
if cls.name not in s.depends:
|
||||||
continue
|
continue
|
||||||
cfg += s.generatequaggaconfig(node)
|
cfg += s.generatequaggaconfig(node)
|
||||||
return cfg
|
return cfg
|
||||||
|
@ -212,7 +212,7 @@ if [ "$1" != "zebra" ]; then
|
||||||
fi
|
fi
|
||||||
confcheck
|
confcheck
|
||||||
bootquagga
|
bootquagga
|
||||||
""" % (cls._configs[0], quagga_sbin_search, quagga_bin_search, constants.QUAGGA_STATE_DIR)
|
""" % (cls.configs[0], quagga_sbin_search, quagga_bin_search, constants.QUAGGA_STATE_DIR)
|
||||||
|
|
||||||
|
|
||||||
class QuaggaService(CoreService):
|
class QuaggaService(CoreService):
|
||||||
|
@ -220,18 +220,18 @@ class QuaggaService(CoreService):
|
||||||
Parent class for Quagga services. Defines properties and methods
|
Parent class for Quagga services. Defines properties and methods
|
||||||
common to Quagga's routing daemons.
|
common to Quagga's routing daemons.
|
||||||
"""
|
"""
|
||||||
_name = None
|
name = None
|
||||||
_group = "Quagga"
|
group = "Quagga"
|
||||||
_depends = ("zebra",)
|
depends = ("zebra",)
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 40
|
startindex = 40
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
_meta = "The config file for this service can be found in the Zebra service."
|
meta = "The config file for this service can be found in the Zebra service."
|
||||||
|
|
||||||
_ipv4_routing = False
|
ipv4_routing = False
|
||||||
_ipv6_routing = False
|
ipv6_routing = False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def routerid(node):
|
def routerid(node):
|
||||||
|
@ -239,7 +239,7 @@ class QuaggaService(CoreService):
|
||||||
Helper to return the first IPv4 address of a node as its router ID.
|
Helper to return the first IPv4 address of a node as its router ID.
|
||||||
"""
|
"""
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
for a in ifc.addrlist:
|
for a in ifc.addrlist:
|
||||||
if a.find(".") >= 0:
|
if a.find(".") >= 0:
|
||||||
|
@ -280,11 +280,11 @@ class Ospfv2(QuaggaService):
|
||||||
not build its own configuration file but has hooks for adding to the
|
not build its own configuration file but has hooks for adding to the
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
_name = "OSPFv2"
|
name = "OSPFv2"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall ospfd",)
|
shutdown = ("killall ospfd",)
|
||||||
_validate = ("pidof ospfd",)
|
validate = ("pidof ospfd",)
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def mtucheck(ifc):
|
def mtucheck(ifc):
|
||||||
|
@ -355,12 +355,12 @@ class Ospfv3(QuaggaService):
|
||||||
not build its own configuration file but has hooks for adding to the
|
not build its own configuration file but has hooks for adding to the
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
_name = "OSPFv3"
|
name = "OSPFv3"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall ospf6d",)
|
shutdown = ("killall ospf6d",)
|
||||||
_validate = ("pidof ospf6d",)
|
validate = ("pidof ospf6d",)
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
_ipv6_routing = True
|
ipv6_routing = True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def minmtu(ifc):
|
def minmtu(ifc):
|
||||||
|
@ -436,8 +436,8 @@ class Ospfv3mdr(Ospfv3):
|
||||||
configuration file but has hooks for adding to the
|
configuration file but has hooks for adding to the
|
||||||
unified Quagga.conf file.
|
unified Quagga.conf file.
|
||||||
"""
|
"""
|
||||||
_name = "OSPFv3MDR"
|
name = "OSPFv3MDR"
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaifcconfig(cls, node, ifc):
|
def generatequaggaifcconfig(cls, node, ifc):
|
||||||
|
@ -464,13 +464,13 @@ class Bgp(QuaggaService):
|
||||||
Peers must be manually configured, with a full mesh for those
|
Peers must be manually configured, with a full mesh for those
|
||||||
having the same AS number.
|
having the same AS number.
|
||||||
"""
|
"""
|
||||||
_name = "BGP"
|
name = "BGP"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall bgpd",)
|
shutdown = ("killall bgpd",)
|
||||||
_validate = ("pidof bgpd",)
|
validate = ("pidof bgpd",)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
_ipv6_routing = True
|
ipv6_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaconfig(cls, node):
|
def generatequaggaconfig(cls, node):
|
||||||
|
@ -489,11 +489,11 @@ class Rip(QuaggaService):
|
||||||
"""
|
"""
|
||||||
The RIP service provides IPv4 routing for wired networks.
|
The RIP service provides IPv4 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
_name = "RIP"
|
name = "RIP"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall ripd",)
|
shutdown = ("killall ripd",)
|
||||||
_validate = ("pidof ripd",)
|
validate = ("pidof ripd",)
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaconfig(cls, node):
|
def generatequaggaconfig(cls, node):
|
||||||
|
@ -512,11 +512,11 @@ class Ripng(QuaggaService):
|
||||||
"""
|
"""
|
||||||
The RIP NG service provides IPv6 routing for wired networks.
|
The RIP NG service provides IPv6 routing for wired networks.
|
||||||
"""
|
"""
|
||||||
_name = "RIPNG"
|
name = "RIPNG"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall ripngd",)
|
shutdown = ("killall ripngd",)
|
||||||
_validate = ("pidof ripngd",)
|
validate = ("pidof ripngd",)
|
||||||
_ipv6_routing = True
|
ipv6_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaconfig(cls, node):
|
def generatequaggaconfig(cls, node):
|
||||||
|
@ -536,11 +536,11 @@ class Babel(QuaggaService):
|
||||||
The Babel service provides a loop-avoiding distance-vector routing
|
The Babel service provides a loop-avoiding distance-vector routing
|
||||||
protocol for IPv6 and IPv4 with fast convergence properties.
|
protocol for IPv6 and IPv4 with fast convergence properties.
|
||||||
"""
|
"""
|
||||||
_name = "Babel"
|
name = "Babel"
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ("killall babeld",)
|
shutdown = ("killall babeld",)
|
||||||
_validate = ("pidof babeld",)
|
validate = ("pidof babeld",)
|
||||||
_ipv6_routing = True
|
ipv6_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaconfig(cls, node):
|
def generatequaggaconfig(cls, node):
|
||||||
|
@ -565,11 +565,11 @@ class Xpimd(QuaggaService):
|
||||||
"""
|
"""
|
||||||
PIM multicast routing based on XORP.
|
PIM multicast routing based on XORP.
|
||||||
"""
|
"""
|
||||||
_name = 'Xpimd'
|
name = 'Xpimd'
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ('killall xpimd',)
|
shutdown = ('killall xpimd',)
|
||||||
_validate = ('pidof xpimd',)
|
validate = ('pidof xpimd',)
|
||||||
_ipv4_routing = True
|
ipv4_routing = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatequaggaconfig(cls, node):
|
def generatequaggaconfig(cls, node):
|
||||||
|
|
|
@ -11,14 +11,14 @@ class SdnService(CoreService):
|
||||||
"""
|
"""
|
||||||
Parent class for SDN services.
|
Parent class for SDN services.
|
||||||
"""
|
"""
|
||||||
_name = None
|
name = None
|
||||||
_group = "SDN"
|
group = "SDN"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -26,27 +26,27 @@ class SdnService(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class OvsService(SdnService):
|
class OvsService(SdnService):
|
||||||
_name = "OvsService"
|
name = "OvsService"
|
||||||
_group = "SDN"
|
group = "SDN"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ("/etc/openvswitch", "/var/run/openvswitch", "/var/log/openvswitch")
|
dirs = ("/etc/openvswitch", "/var/run/openvswitch", "/var/log/openvswitch")
|
||||||
_configs = ('OvsService.sh',)
|
configs = ('OvsService.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh OvsService.sh',)
|
startup = ('sh OvsService.sh',)
|
||||||
_shutdown = ('killall ovs-vswitchd', 'killall ovsdb-server')
|
shutdown = ('killall ovs-vswitchd', 'killall ovsdb-server')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
# Check whether the node is running zebra
|
# Check whether the node is running zebra
|
||||||
has_zebra = 0
|
has_zebra = 0
|
||||||
for s in services:
|
for s in services:
|
||||||
if s._name == "zebra":
|
if s.name == "zebra":
|
||||||
has_zebra = 1
|
has_zebra = 1
|
||||||
|
|
||||||
# Check whether the node is running an SDN controller
|
# Check whether the node is running an SDN controller
|
||||||
has_sdn_ctrlr = 0
|
has_sdn_ctrlr = 0
|
||||||
for s in services:
|
for s in services:
|
||||||
if s._name == "ryuService":
|
if s.name == "ryuService":
|
||||||
has_sdn_ctrlr = 1
|
has_sdn_ctrlr = 1
|
||||||
|
|
||||||
cfg = "#!/bin/sh\n"
|
cfg = "#!/bin/sh\n"
|
||||||
|
@ -100,14 +100,14 @@ class OvsService(SdnService):
|
||||||
|
|
||||||
|
|
||||||
class RyuService(SdnService):
|
class RyuService(SdnService):
|
||||||
_name = "ryuService"
|
name = "ryuService"
|
||||||
_group = "SDN"
|
group = "SDN"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ('ryuService.sh',)
|
configs = ('ryuService.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh ryuService.sh',)
|
startup = ('sh ryuService.sh',)
|
||||||
_shutdown = ('killall ryu-manager',)
|
shutdown = ('killall ryu-manager',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
|
|
@ -9,14 +9,14 @@ from core.service import CoreService
|
||||||
|
|
||||||
|
|
||||||
class VPNClient(CoreService):
|
class VPNClient(CoreService):
|
||||||
_name = "VPNClient"
|
name = "VPNClient"
|
||||||
_group = "Security"
|
group = "Security"
|
||||||
_configs = ('vpnclient.sh',)
|
configs = ('vpnclient.sh',)
|
||||||
_startindex = 60
|
startindex = 60
|
||||||
_startup = ('sh vpnclient.sh',)
|
startup = ('sh vpnclient.sh',)
|
||||||
_shutdown = ("killall openvpn",)
|
shutdown = ("killall openvpn",)
|
||||||
_validate = ("pidof openvpn",)
|
validate = ("pidof openvpn",)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -36,14 +36,14 @@ class VPNClient(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class VPNServer(CoreService):
|
class VPNServer(CoreService):
|
||||||
_name = "VPNServer"
|
name = "VPNServer"
|
||||||
_group = "Security"
|
group = "Security"
|
||||||
_configs = ('vpnserver.sh',)
|
configs = ('vpnserver.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh vpnserver.sh',)
|
startup = ('sh vpnserver.sh',)
|
||||||
_shutdown = ("killall openvpn",)
|
shutdown = ("killall openvpn",)
|
||||||
_validate = ("pidof openvpn",)
|
validate = ("pidof openvpn",)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -64,13 +64,13 @@ class VPNServer(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class IPsec(CoreService):
|
class IPsec(CoreService):
|
||||||
_name = "IPsec"
|
name = "IPsec"
|
||||||
_group = "Security"
|
group = "Security"
|
||||||
_configs = ('ipsec.sh',)
|
configs = ('ipsec.sh',)
|
||||||
_startindex = 60
|
startindex = 60
|
||||||
_startup = ('sh ipsec.sh',)
|
startup = ('sh ipsec.sh',)
|
||||||
_shutdown = ("killall racoon",)
|
shutdown = ("killall racoon",)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -92,12 +92,12 @@ class IPsec(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class Firewall(CoreService):
|
class Firewall(CoreService):
|
||||||
_name = "Firewall"
|
name = "Firewall"
|
||||||
_group = "Security"
|
group = "Security"
|
||||||
_configs = ('firewall.sh',)
|
configs = ('firewall.sh',)
|
||||||
_startindex = 20
|
startindex = 20
|
||||||
_startup = ('sh firewall.sh',)
|
startup = ('sh firewall.sh',)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
|
|
@ -8,15 +8,15 @@ class Startup(CoreService):
|
||||||
"""
|
"""
|
||||||
A CORE service to start other services in order, serially
|
A CORE service to start other services in order, serially
|
||||||
"""
|
"""
|
||||||
_name = 'startup'
|
name = 'startup'
|
||||||
_group = 'Utility'
|
group = 'Utility'
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ('startup.sh',)
|
configs = ('startup.sh',)
|
||||||
_startindex = maxint
|
startindex = maxint
|
||||||
_startup = ('sh startup.sh',)
|
startup = ('sh startup.sh',)
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
_validate = ()
|
validate = ()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_startup_service(s):
|
def is_startup_service(s):
|
||||||
|
@ -24,13 +24,13 @@ class Startup(CoreService):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
if filename != cls._configs[0]:
|
if filename != cls.configs[0]:
|
||||||
return ''
|
return ''
|
||||||
script = '#!/bin/sh\n' \
|
script = '#!/bin/sh\n' \
|
||||||
'# auto-generated by Startup (startup.py)\n\n' \
|
'# auto-generated by Startup (startup.py)\n\n' \
|
||||||
'exec > startup.log 2>&1\n\n'
|
'exec > startup.log 2>&1\n\n'
|
||||||
for s in sorted(services, key=lambda x: x._startindex):
|
for s in sorted(services, key=lambda x: x.startindex):
|
||||||
if cls.is_startup_service(s) or len(str(s._starttime)) > 0:
|
if cls.is_startup_service(s) or len(str(s.starttime)) > 0:
|
||||||
continue
|
continue
|
||||||
start = '\n'.join(s.getstartup(node, services))
|
start = '\n'.join(s.getstartup(node, services))
|
||||||
if start:
|
if start:
|
||||||
|
|
|
@ -8,29 +8,29 @@ UCARP_ETC = "/usr/local/etc/ucarp"
|
||||||
|
|
||||||
|
|
||||||
class Ucarp(CoreService):
|
class Ucarp(CoreService):
|
||||||
_name = "ucarp"
|
name = "ucarp"
|
||||||
_group = "Utility"
|
group = "Utility"
|
||||||
_depends = ( )
|
depends = ( )
|
||||||
_dirs = (UCARP_ETC,)
|
dirs = (UCARP_ETC,)
|
||||||
_configs = (
|
configs = (
|
||||||
UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",)
|
UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",)
|
||||||
_startindex = 65
|
startindex = 65
|
||||||
_startup = ("sh ucarpboot.sh",)
|
startup = ("sh ucarpboot.sh",)
|
||||||
_shutdown = ("killall ucarp",)
|
shutdown = ("killall ucarp",)
|
||||||
_validate = ("pidof ucarp",)
|
validate = ("pidof ucarp",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
"""
|
"""
|
||||||
Return the default file contents
|
Return the default file contents
|
||||||
"""
|
"""
|
||||||
if filename == cls._configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateUcarpConf(node, services)
|
return cls.generateUcarpConf(node, services)
|
||||||
elif filename == cls._configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateVipUp(node, services)
|
return cls.generateVipUp(node, services)
|
||||||
elif filename == cls._configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generateVipDown(node, services)
|
return cls.generateVipDown(node, services)
|
||||||
elif filename == cls._configs[3]:
|
elif filename == cls.configs[3]:
|
||||||
return cls.generateUcarpBoot(node, services)
|
return cls.generateUcarpBoot(node, services)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
|
@ -16,14 +16,14 @@ class UtilService(CoreService):
|
||||||
"""
|
"""
|
||||||
Parent class for utility services.
|
Parent class for utility services.
|
||||||
"""
|
"""
|
||||||
_name = None
|
name = None
|
||||||
_group = "Utility"
|
group = "Utility"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 80
|
startindex = 80
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -31,10 +31,10 @@ class UtilService(CoreService):
|
||||||
|
|
||||||
|
|
||||||
class IPForwardService(UtilService):
|
class IPForwardService(UtilService):
|
||||||
_name = "IPForward"
|
name = "IPForward"
|
||||||
_configs = ("ipforward.sh",)
|
configs = ("ipforward.sh",)
|
||||||
_startindex = 5
|
startindex = 5
|
||||||
_startup = ("sh ipforward.sh",)
|
startup = ("sh ipforward.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -67,9 +67,9 @@ class IPForwardService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class DefaultRouteService(UtilService):
|
class DefaultRouteService(UtilService):
|
||||||
_name = "DefaultRoute"
|
name = "DefaultRoute"
|
||||||
_configs = ("defaultroute.sh",)
|
configs = ("defaultroute.sh",)
|
||||||
_startup = ("sh defaultroute.sh",)
|
startup = ("sh defaultroute.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -101,9 +101,9 @@ class DefaultRouteService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class DefaultMulticastRouteService(UtilService):
|
class DefaultMulticastRouteService(UtilService):
|
||||||
_name = "DefaultMulticastRoute"
|
name = "DefaultMulticastRoute"
|
||||||
_configs = ("defaultmroute.sh",)
|
configs = ("defaultmroute.sh",)
|
||||||
_startup = ("sh defaultmroute.sh",)
|
startup = ("sh defaultmroute.sh",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -113,7 +113,7 @@ class DefaultMulticastRouteService(UtilService):
|
||||||
cfg += "as needed\n"
|
cfg += "as needed\n"
|
||||||
|
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
if os.uname()[0] == "Linux":
|
if os.uname()[0] == "Linux":
|
||||||
rtcmd = "ip route add 224.0.0.0/4 dev"
|
rtcmd = "ip route add 224.0.0.0/4 dev"
|
||||||
|
@ -126,10 +126,10 @@ class DefaultMulticastRouteService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class StaticRouteService(UtilService):
|
class StaticRouteService(UtilService):
|
||||||
_name = "StaticRoute"
|
name = "StaticRoute"
|
||||||
_configs = ("staticroute.sh",)
|
configs = ("staticroute.sh",)
|
||||||
_startup = ("sh staticroute.sh",)
|
startup = ("sh staticroute.sh",)
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -165,12 +165,12 @@ class StaticRouteService(UtilService):
|
||||||
|
|
||||||
|
|
||||||
class SshService(UtilService):
|
class SshService(UtilService):
|
||||||
_name = "SSH"
|
name = "SSH"
|
||||||
_configs = ("startsshd.sh", "/etc/ssh/sshd_config",)
|
configs = ("startsshd.sh", "/etc/ssh/sshd_config",)
|
||||||
_dirs = ("/etc/ssh", "/var/run/sshd",)
|
dirs = ("/etc/ssh", "/var/run/sshd",)
|
||||||
_startup = ("sh startsshd.sh",)
|
startup = ("sh startsshd.sh",)
|
||||||
_shutdown = ("killall sshd",)
|
shutdown = ("killall sshd",)
|
||||||
_validate = ()
|
validate = ()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -178,8 +178,8 @@ class SshService(UtilService):
|
||||||
Use a startup script for launching sshd in order to wait for host
|
Use a startup script for launching sshd in order to wait for host
|
||||||
key generation.
|
key generation.
|
||||||
"""
|
"""
|
||||||
sshcfgdir = cls._dirs[0]
|
sshcfgdir = cls.dirs[0]
|
||||||
sshstatedir = cls._dirs[1]
|
sshstatedir = cls.dirs[1]
|
||||||
sshlibdir = "/usr/lib/openssh"
|
sshlibdir = "/usr/lib/openssh"
|
||||||
if filename == "startsshd.sh":
|
if filename == "startsshd.sh":
|
||||||
return """\
|
return """\
|
||||||
|
@ -233,12 +233,12 @@ UseDNS no
|
||||||
|
|
||||||
|
|
||||||
class DhcpService(UtilService):
|
class DhcpService(UtilService):
|
||||||
_name = "DHCP"
|
name = "DHCP"
|
||||||
_configs = ("/etc/dhcp/dhcpd.conf",)
|
configs = ("/etc/dhcp/dhcpd.conf",)
|
||||||
_dirs = ("/etc/dhcp",)
|
dirs = ("/etc/dhcp",)
|
||||||
_startup = ("dhcpd",)
|
startup = ("dhcpd",)
|
||||||
_shutdown = ("killall dhcpd",)
|
shutdown = ("killall dhcpd",)
|
||||||
_validate = ("pidof dhcpd",)
|
validate = ("pidof dhcpd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -296,11 +296,11 @@ class DhcpClientService(UtilService):
|
||||||
"""
|
"""
|
||||||
Use a DHCP client for all interfaces for addressing.
|
Use a DHCP client for all interfaces for addressing.
|
||||||
"""
|
"""
|
||||||
_name = "DHCPClient"
|
name = "DHCPClient"
|
||||||
_configs = ("startdhcpclient.sh",)
|
configs = ("startdhcpclient.sh",)
|
||||||
_startup = ("sh startdhcpclient.sh",)
|
startup = ("sh startdhcpclient.sh",)
|
||||||
_shutdown = ("killall dhclient",)
|
shutdown = ("killall dhclient",)
|
||||||
_validate = ("pidof dhclient",)
|
validate = ("pidof dhclient",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -327,12 +327,12 @@ class FtpService(UtilService):
|
||||||
"""
|
"""
|
||||||
Start a vsftpd server.
|
Start a vsftpd server.
|
||||||
"""
|
"""
|
||||||
_name = "FTP"
|
name = "FTP"
|
||||||
_configs = ("vsftpd.conf",)
|
configs = ("vsftpd.conf",)
|
||||||
_dirs = ("/var/run/vsftpd/empty", "/var/ftp",)
|
dirs = ("/var/run/vsftpd/empty", "/var/ftp",)
|
||||||
_startup = ("vsftpd ./vsftpd.conf",)
|
startup = ("vsftpd ./vsftpd.conf",)
|
||||||
_shutdown = ("killall vsftpd",)
|
shutdown = ("killall vsftpd",)
|
||||||
_validate = ("pidof vsftpd",)
|
validate = ("pidof vsftpd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -359,14 +359,14 @@ class HttpService(UtilService):
|
||||||
"""
|
"""
|
||||||
Start an apache server.
|
Start an apache server.
|
||||||
"""
|
"""
|
||||||
_name = "HTTP"
|
name = "HTTP"
|
||||||
_configs = ("/etc/apache2/apache2.conf", "/etc/apache2/envvars",
|
configs = ("/etc/apache2/apache2.conf", "/etc/apache2/envvars",
|
||||||
"/var/www/index.html",)
|
"/var/www/index.html",)
|
||||||
_dirs = ("/etc/apache2", "/var/run/apache2", "/var/log/apache2",
|
dirs = ("/etc/apache2", "/var/run/apache2", "/var/log/apache2",
|
||||||
"/run/lock", "/var/lock/apache2", "/var/www",)
|
"/run/lock", "/var/lock/apache2", "/var/www",)
|
||||||
_startup = ("chown www-data /var/lock/apache2", "apache2ctl start",)
|
startup = ("chown www-data /var/lock/apache2", "apache2ctl start",)
|
||||||
_shutdown = ("apache2ctl stop",)
|
shutdown = ("apache2ctl stop",)
|
||||||
_validate = ("pidof apache2",)
|
validate = ("pidof apache2",)
|
||||||
|
|
||||||
APACHEVER22, APACHEVER24 = (22, 24)
|
APACHEVER22, APACHEVER24 = (22, 24)
|
||||||
|
|
||||||
|
@ -375,11 +375,11 @@ class HttpService(UtilService):
|
||||||
"""
|
"""
|
||||||
Generate an apache2.conf configuration file.
|
Generate an apache2.conf configuration file.
|
||||||
"""
|
"""
|
||||||
if filename == cls._configs[0]:
|
if filename == cls.configs[0]:
|
||||||
return cls.generateapache2conf(node, filename, services)
|
return cls.generateapache2conf(node, filename, services)
|
||||||
elif filename == cls._configs[1]:
|
elif filename == cls.configs[1]:
|
||||||
return cls.generateenvvars(node, filename, services)
|
return cls.generateenvvars(node, filename, services)
|
||||||
elif filename == cls._configs[2]:
|
elif filename == cls.configs[2]:
|
||||||
return cls.generatehtml(node, filename, services)
|
return cls.generatehtml(node, filename, services)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
@ -561,7 +561,7 @@ export LANG
|
||||||
<p>The web server software is running but no content has been added, yet.</p>
|
<p>The web server software is running but no content has been added, yet.</p>
|
||||||
""" % node.name
|
""" % node.name
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
body += "<li>%s - %s</li>\n" % (ifc.name, ifc.addrlist)
|
body += "<li>%s - %s</li>\n" % (ifc.name, ifc.addrlist)
|
||||||
return "<html><body>%s</body></html>" % body
|
return "<html><body>%s</body></html>" % body
|
||||||
|
@ -571,14 +571,14 @@ class PcapService(UtilService):
|
||||||
"""
|
"""
|
||||||
Pcap service for logging packets.
|
Pcap service for logging packets.
|
||||||
"""
|
"""
|
||||||
_name = "pcap"
|
name = "pcap"
|
||||||
_configs = ("pcap.sh",)
|
configs = ("pcap.sh",)
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_startindex = 1
|
startindex = 1
|
||||||
_startup = ("sh pcap.sh start",)
|
startup = ("sh pcap.sh start",)
|
||||||
_shutdown = ("sh pcap.sh stop",)
|
shutdown = ("sh pcap.sh stop",)
|
||||||
_validate = ("pidof tcpdump",)
|
validate = ("pidof tcpdump",)
|
||||||
_meta = "logs network traffic to pcap packet capture files"
|
meta = "logs network traffic to pcap packet capture files"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -595,7 +595,7 @@ if [ "x$1" = "xstart" ]; then
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
cfg += '# '
|
cfg += '# '
|
||||||
redir = "< /dev/null"
|
redir = "< /dev/null"
|
||||||
cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % \
|
cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % \
|
||||||
|
@ -611,12 +611,12 @@ fi;
|
||||||
|
|
||||||
|
|
||||||
class RadvdService(UtilService):
|
class RadvdService(UtilService):
|
||||||
_name = "radvd"
|
name = "radvd"
|
||||||
_configs = ("/etc/radvd/radvd.conf",)
|
configs = ("/etc/radvd/radvd.conf",)
|
||||||
_dirs = ("/etc/radvd",)
|
dirs = ("/etc/radvd",)
|
||||||
_startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",)
|
startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",)
|
||||||
_shutdown = ("pkill radvd",)
|
shutdown = ("pkill radvd",)
|
||||||
_validate = ("pidof radvd",)
|
validate = ("pidof radvd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -626,7 +626,7 @@ class RadvdService(UtilService):
|
||||||
"""
|
"""
|
||||||
cfg = "# auto-generated by RADVD service (utility.py)\n"
|
cfg = "# auto-generated by RADVD service (utility.py)\n"
|
||||||
for ifc in node.netifs():
|
for ifc in node.netifs():
|
||||||
if hasattr(ifc, 'control') and ifc.control == True:
|
if hasattr(ifc, 'control') and ifc.control is True:
|
||||||
continue
|
continue
|
||||||
prefixes = map(cls.subnetentry, ifc.addrlist)
|
prefixes = map(cls.subnetentry, ifc.addrlist)
|
||||||
if len(prefixes) < 1:
|
if len(prefixes) < 1:
|
||||||
|
@ -671,11 +671,11 @@ class AtdService(UtilService):
|
||||||
"""
|
"""
|
||||||
Atd service for scheduling at jobs
|
Atd service for scheduling at jobs
|
||||||
"""
|
"""
|
||||||
_name = "atd"
|
name = "atd"
|
||||||
_configs = ("startatd.sh",)
|
configs = ("startatd.sh",)
|
||||||
_dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
|
dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
|
||||||
_startup = ("sh startatd.sh",)
|
startup = ("sh startatd.sh",)
|
||||||
_shutdown = ("pkill atd",)
|
shutdown = ("pkill atd",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -692,6 +692,6 @@ class UserDefinedService(UtilService):
|
||||||
"""
|
"""
|
||||||
Dummy service allowing customization of anything.
|
Dummy service allowing customization of anything.
|
||||||
"""
|
"""
|
||||||
_name = "UserDefined"
|
name = "UserDefined"
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_meta = "Customize this service to do anything upon startup."
|
meta = "Customize this service to do anything upon startup."
|
||||||
|
|
|
@ -11,15 +11,15 @@ class XorpRtrmgr(CoreService):
|
||||||
XORP router manager service builds a config.boot file based on other
|
XORP router manager service builds a config.boot file based on other
|
||||||
enabled XORP services, and launches necessary daemons upon startup.
|
enabled XORP services, and launches necessary daemons upon startup.
|
||||||
"""
|
"""
|
||||||
_name = "xorp_rtrmgr"
|
name = "xorp_rtrmgr"
|
||||||
_group = "XORP"
|
group = "XORP"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ("/etc/xorp",)
|
dirs = ("/etc/xorp",)
|
||||||
_configs = ("/etc/xorp/config.boot",)
|
configs = ("/etc/xorp/config.boot",)
|
||||||
_startindex = 35
|
startindex = 35
|
||||||
_startup = ("xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid" % (_configs[0], _name, _name),)
|
startup = ("xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid" % (configs[0], name, name),)
|
||||||
_shutdown = ("killall xorp_rtrmgr",)
|
shutdown = ("killall xorp_rtrmgr",)
|
||||||
_validate = ("pidof xorp_rtrmgr",)
|
validate = ("pidof xorp_rtrmgr",)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generateconfig(cls, node, filename, services):
|
def generateconfig(cls, node, filename, services):
|
||||||
|
@ -40,10 +40,10 @@ class XorpRtrmgr(CoreService):
|
||||||
|
|
||||||
for s in services:
|
for s in services:
|
||||||
try:
|
try:
|
||||||
s._depends.index(cls._name)
|
s.depends.index(cls.name)
|
||||||
cfg += s.generatexorpconfig(node)
|
cfg += s.generatexorpconfig(node)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.exception("error getting value from service: %s", cls._name)
|
logger.exception("error getting value from service: %s", cls.name)
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
@ -74,15 +74,15 @@ class XorpService(CoreService):
|
||||||
Parent class for XORP services. Defines properties and methods
|
Parent class for XORP services. Defines properties and methods
|
||||||
common to XORP's routing daemons.
|
common to XORP's routing daemons.
|
||||||
"""
|
"""
|
||||||
_name = None
|
name = None
|
||||||
_group = "XORP"
|
group = "XORP"
|
||||||
_depends = ("xorp_rtrmgr",)
|
depends = ("xorp_rtrmgr",)
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ()
|
configs = ()
|
||||||
_startindex = 40
|
startindex = 40
|
||||||
_startup = ()
|
startup = ()
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
_meta = "The config file for this service can be found in the xorp_rtrmgr service."
|
meta = "The config file for this service can be found in the xorp_rtrmgr service."
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def fea(forwarding):
|
def fea(forwarding):
|
||||||
|
@ -165,7 +165,7 @@ class XorpOspfv2(XorpService):
|
||||||
not build its own configuration file but has hooks for adding to the
|
not build its own configuration file but has hooks for adding to the
|
||||||
unified XORP configuration file.
|
unified XORP configuration file.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_OSPFv2"
|
name = "XORP_OSPFv2"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -200,7 +200,7 @@ class XorpOspfv3(XorpService):
|
||||||
not build its own configuration file but has hooks for adding to the
|
not build its own configuration file but has hooks for adding to the
|
||||||
unified XORP configuration file.
|
unified XORP configuration file.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_OSPFv3"
|
name = "XORP_OSPFv3"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -227,8 +227,8 @@ class XorpBgp(XorpService):
|
||||||
"""
|
"""
|
||||||
IPv4 inter-domain routing. AS numbers and peers must be customized.
|
IPv4 inter-domain routing. AS numbers and peers must be customized.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_BGP"
|
name = "XORP_BGP"
|
||||||
_custom_needed = True
|
custom_needed = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -257,7 +257,7 @@ class XorpRip(XorpService):
|
||||||
RIP IPv4 unicast routing.
|
RIP IPv4 unicast routing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name = "XORP_RIP"
|
name = "XORP_RIP"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -289,7 +289,7 @@ class XorpRipng(XorpService):
|
||||||
"""
|
"""
|
||||||
RIP NG IPv6 unicast routing.
|
RIP NG IPv6 unicast routing.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_RIPNG"
|
name = "XORP_RIPNG"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -324,7 +324,7 @@ class XorpPimSm4(XorpService):
|
||||||
"""
|
"""
|
||||||
PIM Sparse Mode IPv4 multicast routing.
|
PIM Sparse Mode IPv4 multicast routing.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_PIMSM4"
|
name = "XORP_PIMSM4"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -383,7 +383,7 @@ class XorpPimSm6(XorpService):
|
||||||
"""
|
"""
|
||||||
PIM Sparse Mode IPv6 multicast routing.
|
PIM Sparse Mode IPv6 multicast routing.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_PIMSM6"
|
name = "XORP_PIMSM6"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
@ -442,7 +442,7 @@ class XorpOlsr(XorpService):
|
||||||
"""
|
"""
|
||||||
OLSR IPv4 unicast MANET routing.
|
OLSR IPv4 unicast MANET routing.
|
||||||
"""
|
"""
|
||||||
_name = "XORP_OLSR"
|
name = "XORP_OLSR"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generatexorpconfig(cls, node):
|
def generatexorpconfig(cls, node):
|
||||||
|
|
|
@ -4,7 +4,7 @@ from core import logger
|
||||||
from core.conf import ConfigShim
|
from core.conf import ConfigShim
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.service import ServiceManager
|
from core.service import ServiceManager, ServiceShim
|
||||||
from core.xml import xmlutils
|
from core.xml import xmlutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -316,7 +316,10 @@ class CoreDocumentParser0(object):
|
||||||
# associate nodes with services
|
# associate nodes with services
|
||||||
for objid in sorted(svclists.keys()):
|
for objid in sorted(svclists.keys()):
|
||||||
n = self.session.get_object(objid)
|
n = self.session.get_object(objid)
|
||||||
self.session.services.addservicestonode(node=n, nodetype=n.type, services_str=svclists[objid])
|
services = svclists[objid]
|
||||||
|
if services:
|
||||||
|
services = services.split("|")
|
||||||
|
self.session.services.addservicestonode(node=n, node_type=n.type, services=services)
|
||||||
|
|
||||||
def parseservice(self, service, n):
|
def parseservice(self, service, n):
|
||||||
"""
|
"""
|
||||||
|
@ -367,16 +370,20 @@ class CoreDocumentParser0(object):
|
||||||
filename = file.getAttribute("name")
|
filename = file.getAttribute("name")
|
||||||
files.append(filename)
|
files.append(filename)
|
||||||
data = xmlutils.get_text_child(file)
|
data = xmlutils.get_text_child(file)
|
||||||
typestr = "service:%s:%s" % (name, filename)
|
self.session.services.setservicefile(node_id=n.objid, service_name=name, filename=filename, data=data)
|
||||||
self.session.services.setservicefile(nodenum=n.objid, type=typestr,
|
|
||||||
filename=filename,
|
|
||||||
srcname=None, data=data)
|
|
||||||
if len(files):
|
if len(files):
|
||||||
values.append("files=%s" % files)
|
values.append("files=%s" % files)
|
||||||
if not bool(service.getAttribute("custom")):
|
if not bool(service.getAttribute("custom")):
|
||||||
return True
|
return True
|
||||||
values = ConfigShim.str_to_dict(values)
|
self.session.services.setcustomservice(n.objid, svc)
|
||||||
self.session.services.setcustomservice(n.objid, svc, values)
|
# set custom values for custom service
|
||||||
|
svc = self.session.services.getcustomservice(n.objid, None)
|
||||||
|
if not svc:
|
||||||
|
raise ValueError("custom service(%s) for node(%s) does not exist", svc.name, n.objid)
|
||||||
|
values = ConfigShim.str_to_dict("|".join(values))
|
||||||
|
for name, value in values.iteritems():
|
||||||
|
ServiceShim.setvalue(svc, name, value)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def parsehooks(self, hooks):
|
def parsehooks(self, hooks):
|
||||||
|
|
|
@ -8,7 +8,7 @@ from core.conf import ConfigShim
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from core.misc.ipaddress import MacAddress
|
from core.misc.ipaddress import MacAddress
|
||||||
from core.service import ServiceManager
|
from core.service import ServiceManager, ServiceShim
|
||||||
from core.xml import xmlutils
|
from core.xml import xmlutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -639,17 +639,19 @@ class CoreDocumentParser1(object):
|
||||||
|
|
||||||
custom = service.getAttribute('custom')
|
custom = service.getAttribute('custom')
|
||||||
if custom and custom.lower() == 'true':
|
if custom and custom.lower() == 'true':
|
||||||
values = ConfigShim.str_to_dict(values)
|
self.session.services.setcustomservice(node.objid, session_service.name)
|
||||||
self.session.services.setcustomservice(node.objid, session_service, values)
|
values = ConfigShim.str_to_dict("|".join(values))
|
||||||
|
for key, value in values.iteritems():
|
||||||
|
ServiceShim.setvalue(session_service, key, value)
|
||||||
|
|
||||||
# NOTE: if a custom service is used, setservicefile() must be
|
# NOTE: if a custom service is used, setservicefile() must be
|
||||||
# called after the custom service exists
|
# called after the custom service exists
|
||||||
for typestr, filename, data in files:
|
for typestr, filename, data in files:
|
||||||
|
svcname = typestr.split(":")[1]
|
||||||
self.session.services.setservicefile(
|
self.session.services.setservicefile(
|
||||||
nodenum=node.objid,
|
node_id=node.objid,
|
||||||
type=typestr,
|
service_name=svcname,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
srcname=None,
|
|
||||||
data=data
|
data=data
|
||||||
)
|
)
|
||||||
return str(name)
|
return str(name)
|
||||||
|
@ -678,10 +680,13 @@ class CoreDocumentParser1(object):
|
||||||
services_str = None # default services will be added
|
services_str = None # default services will be added
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
if services_str:
|
||||||
|
services_str = services_str.split("|")
|
||||||
|
|
||||||
self.session.services.addservicestonode(
|
self.session.services.addservicestonode(
|
||||||
node=node,
|
node=node,
|
||||||
nodetype=node_type,
|
node_type=node_type,
|
||||||
services_str=services_str
|
services=services_str
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_object_presentation(self, obj, element, node_type):
|
def set_object_presentation(self, obj, element, node_type):
|
||||||
|
|
|
@ -284,7 +284,7 @@ class CoreDocumentWriter0(Document):
|
||||||
for svc in defaults:
|
for svc in defaults:
|
||||||
s = self.createElement("Service")
|
s = self.createElement("Service")
|
||||||
spn.appendChild(s)
|
spn.appendChild(s)
|
||||||
s.setAttribute("name", str(svc._name))
|
s.setAttribute("name", str(svc.name))
|
||||||
|
|
||||||
def addservices(self, node):
|
def addservices(self, node):
|
||||||
"""
|
"""
|
||||||
|
@ -302,17 +302,17 @@ class CoreDocumentWriter0(Document):
|
||||||
for svc in node.services:
|
for svc in node.services:
|
||||||
s = self.createElement("Service")
|
s = self.createElement("Service")
|
||||||
spn.appendChild(s)
|
spn.appendChild(s)
|
||||||
s.setAttribute("name", str(svc._name))
|
s.setAttribute("name", str(svc.name))
|
||||||
s.setAttribute("startup_idx", str(svc._startindex))
|
s.setAttribute("startup_idx", str(svc.startindex))
|
||||||
if svc._starttime != "":
|
if svc.starttime != "":
|
||||||
s.setAttribute("start_time", str(svc._starttime))
|
s.setAttribute("start_time", str(svc.starttime))
|
||||||
# only record service names if not a customized service
|
# only record service names if not a customized service
|
||||||
if not svc._custom:
|
if not svc.custom:
|
||||||
continue
|
continue
|
||||||
s.setAttribute("custom", str(svc._custom))
|
s.setAttribute("custom", str(svc.custom))
|
||||||
xmlutils.add_elements_from_list(self, s, svc._dirs, "Directory", "name")
|
xmlutils.add_elements_from_list(self, s, svc.dirs, "Directory", "name")
|
||||||
|
|
||||||
for fn in svc._configs:
|
for fn in svc.configs:
|
||||||
if len(fn) == 0:
|
if len(fn) == 0:
|
||||||
continue
|
continue
|
||||||
f = self.createElement("File")
|
f = self.createElement("File")
|
||||||
|
@ -327,9 +327,9 @@ class CoreDocumentWriter0(Document):
|
||||||
txt = self.createTextNode(data)
|
txt = self.createTextNode(data)
|
||||||
f.appendChild(txt)
|
f.appendChild(txt)
|
||||||
|
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._startup, "Command", (("type", "start"),))
|
xmlutils.add_text_elements_from_list(self, s, svc.startup, "Command", (("type", "start"),))
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._shutdown, "Command", (("type", "stop"),))
|
xmlutils.add_text_elements_from_list(self, s, svc.shutdown, "Command", (("type", "stop"),))
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._validate, "Command", (("type", "validate"),))
|
xmlutils.add_text_elements_from_list(self, s, svc.validate, "Command", (("type", "validate"),))
|
||||||
|
|
||||||
def addaddresses(self, i, netif):
|
def addaddresses(self, i, netif):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -277,7 +277,7 @@ class ScenarioPlan(XmlElement):
|
||||||
for svc in defaults:
|
for svc in defaults:
|
||||||
s = self.createElement("service")
|
s = self.createElement("service")
|
||||||
spn.appendChild(s)
|
spn.appendChild(s)
|
||||||
s.setAttribute("name", str(svc._name))
|
s.setAttribute("name", str(svc.name))
|
||||||
if defaultservices.hasChildNodes():
|
if defaultservices.hasChildNodes():
|
||||||
self.appendChild(defaultservices)
|
self.appendChild(defaultservices)
|
||||||
|
|
||||||
|
@ -680,24 +680,24 @@ class DeviceElement(NamedXmlElement):
|
||||||
for svc in device_object.services:
|
for svc in device_object.services:
|
||||||
s = self.createElement("service")
|
s = self.createElement("service")
|
||||||
spn.appendChild(s)
|
spn.appendChild(s)
|
||||||
s.setAttribute("name", str(svc._name))
|
s.setAttribute("name", str(svc.name))
|
||||||
s.setAttribute("startup_idx", str(svc._startindex))
|
s.setAttribute("startup_idx", str(svc.startindex))
|
||||||
if svc._starttime != "":
|
if svc.starttime != "":
|
||||||
s.setAttribute("start_time", str(svc._starttime))
|
s.setAttribute("start_time", str(svc.starttime))
|
||||||
# only record service names if not a customized service
|
# only record service names if not a customized service
|
||||||
if not svc._custom:
|
if not svc.custom:
|
||||||
continue
|
continue
|
||||||
s.setAttribute("custom", str(svc._custom))
|
s.setAttribute("custom", str(svc.custom))
|
||||||
xmlutils.add_elements_from_list(self, s, svc._dirs, "directory", "name")
|
xmlutils.add_elements_from_list(self, s, svc.dirs, "directory", "name")
|
||||||
|
|
||||||
for fn in svc._configs:
|
for fn in svc.configs:
|
||||||
if len(fn) == 0:
|
if len(fn) == 0:
|
||||||
continue
|
continue
|
||||||
f = self.createElement("file")
|
f = self.createElement("file")
|
||||||
f.setAttribute("name", fn)
|
f.setAttribute("name", fn)
|
||||||
# all file names are added to determine when a file has been deleted
|
# all file names are added to determine when a file has been deleted
|
||||||
s.appendChild(f)
|
s.appendChild(f)
|
||||||
data = self.coreSession.services.getservicefiledata(svc, fn)
|
data = svc.configtxt.get(fn)
|
||||||
if data is None:
|
if data is None:
|
||||||
# this includes only customized file contents and skips
|
# this includes only customized file contents and skips
|
||||||
# the auto-generated files
|
# the auto-generated files
|
||||||
|
@ -705,12 +705,9 @@ class DeviceElement(NamedXmlElement):
|
||||||
txt = self.createTextNode("\n" + data)
|
txt = self.createTextNode("\n" + data)
|
||||||
f.appendChild(txt)
|
f.appendChild(txt)
|
||||||
|
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._startup, "command",
|
xmlutils.add_text_elements_from_list(self, s, svc.startup, "command", (("type", "start"),))
|
||||||
(("type", "start"),))
|
xmlutils.add_text_elements_from_list(self, s, svc.shutdown, "command", (("type", "stop"),))
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._shutdown, "command",
|
xmlutils.add_text_elements_from_list(self, s, svc.validate, "command", (("type", "validate"),))
|
||||||
(("type", "stop"),))
|
|
||||||
xmlutils.add_text_elements_from_list(self, s, svc._validate, "command",
|
|
||||||
(("type", "validate"),))
|
|
||||||
|
|
||||||
|
|
||||||
class ChannelElement(NamedXmlElement):
|
class ChannelElement(NamedXmlElement):
|
||||||
|
|
|
@ -159,7 +159,7 @@ def main():
|
||||||
n.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
|
n.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
|
||||||
n.cmd([constants.SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"])
|
n.cmd([constants.SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"])
|
||||||
if options.services is not None:
|
if options.services is not None:
|
||||||
session.services.addservicestonode(n, "", options.services)
|
session.services.addservicestonode(n, "", options.services.split("|"))
|
||||||
n.boot()
|
n.boot()
|
||||||
nodelist.append(n)
|
nodelist.append(n)
|
||||||
if i % 25 == 0:
|
if i % 25 == 0:
|
||||||
|
|
|
@ -429,8 +429,7 @@ class Experiment(object):
|
||||||
self.net.link(prev.netif(0), tmp.netif(0))
|
self.net.link(prev.netif(0), tmp.netif(0))
|
||||||
prev = tmp
|
prev = tmp
|
||||||
|
|
||||||
def createemanesession(self, numnodes, verbose=False, cls=None,
|
def createemanesession(self, numnodes, verbose=False, cls=None, values=None):
|
||||||
values=None):
|
|
||||||
""" Build a topology consisting of the given number of LxcNodes
|
""" Build a topology consisting of the given number of LxcNodes
|
||||||
connected to an EMANE WLAN.
|
connected to an EMANE WLAN.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,7 +7,6 @@ import os
|
||||||
import pytest
|
import pytest
|
||||||
from mock.mock import MagicMock
|
from mock.mock import MagicMock
|
||||||
|
|
||||||
from core import services
|
|
||||||
from core.api.coreapi import CoreConfMessage
|
from core.api.coreapi import CoreConfMessage
|
||||||
from core.api.coreapi import CoreEventMessage
|
from core.api.coreapi import CoreEventMessage
|
||||||
from core.api.coreapi import CoreExecMessage
|
from core.api.coreapi import CoreExecMessage
|
||||||
|
@ -29,6 +28,7 @@ from core.enumerations import NodeTlvs
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.misc import ipaddress
|
from core.misc import ipaddress
|
||||||
from core.misc.ipaddress import MacAddress
|
from core.misc.ipaddress import MacAddress
|
||||||
|
from core.service import ServiceManager
|
||||||
|
|
||||||
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
|
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
|
||||||
|
|
||||||
|
@ -199,6 +199,7 @@ class CoreServerTest(object):
|
||||||
self.request_handler.handle_message(message)
|
self.request_handler.handle_message(message)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
self.server.coreemu.shutdown()
|
||||||
self.server.shutdown()
|
self.server.shutdown()
|
||||||
self.server.server_close()
|
self.server.server_close()
|
||||||
|
|
||||||
|
@ -223,6 +224,9 @@ def session():
|
||||||
# shutdown coreemu
|
# shutdown coreemu
|
||||||
coreemu.shutdown()
|
coreemu.shutdown()
|
||||||
|
|
||||||
|
# clear services, since they will be reloaded
|
||||||
|
ServiceManager.services.clear()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
@pytest.fixture(scope="module")
|
||||||
def ip_prefixes():
|
def ip_prefixes():
|
||||||
|
@ -231,9 +235,6 @@ def ip_prefixes():
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def cored():
|
def cored():
|
||||||
# load default services
|
|
||||||
services.load()
|
|
||||||
|
|
||||||
# create and return server
|
# create and return server
|
||||||
server = CoreServerTest()
|
server = CoreServerTest()
|
||||||
yield server
|
yield server
|
||||||
|
@ -241,6 +242,11 @@ def cored():
|
||||||
# cleanup
|
# cleanup
|
||||||
server.shutdown()
|
server.shutdown()
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
# cleanup services
|
||||||
|
ServiceManager.services.clear()
|
||||||
|
|
||||||
|
|
||||||
def ping(from_node, to_node, ip_prefixes, count=3):
|
def ping(from_node, to_node, ip_prefixes, count=3):
|
||||||
address = ip_prefixes.ip4_address(to_node)
|
address = ip_prefixes.ip4_address(to_node)
|
||||||
|
|
|
@ -6,22 +6,22 @@ from core.service import CoreService
|
||||||
|
|
||||||
|
|
||||||
class MyService(CoreService):
|
class MyService(CoreService):
|
||||||
_name = "MyService"
|
name = "MyService"
|
||||||
_group = "Utility"
|
group = "Utility"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ('myservice.sh',)
|
configs = ('myservice.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh myservice.sh',)
|
startup = ('sh myservice.sh',)
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
||||||
|
|
||||||
class MyService2(CoreService):
|
class MyService2(CoreService):
|
||||||
_name = "MyService2"
|
name = "MyService2"
|
||||||
_group = "Utility"
|
group = "Utility"
|
||||||
_depends = ()
|
depends = ()
|
||||||
_dirs = ()
|
dirs = ()
|
||||||
_configs = ('myservice.sh',)
|
configs = ('myservice.sh',)
|
||||||
_startindex = 50
|
startindex = 50
|
||||||
_startup = ('sh myservice.sh',)
|
startup = ('sh myservice.sh',)
|
||||||
_shutdown = ()
|
shutdown = ()
|
||||||
|
|
|
@ -15,10 +15,8 @@ from core.enumerations import NodeTypes
|
||||||
from core.mobility import BasicRangeModel
|
from core.mobility import BasicRangeModel
|
||||||
from core.mobility import Ns2ScriptedMobility
|
from core.mobility import Ns2ScriptedMobility
|
||||||
from core.netns.vnodeclient import VnodeClient
|
from core.netns.vnodeclient import VnodeClient
|
||||||
from core.service import ServiceManager
|
|
||||||
|
|
||||||
_PATH = os.path.abspath(os.path.dirname(__file__))
|
_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||||
_SERVICES_PATH = os.path.join(_PATH, "myservices")
|
|
||||||
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
|
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
|
||||||
_WIRED = [
|
_WIRED = [
|
||||||
NodeTypes.PEER_TO_PEER,
|
NodeTypes.PEER_TO_PEER,
|
||||||
|
@ -51,16 +49,6 @@ def ping(from_node, to_node, ip_prefixes):
|
||||||
|
|
||||||
|
|
||||||
class TestCore:
|
class TestCore:
|
||||||
def test_import_service(self):
|
|
||||||
"""
|
|
||||||
Test importing a custom service.
|
|
||||||
|
|
||||||
:param conftest.Core core: core fixture to test with
|
|
||||||
"""
|
|
||||||
ServiceManager.add_services(_SERVICES_PATH)
|
|
||||||
assert ServiceManager.get("MyService")
|
|
||||||
assert ServiceManager.get("MyService2")
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("net_type", _WIRED)
|
@pytest.mark.parametrize("net_type", _WIRED)
|
||||||
def test_wired_ping(self, session, net_type, ip_prefixes):
|
def test_wired_ping(self, session, net_type, ip_prefixes):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -101,7 +101,7 @@ def run_cmd(node, exec_cmd):
|
||||||
|
|
||||||
|
|
||||||
class TestGui:
|
class TestGui:
|
||||||
def test_broker(self, session, cored):
|
def test_broker(self, cored):
|
||||||
"""
|
"""
|
||||||
Test session broker creation.
|
Test session broker creation.
|
||||||
|
|
||||||
|
@ -119,6 +119,7 @@ class TestGui:
|
||||||
daemon = "localhost"
|
daemon = "localhost"
|
||||||
|
|
||||||
# add server
|
# add server
|
||||||
|
session = cored.server.coreemu.create_session()
|
||||||
session.broker.addserver(daemon, "127.0.0.1", CORE_API_PORT)
|
session.broker.addserver(daemon, "127.0.0.1", CORE_API_PORT)
|
||||||
|
|
||||||
# setup server
|
# setup server
|
||||||
|
|
18
daemon/tests/test_services.py
Normal file
18
daemon/tests/test_services.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
from core.service import ServiceManager
|
||||||
|
|
||||||
|
_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
_SERVICES_PATH = os.path.join(_PATH, "myservices")
|
||||||
|
|
||||||
|
|
||||||
|
class TestServices:
|
||||||
|
def test_import_service(self):
|
||||||
|
"""
|
||||||
|
Test importing a custom service.
|
||||||
|
|
||||||
|
:param conftest.Core core: core fixture to test with
|
||||||
|
"""
|
||||||
|
ServiceManager.add_services(_SERVICES_PATH)
|
||||||
|
assert ServiceManager.get("MyService")
|
||||||
|
assert ServiceManager.get("MyService2")
|
|
@ -6,6 +6,7 @@ from core.emane.ieee80211abg import EmaneIeee80211abgModel
|
||||||
from core.emulator.emudata import NodeOptions
|
from core.emulator.emudata import NodeOptions
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.mobility import BasicRangeModel
|
from core.mobility import BasicRangeModel
|
||||||
|
from core.services.utility import SshService
|
||||||
|
|
||||||
_XML_VERSIONS = [
|
_XML_VERSIONS = [
|
||||||
"0.0",
|
"0.0",
|
||||||
|
@ -68,6 +69,75 @@ class TestXml:
|
||||||
assert session.get_object(n1_id)
|
assert session.get_object(n1_id)
|
||||||
assert session.get_object(n2_id)
|
assert session.get_object(n2_id)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||||
|
def test_xml_ptp_services(self, session, tmpdir, version, ip_prefixes):
|
||||||
|
"""
|
||||||
|
Test xml client methods for a ptp neetwork.
|
||||||
|
|
||||||
|
:param session: session for test
|
||||||
|
:param tmpdir: tmpdir to create data in
|
||||||
|
:param str version: xml version to write and parse
|
||||||
|
:param ip_prefixes: generates ip addresses for nodes
|
||||||
|
"""
|
||||||
|
# create ptp
|
||||||
|
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
|
||||||
|
|
||||||
|
# create nodes
|
||||||
|
node_options = NodeOptions(model="host")
|
||||||
|
node_one = session.add_node(node_options=node_options)
|
||||||
|
node_two = session.add_node()
|
||||||
|
|
||||||
|
# link nodes to ptp net
|
||||||
|
for node in [node_one, node_two]:
|
||||||
|
interface = ip_prefixes.create_interface(node)
|
||||||
|
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
|
||||||
|
|
||||||
|
# set custom values for node service\
|
||||||
|
custom_start = 50
|
||||||
|
session.services.setcustomservice(node_one.objid, SshService.name)
|
||||||
|
service = session.services.getcustomservice(node_one.objid, SshService.name)
|
||||||
|
service.startindex = custom_start
|
||||||
|
service_file = SshService.configs[0]
|
||||||
|
file_data = "# test"
|
||||||
|
session.services.setservicefile(node_one.objid, SshService.name, service_file, file_data)
|
||||||
|
|
||||||
|
# instantiate session
|
||||||
|
session.instantiate()
|
||||||
|
|
||||||
|
# get ids for nodes
|
||||||
|
n1_id = node_one.objid
|
||||||
|
n2_id = node_two.objid
|
||||||
|
|
||||||
|
# save xml
|
||||||
|
xml_file = tmpdir.join("session.xml")
|
||||||
|
file_path = xml_file.strpath
|
||||||
|
session.save_xml(file_path, version)
|
||||||
|
|
||||||
|
# verify xml file was created and can be parsed
|
||||||
|
assert xml_file.isfile()
|
||||||
|
assert ElementTree.parse(file_path)
|
||||||
|
|
||||||
|
# stop current session, clearing data
|
||||||
|
session.shutdown()
|
||||||
|
|
||||||
|
# verify nodes have been removed from session
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
assert not session.get_object(n1_id)
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
assert not session.get_object(n2_id)
|
||||||
|
|
||||||
|
# load saved xml
|
||||||
|
session.open_xml(file_path, start=True)
|
||||||
|
|
||||||
|
# retrieve custom service
|
||||||
|
service = session.services.getcustomservice(node_one.objid, SshService.name)
|
||||||
|
|
||||||
|
# verify nodes have been recreated
|
||||||
|
assert session.get_object(n1_id)
|
||||||
|
assert session.get_object(n2_id)
|
||||||
|
assert service.startindex == custom_start
|
||||||
|
assert service.configtxt.get(service_file) == file_data
|
||||||
|
|
||||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||||
def test_xml_mobility(self, session, tmpdir, version, ip_prefixes):
|
def test_xml_mobility(self, session, tmpdir, version, ip_prefixes):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -16,13 +16,13 @@ import sys
|
||||||
|
|
||||||
import ns.core
|
import ns.core
|
||||||
import ns.network
|
import ns.network
|
||||||
|
from corens3.obj import Ns3Session
|
||||||
|
from corens3.obj import Ns3WifiNet
|
||||||
|
|
||||||
from core import logger
|
from core import logger
|
||||||
from core.misc import ipaddress
|
from core.misc import ipaddress
|
||||||
from core.misc import nodemaps
|
from core.misc import nodemaps
|
||||||
from core.misc import nodeutils
|
from core.misc import nodeutils
|
||||||
from corens3.obj import Ns3Session
|
|
||||||
from corens3.obj import Ns3WifiNet
|
|
||||||
|
|
||||||
|
|
||||||
def add_to_server(session):
|
def add_to_server(session):
|
||||||
|
@ -60,7 +60,7 @@ def wifisession(opt):
|
||||||
node = session.addnode(name="n%d" % i)
|
node = session.addnode(name="n%d" % i)
|
||||||
node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
|
node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
session.services.addservicestonode(node, "router", services_str)
|
session.services.addservicestonode(node, "router", services_str.split("|"))
|
||||||
session.services.bootnodeservices(node)
|
session.services.bootnodeservices(node)
|
||||||
session.setuprandomwalkmobility(bounds=(1000.0, 750.0, 0))
|
session.setuprandomwalkmobility(bounds=(1000.0, 750.0, 0))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue