refactored configs back to be able to provide instance conifgurations for sessions

This commit is contained in:
Blake J. Harnden 2018-06-13 11:59:50 -07:00
parent eb415aa4d4
commit 3a39432fc7
22 changed files with 560 additions and 319 deletions

View file

@ -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())

View file

@ -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)

View file

@ -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"}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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]

View file

@ -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):

View file

@ -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()

View file

@ -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:

View file

@ -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.

View file

@ -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)

View file

@ -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):
"""

View file

@ -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),))

View file

@ -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),))

View file

@ -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 = []

View file

@ -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

View file

@ -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
View 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"