added modelmanager for both mobility and emane to leverage and reduce duplicate logic
This commit is contained in:
parent
a52e454111
commit
25cfb21586
5 changed files with 171 additions and 192 deletions
|
@ -265,3 +265,87 @@ class ConfigurableOptions(object):
|
|||
:rtype: OrderedDict
|
||||
"""
|
||||
return OrderedDict([(config.id, config.default) for config in cls.configurations()])
|
||||
|
||||
|
||||
class ModelManager(ConfigurableManager):
|
||||
def __init__(self):
|
||||
super(ModelManager, self).__init__()
|
||||
self.models = {}
|
||||
self.node_models = {}
|
||||
|
||||
def set_model_config(self, node_id, model_name, config=None):
|
||||
"""
|
||||
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.models.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)
|
||||
if not config:
|
||||
config = {}
|
||||
for key, value in config.iteritems():
|
||||
node_config[key] = value
|
||||
|
||||
# set as node model for startup
|
||||
self.node_models[node_id] = model_name
|
||||
|
||||
# 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.models.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 set_model(self, node, model_class, config=None):
|
||||
logger.info("setting mobility model(%s) for node(%s): %s", model_class.name, node.objid, 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 getmodels(self, node):
|
||||
"""
|
||||
Return a list of model classes and values for a net if one has been
|
||||
configured. This is invoked when exporting a session to XML.
|
||||
|
||||
:param node: network node to get models for
|
||||
:return: list of model and values tuples for the network node
|
||||
:rtype: list
|
||||
"""
|
||||
models = []
|
||||
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.models[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
|
||||
|
|
|
@ -42,8 +42,6 @@ from core.enumerations import SessionTlvs
|
|||
from core.misc import nodeutils
|
||||
from core.misc import structutils
|
||||
from core.misc import utils
|
||||
from core.mobility import BasicRangeModel
|
||||
from core.mobility import Ns2ScriptedMobility
|
||||
from core.service import CoreService
|
||||
from core.service import ServiceManager
|
||||
|
||||
|
@ -380,13 +378,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.broker.config_type, self.session.broker.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.location.config_type, self.session.location.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.mobility.config_type, self.session.mobility.name)
|
||||
for model_name in self.session.mobility.mobility_models():
|
||||
model_class = self.session.mobility.get_model_class(model_name)
|
||||
for model_class in self.session.mobility.models.itervalues():
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.services.config_type, self.session.services.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.emane.config_type, self.session.emane.name)
|
||||
for model_name in self.session.emane.emane_models():
|
||||
model_class = self.session.emane.get_model_class(model_name)
|
||||
for model_class in self.session.emane.models.itervalues():
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(model_class.config_type, model_class.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.options.config_type, self.session.options.name)
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(self.session.metadata.config_type, self.session.metadata.name)
|
||||
|
@ -937,11 +933,11 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
replies = self.handle_config_services(message_type, config_data)
|
||||
elif config_data.object == self.session.mobility.name:
|
||||
self.handle_config_mobility(message_type, config_data)
|
||||
elif config_data.object in [BasicRangeModel.name, Ns2ScriptedMobility.name]:
|
||||
elif config_data.object in self.session.mobility.models:
|
||||
replies = self.handle_config_mobility_models(message_type, config_data)
|
||||
elif config_data.object == self.session.emane.name:
|
||||
replies = self.handle_config_emane(message_type, config_data)
|
||||
elif config_data.object in self.session.emane.emane_models():
|
||||
elif config_data.object in self.session.emane.models:
|
||||
replies = self.handle_config_emane_models(message_type, config_data)
|
||||
else:
|
||||
raise Exception("no handler for configuration: %s", config_data.object)
|
||||
|
@ -1181,7 +1177,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.info("replying to configure request for model: %s", object_name)
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
|
||||
model_class = self.session.mobility.get_model_class(object_name)
|
||||
model_class = self.session.mobility.models.get(object_name)
|
||||
if not model_class:
|
||||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
@ -1251,7 +1247,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
logger.info("replying to configure request for model: %s", object_name)
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
|
||||
model_class = self.session.emane.get_model_class(object_name)
|
||||
model_class = self.session.emane.models.get(object_name)
|
||||
if not model_class:
|
||||
logger.warn("model class does not exist: %s", object_name)
|
||||
return []
|
||||
|
|
|
@ -11,8 +11,9 @@ from core import constants
|
|||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.api import dataconversion
|
||||
from core.conf import ConfigShim, ConfigurableManager
|
||||
from core.conf import ConfigShim
|
||||
from core.conf import Configuration
|
||||
from core.conf import ModelManager
|
||||
from core.emane import emanemanifest
|
||||
from core.emane.bypass import EmaneBypassModel
|
||||
from core.emane.commeffect import EmaneCommEffectModel
|
||||
|
@ -53,7 +54,7 @@ EMANE_MODELS = [
|
|||
]
|
||||
|
||||
|
||||
class EmaneManager(ConfigurableManager):
|
||||
class EmaneManager(ModelManager):
|
||||
"""
|
||||
EMANE controller object. Lives in a Session instance and is used for
|
||||
building EMANE config files from all of the EmaneNode objects in this
|
||||
|
@ -89,64 +90,11 @@ class EmaneManager(ConfigurableManager):
|
|||
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 = {}
|
||||
|
||||
session.broker.handlers.add(self.handledistributed)
|
||||
self.service = None
|
||||
self.event_device = None
|
||||
self._modelclsmap = {}
|
||||
|
||||
self.service = None
|
||||
self.emane_check()
|
||||
|
||||
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
|
||||
|
||||
# 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 getifcconfig(self, node_id, interface, model_name):
|
||||
"""
|
||||
Retrieve interface configuration or node configuration if not provided.
|
||||
|
@ -189,24 +137,10 @@ class EmaneManager(ConfigurableManager):
|
|||
|
||||
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()
|
||||
|
||||
def get_model_class(self, model_name):
|
||||
return self._modelclsmap[model_name]
|
||||
|
||||
def emane_check(self):
|
||||
"""
|
||||
Check if emane is installed and load models.
|
||||
|
@ -281,7 +215,7 @@ class EmaneManager(ConfigurableManager):
|
|||
"""
|
||||
for emane_model in emane_models:
|
||||
logger.info("loading emane model: %s", emane_model.__name__)
|
||||
self._modelclsmap[emane_model.name] = emane_model
|
||||
self.models[emane_model.name] = emane_model
|
||||
|
||||
def add_node(self, emane_node):
|
||||
"""
|
||||
|
@ -307,22 +241,6 @@ class EmaneManager(ConfigurableManager):
|
|||
nodes.add(netif.node)
|
||||
return nodes
|
||||
|
||||
def getmodels(self, node):
|
||||
"""
|
||||
Used with XML export.
|
||||
"""
|
||||
models = []
|
||||
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 for node(%s): %s", node.objid, models)
|
||||
return models
|
||||
|
||||
def setup(self):
|
||||
"""
|
||||
Populate self._objs with EmaneNodes; perform distributed setup;
|
||||
|
@ -650,7 +568,7 @@ class EmaneManager(ConfigurableManager):
|
|||
|
||||
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]
|
||||
model_class = self.models[model_name]
|
||||
emane_node.setmodel(model_class, config)
|
||||
|
||||
def nemlookup(self, nemid):
|
||||
|
|
|
@ -9,8 +9,9 @@ import threading
|
|||
import time
|
||||
|
||||
from core import logger
|
||||
from core.conf import ConfigurableOptions, ConfigurableManager
|
||||
from core.conf import ConfigurableOptions
|
||||
from core.conf import Configuration
|
||||
from core.conf import ModelManager
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.data import EventData
|
||||
from core.data import LinkData
|
||||
|
@ -25,7 +26,7 @@ from core.misc import utils
|
|||
from core.misc.ipaddress import IpAddress
|
||||
|
||||
|
||||
class MobilityManager(ConfigurableManager):
|
||||
class MobilityManager(ModelManager):
|
||||
"""
|
||||
Member of session class for handling configuration data for mobility and
|
||||
range models.
|
||||
|
@ -41,90 +42,14 @@ class MobilityManager(ConfigurableManager):
|
|||
"""
|
||||
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
|
||||
self._modelclsmap = {
|
||||
BasicRangeModel.name: BasicRangeModel,
|
||||
Ns2ScriptedMobility.name: Ns2ScriptedMobility
|
||||
}
|
||||
self.models[BasicRangeModel.name] = BasicRangeModel
|
||||
self.models[Ns2ScriptedMobility.name] = Ns2ScriptedMobility
|
||||
|
||||
# dummy node objects for tracking position of nodes on other servers
|
||||
self.phys = {}
|
||||
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()
|
||||
|
||||
def get_model_class(self, model_name):
|
||||
return self._modelclsmap[model_name]
|
||||
|
||||
def getmodels(self, node):
|
||||
"""
|
||||
Return a list of model classes and values for a net if one has been
|
||||
configured. This is invoked when exporting a session to XML.
|
||||
|
||||
:param node: network node to get models for
|
||||
:return: list of model and values tuples for the network node
|
||||
:rtype: list
|
||||
"""
|
||||
models = []
|
||||
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("mobility models for node(%s): %s", node.objid, models)
|
||||
return models
|
||||
|
||||
def startup(self, node_ids=None):
|
||||
"""
|
||||
Session is transitioning from instantiation to runtime state.
|
||||
|
@ -146,11 +71,11 @@ class MobilityManager(ConfigurableManager):
|
|||
logger.warn("skipping mobility configuration for unknown node: %s", node_id)
|
||||
continue
|
||||
|
||||
for model_name in self._modelclsmap.iterkeys():
|
||||
for model_name in self.models.iterkeys():
|
||||
config = self.get_configs(node_id=node_id, config_type=model_name)
|
||||
if not config:
|
||||
continue
|
||||
model_class = self._modelclsmap[model_name]
|
||||
model_class = self.models[model_name]
|
||||
self.set_model(node, model_class, config)
|
||||
|
||||
if self.session.master:
|
||||
|
@ -159,14 +84,6 @@ class MobilityManager(ConfigurableManager):
|
|||
if node.mobility:
|
||||
self.session.event_loop.add_event(0.0, node.mobility.startup)
|
||||
|
||||
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):
|
||||
"""
|
||||
Handle an Event Message used to start, stop, or pause
|
||||
|
@ -189,7 +106,7 @@ class MobilityManager(ConfigurableManager):
|
|||
models = name[9:].split(',')
|
||||
for model in models:
|
||||
try:
|
||||
cls = self._modelclsmap[model]
|
||||
cls = self.models[model]
|
||||
except KeyError:
|
||||
logger.warn("Ignoring event for unknown model '%s'", model)
|
||||
continue
|
||||
|
@ -299,7 +216,6 @@ class MobilityManager(ConfigurableManager):
|
|||
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
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
from core.conf import ConfigurableOptions, ConfigurableManager
|
||||
import pytest
|
||||
|
||||
from core.conf import ConfigurableOptions, ConfigurableManager, ModelManager
|
||||
from core.conf import Configuration
|
||||
from core.enumerations import ConfigDataTypes
|
||||
from core.emane.ieee80211abg import EmaneIeee80211abgModel
|
||||
from core.enumerations import ConfigDataTypes, NodeTypes
|
||||
from core.mobility import BasicRangeModel
|
||||
|
||||
|
||||
class TestConfigurableOptions(ConfigurableOptions):
|
||||
|
@ -117,3 +121,64 @@ class TestConf:
|
|||
# then
|
||||
assert defaults_value == value
|
||||
assert node_value == value
|
||||
|
||||
def test_model_setget_config(self):
|
||||
# given
|
||||
manager = ModelManager()
|
||||
manager.models[BasicRangeModel.name] = BasicRangeModel
|
||||
|
||||
# when
|
||||
manager.set_model_config(1, BasicRangeModel.name)
|
||||
|
||||
# then
|
||||
assert manager.get_model_config(1, BasicRangeModel.name)
|
||||
|
||||
def test_model_set_config_error(self):
|
||||
# given
|
||||
manager = ModelManager()
|
||||
manager.models[BasicRangeModel.name] = BasicRangeModel
|
||||
bad_name = "bad-model"
|
||||
|
||||
# when/then
|
||||
with pytest.raises(ValueError):
|
||||
manager.set_model_config(1, bad_name)
|
||||
|
||||
def test_model_get_config_error(self):
|
||||
# given
|
||||
manager = ModelManager()
|
||||
manager.models[BasicRangeModel.name] = BasicRangeModel
|
||||
bad_name = "bad-model"
|
||||
|
||||
# when/then
|
||||
with pytest.raises(ValueError):
|
||||
manager.get_model_config(1, bad_name)
|
||||
|
||||
def test_model_set(self, session):
|
||||
# given
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
|
||||
# when
|
||||
session.mobility.set_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# then
|
||||
assert session.mobility.get_model_config(wlan_node.objid, BasicRangeModel.name)
|
||||
|
||||
def test_model_set_error(self, session):
|
||||
# given
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
|
||||
# when / then
|
||||
with pytest.raises(ValueError):
|
||||
session.mobility.set_model(wlan_node, EmaneIeee80211abgModel)
|
||||
|
||||
def test_get_models(self, session):
|
||||
# given
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
session.mobility.set_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# when
|
||||
models = session.mobility.getmodels(wlan_node)
|
||||
|
||||
# then
|
||||
assert models
|
||||
assert len(models) == 1
|
||||
|
|
Loading…
Add table
Reference in a new issue