refactored configs back to be able to provide instance conifgurations for sessions
This commit is contained in:
parent
eb415aa4d4
commit
3a39432fc7
22 changed files with 560 additions and 319 deletions
|
@ -90,11 +90,57 @@ class Configuration(object):
|
|||
self.__class__.__name__, self.id, self.type, self.default, self.options)
|
||||
|
||||
|
||||
class ConfigurableManager(object):
|
||||
_default_node = -1
|
||||
_default_type = _default_node
|
||||
|
||||
def __init__(self):
|
||||
self._configuration_maps = {}
|
||||
|
||||
def nodes(self):
|
||||
return [node_id for node_id in self._configuration_maps.iterkeys() if node_id != self._default_node]
|
||||
|
||||
def has_configs(self, node_id):
|
||||
return node_id in self._configuration_maps
|
||||
|
||||
def config_reset(self, node_id=None):
|
||||
logger.debug("resetting all configurations: %s", self.__class__.__name__)
|
||||
if not node_id:
|
||||
self._configuration_maps.clear()
|
||||
elif node_id in self._configuration_maps:
|
||||
self._configuration_maps.pop(node_id)
|
||||
|
||||
def set_config(self, _id, value, node_id=_default_node, config_type=_default_type):
|
||||
logger.debug("setting config for node(%s) type(%s): %s=%s", node_id, config_type, _id, value)
|
||||
node_type_map = self.get_configs(node_id, config_type)
|
||||
node_type_map[_id] = value
|
||||
|
||||
def set_configs(self, config, node_id=_default_node, config_type=_default_type):
|
||||
logger.debug("setting config for node(%s) type(%s): %s", node_id, config_type, config)
|
||||
node_configs = self.get_all_configs(node_id)
|
||||
if config_type in node_configs:
|
||||
node_configs.pop(config_type)
|
||||
node_configs[config_type] = config
|
||||
|
||||
def get_config(self, _id, node_id=_default_node, config_type=_default_type, default=None):
|
||||
logger.debug("getting config for node(%s) type(%s): %s", node_id, config_type, _id)
|
||||
node_type_map = self.get_configs(node_id, config_type)
|
||||
return node_type_map.get(_id, default)
|
||||
|
||||
def get_configs(self, node_id=_default_node, config_type=_default_type):
|
||||
logger.debug("getting configs for node(%s) type(%s)", node_id, config_type)
|
||||
node_map = self.get_all_configs(node_id)
|
||||
return node_map.setdefault(config_type, {})
|
||||
|
||||
def get_all_configs(self, node_id=_default_node):
|
||||
logger.debug("getting all configs for node(%s)", node_id)
|
||||
return self._configuration_maps.setdefault(node_id, OrderedDict())
|
||||
|
||||
|
||||
class ConfigurableOptions(object):
|
||||
# unique name to receive configuration changes
|
||||
name = None
|
||||
bitmap = None
|
||||
configuration_maps = None
|
||||
_default_node = -1
|
||||
|
||||
@classmethod
|
||||
|
@ -108,42 +154,3 @@ class ConfigurableOptions(object):
|
|||
@classmethod
|
||||
def default_values(cls):
|
||||
return OrderedDict([(config.id, config.default) for config in cls.configurations()])
|
||||
|
||||
@classmethod
|
||||
def nodes(cls):
|
||||
return {node_id for node_id in cls.configuration_maps.iterkeys() if node_id != cls._default_node}
|
||||
|
||||
@classmethod
|
||||
def config_reset(cls, node_id=None):
|
||||
if not node_id:
|
||||
logger.debug("resetting all configurations: %s", cls.__name__)
|
||||
cls.configuration_maps.clear()
|
||||
elif node_id in cls.configuration_maps:
|
||||
logger.debug("resetting node(%s) configurations: %s", node_id, cls.__name__)
|
||||
cls.configuration_maps.pop(node_id)
|
||||
|
||||
@classmethod
|
||||
def set_config(cls, _id, value, node_id=_default_node):
|
||||
logger.debug("setting config for node(%s) type(%s): %s=%s", node_id, _id, value)
|
||||
node_configs = cls.get_configs(node_id)
|
||||
node_configs[_id] = value
|
||||
|
||||
@classmethod
|
||||
def get_config(cls, _id, node_id=_default_node, default=None):
|
||||
node_configs = cls.get_configs(node_id)
|
||||
value = node_configs.get(_id, default)
|
||||
logger.debug("getting config for node(%s): %s = %s", node_id, _id, value)
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def set_configs(cls, config=None, node_id=_default_node):
|
||||
logger.debug("setting config for node(%s): %s", node_id, config)
|
||||
node_config = cls.get_configs(node_id)
|
||||
if config:
|
||||
for key, value in config.iteritems():
|
||||
node_config[key] = value
|
||||
|
||||
@classmethod
|
||||
def get_configs(cls, node_id=_default_node):
|
||||
logger.debug("getting configs for node(%s)", node_id)
|
||||
return cls.configuration_maps.setdefault(node_id, cls.default_values())
|
||||
|
|
|
@ -1186,7 +1186,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
||||
config = model_class.get_configs(node_id=node_id)
|
||||
config = self.session.mobility.get_model_config(node_id, object_name)
|
||||
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||
replies.append(config_response)
|
||||
elif message_type != ConfigFlags.RESET:
|
||||
|
@ -1195,17 +1195,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.warn("no configuration object for node: %s", node_id)
|
||||
return []
|
||||
|
||||
model_class = self.session.mobility.get_model_class(object_name)
|
||||
if not model_class:
|
||||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
||||
parsed_config = {}
|
||||
if values_str:
|
||||
parsed_config = ConfigShim.str_to_dict(values_str)
|
||||
model_class.set_configs(parsed_config, node_id=node_id)
|
||||
|
||||
config = model_class.get_configs(node_id)
|
||||
model_class.set_configs(config, node_id=node_id)
|
||||
self.session.mobility.set_model_config(node_id, object_name, parsed_config)
|
||||
|
||||
return replies
|
||||
|
||||
|
@ -1213,7 +1207,6 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
replies = []
|
||||
node_id = config_data.node
|
||||
object_name = config_data.object
|
||||
config_type = config_data.type
|
||||
interface_id = config_data.interface_number
|
||||
values_str = config_data.data_values
|
||||
|
||||
|
@ -1263,7 +1256,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
||||
config = model_class.get_configs(node_id=node_id)
|
||||
config = self.session.emane.get_model_config(node_id, object_name)
|
||||
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||
replies.append(config_response)
|
||||
elif message_type != ConfigFlags.RESET:
|
||||
|
@ -1272,18 +1265,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.warn("no configuration object for node: %s", node_id)
|
||||
return []
|
||||
|
||||
model_class = self.session.emane.get_model_class(object_name)
|
||||
if not model_class:
|
||||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
||||
parsed_config = {}
|
||||
if values_str:
|
||||
parsed_config = ConfigShim.str_to_dict(values_str)
|
||||
model_class.set_configs(parsed_config, node_id=node_id)
|
||||
|
||||
config = model_class.get_configs(node_id)
|
||||
model_class.set_configs(config, node_id=node_id)
|
||||
self.session.emane.set_node_model(node_id, object_name)
|
||||
self.session.emane.set_model_config(node_id, object_name, parsed_config)
|
||||
|
||||
return replies
|
||||
|
||||
|
@ -1435,7 +1421,8 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
return ()
|
||||
elif event_type == EventTypes.FILE_SAVE:
|
||||
filename = event_data.name
|
||||
self.session.save_xml(filename, self.session.config["xmlfilever"])
|
||||
xml_version = self.session.options.get_config("xmlfilever")
|
||||
self.session.save_xml(filename, xml_version)
|
||||
elif event_type == EventTypes.SCHEDULED:
|
||||
etime = event_data.time
|
||||
node = event_data.node
|
||||
|
@ -1600,10 +1587,9 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
self.session.broadcast_config(config_data)
|
||||
|
||||
# send emane model info
|
||||
for model_name in self.session.emane.emane_models():
|
||||
model_class = self.session.emane.get_model_class(model_name)
|
||||
for node_id in model_class.nodes():
|
||||
config = model_class.get_configs(node_id)
|
||||
for node_id in self.session.emane.nodes():
|
||||
node = self.session.get_object(node_id)
|
||||
for model_class, config in self.session.emane.getmodels(node):
|
||||
logger.info("emane config: node(%s) class(%s) values(%s)", node_id, model_class, config)
|
||||
config_data = ConfigShim.config_data(0, node_id, ConfigFlags.UPDATE.value, model_class, config)
|
||||
self.session.broadcast_config(config_data)
|
||||
|
|
|
@ -8,7 +8,6 @@ from core.enumerations import ConfigDataTypes
|
|||
|
||||
class EmaneBypassModel(emanemodel.EmaneModel):
|
||||
name = "emane_bypass"
|
||||
configuration_maps = {}
|
||||
|
||||
# values to ignore, when writing xml files
|
||||
config_ignore = {"none"}
|
||||
|
|
|
@ -29,7 +29,6 @@ def convert_none(x):
|
|||
|
||||
class EmaneCommEffectModel(emanemodel.EmaneModel):
|
||||
name = "emane_commeffect"
|
||||
configuration_maps = {}
|
||||
|
||||
shim_library = "commeffectshim"
|
||||
shim_xml = "/usr/share/emane/manifest/commeffectshim.xml"
|
||||
|
@ -55,7 +54,7 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
|||
:param interface: interface for the emane node
|
||||
:return: nothing
|
||||
"""
|
||||
config = self.getifcconfig(self.object_id, interface)
|
||||
config = emane_manager.getifcconfig(self.object_id, interface, self.name)
|
||||
if not config:
|
||||
return
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ from core import constants
|
|||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.api import dataconversion
|
||||
from core.conf import ConfigShim
|
||||
from core.conf import ConfigShim, ConfigurableManager
|
||||
from core.conf import Configuration
|
||||
from core.emane import emanemanifest
|
||||
from core.emane.bypass import EmaneBypassModel
|
||||
|
@ -53,7 +53,7 @@ EMANE_MODELS = [
|
|||
]
|
||||
|
||||
|
||||
class EmaneManager(object):
|
||||
class EmaneManager(ConfigurableManager):
|
||||
"""
|
||||
EMANE controller object. Lives in a Session instance and is used for
|
||||
building EMANE config files from all of the EmaneNode objects in this
|
||||
|
@ -73,6 +73,7 @@ class EmaneManager(object):
|
|||
:param core.session.Session session: session this manager is tied to
|
||||
:return: nothing
|
||||
"""
|
||||
super(EmaneManager, self).__init__()
|
||||
self.session = session
|
||||
self._emane_nodes = {}
|
||||
self._emane_node_lock = threading.Lock()
|
||||
|
@ -86,6 +87,7 @@ class EmaneManager(object):
|
|||
|
||||
# model for global EMANE configuration options
|
||||
self.emane_config = EmaneGlobalModel(session)
|
||||
self.set_configs(self.emane_config.default_values())
|
||||
|
||||
# store the last configured model for a node, used during startup
|
||||
self.node_models = {}
|
||||
|
@ -98,19 +100,106 @@ class EmaneManager(object):
|
|||
self.service = None
|
||||
self.emane_check()
|
||||
|
||||
def set_node_model(self, node_id, model_name):
|
||||
if model_name not in self._modelclsmap:
|
||||
raise ValueError("unknown emane model: %s", model_name)
|
||||
def set_model_config(self, node_id, model_name, config):
|
||||
"""
|
||||
Set configuration data for a model.
|
||||
|
||||
:param int node_id: node id to set model configuration for
|
||||
:param str model_name: model to set configuration for
|
||||
:param dict config: configuration data to set for model
|
||||
:return: nothing
|
||||
"""
|
||||
# get model class to configure
|
||||
model_class = self._modelclsmap.get(model_name)
|
||||
if not model_class:
|
||||
raise ValueError("%s is an invalid model" % model_name)
|
||||
|
||||
# retrieve default values
|
||||
node_config = self.get_model_config(node_id, model_name)
|
||||
for key, value in config.iteritems():
|
||||
node_config[key] = value
|
||||
|
||||
# set as node model for startup
|
||||
self.node_models[node_id] = model_name
|
||||
|
||||
def config_reset(self, node_id=None):
|
||||
# clear and reset current emane configuration
|
||||
self.emane_config.config_reset()
|
||||
self.emane_config.set_configs()
|
||||
# set configuration
|
||||
self.set_configs(node_config, node_id=node_id, config_type=model_name)
|
||||
|
||||
# reset model configurations
|
||||
for model_class in self._modelclsmap.itervalues():
|
||||
model_class.config_reset(node_id=node_id)
|
||||
def get_model_config(self, node_id, model_name):
|
||||
"""
|
||||
Set configuration data for a model.
|
||||
|
||||
:param int node_id: node id to set model configuration for
|
||||
:param str model_name: model to set configuration for
|
||||
:return: current model configuration for node
|
||||
:rtype: dict
|
||||
"""
|
||||
# get model class to configure
|
||||
model_class = self._modelclsmap.get(model_name)
|
||||
if not model_class:
|
||||
raise ValueError("%s is an invalid model" % model_name)
|
||||
|
||||
config = self.get_configs(node_id=node_id, config_type=model_name)
|
||||
if not config:
|
||||
# set default values, when not already set
|
||||
config = model_class.default_values()
|
||||
self.set_configs(config, node_id=node_id, config_type=model_name)
|
||||
|
||||
return config
|
||||
|
||||
def getifcconfig(self, node_id, interface, model_name):
|
||||
"""
|
||||
Retrieve interface configuration or node configuration if not provided.
|
||||
|
||||
:param int node_id: node id
|
||||
:param interface: node interface
|
||||
:param str model_name: model to get configuration for
|
||||
:return: node/interface model configuration
|
||||
:rtype: dict
|
||||
"""
|
||||
# use the network-wide config values or interface(NEM)-specific values?
|
||||
if interface is None:
|
||||
return self.get_configs(node_id=node_id, config_type=model_name)
|
||||
else:
|
||||
# don"t use default values when interface config is the same as net
|
||||
# note here that using ifc.node.objid as key allows for only one type
|
||||
# of each model per node;
|
||||
# TODO: use both node and interface as key
|
||||
|
||||
# Adamson change: first check for iface config keyed by "node:ifc.name"
|
||||
# (so that nodes w/ multiple interfaces of same conftype can have
|
||||
# different configs for each separate interface)
|
||||
key = 1000 * interface.node.objid
|
||||
if interface.netindex is not None:
|
||||
key += interface.netindex
|
||||
|
||||
# try retrieve interface specific configuration, avoid getting defaults
|
||||
config = {}
|
||||
if self.has_configs(key):
|
||||
config = self.get_configs(key)
|
||||
|
||||
# otherwise retrieve the interfaces node configuration, avoid using defaults
|
||||
if not config and self.has_configs(interface.node.objid):
|
||||
config = self.get_configs(node_id=interface.node.objid, config_type=model_name)
|
||||
|
||||
if not config and interface.transport_type == "raw":
|
||||
# with EMANE 0.9.2+, we need an extra NEM XML from
|
||||
# model.buildnemxmlfiles(), so defaults are returned here
|
||||
config = self.get_configs(node_id=node_id, config_type=model_name)
|
||||
|
||||
return config
|
||||
|
||||
def set_model(self, node, model_class, config=None):
|
||||
logger.info("setting emane model(%s) for node(%s): %s", model_class.name, node.objid, config)
|
||||
if not config:
|
||||
config = {}
|
||||
self.set_model_config(node.objid, model_class.name, config)
|
||||
config = self.get_model_config(node.objid, model_class.name)
|
||||
node.setmodel(model_class, config)
|
||||
|
||||
def config_reset(self, node_id=None):
|
||||
super(EmaneManager, self).config_reset(node_id)
|
||||
self.set_configs(self.emane_config.default_values())
|
||||
|
||||
def emane_models(self):
|
||||
return self._modelclsmap.keys()
|
||||
|
@ -162,8 +251,8 @@ class EmaneManager(object):
|
|||
return
|
||||
|
||||
# Get the control network to be used for events
|
||||
group, port = self.emane_config.get_config("eventservicegroup").split(":")
|
||||
self.event_device = self.emane_config.get_config("eventservicedevice")
|
||||
group, port = self.get_config("eventservicegroup").split(":")
|
||||
self.event_device = self.get_config("eventservicedevice")
|
||||
eventnetidx = self.session.get_control_net_index(self.event_device)
|
||||
if eventnetidx < 0:
|
||||
logger.error("invalid emane event service device provided: %s", self.event_device)
|
||||
|
@ -223,11 +312,15 @@ class EmaneManager(object):
|
|||
Used with XML export.
|
||||
"""
|
||||
models = []
|
||||
for model_class in self._modelclsmap.itervalues():
|
||||
if node.objid in model_class.configuration_maps:
|
||||
config = model_class.get_configs(node_id=node.objid)
|
||||
all_configs = {}
|
||||
if self.has_configs(node_id=node.objid):
|
||||
all_configs = self.get_all_configs(node_id=node.objid)
|
||||
|
||||
for model_name in all_configs.iterkeys():
|
||||
model_class = self._modelclsmap[model_name]
|
||||
config = self.get_configs(node_id=node.objid, config_type=model_name)
|
||||
models.append((model_class, config))
|
||||
logger.debug("emane models: %s", models)
|
||||
logger.debug("emane models for node(%s): %s", node.objid, models)
|
||||
return models
|
||||
|
||||
def setup(self):
|
||||
|
@ -254,7 +347,7 @@ class EmaneManager(object):
|
|||
# - needs to be configured before checkdistributed() for distributed
|
||||
# - needs to exist when eventservice binds to it (initeventservice)
|
||||
if self.session.master:
|
||||
otadev = self.emane_config.get_config("otamanagerdevice")
|
||||
otadev = self.get_config("otamanagerdevice")
|
||||
netidx = self.session.get_control_net_index(otadev)
|
||||
logger.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
|
||||
if netidx < 0:
|
||||
|
@ -263,7 +356,7 @@ class EmaneManager(object):
|
|||
|
||||
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
|
||||
self.distributedctrlnet(ctrlnet)
|
||||
eventdev = self.emane_config.get_config("eventservicedevice")
|
||||
eventdev = self.get_config("eventservicedevice")
|
||||
logger.debug("emane event service device: eventdev(%s)", eventdev)
|
||||
if eventdev != otadev:
|
||||
netidx = self.session.get_control_net_index(eventdev)
|
||||
|
@ -279,7 +372,7 @@ class EmaneManager(object):
|
|||
# we are slave, but haven't received a platformid yet
|
||||
platform_id_start = "platform_id_start"
|
||||
default_values = self.emane_config.default_values()
|
||||
value = self.emane_config.get_config(platform_id_start)
|
||||
value = self.get_config(platform_id_start)
|
||||
if value == default_values[platform_id_start]:
|
||||
return EmaneManager.NOT_READY
|
||||
|
||||
|
@ -411,10 +504,10 @@ class EmaneManager(object):
|
|||
emane_node = self._emane_nodes[key]
|
||||
nemcount += emane_node.numnetif()
|
||||
|
||||
nemid = int(self.emane_config.get_config("nem_id_start"))
|
||||
nemid = int(self.get_config("nem_id_start"))
|
||||
nemid += nemcount
|
||||
|
||||
platformid = int(self.emane_config.get_config("platform_id_start"))
|
||||
platformid = int(self.get_config("platform_id_start"))
|
||||
|
||||
# build an ordered list of servers so platform ID is deterministic
|
||||
servers = []
|
||||
|
@ -433,8 +526,8 @@ class EmaneManager(object):
|
|||
|
||||
platformid += 1
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
self.emane_config.set_config("platform_id_start", str(platformid))
|
||||
self.emane_config.set_config("nem_id_start", str(nemid))
|
||||
self.set_config("platform_id_start", str(platformid))
|
||||
self.set_config("nem_id_start", str(nemid))
|
||||
config_data = ConfigShim.config_data(0, None, typeflags, self.emane_config, self.get_configs())
|
||||
message = dataconversion.convert_config(config_data)
|
||||
server.sock.send(message)
|
||||
|
@ -555,9 +648,9 @@ class EmaneManager(object):
|
|||
logger.error("emane node(%s) has no node model", node_id)
|
||||
raise ValueError("emane node has no model set")
|
||||
|
||||
config = self.get_model_config(node_id=node_id, model_name=model_name)
|
||||
logger.debug("setting emane model(%s) config(%s)", model_name, config)
|
||||
model_class = self._modelclsmap[model_name]
|
||||
config = model_class.get_configs(node_id=node_id)
|
||||
logger.debug("setting emane model(%s) config(%s)", model_class, config)
|
||||
emane_node.setmodel(model_class, config)
|
||||
|
||||
def nemlookup(self, nemid):
|
||||
|
@ -597,10 +690,10 @@ class EmaneManager(object):
|
|||
plat = doc.getElementsByTagName("platform").pop()
|
||||
|
||||
if otadev:
|
||||
self.emane_config.set_config("otamanagerdevice", otadev)
|
||||
self.set_config("otamanagerdevice", otadev)
|
||||
|
||||
if eventdev:
|
||||
self.emane_config.set_config("eventservicedevice", eventdev)
|
||||
self.set_config("eventservicedevice", eventdev)
|
||||
|
||||
# append all platform options (except starting id) to doc
|
||||
for configuration in self.emane_config.emulator_config:
|
||||
|
@ -608,7 +701,7 @@ class EmaneManager(object):
|
|||
if name == "platform_id_start":
|
||||
continue
|
||||
|
||||
value = self.emane_config.get_config(name)
|
||||
value = self.get_config(name)
|
||||
param = self.xmlparam(doc, name, value)
|
||||
plat.appendChild(param)
|
||||
|
||||
|
@ -618,7 +711,7 @@ class EmaneManager(object):
|
|||
"""
|
||||
Build a platform.xml file now that all nodes are configured.
|
||||
"""
|
||||
nemid = int(self.emane_config.get_config("nem_id_start"))
|
||||
nemid = int(self.get_config("nem_id_start"))
|
||||
platformxmls = {}
|
||||
|
||||
# assume self._objslock is already held here
|
||||
|
@ -695,7 +788,7 @@ class EmaneManager(object):
|
|||
default_values = self.emane_config.default_values()
|
||||
for name in ["eventservicegroup", "eventservicedevice"]:
|
||||
a = default_values[name]
|
||||
b = self.emane_config.get_config(name)
|
||||
b = self.get_config(name)
|
||||
if a != b:
|
||||
need_xml = True
|
||||
|
||||
|
@ -705,12 +798,12 @@ class EmaneManager(object):
|
|||
return
|
||||
|
||||
try:
|
||||
group, port = self.emane_config.get_config("eventservicegroup").split(":")
|
||||
group, port = self.get_config("eventservicegroup").split(":")
|
||||
except ValueError:
|
||||
logger.exception("invalid eventservicegroup in EMANE config")
|
||||
return
|
||||
|
||||
dev = self.emane_config.get_config("eventservicedevice")
|
||||
dev = self.get_config("eventservicedevice")
|
||||
doc = self.xmldoc("emaneeventmsgsvc")
|
||||
es = doc.getElementsByTagName("emaneeventmsgsvc").pop()
|
||||
kvs = (("group", group), ("port", port), ("device", dev), ("mcloop", "1"), ("ttl", "32"))
|
||||
|
@ -737,12 +830,12 @@ class EmaneManager(object):
|
|||
if realtime:
|
||||
emanecmd += "-r",
|
||||
|
||||
otagroup, otaport = self.emane_config.get_config("otamanagergroup").split(":")
|
||||
otadev = self.emane_config.get_config("otamanagerdevice")
|
||||
otagroup, otaport = self.get_config("otamanagergroup").split(":")
|
||||
otadev = self.get_config("otamanagerdevice")
|
||||
otanetidx = self.session.get_control_net_index(otadev)
|
||||
|
||||
eventgroup, eventport = self.emane_config.get_config("eventservicegroup").split(":")
|
||||
eventdev = self.emane_config.get_config("eventservicedevice")
|
||||
eventgroup, eventport = self.get_config("eventservicegroup").split(":")
|
||||
eventdev = self.get_config("eventservicedevice")
|
||||
eventservicenetidx = self.session.get_control_net_index(eventdev)
|
||||
|
||||
run_emane_on_host = False
|
||||
|
|
|
@ -79,7 +79,7 @@ class EmaneModel(WirelessModel):
|
|||
:return: nothing
|
||||
"""
|
||||
# retrieve configuration values
|
||||
config = self.getifcconfig(self.object_id, interface)
|
||||
config = emane_manager.getifcconfig(self.object_id, interface, self.name)
|
||||
if not config:
|
||||
return
|
||||
|
||||
|
@ -149,7 +149,7 @@ class EmaneModel(WirelessModel):
|
|||
continue
|
||||
|
||||
# check if value is a multi param
|
||||
value = config[name]
|
||||
value = str(config[name])
|
||||
param = value_to_params(mac_document, name, value)
|
||||
if not param:
|
||||
param = emane_manager.xmlparam(mac_document, name, value)
|
||||
|
@ -182,7 +182,7 @@ class EmaneModel(WirelessModel):
|
|||
continue
|
||||
|
||||
# check if value is a multi param
|
||||
value = config[name]
|
||||
value = str(config[name])
|
||||
param = value_to_params(phy_document, name, value)
|
||||
if not param:
|
||||
param = emane_manager.xmlparam(phy_document, name, value)
|
||||
|
@ -269,7 +269,7 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
if interface:
|
||||
node_id = interface.node.objid
|
||||
if self.getifcconfig(node_id, interface):
|
||||
if self.session.emane.getifcconfig(node_id, interface, self.name):
|
||||
name = interface.localname.replace(".", "_")
|
||||
|
||||
return "%s%s" % (name, self.name)
|
||||
|
@ -348,43 +348,3 @@ class EmaneModel(WirelessModel):
|
|||
:return: nothing
|
||||
"""
|
||||
logger.warn("emane model(%s) does not support link configuration", self.name)
|
||||
|
||||
def getifcconfig(self, node_id, ifc):
|
||||
"""
|
||||
Retrieve interface configuration or node configuration if not provided.
|
||||
|
||||
:param int node_id: node id
|
||||
:param ifc: node interface
|
||||
:return:
|
||||
"""
|
||||
# use the network-wide config values or interface(NEM)-specific values?
|
||||
if ifc is None:
|
||||
return self.get_configs(node_id)
|
||||
else:
|
||||
# don"t use default values when interface config is the same as net
|
||||
# note here that using ifc.node.objid as key allows for only one type
|
||||
# of each model per node;
|
||||
# TODO: use both node and interface as key
|
||||
|
||||
# Adamson change: first check for iface config keyed by "node:ifc.name"
|
||||
# (so that nodes w/ multiple interfaces of same conftype can have
|
||||
# different configs for each separate interface)
|
||||
key = 1000 * ifc.node.objid
|
||||
if ifc.netindex is not None:
|
||||
key += ifc.netindex
|
||||
|
||||
# try retrieve interface specific configuration, avoid getting defaults
|
||||
config = {}
|
||||
if key in self.configuration_maps:
|
||||
config = self.get_configs(key)
|
||||
|
||||
# otherwise retrieve the interfaces node configuration, avoid using defaults
|
||||
if not config and ifc.node.objid in self.configuration_maps:
|
||||
config = self.get_configs(ifc.node.objid)
|
||||
|
||||
if not config and ifc.transport_type == "raw":
|
||||
# with EMANE 0.9.2+, we need an extra NEM XML from
|
||||
# model.buildnemxmlfiles(), so defaults are returned here
|
||||
config = self.get_configs(node_id)
|
||||
|
||||
return config
|
||||
|
|
|
@ -9,7 +9,6 @@ from core.emane import emanemodel
|
|||
class EmaneIeee80211abgModel(emanemodel.EmaneModel):
|
||||
# model name
|
||||
name = "emane_ieee80211abg"
|
||||
configuration_maps = {}
|
||||
|
||||
# mac configuration
|
||||
mac_library = "ieee80211abgmaclayer"
|
||||
|
|
|
@ -73,7 +73,7 @@ class EmaneNode(EmaneNet):
|
|||
logger.info("node(%s) updating model(%s): %s", self.objid, self.model.name, config)
|
||||
self.model.set_configs(config, node_id=self.objid)
|
||||
|
||||
def setmodel(self, model, config=None):
|
||||
def setmodel(self, model, config):
|
||||
"""
|
||||
set the EmaneModel associated with this node
|
||||
"""
|
||||
|
@ -81,9 +81,11 @@ class EmaneNode(EmaneNet):
|
|||
if model.config_type == RegisterTlvs.WIRELESS.value:
|
||||
# EmaneModel really uses values from ConfigurableManager
|
||||
# when buildnemxml() is called, not during init()
|
||||
self.model = model(session=self.session, object_id=self.objid, config=config)
|
||||
self.model = model(session=self.session, object_id=self.objid)
|
||||
self.model.update_config(config)
|
||||
elif model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
self.mobility = model(session=self.session, object_id=self.objid, config=config)
|
||||
self.mobility = model(session=self.session, object_id=self.objid)
|
||||
self.mobility.update_config(config)
|
||||
|
||||
def setnemid(self, netif, nemid):
|
||||
"""
|
||||
|
@ -180,8 +182,7 @@ class EmaneNode(EmaneNet):
|
|||
trans.setAttribute("library", "trans%s" % transport_type.lower())
|
||||
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
|
||||
|
||||
model_class = emane.get_model_class(self.model.name)
|
||||
config = model_class.get_configs(self.objid)
|
||||
config = emane.get_configs(node_id=self.objid, config_type=self.model.name)
|
||||
logger.debug("transport xml config: %s", config)
|
||||
flowcontrol = config.get("flowcontrolenable", "0") == "1"
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ from core.emane import emanemodel
|
|||
class EmaneRfPipeModel(emanemodel.EmaneModel):
|
||||
# model name
|
||||
name = "emane_rfpipe"
|
||||
configuration_maps = {}
|
||||
|
||||
# mac configuration
|
||||
mac_library = "rfpipemaclayer"
|
||||
|
|
|
@ -16,7 +16,6 @@ from core.misc import utils
|
|||
class EmaneTdmaModel(emanemodel.EmaneModel):
|
||||
# model name
|
||||
name = "emane_tdma"
|
||||
configuration_maps = {}
|
||||
|
||||
# mac configuration
|
||||
mac_library = "tdmaeventschedulerradiomodel"
|
||||
|
@ -47,7 +46,7 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
|
|||
:return: nothing
|
||||
"""
|
||||
# get configured schedule
|
||||
config = self.get_configs(self.object_id)
|
||||
config = self.session.emane.get_configs(node_id=self.object_id, config_type=self.name)
|
||||
if not config:
|
||||
return
|
||||
schedule = config[self.schedule_name]
|
||||
|
|
|
@ -739,6 +739,7 @@ class EmuSession(Session):
|
|||
self.delete_objects()
|
||||
self.del_hooks()
|
||||
self.broker.reset()
|
||||
self.emane.reset()
|
||||
|
||||
def start_events(self):
|
||||
"""
|
||||
|
@ -778,7 +779,7 @@ class EmuSession(Session):
|
|||
node_options.model = "mdr"
|
||||
return self.add_node(_type=NodeTypes.DEFAULT, _id=_id, node_options=node_options)
|
||||
|
||||
def create_emane_network(self, model, geo_reference, geo_scale=None, node_options=NodeOptions()):
|
||||
def create_emane_network(self, model, geo_reference, geo_scale=None, node_options=NodeOptions(), config=None):
|
||||
"""
|
||||
Convenience method for creating an emane network.
|
||||
|
||||
|
@ -786,6 +787,7 @@ class EmuSession(Session):
|
|||
:param geo_reference: geo reference point to use for emane node locations
|
||||
:param geo_scale: geo scale to use for emane node locations, defaults to 1.0
|
||||
:param core.emulator.emudata.NodeOptions node_options: options for emane node being created
|
||||
:param dict config: emane model configuration
|
||||
:return: create emane network
|
||||
"""
|
||||
# required to be set for emane to function properly
|
||||
|
@ -795,7 +797,7 @@ class EmuSession(Session):
|
|||
|
||||
# create and return network
|
||||
emane_network = self.add_node(_type=NodeTypes.EMANE, node_options=node_options)
|
||||
emane_network.setmodel(model)
|
||||
self.emane.set_model(emane_network, model, config)
|
||||
return emane_network
|
||||
|
||||
def wireless_link_all(self, network, nodes):
|
||||
|
|
|
@ -9,7 +9,7 @@ import threading
|
|||
import time
|
||||
|
||||
from core import logger
|
||||
from core.conf import ConfigurableOptions
|
||||
from core.conf import ConfigurableOptions, ConfigurableManager
|
||||
from core.conf import Configuration
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.data import EventData
|
||||
|
@ -25,7 +25,7 @@ from core.misc import utils
|
|||
from core.misc.ipaddress import IpAddress
|
||||
|
||||
|
||||
class MobilityManager(object):
|
||||
class MobilityManager(ConfigurableManager):
|
||||
"""
|
||||
Member of session class for handling configuration data for mobility and
|
||||
range models.
|
||||
|
@ -39,6 +39,7 @@ class MobilityManager(object):
|
|||
|
||||
:param core.session.Session session: session this manager is tied to
|
||||
"""
|
||||
super(MobilityManager, self).__init__()
|
||||
self.session = session
|
||||
# configurations for basic range, indexed by WLAN node number, are stored in configurations
|
||||
# mapping from model names to their classes
|
||||
|
@ -52,6 +53,50 @@ class MobilityManager(object):
|
|||
self.physnets = {}
|
||||
self.session.broker.handlers.add(self.physnodehandlelink)
|
||||
|
||||
def set_model_config(self, node_id, model_name, config):
|
||||
"""
|
||||
Set configuration data for a model.
|
||||
|
||||
:param int node_id: node id to set model configuration for
|
||||
:param str model_name: model to set configuration for
|
||||
:param dict config: configuration data to set for model
|
||||
:return: nothing
|
||||
"""
|
||||
# get model class to configure
|
||||
model_class = self._modelclsmap.get(model_name)
|
||||
if not model_class:
|
||||
raise ValueError("%s is an invalid model" % model_name)
|
||||
|
||||
# retrieve default values
|
||||
node_config = self.get_model_config(node_id, model_name)
|
||||
for key, value in config.iteritems():
|
||||
node_config[key] = value
|
||||
|
||||
# set configuration
|
||||
self.set_configs(node_config, node_id=node_id, config_type=model_name)
|
||||
|
||||
def get_model_config(self, node_id, model_name):
|
||||
"""
|
||||
Set configuration data for a model.
|
||||
|
||||
:param int node_id: node id to set model configuration for
|
||||
:param str model_name: model to set configuration for
|
||||
:return: current model configuration for node
|
||||
:rtype: dict
|
||||
"""
|
||||
# get model class to configure
|
||||
model_class = self._modelclsmap.get(model_name)
|
||||
if not model_class:
|
||||
raise ValueError("%s is an invalid model" % model_name)
|
||||
|
||||
config = self.get_configs(node_id=node_id, config_type=model_name)
|
||||
if not config:
|
||||
# set default values, when not already set
|
||||
config = model_class.default_values()
|
||||
self.set_configs(config, node_id=node_id, config_type=model_name)
|
||||
|
||||
return config
|
||||
|
||||
def mobility_models(self):
|
||||
return self._modelclsmap.keys()
|
||||
|
||||
|
@ -68,17 +113,17 @@ class MobilityManager(object):
|
|||
:rtype: list
|
||||
"""
|
||||
models = []
|
||||
for model_class in self._modelclsmap.itervalues():
|
||||
if node.objid in model_class.configuration_maps:
|
||||
config = model_class.get_configs(node_id=node.objid)
|
||||
models.append((model_class, config))
|
||||
return models
|
||||
all_configs = {}
|
||||
if self.has_configs(node_id=node.objid):
|
||||
all_configs = self.get_all_configs(node_id=node.objid)
|
||||
|
||||
def nodes(self):
|
||||
node_ids = set()
|
||||
for model_class in self._modelclsmap.itervalues():
|
||||
node_ids |= model_class.nodes()
|
||||
return node_ids
|
||||
for model_name in all_configs.iterkeys():
|
||||
model_class = self._modelclsmap[model_name]
|
||||
config = self.get_configs(node_id=node.objid, config_type=model_name)
|
||||
models.append((model_class, config))
|
||||
|
||||
logger.debug("mobility models for node(%s): %s", node.objid, models)
|
||||
return models
|
||||
|
||||
def startup(self, node_ids=None):
|
||||
"""
|
||||
|
@ -93,6 +138,7 @@ class MobilityManager(object):
|
|||
|
||||
for node_id in node_ids:
|
||||
logger.info("checking mobility startup for node: %s", node_id)
|
||||
logger.info("node mobility configurations: %s", self.get_all_configs(node_id))
|
||||
|
||||
try:
|
||||
node = self.session.get_object(node_id)
|
||||
|
@ -100,13 +146,12 @@ class MobilityManager(object):
|
|||
logger.warn("skipping mobility configuration for unknown node: %s", node_id)
|
||||
continue
|
||||
|
||||
for model_class in self._modelclsmap.itervalues():
|
||||
logger.debug("model(%s) configurations: %s", model_class, model_class.configuration_maps)
|
||||
if node_id not in model_class.configuration_maps:
|
||||
for model_name in self._modelclsmap.iterkeys():
|
||||
config = self.get_configs(node_id=node_id, config_type=model_name)
|
||||
if not config:
|
||||
continue
|
||||
config = model_class.get_configs(node_id=node_id)
|
||||
logger.info("setting mobility model(%s) to node: %s", model_class.name, config)
|
||||
node.setmodel(model_class, config)
|
||||
model_class = self._modelclsmap[model_name]
|
||||
self.set_model(node, model_class, config)
|
||||
|
||||
if self.session.master:
|
||||
self.installphysnodes(node)
|
||||
|
@ -114,15 +159,13 @@ class MobilityManager(object):
|
|||
if node.mobility:
|
||||
self.session.event_loop.add_event(0.0, node.mobility.startup)
|
||||
|
||||
def config_reset(self, node_id=None):
|
||||
"""
|
||||
Reset all configs.
|
||||
|
||||
:param int node_id: node configuration to reset or None for all configurations
|
||||
:return: nothing
|
||||
"""
|
||||
for model in self._modelclsmap.itervalues():
|
||||
model.config_reset(node_id=node_id)
|
||||
def set_model(self, node, model_class, config=None):
|
||||
logger.info("setting mobility model(%s) for node(%s): %s", model_class.name, node.objid, config)
|
||||
if not config:
|
||||
config = {}
|
||||
self.set_model_config(node.objid, model_class.name, config)
|
||||
config = self.get_model_config(node.objid, model_class.name)
|
||||
node.setmodel(model_class, config)
|
||||
|
||||
def handleevent(self, event_data):
|
||||
"""
|
||||
|
@ -234,6 +277,7 @@ class MobilityManager(object):
|
|||
self.physnets[netnum].append(node_id)
|
||||
|
||||
# TODO: remove need for handling old style message
|
||||
|
||||
def physnodehandlelink(self, message):
|
||||
"""
|
||||
Broker handler. Snoop Link add messages to get
|
||||
|
@ -255,6 +299,7 @@ class MobilityManager(object):
|
|||
self.addphys(nn[0], dummy)
|
||||
|
||||
# TODO: remove need to handling old style messages
|
||||
|
||||
def physnodeupdateposition(self, message):
|
||||
"""
|
||||
Snoop node messages belonging to physical nodes. The dummy object
|
||||
|
@ -303,7 +348,7 @@ class WirelessModel(ConfigurableOptions):
|
|||
bitmap = None
|
||||
position_callback = None
|
||||
|
||||
def __init__(self, session, object_id, config=None):
|
||||
def __init__(self, session, object_id):
|
||||
"""
|
||||
Create a WirelessModel instance.
|
||||
|
||||
|
@ -313,8 +358,6 @@ class WirelessModel(ConfigurableOptions):
|
|||
"""
|
||||
self.session = session
|
||||
self.object_id = object_id
|
||||
if config:
|
||||
self.set_configs(config, node_id=self.object_id)
|
||||
|
||||
def all_link_data(self, flags):
|
||||
"""
|
||||
|
@ -337,15 +380,15 @@ class WirelessModel(ConfigurableOptions):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def updateconfig(self):
|
||||
def update_config(self, config):
|
||||
"""
|
||||
For run-time updates of model config. Returns True when position callback and set link
|
||||
parameters should be invoked.
|
||||
|
||||
:return: False
|
||||
:rtype: bool
|
||||
:param dict config: configuration values to update
|
||||
:return: nothing
|
||||
"""
|
||||
return False
|
||||
pass
|
||||
|
||||
|
||||
class BasicRangeModel(WirelessModel):
|
||||
|
@ -355,7 +398,6 @@ class BasicRangeModel(WirelessModel):
|
|||
the GUI.
|
||||
"""
|
||||
name = "basic_range"
|
||||
configuration_maps = {}
|
||||
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
|
@ -372,7 +414,7 @@ class BasicRangeModel(WirelessModel):
|
|||
def config_groups(cls):
|
||||
return "Basic Range Parameters:1-%d" % len(cls.configurations())
|
||||
|
||||
def __init__(self, session, object_id, config=None):
|
||||
def __init__(self, session, object_id):
|
||||
"""
|
||||
Create a BasicRangeModel instance.
|
||||
|
||||
|
@ -386,17 +428,12 @@ class BasicRangeModel(WirelessModel):
|
|||
self._netifs = {}
|
||||
self._netifslock = threading.Lock()
|
||||
|
||||
# retrieve current configuration
|
||||
config = self.get_configs(node_id=self.object_id)
|
||||
|
||||
self.range = None
|
||||
self.bw = None
|
||||
self.delay = None
|
||||
self.loss = None
|
||||
self.jitter = None
|
||||
|
||||
self.values_from_config(config)
|
||||
|
||||
def values_from_config(self, config):
|
||||
"""
|
||||
Values to convert to link parameters.
|
||||
|
@ -546,15 +583,13 @@ class BasicRangeModel(WirelessModel):
|
|||
c = p1[2] - p2[2]
|
||||
return math.hypot(math.hypot(a, b), c)
|
||||
|
||||
def updateconfig(self):
|
||||
def update_config(self, config):
|
||||
"""
|
||||
Configuration has changed during runtime.
|
||||
|
||||
:param dict config: values to update configuration
|
||||
:return: was update successful
|
||||
:rtype: bool
|
||||
:return: nothing
|
||||
"""
|
||||
config = self.get_configs(node_id=self.object_id)
|
||||
self.values_from_config(config)
|
||||
self.setlinkparams()
|
||||
return True
|
||||
|
@ -655,16 +690,15 @@ class WayPointMobility(WirelessModel):
|
|||
STATE_RUNNING = 1
|
||||
STATE_PAUSED = 2
|
||||
|
||||
def __init__(self, session, object_id, config=None):
|
||||
def __init__(self, session, object_id):
|
||||
"""
|
||||
Create a WayPointMobility instance.
|
||||
|
||||
:param core.session.Session session: CORE session instance
|
||||
:param int object_id: object id
|
||||
:param config: values for this model
|
||||
:return:
|
||||
"""
|
||||
super(WayPointMobility, self).__init__(session=session, object_id=object_id, config=config)
|
||||
super(WayPointMobility, self).__init__(session=session, object_id=object_id)
|
||||
|
||||
self.state = self.STATE_STOPPED
|
||||
self.queue = []
|
||||
|
@ -957,7 +991,6 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
BonnMotion.
|
||||
"""
|
||||
name = "ns2script"
|
||||
configuration_maps = {}
|
||||
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
|
@ -976,7 +1009,7 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
def config_groups(cls):
|
||||
return "ns-2 Mobility Script Parameters:1-%d" % len(cls.configurations())
|
||||
|
||||
def __init__(self, session, object_id, config=None):
|
||||
def __init__(self, session, object_id):
|
||||
"""
|
||||
Creates a Ns2ScriptedMobility instance.
|
||||
|
||||
|
@ -984,14 +1017,22 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
:param int object_id: object id
|
||||
:param config: values
|
||||
"""
|
||||
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id, config=config)
|
||||
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id)
|
||||
self._netifs = {}
|
||||
self._netifslock = threading.Lock()
|
||||
|
||||
# retrieve current configuration
|
||||
config = self.get_configs(self.object_id)
|
||||
self.file = None
|
||||
self.refresh_ms = None
|
||||
self.loop = None
|
||||
self.autostart = None
|
||||
self.nodemap = {}
|
||||
self.script_start = None
|
||||
self.script_pause = None
|
||||
self.script_stop = None
|
||||
|
||||
def update_config(self, config):
|
||||
self.file = config["file"]
|
||||
logger.info("ns-2 scripted mobility configured for WLAN %d using file: %s", self.object_id, self.file)
|
||||
self.refresh_ms = int(config["refresh_ms"])
|
||||
self.loop = config["loop"].lower() == "on"
|
||||
self.autostart = config["autostart"]
|
||||
|
@ -999,7 +1040,6 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
self.script_start = config["script_start"]
|
||||
self.script_pause = config["script_pause"]
|
||||
self.script_stop = config["script_stop"]
|
||||
logger.info("ns-2 scripted mobility configured for WLAN %d using file: %s", object_id, self.file)
|
||||
self.readscriptfile()
|
||||
self.copywaypoints()
|
||||
self.setendtime()
|
||||
|
|
|
@ -377,17 +377,18 @@ class WlanNode(LxBrNet):
|
|||
# invokes any netif.poshook
|
||||
netif.setposition(x, y, z)
|
||||
|
||||
def setmodel(self, model, config=None):
|
||||
def setmodel(self, model, config):
|
||||
"""
|
||||
Sets the mobility and wireless model.
|
||||
|
||||
:param core.mobility.WirelessModel.cls model: wireless model to set to
|
||||
:param dict config: model configuration
|
||||
:param dict config: configuration for model being set
|
||||
:return: nothing
|
||||
"""
|
||||
logger.info("adding model: %s", model.name)
|
||||
if model.config_type == RegisterTlvs.WIRELESS.value:
|
||||
self.model = model(session=self.session, object_id=self.objid, config=config)
|
||||
self.model = model(session=self.session, object_id=self.objid)
|
||||
self.model.update_config(config)
|
||||
if self.model.position_callback:
|
||||
for netif in self.netifs():
|
||||
netif.poshook = self.model.position_callback
|
||||
|
@ -396,7 +397,8 @@ class WlanNode(LxBrNet):
|
|||
netif.poshook(netif, x, y, z)
|
||||
self.model.setlinkparams()
|
||||
elif model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
self.mobility = model(session=self.session, object_id=self.objid, config=config)
|
||||
self.mobility = model(session=self.session, object_id=self.objid)
|
||||
self.mobility.update_config(config)
|
||||
|
||||
def update_mobility(self, config):
|
||||
if not self.mobility:
|
||||
|
|
|
@ -17,6 +17,7 @@ from core import constants
|
|||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.broker import CoreBroker
|
||||
from core.conf import ConfigurableManager
|
||||
from core.conf import ConfigurableOptions
|
||||
from core.conf import Configuration
|
||||
from core.data import EventData
|
||||
|
@ -94,7 +95,8 @@ class Session(object):
|
|||
self.options = SessionConfig()
|
||||
if not config:
|
||||
config = {}
|
||||
self.options.set_configs(config)
|
||||
for key, value in config.iteritems():
|
||||
self.options.set_config(key, value)
|
||||
self.metadata = SessionMetaData()
|
||||
|
||||
# initialize session feature helpers
|
||||
|
@ -1044,7 +1046,7 @@ class Session(object):
|
|||
node.cmd(data, wait=False)
|
||||
|
||||
|
||||
class SessionConfig(ConfigurableOptions):
|
||||
class SessionConfig(ConfigurableManager, ConfigurableOptions):
|
||||
"""
|
||||
Session configuration object.
|
||||
"""
|
||||
|
@ -1075,10 +1077,12 @@ class SessionConfig(ConfigurableOptions):
|
|||
return "Options:1-%d" % len(cls.configurations())
|
||||
|
||||
def __init__(self):
|
||||
self.set_configs()
|
||||
super(SessionConfig, self).__init__()
|
||||
self.set_configs(self.default_values())
|
||||
|
||||
def get_config(cls, _id, node_id=ConfigurableOptions._default_node, default=None):
|
||||
value = super(SessionConfig, cls).get_config(_id, node_id, default)
|
||||
def get_config(self, _id, node_id=ConfigurableManager._default_node,
|
||||
config_type=ConfigurableManager._default_type, default=None):
|
||||
value = super(SessionConfig, self).get_config(_id, node_id, config_type, default)
|
||||
if value == "":
|
||||
value = default
|
||||
return value
|
||||
|
@ -1096,7 +1100,7 @@ class SessionConfig(ConfigurableOptions):
|
|||
return value
|
||||
|
||||
|
||||
class SessionMetaData(ConfigurableOptions):
|
||||
class SessionMetaData(ConfigurableManager):
|
||||
"""
|
||||
Metadata is simply stored in a configs[] dict. Key=value pairs are
|
||||
passed in from configure messages destined to the "metadata" object.
|
||||
|
|
|
@ -72,7 +72,12 @@ class CoreDocumentParser0(object):
|
|||
"""
|
||||
Helper to return tuple of attributes common to nodes and nets.
|
||||
"""
|
||||
node_id = int(obj.getAttribute("id"))
|
||||
node_id = obj.getAttribute("id")
|
||||
try:
|
||||
node_id = int(node_id)
|
||||
except:
|
||||
logger.debug("parsing node without integer id: %s", node_id)
|
||||
|
||||
name = str(obj.getAttribute("name"))
|
||||
node_type = str(obj.getAttribute("type"))
|
||||
return node_id, name, node_type
|
||||
|
@ -205,7 +210,8 @@ class CoreDocumentParser0(object):
|
|||
|
||||
# TODO: assign other config managers here
|
||||
if mgr:
|
||||
mgr.setconfig_keyvalues(nodenum, name, kvs)
|
||||
for k, v in kvs:
|
||||
mgr.set_config(k, v, node_id=nodenum, config_type=name)
|
||||
|
||||
def parsenetem(self, model, obj, kvs):
|
||||
"""
|
||||
|
@ -218,7 +224,6 @@ class CoreDocumentParser0(object):
|
|||
# nodes and interfaces do not exist yet, at this point of the parsing,
|
||||
# save (key, value) pairs for later
|
||||
try:
|
||||
# kvs = map(lambda(k, v): (int(v)), kvs)
|
||||
kvs = map(self.numericvalue, kvs)
|
||||
except ValueError:
|
||||
logger.warn("error parsing link parameters for '%s' on '%s'", ifname, peer)
|
||||
|
@ -394,7 +399,7 @@ class CoreDocumentParser0(object):
|
|||
v = str(param.getAttribute("value"))
|
||||
if v == '':
|
||||
v = xmlutils.get_text_child(param) # allow attribute/text for newlines
|
||||
setattr(self.session.options, k, v)
|
||||
self.session.options.set_config(k, v)
|
||||
hooks = xmlutils.get_one_element(self.meta, "Hooks")
|
||||
if hooks:
|
||||
self.parsehooks(hooks)
|
||||
|
@ -405,4 +410,4 @@ class CoreDocumentParser0(object):
|
|||
v = str(param.getAttribute("value"))
|
||||
if v == '':
|
||||
v = xmlutils.get_text_child(param)
|
||||
self.session.metadata.add_item(k, v)
|
||||
self.session.metadata.set_config(k, v)
|
||||
|
|
|
@ -210,12 +210,11 @@ class CoreDocumentParser1(object):
|
|||
raise NotImplementedError
|
||||
logger.info("setting wireless link params: node(%s) model(%s) mobility_model(%s)",
|
||||
nodenum, model_name, mobility_model_name)
|
||||
model_class = mgr.get_model_class(model_name)
|
||||
model_class.set_configs(link_params, node_id=nodenum)
|
||||
mgr.set_model_config(node_id=nodenum, model_name=model_name, config=link_params)
|
||||
|
||||
if mobility_model_name and mobility_params:
|
||||
model_class = mgr.get_model_class(mobility_model_name)
|
||||
model_class.set_configs(mobility_params, node_id=nodenum)
|
||||
self.session.mobility.set_model_config(node_id=nodenum, model_name=mobility_model_name,
|
||||
config=mobility_params)
|
||||
|
||||
def link_layer2_devices(self, device1, ifname1, device2, ifname2):
|
||||
"""
|
||||
|
|
|
@ -6,7 +6,7 @@ import pwd
|
|||
from core import logger
|
||||
from core.coreobj import PyCoreNet
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.enumerations import RegisterTlvs
|
||||
from core.enumerations import RegisterTlvs, EventTypes
|
||||
from core.xml import xmlutils
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ class CoreDocumentWriter0(Document):
|
|||
self.populatefromsession()
|
||||
|
||||
def populatefromsession(self):
|
||||
if self.session.state != EventTypes.RUNTIME_STATE.value:
|
||||
self.session.emane.setup() # not during runtime?
|
||||
self.addorigin()
|
||||
self.adddefaultservices()
|
||||
|
@ -136,14 +137,14 @@ class CoreDocumentWriter0(Document):
|
|||
for m, conf in configs:
|
||||
model = self.createElement("model")
|
||||
n.appendChild(model)
|
||||
model.setAttribute("name", m._name)
|
||||
model.setAttribute("name", m.name)
|
||||
type = "wireless"
|
||||
if m._type == RegisterTlvs.MOBILITY.value:
|
||||
if m.config_type == RegisterTlvs.MOBILITY.value:
|
||||
type = "mobility"
|
||||
model.setAttribute("type", type)
|
||||
for i, k in enumerate(m.getnames()):
|
||||
|
||||
for k, value in conf.iteritems():
|
||||
key = self.createElement(k)
|
||||
value = conf[i]
|
||||
if value is None:
|
||||
value = ""
|
||||
key.appendChild(self.createTextNode("%s" % value))
|
||||
|
@ -193,8 +194,8 @@ class CoreDocumentWriter0(Document):
|
|||
# could use ifc.params, transport_type
|
||||
self.addaddresses(i, ifc)
|
||||
# per-interface models
|
||||
if netmodel and netmodel._name[:6] == "emane_":
|
||||
cfg = netmodel.getifcconfig(node.objid, ifc)
|
||||
if netmodel and netmodel.name[:6] == "emane_":
|
||||
cfg = self.session.emane.getifcconfig(node.objid, ifc, netmodel.name)
|
||||
if cfg:
|
||||
self.addmodels(i, ((netmodel, cfg),))
|
||||
|
||||
|
|
|
@ -654,7 +654,7 @@ class DeviceElement(NamedXmlElement):
|
|||
# per-interface models
|
||||
# XXX Remove???
|
||||
if netmodel and netmodel.name[:6] == "emane_":
|
||||
cfg = netmodel.getifcconfig(device_object.objid, interface_object)
|
||||
cfg = self.coreSession.emane.getifcconfig(device_object.objid, interface_object, netmodel.name)
|
||||
if cfg:
|
||||
interface_element.addModels(((netmodel, cfg),))
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ def example(options):
|
|||
|
||||
# create wlan network node
|
||||
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
wlan.setmodel(BasicRangeModel)
|
||||
session.mobility.set_model(wlan, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
wireless_nodes = []
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from core.conf import ConfigurableOptions
|
||||
from core.conf import ConfigurableOptions, ConfigurableManager
|
||||
from core.conf import Configuration
|
||||
from core.enumerations import ConfigDataTypes
|
||||
|
||||
|
@ -43,7 +43,7 @@ class TestConf:
|
|||
|
||||
def test_nodes(self):
|
||||
# given
|
||||
config_manager = TestConfigurableOptions()
|
||||
config_manager = ConfigurableManager()
|
||||
test_config = {1: 2}
|
||||
node_id = 1
|
||||
config_manager.set_configs(test_config)
|
||||
|
@ -58,7 +58,7 @@ class TestConf:
|
|||
|
||||
def test_config_reset_all(self):
|
||||
# given
|
||||
config_manager = TestConfigurableOptions()
|
||||
config_manager = ConfigurableManager()
|
||||
test_config = {1: 2}
|
||||
node_id = 1
|
||||
config_manager.set_configs(test_config)
|
||||
|
@ -68,11 +68,11 @@ class TestConf:
|
|||
config_manager.config_reset()
|
||||
|
||||
# then
|
||||
assert not config_manager.configuration_maps
|
||||
assert not config_manager._configuration_maps
|
||||
|
||||
def test_config_reset_node(self):
|
||||
# given
|
||||
config_manager = TestConfigurableOptions()
|
||||
config_manager = ConfigurableManager()
|
||||
test_config = {1: 2}
|
||||
node_id = 1
|
||||
config_manager.set_configs(test_config)
|
||||
|
@ -82,12 +82,12 @@ class TestConf:
|
|||
config_manager.config_reset(node_id)
|
||||
|
||||
# then
|
||||
assert node_id not in config_manager.configuration_maps
|
||||
assert node_id not in config_manager._configuration_maps
|
||||
assert config_manager.get_configs()
|
||||
|
||||
def test_configs_setget(self):
|
||||
# given
|
||||
config_manager = TestConfigurableOptions()
|
||||
config_manager = ConfigurableManager()
|
||||
test_config = {1: 2}
|
||||
node_id = 1
|
||||
config_manager.set_configs(test_config)
|
||||
|
@ -103,7 +103,7 @@ class TestConf:
|
|||
|
||||
def test_config_setget(self):
|
||||
# given
|
||||
config_manager = TestConfigurableOptions()
|
||||
config_manager = ConfigurableManager()
|
||||
name = "test"
|
||||
value = "1"
|
||||
node_id = 1
|
||||
|
|
|
@ -5,24 +5,21 @@ Unit tests for testing basic CORE networks.
|
|||
import os
|
||||
import stat
|
||||
import threading
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import pytest
|
||||
from mock import MagicMock
|
||||
|
||||
from core.emulator.emudata import NodeOptions
|
||||
from core.enumerations import MessageFlags, NodeTypes
|
||||
from core.mobility import BasicRangeModel, Ns2ScriptedMobility
|
||||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import NodeTypes
|
||||
from core.mobility import BasicRangeModel
|
||||
from core.mobility import Ns2ScriptedMobility
|
||||
from core.netns.vnodeclient import VnodeClient
|
||||
from core.service import ServiceManager
|
||||
|
||||
_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
_SERVICES_PATH = os.path.join(_PATH, "myservices")
|
||||
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
|
||||
_XML_VERSIONS = [
|
||||
"0.0",
|
||||
"1.0"
|
||||
]
|
||||
_WIRED = [
|
||||
NodeTypes.PEER_TO_PEER,
|
||||
NodeTypes.HUB,
|
||||
|
@ -93,60 +90,6 @@ class TestCore:
|
|||
status = ping(node_one, node_two, ip_prefixes)
|
||||
assert not status
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml(self, session, tmpdir, version, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods.
|
||||
|
||||
: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_one = session.add_node()
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# verify nodes have been recreated
|
||||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
|
||||
def test_vnode_client(self, session, ip_prefixes):
|
||||
"""
|
||||
Test vnode client methods.
|
||||
|
@ -257,7 +200,7 @@ class TestCore:
|
|||
|
||||
# create wlan
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
wlan_node.setmodel(BasicRangeModel)
|
||||
session.mobility.set_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
node_options = NodeOptions()
|
||||
|
@ -290,7 +233,7 @@ class TestCore:
|
|||
|
||||
# create wlan
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
wlan_node.setmodel(BasicRangeModel)
|
||||
session.mobility.set_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
node_options = NodeOptions()
|
||||
|
@ -317,7 +260,7 @@ class TestCore:
|
|||
"script_pause": "",
|
||||
"script_stop": "",
|
||||
}
|
||||
wlan_node.setmodel(Ns2ScriptedMobility, config)
|
||||
session.mobility.set_model(wlan_node, Ns2ScriptedMobility, config)
|
||||
|
||||
# add handler for receiving node updates
|
||||
event = threading.Event()
|
||||
|
|
203
daemon/tests/test_xml.py
Normal file
203
daemon/tests/test_xml.py
Normal file
|
@ -0,0 +1,203 @@
|
|||
from xml.etree import ElementTree
|
||||
|
||||
import pytest
|
||||
|
||||
from core.emane.ieee80211abg import EmaneIeee80211abgModel
|
||||
from core.emulator.emudata import NodeOptions
|
||||
from core.enumerations import NodeTypes
|
||||
from core.mobility import BasicRangeModel
|
||||
|
||||
_XML_VERSIONS = [
|
||||
"0.0",
|
||||
"1.0"
|
||||
]
|
||||
|
||||
|
||||
class TestXml:
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_ptp(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_one = session.add_node()
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# verify nodes have been recreated
|
||||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_mobility(self, session, tmpdir, version, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for mobility.
|
||||
|
||||
: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 wlan
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
session.mobility.set_model(wlan_node, BasicRangeModel, {"test": "1"})
|
||||
|
||||
# create nodes
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(0, 0)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
# link nodes
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
|
||||
|
||||
# link nodes in wlan
|
||||
session.wireless_link_all(wlan_node, [node_one, node_two])
|
||||
|
||||
# instantiate session
|
||||
session.instantiate()
|
||||
|
||||
# get ids for nodes
|
||||
wlan_id = wlan_node.objid
|
||||
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 configuration we set originally
|
||||
value = str(session.mobility.get_config("test", wlan_id, BasicRangeModel.name))
|
||||
|
||||
# verify nodes and configuration were restored
|
||||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
assert session.get_object(wlan_id)
|
||||
assert value == "1"
|
||||
|
||||
@pytest.mark.parametrize("version", ["1.0"])
|
||||
def test_xml_emane(self, session, tmpdir, version, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for emane.
|
||||
|
||||
: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 emane node for networking the core nodes
|
||||
emane_network = session.create_emane_network(
|
||||
EmaneIeee80211abgModel,
|
||||
geo_reference=(47.57917, -122.13232, 2.00000),
|
||||
config={"test": "1"}
|
||||
)
|
||||
emane_network.setposition(x=80, y=50)
|
||||
|
||||
# create nodes
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(150, 150)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_options.set_position(300, 150)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
for i, node in enumerate([node_one, node_two]):
|
||||
node.setposition(x=150 * (i + 1), y=150)
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, emane_network.objid, interface_one=interface)
|
||||
|
||||
# instantiate session
|
||||
session.instantiate()
|
||||
|
||||
# get ids for nodes
|
||||
emane_id = emane_network.objid
|
||||
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 configuration we set originally
|
||||
value = str(session.emane.get_config("test", emane_id, EmaneIeee80211abgModel.name))
|
||||
|
||||
# verify nodes and configuration were restored
|
||||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
assert session.get_object(emane_id)
|
||||
assert value == "1"
|
Loading…
Reference in a new issue