initial commit with things working for the most part
This commit is contained in:
parent
c1b6747a26
commit
2ede43e3ae
21 changed files with 1018 additions and 1397 deletions
|
@ -11,7 +11,6 @@ import threading
|
|||
|
||||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.conf import ConfigurableManager
|
||||
from core.coreobj import PyCoreNet
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.enumerations import ConfigDataTypes
|
||||
|
@ -81,7 +80,7 @@ class CoreDistributedServer(object):
|
|||
self.sock = None
|
||||
|
||||
|
||||
class CoreBroker(ConfigurableManager):
|
||||
class CoreBroker(object):
|
||||
"""
|
||||
Helps with brokering messages between CORE daemon servers.
|
||||
"""
|
||||
|
@ -100,7 +99,7 @@ class CoreBroker(ConfigurableManager):
|
|||
:return: nothing
|
||||
"""
|
||||
|
||||
ConfigurableManager.__init__(self)
|
||||
# ConfigurableManager.__init__(self)
|
||||
self.session = session
|
||||
self.session_clients = []
|
||||
self.session_id_master = None
|
||||
|
@ -611,62 +610,6 @@ class CoreBroker(ConfigurableManager):
|
|||
"""
|
||||
self.physical_nodes.add(nodenum)
|
||||
|
||||
def configure_reset(self, config_data):
|
||||
"""
|
||||
Ignore reset messages, because node delete responses may still
|
||||
arrive and require the use of nodecounts.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: nothing
|
||||
"""
|
||||
return None
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Receive configuration message with a list of server:host:port
|
||||
combinations that we"ll need to connect with.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: nothing
|
||||
"""
|
||||
values = config_data.data_values
|
||||
session_id = config_data.session
|
||||
|
||||
if values is None:
|
||||
logger.info("emulation server data missing")
|
||||
return None
|
||||
values = values.split("|")
|
||||
|
||||
# string of "server:ip:port,server:ip:port,..."
|
||||
server_strings = values[0]
|
||||
server_list = server_strings.split(",")
|
||||
|
||||
for server in server_list:
|
||||
server_items = server.split(":")
|
||||
(name, host, port) = server_items[:3]
|
||||
|
||||
if host == "":
|
||||
host = None
|
||||
|
||||
if port == "":
|
||||
port = None
|
||||
else:
|
||||
port = int(port)
|
||||
|
||||
if session_id is not None:
|
||||
# receive session ID and my IP from master
|
||||
self.session_id_master = int(session_id.split("|")[0])
|
||||
self.myip = host
|
||||
host = None
|
||||
port = None
|
||||
|
||||
# this connects to the server immediately; maybe we should wait
|
||||
# or spin off a new "client" thread here
|
||||
self.addserver(name, host, port)
|
||||
self.setupserver(name)
|
||||
|
||||
return None
|
||||
|
||||
def handle_message(self, message):
|
||||
"""
|
||||
Handle an API message. Determine whether this needs to be handled
|
||||
|
@ -733,6 +676,7 @@ class CoreBroker(ConfigurableManager):
|
|||
if server is None:
|
||||
logger.warn("ignoring unknown server: %s", servername)
|
||||
return
|
||||
|
||||
if server.sock is None or server.host is None or server.port is None:
|
||||
logger.info("ignoring disconnected server: %s", servername)
|
||||
return
|
||||
|
|
|
@ -2,384 +2,24 @@
|
|||
Common support for configurable CORE objects.
|
||||
"""
|
||||
|
||||
import string
|
||||
from collections import OrderedDict
|
||||
|
||||
from core import logger
|
||||
from core.data import ConfigData
|
||||
from core.enumerations import ConfigDataTypes
|
||||
from core.enumerations import ConfigFlags
|
||||
|
||||
|
||||
class ConfigurableManager(object):
|
||||
"""
|
||||
A generic class for managing Configurables. This class can register
|
||||
with a session to receive Config Messages for setting some parameters
|
||||
for itself or for the Configurables that it manages.
|
||||
"""
|
||||
# name corresponds to configuration object field
|
||||
name = ""
|
||||
|
||||
# type corresponds with register message types
|
||||
config_type = None
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Creates a ConfigurableManager instance.
|
||||
"""
|
||||
# configurable key=values, indexed by node number
|
||||
self.configs = {}
|
||||
|
||||
# TODO: fix the need for this and isolate to the mobility class that wants it
|
||||
self._modelclsmap = {}
|
||||
|
||||
def configure(self, session, config_data):
|
||||
"""
|
||||
Handle configure messages. The configuration message sent to a
|
||||
ConfigurableManager usually is used to:
|
||||
1. Request a list of Configurables (request flag)
|
||||
2. Reset manager and clear configs (reset flag)
|
||||
3. Send values that configure the manager or one of its Configurables
|
||||
|
||||
:param core.session.Session session: CORE session object
|
||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: response messages
|
||||
"""
|
||||
|
||||
if config_data.type == ConfigFlags.REQUEST.value:
|
||||
return self.configure_request(config_data)
|
||||
elif config_data.type == ConfigFlags.RESET.value:
|
||||
return self.configure_reset(config_data)
|
||||
else:
|
||||
return self.configure_values(config_data)
|
||||
|
||||
def configure_request(self, config_data):
|
||||
"""
|
||||
Request configuration data.
|
||||
|
||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: nothing
|
||||
"""
|
||||
return None
|
||||
|
||||
def configure_reset(self, config_data):
|
||||
"""
|
||||
By default, resets this manager to clear configs.
|
||||
|
||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: reset response messages, or None
|
||||
"""
|
||||
return self.reset()
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Values have been sent to this manager.
|
||||
|
||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: nothing
|
||||
"""
|
||||
return None
|
||||
|
||||
def configure_values_keyvalues(self, config_data, target, keys):
|
||||
"""
|
||||
Helper that can be used for configure_values for parsing in
|
||||
'key=value' strings from a values field. The key name must be
|
||||
in the keys list, and target.key=value is set.
|
||||
|
||||
:param ConfigData config_data: configuration data for carrying out a configuration
|
||||
:param target: target to set attribute values on
|
||||
:param keys: list of keys to verify validity
|
||||
:return: nothing
|
||||
"""
|
||||
values = config_data.data_values
|
||||
|
||||
if values is None:
|
||||
return None
|
||||
|
||||
kvs = values.split('|')
|
||||
for kv in kvs:
|
||||
try:
|
||||
key, value = kv.split('=', 1)
|
||||
if value is not None and not value.strip():
|
||||
value = None
|
||||
except ValueError:
|
||||
# value only
|
||||
key = keys[kvs.index(kv)]
|
||||
value = kv
|
||||
if key not in keys:
|
||||
raise ValueError("invalid key: %s" % key)
|
||||
if value is not None:
|
||||
setattr(target, key, value)
|
||||
|
||||
return None
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset functionality for the configurable class.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
return None
|
||||
|
||||
def setconfig(self, nodenum, conftype, values):
|
||||
"""
|
||||
Add configuration values for a node to a dictionary; values are
|
||||
usually received from a Configuration Message, and may refer to a
|
||||
node for which no object exists yet
|
||||
|
||||
:param int nodenum: node id
|
||||
:param conftype: configuration types
|
||||
:param values: configuration values
|
||||
:return: nothing
|
||||
"""
|
||||
logger.info("setting config for node(%s): %s - %s", nodenum, conftype, values)
|
||||
conflist = []
|
||||
if nodenum in self.configs:
|
||||
oldlist = self.configs[nodenum]
|
||||
found = False
|
||||
for t, v in oldlist:
|
||||
if t == conftype:
|
||||
# replace existing config
|
||||
found = True
|
||||
conflist.append((conftype, values))
|
||||
else:
|
||||
conflist.append((t, v))
|
||||
if not found:
|
||||
conflist.append((conftype, values))
|
||||
else:
|
||||
conflist.append((conftype, values))
|
||||
self.configs[nodenum] = conflist
|
||||
|
||||
def getconfig(self, nodenum, conftype, defaultvalues):
|
||||
"""
|
||||
Get configuration values for a node; if the values don't exist in
|
||||
our dictionary then return the default values supplied
|
||||
|
||||
:param int nodenum: node id
|
||||
:param conftype: configuration type
|
||||
:param defaultvalues: default values
|
||||
:return: configuration type and default values
|
||||
:type: tuple
|
||||
"""
|
||||
logger.info("getting config for node(%s): %s - default(%s)",
|
||||
nodenum, conftype, defaultvalues)
|
||||
if nodenum in self.configs:
|
||||
# return configured values
|
||||
conflist = self.configs[nodenum]
|
||||
for t, v in conflist:
|
||||
if conftype is None or t == conftype:
|
||||
return t, v
|
||||
# return default values provided (may be None)
|
||||
return conftype, defaultvalues
|
||||
|
||||
def getallconfigs(self, use_clsmap=True):
|
||||
"""
|
||||
Return (nodenum, conftype, values) tuples for all stored configs.
|
||||
Used when reconnecting to a session.
|
||||
|
||||
:param bool use_clsmap: should a class map be used, default to True
|
||||
:return: list of all configurations
|
||||
:rtype: list
|
||||
"""
|
||||
r = []
|
||||
for nodenum in self.configs:
|
||||
for t, v in self.configs[nodenum]:
|
||||
if use_clsmap:
|
||||
t = self._modelclsmap[t]
|
||||
r.append((nodenum, t, v))
|
||||
return r
|
||||
|
||||
def clearconfig(self, nodenum):
|
||||
"""
|
||||
remove configuration values for the specified node;
|
||||
when nodenum is None, remove all configuration values
|
||||
|
||||
:param int nodenum: node id
|
||||
:return: nothing
|
||||
"""
|
||||
if nodenum is None:
|
||||
self.configs = {}
|
||||
return
|
||||
if nodenum in self.configs:
|
||||
self.configs.pop(nodenum)
|
||||
|
||||
def setconfig_keyvalues(self, nodenum, conftype, keyvalues):
|
||||
"""
|
||||
Key values list of tuples for a node.
|
||||
|
||||
:param int nodenum: node id
|
||||
:param conftype: configuration type
|
||||
:param keyvalues: key valyes
|
||||
:return: nothing
|
||||
"""
|
||||
if conftype not in self._modelclsmap:
|
||||
logger.warn("unknown model type '%s'", conftype)
|
||||
return
|
||||
model = self._modelclsmap[conftype]
|
||||
keys = model.getnames()
|
||||
# defaults are merged with supplied values here
|
||||
values = list(model.getdefaultvalues())
|
||||
for key, value in keyvalues:
|
||||
if key not in keys:
|
||||
logger.warn("Skipping unknown configuration key for %s: '%s'", conftype, key)
|
||||
continue
|
||||
i = keys.index(key)
|
||||
values[i] = value
|
||||
self.setconfig(nodenum, conftype, values)
|
||||
|
||||
def getmodels(self, n):
|
||||
"""
|
||||
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.
|
||||
This assumes self.configs contains an iterable of (model-names, values)
|
||||
and a self._modelclsmapdict exists.
|
||||
|
||||
:param n: network node to get models for
|
||||
:return: list of model and values tuples for the network node
|
||||
:rtype: list
|
||||
"""
|
||||
r = []
|
||||
if n.objid in self.configs:
|
||||
v = self.configs[n.objid]
|
||||
for model in v:
|
||||
cls = self._modelclsmap[model[0]]
|
||||
vals = model[1]
|
||||
r.append((cls, vals))
|
||||
return r
|
||||
|
||||
|
||||
class Configurable(object):
|
||||
"""
|
||||
A generic class for managing configuration parameters.
|
||||
Parameters are sent via Configuration Messages, which allow the GUI
|
||||
to build dynamic dialogs depending on what is being configured.
|
||||
"""
|
||||
name = ""
|
||||
# Configuration items:
|
||||
# ('name', 'type', 'default', 'possible-value-list', 'caption')
|
||||
config_matrix = []
|
||||
config_groups = None
|
||||
bitmap = None
|
||||
|
||||
def __init__(self, session=None, object_id=None):
|
||||
"""
|
||||
Creates a Configurable instance.
|
||||
|
||||
:param core.session.Session session: session for this configurable
|
||||
:param object_id:
|
||||
"""
|
||||
self.session = session
|
||||
self.object_id = object_id
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset method.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
|
||||
def register(self):
|
||||
"""
|
||||
Register method.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
pass
|
||||
class ConfigShim(object):
|
||||
@classmethod
|
||||
def str_to_dict(cls, key_values):
|
||||
key_values = key_values.split("|")
|
||||
values = OrderedDict()
|
||||
for key_value in key_values:
|
||||
key, value = key_value.split("=", 1)
|
||||
values[key] = value
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def getdefaultvalues(cls):
|
||||
"""
|
||||
Retrieve default values from configuration matrix.
|
||||
|
||||
:return: tuple of default values
|
||||
:rtype: tuple
|
||||
"""
|
||||
return tuple(map(lambda x: x[2], cls.config_matrix))
|
||||
|
||||
@classmethod
|
||||
def getnames(cls):
|
||||
"""
|
||||
Retrieve name values from configuration matrix.
|
||||
|
||||
:return: tuple of name values
|
||||
:rtype: tuple
|
||||
"""
|
||||
return tuple(map(lambda x: x[0], cls.config_matrix))
|
||||
|
||||
@classmethod
|
||||
def configure(cls, manager, config_data):
|
||||
"""
|
||||
Handle configuration messages for this object.
|
||||
|
||||
:param ConfigurableManager manager: configuration manager
|
||||
:param config_data: configuration data
|
||||
:return: configuration data object
|
||||
:rtype: ConfigData
|
||||
"""
|
||||
reply = None
|
||||
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
|
||||
|
||||
if interface_id is not None:
|
||||
node_id = node_id * 1000 + interface_id
|
||||
|
||||
logger.debug("received configure message for %s nodenum:%s", cls.name, str(node_id))
|
||||
if config_type == ConfigFlags.REQUEST.value:
|
||||
logger.info("replying to configure request for %s model", cls.name)
|
||||
# when object name is "all", the reply to this request may be None
|
||||
# if this node has not been configured for this model; otherwise we
|
||||
# reply with the defaults for this model
|
||||
if object_name == "all":
|
||||
defaults = None
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
else:
|
||||
defaults = cls.getdefaultvalues()
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
values = manager.getconfig(node_id, cls.name, defaults)[1]
|
||||
if values is None:
|
||||
logger.warn("no active configuration for node (%s), ignoring request")
|
||||
# node has no active config for this model (don't send defaults)
|
||||
return None
|
||||
# reply with config options
|
||||
reply = cls.config_data(0, node_id, typeflags, values)
|
||||
elif config_type == ConfigFlags.RESET.value:
|
||||
if object_name == "all":
|
||||
manager.clearconfig(node_id)
|
||||
# elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE:
|
||||
else:
|
||||
# store the configuration values for later use, when the node
|
||||
# object has been created
|
||||
if object_name is None:
|
||||
logger.info("no configuration object for node %s", node_id)
|
||||
return None
|
||||
defaults = cls.getdefaultvalues()
|
||||
if values_str is None:
|
||||
# use default or preconfigured values
|
||||
values = manager.getconfig(node_id, cls.name, defaults)[1]
|
||||
else:
|
||||
# use new values supplied from the conf message
|
||||
values = values_str.split('|')
|
||||
# determine new or old style config
|
||||
new = cls.haskeyvalues(values)
|
||||
if new:
|
||||
new_values = list(defaults)
|
||||
keys = cls.getnames()
|
||||
for v in values:
|
||||
key, value = v.split('=', 1)
|
||||
try:
|
||||
new_values[keys.index(key)] = value
|
||||
except ValueError:
|
||||
logger.info("warning: ignoring invalid key '%s'" % key)
|
||||
values = new_values
|
||||
manager.setconfig(node_id, object_name, values)
|
||||
|
||||
return reply
|
||||
|
||||
@classmethod
|
||||
def config_data(cls, flags, node_id, type_flags, values):
|
||||
def config_data(cls, flags, node_id, type_flags, configurable_options, config):
|
||||
"""
|
||||
Convert this class to a Config API message. Some TLVs are defined
|
||||
by the class, but node number, conf type flags, and values must
|
||||
|
@ -388,106 +28,143 @@ class Configurable(object):
|
|||
:param flags: message flags
|
||||
:param int node_id: node id
|
||||
:param type_flags: type flags
|
||||
:param values: values
|
||||
:param ConfigurableOptions configurable_options: options to create config data for
|
||||
:param dict config: configuration values for options
|
||||
:return: configuration data object
|
||||
:rtype: ConfigData
|
||||
"""
|
||||
keys = cls.getnames()
|
||||
keyvalues = map(lambda a, b: "%s=%s" % (a, b), keys, values)
|
||||
values_str = string.join(keyvalues, '|')
|
||||
datatypes = tuple(map(lambda x: x[1], cls.config_matrix))
|
||||
captions = reduce(lambda a, b: a + '|' + b, map(lambda x: x[4], cls.config_matrix))
|
||||
possible_valuess = reduce(lambda a, b: a + '|' + b, map(lambda x: x[3], cls.config_matrix))
|
||||
key_values = None
|
||||
captions = None
|
||||
data_types = []
|
||||
possible_values = []
|
||||
logger.debug("configurable: %s", configurable_options)
|
||||
logger.debug("configuration options: %s", configurable_options.configurations)
|
||||
logger.debug("configuration data: %s", config)
|
||||
for configuration in configurable_options.configurations():
|
||||
if not captions:
|
||||
captions = configuration.label
|
||||
else:
|
||||
captions += "|%s" % configuration.label
|
||||
|
||||
data_types.append(configuration.type.value)
|
||||
|
||||
options = ",".join(configuration.options)
|
||||
possible_values.append(options)
|
||||
|
||||
_id = configuration.id
|
||||
config_value = config.get(_id, configuration.default)
|
||||
key_value = "%s=%s" % (_id, config_value)
|
||||
if not key_values:
|
||||
key_values = key_value
|
||||
else:
|
||||
key_values += "|%s" % key_value
|
||||
|
||||
return ConfigData(
|
||||
message_type=flags,
|
||||
node=node_id,
|
||||
object=cls.name,
|
||||
object=configurable_options.name,
|
||||
type=type_flags,
|
||||
data_types=datatypes,
|
||||
data_values=values_str,
|
||||
data_types=tuple(data_types),
|
||||
data_values=key_values,
|
||||
captions=captions,
|
||||
possible_values=possible_valuess,
|
||||
bitmap=cls.bitmap,
|
||||
groups=cls.config_groups
|
||||
possible_values="|".join(possible_values),
|
||||
bitmap=configurable_options.bitmap,
|
||||
groups=configurable_options.config_groups()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def booltooffon(value):
|
||||
"""
|
||||
Convenience helper turns bool into on (True) or off (False) string.
|
||||
|
||||
:param str value: value to retrieve on/off value for
|
||||
:return: on or off string
|
||||
:rtype: str
|
||||
"""
|
||||
if value == "1" or value == "true" or value == "on":
|
||||
return "on"
|
||||
else:
|
||||
return "off"
|
||||
class Configuration(object):
|
||||
def __init__(self, _id, _type, label, default="", options=None):
|
||||
self.id = _id
|
||||
self.type = _type
|
||||
self.default = default
|
||||
if not options:
|
||||
options = []
|
||||
self.options = options
|
||||
if not label:
|
||||
label = _id
|
||||
self.label = label
|
||||
|
||||
@staticmethod
|
||||
def offontobool(value):
|
||||
"""
|
||||
Convenience helper for converting an on/off string to a integer.
|
||||
def __str__(self):
|
||||
return "%s(id=%s, type=%s, default=%s, options=%s)" % (
|
||||
self.__class__.__name__, self.id, self.type, self.default, self.options)
|
||||
|
||||
:param str value: on/off string
|
||||
:return: on/off integer value
|
||||
:rtype: int
|
||||
"""
|
||||
if type(value) == str:
|
||||
if value.lower() == "on":
|
||||
return 1
|
||||
elif value.lower() == "off":
|
||||
return 0
|
||||
return value
|
||||
|
||||
class ConfigurableOptions(object):
|
||||
# unique name to receive configuration changes
|
||||
name = None
|
||||
bitmap = None
|
||||
|
||||
@classmethod
|
||||
def valueof(cls, name, values):
|
||||
def configurations(cls):
|
||||
"""
|
||||
Helper to return a value by the name defined in confmatrix.
|
||||
Checks if it is boolean
|
||||
Returns configuration options supported by this class.
|
||||
|
||||
:param str name: name to get value of
|
||||
:param values: values to get value from
|
||||
:return: value for name
|
||||
:return: list of configuration options
|
||||
:rtype: list[Configuration]
|
||||
"""
|
||||
i = cls.getnames().index(name)
|
||||
if cls.config_matrix[i][1] == ConfigDataTypes.BOOL.value and values[i] != "":
|
||||
return cls.booltooffon(values[i])
|
||||
else:
|
||||
return values[i]
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def haskeyvalues(values):
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
"""
|
||||
Helper to check for list of key=value pairs versus a plain old
|
||||
list of values. Returns True if all elements are "key=value".
|
||||
String formatted to specify configuration groupings, using list index positions.
|
||||
|
||||
:param values: items to check for key/value pairs
|
||||
:return: True if all values are key/value pairs, False otherwise
|
||||
:rtype: bool
|
||||
Example:
|
||||
"Group1:start-stop|Group2:start-stop"
|
||||
|
||||
:return: config groups
|
||||
:rtype: str
|
||||
"""
|
||||
if len(values) == 0:
|
||||
return False
|
||||
for v in values:
|
||||
if "=" not in v:
|
||||
return False
|
||||
return True
|
||||
return None
|
||||
|
||||
def getkeyvaluelist(self):
|
||||
@classmethod
|
||||
def default_values(cls):
|
||||
"""
|
||||
Helper to return a list of (key, value) tuples. Keys come from
|
||||
configuration matrix and values are instance attributes.
|
||||
Retrieves default values for configurations.
|
||||
|
||||
:return: tuples of key value pairs
|
||||
:rtype: list
|
||||
:return: mapping of configuration options that can also be iterated in order of definition
|
||||
:rtype: OrderedDict
|
||||
"""
|
||||
key_values = []
|
||||
return OrderedDict([(config.id, config.default) for config in cls.configurations()])
|
||||
|
||||
for name in self.getnames():
|
||||
if hasattr(self, name):
|
||||
value = getattr(self, name)
|
||||
key_values.append((name, value))
|
||||
|
||||
return key_values
|
||||
class NewConfigurableManager(object):
|
||||
_default_node = -1
|
||||
_default_type = "default"
|
||||
|
||||
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 config_reset(self, node_id=None):
|
||||
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_type_map = self.get_configs(node_id, config_type)
|
||||
node_type_map.clear()
|
||||
node_type_map.update(config)
|
||||
|
||||
def get_config(self, _id, node_id=_default_node, config_type=_default_type):
|
||||
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)
|
||||
|
||||
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._configuration_maps.setdefault(node_id, {})
|
||||
return node_map.setdefault(config_type, {})
|
||||
|
||||
def get_config_types(self, node_id=_default_node):
|
||||
return self._configuration_maps.get(node_id, {})
|
||||
|
|
|
@ -10,15 +10,17 @@ import shutil
|
|||
import sys
|
||||
import threading
|
||||
import time
|
||||
from itertools import repeat
|
||||
|
||||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.conf import ConfigShim
|
||||
from core.data import ConfigData
|
||||
from core.data import EventData
|
||||
from core.emulator.emudata import InterfaceData
|
||||
from core.emulator.emudata import LinkOptions
|
||||
from core.emulator.emudata import NodeOptions
|
||||
from core.enumerations import ConfigTlvs
|
||||
from core.enumerations import ConfigTlvs, ConfigFlags, ConfigDataTypes
|
||||
from core.enumerations import EventTlvs
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import ExceptionTlvs
|
||||
|
@ -35,6 +37,8 @@ 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, Ns2ScriptedMobility
|
||||
from core.service import ServiceManager
|
||||
|
||||
|
||||
class CoreHandler(SocketServer.BaseRequestHandler):
|
||||
|
@ -407,12 +411,19 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
tlv_data = ""
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, "core-daemon")
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.EMULATION_SERVER.value, "core-daemon")
|
||||
|
||||
# get config objects for session
|
||||
for name in self.session.config_objects:
|
||||
config_type, callback = self.session.config_objects[name]
|
||||
# type must be in coreapi.reg_tlvs
|
||||
tlv_data += coreapi.CoreRegisterTlv.pack(config_type, name)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
return coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlv_data)
|
||||
|
||||
|
@ -941,15 +952,399 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
opaque=message.get_tlv(ConfigTlvs.OPAQUE.value)
|
||||
)
|
||||
logger.debug("configuration message for %s node %s", config_data.object, config_data.node)
|
||||
message_type = ConfigFlags(config_data.type)
|
||||
|
||||
# dispatch to any registered callback for this object type
|
||||
replies = self.session.config_object(config_data)
|
||||
replies = []
|
||||
|
||||
# handle session configuration
|
||||
if config_data.object == "all":
|
||||
replies = self.handle_config_all(message_type, config_data)
|
||||
elif config_data.object == self.session.options.name:
|
||||
replies = self.handle_config_session(message_type, config_data)
|
||||
elif config_data.object == self.session.location.name:
|
||||
self.handle_config_location(message_type, config_data)
|
||||
elif config_data.object == self.session.metadata.name:
|
||||
replies = self.handle_config_metadata(message_type, config_data)
|
||||
elif config_data.object == self.session.broker.name:
|
||||
self.handle_config_broker(message_type, config_data)
|
||||
elif config_data.object == self.session.services.name:
|
||||
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]:
|
||||
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():
|
||||
replies = self.handle_config_emane_models(message_type, config_data)
|
||||
else:
|
||||
raise Exception("no handler for configuration: %s", config_data.object)
|
||||
|
||||
for reply in replies:
|
||||
self.handle_broadcast_config(reply)
|
||||
|
||||
return []
|
||||
|
||||
def handle_config_all(self, message_type, config_data):
|
||||
replies = []
|
||||
|
||||
if message_type == ConfigFlags.RESET:
|
||||
node_id = config_data.node
|
||||
self.session.location.reset()
|
||||
self.session.services.reset()
|
||||
self.session.mobility.reset()
|
||||
self.session.mobility.config_reset(node_id)
|
||||
self.session.emane.config_reset(node_id)
|
||||
else:
|
||||
raise Exception("cant handle config all: %s" % message_type)
|
||||
|
||||
return replies
|
||||
|
||||
def handle_config_session(self, message_type, config_data):
|
||||
replies = []
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
type_flags = ConfigFlags.NONE.value
|
||||
config = self.session.options.get_configs()
|
||||
config_response = ConfigShim.config_data(0, None, type_flags, self.session.options, config)
|
||||
replies.append(config_response)
|
||||
elif message_type != ConfigFlags.RESET and config_data.data_values:
|
||||
values = ConfigShim.str_to_dict(config_data.data_values)
|
||||
for key, value in values.iteritems():
|
||||
self.session.options.set_config(key, value)
|
||||
return replies
|
||||
|
||||
def handle_config_location(self, message_type, config_data):
|
||||
if message_type == ConfigFlags.RESET:
|
||||
self.session.location.reset()
|
||||
else:
|
||||
if not config_data.data_values:
|
||||
logger.warn("location data missing")
|
||||
else:
|
||||
values = config_data.data_values.split("|")
|
||||
|
||||
# Cartesian coordinate reference point
|
||||
refx, refy = map(lambda x: float(x), values[0:2])
|
||||
refz = 0.0
|
||||
lat, lon, alt = map(lambda x: float(x), values[2:5])
|
||||
# xyz point
|
||||
self.session.location.refxyz = (refx, refy, refz)
|
||||
# geographic reference point
|
||||
self.session.location.setrefgeo(lat, lon, alt)
|
||||
self.session.location.refscale = float(values[5])
|
||||
logger.info("location configured: %s = %s scale=%s", self.session.location.refxyz,
|
||||
self.session.location.refgeo, self.session.location.refscale)
|
||||
logger.info("location configured: UTM%s", self.session.location.refutm)
|
||||
|
||||
def handle_config_metadata(self, message_type, config_data):
|
||||
replies = []
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
node_id = config_data.node
|
||||
data_values = "|".join(["%s=%s" % item for item in self.session.metadata.get_configs().iteritems()])
|
||||
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.session.metadata.get_configs())
|
||||
config_response = ConfigData(
|
||||
message_type=0,
|
||||
node=node_id,
|
||||
object=self.session.metadata.name,
|
||||
type=ConfigFlags.NONE.value,
|
||||
data_types=data_types,
|
||||
data_values=data_values
|
||||
)
|
||||
replies.append(config_response)
|
||||
elif message_type != ConfigFlags.RESET and config_data.data_values:
|
||||
values = ConfigShim.str_to_dict(config_data.data_values)
|
||||
for key, value in values.iteritems():
|
||||
self.session.metadata.set_config(key, value)
|
||||
return replies
|
||||
|
||||
def handle_config_broker(self, message_type, config_data):
|
||||
if message_type not in [ConfigFlags.REQUEST, ConfigFlags.RESET]:
|
||||
session_id = config_data.session
|
||||
if not config_data.data_values:
|
||||
logger.info("emulation server data missing")
|
||||
else:
|
||||
values = config_data.data_values.split("|")
|
||||
|
||||
# string of "server:ip:port,server:ip:port,..."
|
||||
server_strings = values[0]
|
||||
server_list = server_strings.split(",")
|
||||
|
||||
for server in server_list:
|
||||
server_items = server.split(":")
|
||||
name, host, port = server_items[:3]
|
||||
|
||||
if host == "":
|
||||
host = None
|
||||
|
||||
if port == "":
|
||||
port = None
|
||||
else:
|
||||
port = int(port)
|
||||
|
||||
if session_id is not None:
|
||||
# receive session ID and my IP from master
|
||||
self.session.broker.session_id_master = int(session_id.split("|")[0])
|
||||
self.session.broker.myip = host
|
||||
host = None
|
||||
port = None
|
||||
|
||||
# this connects to the server immediately; maybe we should wait
|
||||
# or spin off a new "client" thread here
|
||||
self.session.broker.addserver(name, host, port)
|
||||
self.session.broker.setupserver(name)
|
||||
|
||||
def handle_config_services(self, message_type, config_data):
|
||||
replies = []
|
||||
node_id = config_data.node
|
||||
opaque = config_data.opaque
|
||||
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
session_id = config_data.session
|
||||
opaque = config_data.opaque
|
||||
|
||||
logger.debug("configuration request: node(%s) session(%s) opaque(%s)", node_id, session_id, opaque)
|
||||
|
||||
# send back a list of available services
|
||||
if opaque is None:
|
||||
type_flag = ConfigFlags.NONE.value
|
||||
data_types = tuple(repeat(ConfigDataTypes.BOOL.value, len(ServiceManager.services)))
|
||||
values = "|".join(repeat('0', len(ServiceManager.services)))
|
||||
names = map(lambda x: x._name, ServiceManager.services)
|
||||
captions = "|".join(names)
|
||||
possible_values = ""
|
||||
for s in ServiceManager.services:
|
||||
if s._custom_needed:
|
||||
possible_values += '1'
|
||||
possible_values += '|'
|
||||
groups = self.session.services.buildgroups(ServiceManager.services)
|
||||
# send back the properties for this service
|
||||
else:
|
||||
if not node_id:
|
||||
return replies
|
||||
|
||||
node = self.session.get_object(node_id)
|
||||
if node is None:
|
||||
logger.warn("Request to configure service for unknown node %s", node_id)
|
||||
return replies
|
||||
servicesstring = opaque.split(':')
|
||||
services, unknown = self.session.services.servicesfromopaque(opaque, node.objid)
|
||||
for u in unknown:
|
||||
logger.warn("Request for unknown service '%s'" % u)
|
||||
|
||||
if not services:
|
||||
return replies
|
||||
|
||||
if len(servicesstring) == 3:
|
||||
# a file request: e.g. "service:zebra:quagga.conf"
|
||||
file_data = self.session.services.getservicefile(services, node, servicesstring[2])
|
||||
self.session.broadcast_file(file_data)
|
||||
# short circuit this request early to avoid returning response below
|
||||
return replies
|
||||
|
||||
# the first service in the list is the one being configured
|
||||
svc = services[0]
|
||||
# send back:
|
||||
# dirs, configs, startindex, startup, shutdown, metadata, config
|
||||
type_flag = ConfigFlags.UPDATE.value
|
||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(svc.keys)))
|
||||
values = svc.tovaluelist(node, services)
|
||||
captions = None
|
||||
possible_values = None
|
||||
groups = None
|
||||
|
||||
config_response = ConfigData(
|
||||
message_type=0,
|
||||
node=node_id,
|
||||
object=self.session.services.name,
|
||||
type=type_flag,
|
||||
data_types=data_types,
|
||||
data_values=values,
|
||||
captions=captions,
|
||||
possible_values=possible_values,
|
||||
groups=groups,
|
||||
session=session_id,
|
||||
opaque=opaque
|
||||
)
|
||||
replies.append(config_response)
|
||||
elif message_type == ConfigFlags.RESET:
|
||||
self.session.services.reset()
|
||||
else:
|
||||
data_types = config_data.data_types
|
||||
values = config_data.data_values
|
||||
|
||||
error_message = "services config message that I don't know how to handle"
|
||||
if values is None:
|
||||
logger.error(error_message)
|
||||
else:
|
||||
if opaque is None:
|
||||
values = values.split('|')
|
||||
# store default services for a node type in self.defaultservices[]
|
||||
if data_types is None or data_types[0] != ConfigDataTypes.STRING.value:
|
||||
logger.info(error_message)
|
||||
return None
|
||||
key = values.pop(0)
|
||||
self.session.services.defaultservices[key] = values
|
||||
logger.debug("default services for type %s set to %s", key, values)
|
||||
elif node_id:
|
||||
# store service customized config in self.customservices[]
|
||||
services, unknown = self.session.services.servicesfromopaque(opaque, node_id)
|
||||
for u in unknown:
|
||||
logger.warn("Request for unknown service '%s'" % u)
|
||||
|
||||
if services:
|
||||
svc = services[0]
|
||||
values = ConfigShim.str_to_dict(values)
|
||||
self.session.services.setcustomservice(node_id, svc, values)
|
||||
|
||||
return replies
|
||||
|
||||
def handle_config_mobility(self, message_type, _):
|
||||
if message_type == ConfigFlags.RESET:
|
||||
self.session.mobility.reset()
|
||||
|
||||
def handle_config_mobility_models(self, message_type, config_data):
|
||||
replies = []
|
||||
node_id = config_data.node
|
||||
object_name = config_data.object
|
||||
interface_id = config_data.interface_number
|
||||
values_str = config_data.data_values
|
||||
|
||||
if interface_id is not None:
|
||||
node_id = node_id * 1000 + interface_id
|
||||
|
||||
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
logger.info("replying to configure request for model: %s", object_name)
|
||||
if object_name == "all":
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
else:
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
|
||||
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 []
|
||||
|
||||
config = self.session.mobility.get_configs(node_id, object_name)
|
||||
if not config:
|
||||
config = model_class.default_values()
|
||||
|
||||
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||
replies.append(config_response)
|
||||
elif message_type == ConfigFlags.RESET:
|
||||
if object_name == "all":
|
||||
self.session.mobility.config_reset(node_id)
|
||||
else:
|
||||
# store the configuration values for later use, when the node
|
||||
if not object_name:
|
||||
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 []
|
||||
|
||||
if values_str:
|
||||
config = ConfigShim.str_to_dict(values_str)
|
||||
else:
|
||||
config = model_class.default_values()
|
||||
|
||||
self.session.mobility.set_configs(config, node_id, object_name)
|
||||
|
||||
return replies
|
||||
|
||||
def handle_config_emane(self, message_type, config_data):
|
||||
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
|
||||
|
||||
if interface_id is not None:
|
||||
node_id = node_id * 1000 + interface_id
|
||||
|
||||
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
logger.info("replying to configure request for %s model", object_name)
|
||||
if object_name == "all":
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
else:
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
config = self.session.emane.get_configs()
|
||||
config_response = ConfigShim.config_data(0, node_id, typeflags, self.session.emane.emane_config, config)
|
||||
replies.append(config_response)
|
||||
elif config_type == ConfigFlags.RESET.value:
|
||||
if object_name == "all":
|
||||
self.session.emane.config_reset(node_id)
|
||||
else:
|
||||
if not object_name:
|
||||
logger.info("no configuration object for node %s", node_id)
|
||||
return []
|
||||
|
||||
if values_str:
|
||||
config = ConfigShim.str_to_dict(values_str)
|
||||
self.session.emane.set_configs(config)
|
||||
|
||||
# extra logic to start slave Emane object after nemid has been configured from the master
|
||||
if message_type == ConfigFlags.UPDATE and self.session.master is False:
|
||||
# instantiation was previously delayed by setup returning Emane.NOT_READY
|
||||
self.session.instantiate()
|
||||
|
||||
return replies
|
||||
|
||||
def handle_config_emane_models(self, message_type, config_data):
|
||||
replies = []
|
||||
node_id = config_data.node
|
||||
object_name = config_data.object
|
||||
interface_id = config_data.interface_number
|
||||
values_str = config_data.data_values
|
||||
|
||||
if interface_id is not None:
|
||||
node_id = node_id * 1000 + interface_id
|
||||
|
||||
logger.debug("received configure message for %s nodenum: %s", object_name, node_id)
|
||||
if message_type == ConfigFlags.REQUEST:
|
||||
logger.info("replying to configure request for model: %s", object_name)
|
||||
if object_name == "all":
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
else:
|
||||
typeflags = ConfigFlags.NONE.value
|
||||
|
||||
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 []
|
||||
|
||||
config = self.session.emane.get_configs(node_id, object_name)
|
||||
if not config:
|
||||
config = model_class.default_values()
|
||||
|
||||
config_response = ConfigShim.config_data(0, node_id, typeflags, model_class, config)
|
||||
replies.append(config_response)
|
||||
elif message_type == ConfigFlags.RESET:
|
||||
if object_name == "all":
|
||||
self.session.emane.config_reset(node_id)
|
||||
else:
|
||||
# store the configuration values for later use, when the node
|
||||
if not object_name:
|
||||
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 []
|
||||
|
||||
if values_str:
|
||||
config = ConfigShim.str_to_dict(values_str)
|
||||
else:
|
||||
config = model_class.default_values()
|
||||
|
||||
self.session.emane.set_configs(config, node_id, object_name)
|
||||
|
||||
return replies
|
||||
|
||||
def handle_file_message(self, message):
|
||||
"""
|
||||
File Message handler
|
||||
|
|
|
@ -305,8 +305,8 @@ class PyCoreNode(PyCoreObj):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
preserve = getattr(self.session.options, "preservedir", None)
|
||||
if preserve == "1":
|
||||
preserve = self.session.options.get_config("preservedir") == "1"
|
||||
if preserve:
|
||||
return
|
||||
|
||||
if self.tmpnodedir:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
EMANE Bypass model for CORE
|
||||
"""
|
||||
|
||||
from core.conf import Configuration
|
||||
from core.emane import emanemodel
|
||||
from core.enumerations import ConfigDataTypes
|
||||
|
||||
|
@ -15,13 +15,20 @@ class EmaneBypassModel(emanemodel.EmaneModel):
|
|||
# mac definitions
|
||||
mac_library = "bypassmaclayer"
|
||||
mac_config = [
|
||||
("none", ConfigDataTypes.BOOL.value, "0", "True,False",
|
||||
"There are no parameters for the bypass model."),
|
||||
Configuration(
|
||||
_id="none",
|
||||
_type=ConfigDataTypes.BOOL,
|
||||
default="0",
|
||||
options=["True", "False"],
|
||||
label="There are no parameters for the bypass model."
|
||||
)
|
||||
]
|
||||
|
||||
# phy definitions
|
||||
phy_library = "bypassphylayer"
|
||||
phy_config = []
|
||||
|
||||
# override gui display tabs
|
||||
config_groups_override = "Bypass Parameters:1-1"
|
||||
# override config groups
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "Bypass Parameters:1-1"
|
||||
|
|
|
@ -35,8 +35,13 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
|||
shim_defaults = {}
|
||||
config_shim = emanemanifest.parse(shim_xml, shim_defaults)
|
||||
|
||||
config_groups_override = "CommEffect SHIM Parameters:1-%d" % len(config_shim)
|
||||
config_matrix_override = config_shim
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return cls.config_shim
|
||||
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "CommEffect SHIM Parameters:1-%d" % len(cls.configurations())
|
||||
|
||||
def build_xml_files(self, emane_manager, interface):
|
||||
"""
|
||||
|
@ -49,8 +54,9 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
|||
:param interface: interface for the emane node
|
||||
:return: nothing
|
||||
"""
|
||||
values = emane_manager.getifcconfig(self.object_id, self.name, self.getdefaultvalues(), interface)
|
||||
if values is None:
|
||||
default_values = self.default_values()
|
||||
config = emane_manager.getifcconfig(self.object_id, self.name, default_values, interface)
|
||||
if not config:
|
||||
return
|
||||
|
||||
# retrieve xml names
|
||||
|
@ -67,23 +73,22 @@ class EmaneCommEffectModel(emanemodel.EmaneModel):
|
|||
nem_element.appendChild(shim_xml)
|
||||
emane_manager.xmlwrite(nem_document, nem_name)
|
||||
|
||||
names = self.getnames()
|
||||
shim_names = list(names)
|
||||
shim_names.remove("filterfile")
|
||||
|
||||
shim_document = emane_manager.xmldoc("shim")
|
||||
shim_element = shim_document.getElementsByTagName("shim").pop()
|
||||
shim_element.setAttribute("name", "%s SHIM" % self.name)
|
||||
shim_element.setAttribute("library", self.shim_library)
|
||||
|
||||
# append all shim options (except filterfile) to shimdoc
|
||||
for name in shim_names:
|
||||
value = self.valueof(name, values)
|
||||
for configuration in self.config_shim:
|
||||
name = configuration.id
|
||||
if name == "filterfile":
|
||||
continue
|
||||
value = config[name]
|
||||
param = emane_manager.xmlparam(shim_document, name, value)
|
||||
shim_element.appendChild(param)
|
||||
|
||||
# empty filterfile is not allowed
|
||||
ff = self.valueof("filterfile", values)
|
||||
ff = config["filterfile"]
|
||||
if ff.strip() != "":
|
||||
shim_element.appendChild(emane_manager.xmlparam(shim_document, "filterfile", ff))
|
||||
emane_manager.xmlwrite(shim_document, shim_name)
|
||||
|
|
|
@ -10,7 +10,9 @@ from core import CoreCommandError
|
|||
from core import constants
|
||||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.conf import ConfigurableManager
|
||||
from core.conf import ConfigShim
|
||||
from core.conf import Configuration
|
||||
from core.conf import NewConfigurableManager
|
||||
from core.emane import emanemanifest
|
||||
from core.emane.bypass import EmaneBypassModel
|
||||
from core.emane.commeffect import EmaneCommEffectModel
|
||||
|
@ -50,7 +52,7 @@ EMANE_MODELS = [
|
|||
]
|
||||
|
||||
|
||||
class EmaneManager(ConfigurableManager):
|
||||
class EmaneManager(NewConfigurableManager):
|
||||
"""
|
||||
EMANE controller object. Lives in a Session instance and is used for
|
||||
building EMANE config files from all of the EmaneNode objects in this
|
||||
|
@ -70,7 +72,7 @@ class EmaneManager(ConfigurableManager):
|
|||
:param core.session.Session session: session this manager is tied to
|
||||
:return: nothing
|
||||
"""
|
||||
ConfigurableManager.__init__(self)
|
||||
super(EmaneManager, self).__init__()
|
||||
self.session = session
|
||||
self._emane_nodes = {}
|
||||
self._emane_node_lock = threading.Lock()
|
||||
|
@ -84,16 +86,22 @@ class EmaneManager(ConfigurableManager):
|
|||
|
||||
# model for global EMANE configuration options
|
||||
self.emane_config = EmaneGlobalModel(session, None)
|
||||
self.set_configs(self.emane_config.default_values())
|
||||
|
||||
session.broker.handlers.add(self.handledistributed)
|
||||
self.service = None
|
||||
self.event_device = None
|
||||
self._modelclsmap = {
|
||||
self.emane_config.name: self.emane_config
|
||||
}
|
||||
self._modelclsmap = {}
|
||||
|
||||
self.service = None
|
||||
self.emane_check()
|
||||
|
||||
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.
|
||||
|
@ -138,9 +146,8 @@ class EmaneManager(ConfigurableManager):
|
|||
return
|
||||
|
||||
# Get the control network to be used for events
|
||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
||||
group, port = self.emane_config.valueof("eventservicegroup", values).split(":")
|
||||
self.event_device = self.emane_config.valueof("eventservicedevice", values)
|
||||
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)
|
||||
|
@ -170,7 +177,6 @@ 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.session.add_config_object(emane_model.name, emane_model.config_type, emane_model.configure_emane)
|
||||
|
||||
def add_node(self, emane_node):
|
||||
"""
|
||||
|
@ -196,26 +202,31 @@ class EmaneManager(ConfigurableManager):
|
|||
nodes.add(netif.node)
|
||||
return nodes
|
||||
|
||||
def getmodels(self, n):
|
||||
def getmodels(self, node):
|
||||
"""
|
||||
Used with XML export; see ConfigurableManager.getmodels()
|
||||
Used with XML export.
|
||||
"""
|
||||
r = ConfigurableManager.getmodels(self, n)
|
||||
# EMANE global params are stored with first EMANE node (if non-default
|
||||
# values are configured)
|
||||
sorted_ids = sorted(self.configs.keys())
|
||||
if None in self.configs and len(sorted_ids) > 1 and n.objid == sorted_ids[1]:
|
||||
v = self.configs[None]
|
||||
for model in v:
|
||||
cls = self._modelclsmap[model[0]]
|
||||
vals = model[1]
|
||||
r.append((cls, vals))
|
||||
return r
|
||||
configs = self.get_config_types(node.objid)
|
||||
models = []
|
||||
for model_name, config in configs.iteritems():
|
||||
model_class = self._modelclsmap[model_name]
|
||||
models.append((model_class, config))
|
||||
logger.debug("emane models: %s", models)
|
||||
return models
|
||||
|
||||
def getifcconfig(self, nodenum, conftype, defaultvalues, ifc):
|
||||
def getifcconfig(self, node_id, config_type, default_values, ifc):
|
||||
"""
|
||||
Retrieve interface configuration or node configuration if not provided.
|
||||
|
||||
:param int node_id: node id
|
||||
:param str config_type: configuration type
|
||||
:param dict default_values: default configuration values
|
||||
:param ifc: node interface
|
||||
:return:
|
||||
"""
|
||||
# use the network-wide config values or interface(NEM)-specific values?
|
||||
if ifc is None:
|
||||
return self.getconfig(nodenum, conftype, defaultvalues)[1]
|
||||
return self.get_configs(node_id, config_type) or default_values
|
||||
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
|
||||
|
@ -229,16 +240,19 @@ class EmaneManager(ConfigurableManager):
|
|||
if ifc.netindex is not None:
|
||||
key += ifc.netindex
|
||||
|
||||
values = self.getconfig(key, conftype, None)[1]
|
||||
if not values:
|
||||
values = self.getconfig(ifc.node.objid, conftype, None)[1]
|
||||
# try retrieve interface specific configuration
|
||||
config = self.get_configs(key, config_type)
|
||||
|
||||
if not values and ifc.transport_type == "raw":
|
||||
# otherwise retrieve the interfaces node configuration
|
||||
if not config:
|
||||
config = self.get_configs(ifc.node.objid, config_type)
|
||||
|
||||
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
|
||||
values = self.getconfig(nodenum, conftype, defaultvalues)[1]
|
||||
config = self.get_configs(node_id, config_type) or default_values
|
||||
|
||||
return values
|
||||
return config
|
||||
|
||||
def setup(self):
|
||||
"""
|
||||
|
@ -264,9 +278,7 @@ class EmaneManager(ConfigurableManager):
|
|||
# - needs to be configured before checkdistributed() for distributed
|
||||
# - needs to exist when eventservice binds to it (initeventservice)
|
||||
if self.session.master:
|
||||
values = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
||||
logger.debug("emane config default values: %s", values)
|
||||
otadev = self.emane_config.valueof("otamanagerdevice", values)
|
||||
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:
|
||||
|
@ -275,7 +287,7 @@ class EmaneManager(ConfigurableManager):
|
|||
|
||||
ctrlnet = self.session.add_remove_control_net(net_index=netidx, remove=False, conf_required=False)
|
||||
self.distributedctrlnet(ctrlnet)
|
||||
eventdev = self.emane_config.valueof("eventservicedevice", values)
|
||||
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)
|
||||
|
@ -288,10 +300,11 @@ class EmaneManager(ConfigurableManager):
|
|||
self.distributedctrlnet(ctrlnet)
|
||||
|
||||
if self.checkdistributed():
|
||||
# we are slave, but haven"t received a platformid yet
|
||||
cfgval = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
||||
i = self.emane_config.getnames().index("platform_id_start")
|
||||
if cfgval[i] == self.emane_config.getdefaultvalues()[i]:
|
||||
# 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.get_config(platform_id_start)
|
||||
if value == default_values[platform_id_start]:
|
||||
return EmaneManager.NOT_READY
|
||||
|
||||
self.setnodemodels()
|
||||
|
@ -359,7 +372,7 @@ class EmaneManager(ConfigurableManager):
|
|||
with self._emane_node_lock:
|
||||
self._emane_nodes.clear()
|
||||
|
||||
# don"t clear self._ifccounts here; NEM counts are needed for buildxml
|
||||
# don't clear self._ifccounts here; NEM counts are needed for buildxml
|
||||
self.platformport = self.session.get_config_item_int("emane_platform_port", 8100)
|
||||
self.transformport = self.session.get_config_item_int("emane_transform_port", 8200)
|
||||
|
||||
|
@ -416,20 +429,16 @@ class EmaneManager(ConfigurableManager):
|
|||
if not master:
|
||||
return True
|
||||
|
||||
cfgval = self.getconfig(None, self.emane_config.name, self.emane_config.getdefaultvalues())[1]
|
||||
values = list(cfgval)
|
||||
|
||||
nemcount = 0
|
||||
with self._emane_node_lock:
|
||||
for key in self._emane_nodes:
|
||||
emane_node = self._emane_nodes[key]
|
||||
nemcount += emane_node.numnetif()
|
||||
|
||||
nemid = int(self.emane_config.valueof("nem_id_start", values))
|
||||
nemid = int(self.get_config("nem_id_start"))
|
||||
nemid += nemcount
|
||||
|
||||
platformid = int(self.emane_config.valueof("platform_id_start", values))
|
||||
names = list(self.emane_config.getnames())
|
||||
platformid = int(self.get_config("platform_id_start"))
|
||||
|
||||
# build an ordered list of servers so platform ID is deterministic
|
||||
servers = []
|
||||
|
@ -448,9 +457,10 @@ class EmaneManager(ConfigurableManager):
|
|||
|
||||
platformid += 1
|
||||
typeflags = ConfigFlags.UPDATE.value
|
||||
values[names.index("platform_id_start")] = str(platformid)
|
||||
values[names.index("nem_id_start")] = str(nemid)
|
||||
msg = EmaneGlobalModel.config_data(flags=0, node_id=None, type_flags=typeflags, values=values)
|
||||
self.set_config("platform_id_start", str(platformid))
|
||||
self.set_config("nem_id_start", str(nemid))
|
||||
msg = ConfigShim.config_data(0, None, typeflags, self.emane_config, self.get_configs())
|
||||
# TODO: this needs to be converted into a sendable TLV message
|
||||
server.sock.send(msg)
|
||||
# increment nemid for next server by number of interfaces
|
||||
with self._ifccountslock:
|
||||
|
@ -489,8 +499,9 @@ class EmaneManager(ConfigurableManager):
|
|||
if len(servers) < 2:
|
||||
return
|
||||
|
||||
prefix = session.config.get("controlnet")
|
||||
prefix = getattr(session.options, "controlnet", prefix)
|
||||
prefix = session.options.get_config("controlnet")
|
||||
if not prefix:
|
||||
prefix = session.config.get("controlnet")
|
||||
prefixes = prefix.split()
|
||||
# normal Config messaging will distribute controlnets
|
||||
if len(prefixes) >= len(servers):
|
||||
|
@ -557,24 +568,17 @@ class EmaneManager(ConfigurableManager):
|
|||
for key in self._emane_nodes:
|
||||
self.setnodemodel(key)
|
||||
|
||||
def setnodemodel(self, key):
|
||||
logger.debug("setting emane node model: %s", key)
|
||||
emane_node = self._emane_nodes[key]
|
||||
if key not in self.configs:
|
||||
logger.debug("no emane node model configuration, leaving")
|
||||
def setnodemodel(self, node_id):
|
||||
logger.debug("setting emane models for node: %s", node_id)
|
||||
node_config_types = self.get_config_types(node_id)
|
||||
if not node_config_types:
|
||||
logger.debug("no emane node model configuration, leaving: %s", node_id)
|
||||
return False
|
||||
|
||||
for t, v in self.configs[key]:
|
||||
logger.debug("configuration: key(%s) value(%s)", t, v)
|
||||
if t is None:
|
||||
continue
|
||||
if t == self.emane_config.name:
|
||||
continue
|
||||
|
||||
# only use the first valid EmaneModel
|
||||
# convert model name to class (e.g. emane_rfpipe -> EmaneRfPipe)
|
||||
cls = self._modelclsmap[t]
|
||||
emane_node.setmodel(cls, v)
|
||||
emane_node = self._emane_nodes[node_id]
|
||||
for model_class, config in self.getmodels(emane_node):
|
||||
logger.debug("setting emane model(%s) config(%s)", model_class, config)
|
||||
emane_node.setmodel(model_class, config)
|
||||
return True
|
||||
|
||||
# no model has been configured for this EmaneNode
|
||||
|
@ -588,8 +592,8 @@ class EmaneManager(ConfigurableManager):
|
|||
emane_node = None
|
||||
netif = None
|
||||
|
||||
for key in self._emane_nodes:
|
||||
emane_node = self._emane_nodes[key]
|
||||
for node_id in self._emane_nodes:
|
||||
emane_node = self._emane_nodes[node_id]
|
||||
netif = emane_node.getnemnetif(nemid)
|
||||
if netif is not None:
|
||||
break
|
||||
|
@ -607,7 +611,7 @@ class EmaneManager(ConfigurableManager):
|
|||
count += len(emane_node.netifs())
|
||||
return count
|
||||
|
||||
def newplatformxmldoc(self, values, otadev=None, eventdev=None):
|
||||
def newplatformxmldoc(self, otadev=None, eventdev=None):
|
||||
"""
|
||||
Start a new platform XML file. Use global EMANE config values
|
||||
as keys. Override OTA manager and event service devices if
|
||||
|
@ -615,21 +619,20 @@ class EmaneManager(ConfigurableManager):
|
|||
"""
|
||||
doc = self.xmldoc("platform")
|
||||
plat = doc.getElementsByTagName("platform").pop()
|
||||
names = list(self.emane_config.getnames())
|
||||
platform_names = names[:len(self.emane_config.emulator_config)]
|
||||
platform_names.remove("platform_id_start")
|
||||
platform_values = list(values)
|
||||
|
||||
if otadev:
|
||||
i = platform_names.index("otamanagerdevice")
|
||||
platform_values[i] = otadev
|
||||
self.set_config("otamanagerdevice", otadev)
|
||||
|
||||
if eventdev:
|
||||
i = platform_names.index("eventservicedevice")
|
||||
platform_values[i] = eventdev
|
||||
self.set_config("eventservicedevice", eventdev)
|
||||
|
||||
# append all platform options (except starting id) to doc
|
||||
for name in platform_names:
|
||||
value = self.emane_config.valueof(name, platform_values)
|
||||
for configuration in self.emane_config.emulator_config:
|
||||
name = configuration.id
|
||||
if name == "platform_id_start":
|
||||
continue
|
||||
|
||||
value = self.get_config(name)
|
||||
param = self.xmlparam(doc, name, value)
|
||||
plat.appendChild(param)
|
||||
|
||||
|
@ -639,8 +642,7 @@ class EmaneManager(ConfigurableManager):
|
|||
"""
|
||||
Build a platform.xml file now that all nodes are configured.
|
||||
"""
|
||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
||||
nemid = int(self.emane_config.valueof("nem_id_start", values))
|
||||
nemid = int(self.get_config("nem_id_start"))
|
||||
platformxmls = {}
|
||||
|
||||
# assume self._objslock is already held here
|
||||
|
@ -660,7 +662,7 @@ class EmaneManager(ConfigurableManager):
|
|||
eventdev = None
|
||||
|
||||
if key not in platformxmls:
|
||||
platformxmls[key] = self.newplatformxmldoc(values, otadev, eventdev)
|
||||
platformxmls[key] = self.newplatformxmldoc(otadev, eventdev)
|
||||
|
||||
doc = platformxmls[key]
|
||||
plat = doc.getElementsByTagName("platform").pop()
|
||||
|
@ -713,13 +715,11 @@ class EmaneManager(ConfigurableManager):
|
|||
Build the libemaneeventservice.xml file if event service options
|
||||
were changed in the global config.
|
||||
"""
|
||||
defaults = self.emane_config.getdefaultvalues()
|
||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
||||
need_xml = False
|
||||
keys = ("eventservicegroup", "eventservicedevice")
|
||||
for k in keys:
|
||||
a = self.emane_config.valueof(k, defaults)
|
||||
b = self.emane_config.valueof(k, values)
|
||||
default_values = self.emane_config.default_values()
|
||||
for name in ["eventservicegroup", "eventservicedevice"]:
|
||||
a = default_values[name]
|
||||
b = self.get_config(name)
|
||||
if a != b:
|
||||
need_xml = True
|
||||
|
||||
|
@ -729,12 +729,12 @@ class EmaneManager(ConfigurableManager):
|
|||
return
|
||||
|
||||
try:
|
||||
group, port = self.emane_config.valueof("eventservicegroup", values).split(":")
|
||||
group, port = self.get_config("eventservicegroup").split(":")
|
||||
except ValueError:
|
||||
logger.exception("invalid eventservicegroup in EMANE config")
|
||||
return
|
||||
|
||||
dev = self.emane_config.valueof("eventservicedevice", values)
|
||||
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"))
|
||||
|
@ -761,13 +761,12 @@ class EmaneManager(ConfigurableManager):
|
|||
if realtime:
|
||||
emanecmd += "-r",
|
||||
|
||||
values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1]
|
||||
otagroup, otaport = self.emane_config.valueof("otamanagergroup", values).split(":")
|
||||
otadev = self.emane_config.valueof("otamanagerdevice", values)
|
||||
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.valueof("eventservicegroup", values).split(":")
|
||||
eventdev = self.emane_config.valueof("eventservicedevice", values)
|
||||
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
|
||||
|
@ -799,8 +798,7 @@ class EmaneManager(ConfigurableManager):
|
|||
node.check_cmd(args)
|
||||
|
||||
# start emane
|
||||
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n),
|
||||
os.path.join(path, "platform%d.xml" % n)]
|
||||
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)]
|
||||
output = node.check_cmd(args)
|
||||
logger.info("node(%s) emane daemon running: %s", node.name, args)
|
||||
logger.info("node(%s) emane daemon output: %s", node.name, output)
|
||||
|
@ -855,23 +853,6 @@ class EmaneManager(ConfigurableManager):
|
|||
emane_node = self._emane_nodes[key]
|
||||
emane_node.deinstallnetifs()
|
||||
|
||||
def configure(self, session, config_data):
|
||||
"""
|
||||
Handle configuration messages for global EMANE config.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
"""
|
||||
r = self.emane_config.configure_emane(session, config_data)
|
||||
|
||||
# extra logic to start slave Emane object after nemid has been configured from the master
|
||||
config_type = config_data.type
|
||||
if config_type == ConfigFlags.UPDATE.value and self.session.master is False:
|
||||
# instantiation was previously delayed by self.setup()
|
||||
# returning Emane.NOT_READY
|
||||
self.session.instantiate()
|
||||
|
||||
return r
|
||||
|
||||
def doeventmonitor(self):
|
||||
"""
|
||||
Returns boolean whether or not EMANE events will be monitored.
|
||||
|
@ -900,11 +881,10 @@ class EmaneManager(ConfigurableManager):
|
|||
return
|
||||
|
||||
if self.service is None:
|
||||
errmsg = "Warning: EMANE events will not be generated " \
|
||||
"because the emaneeventservice\n binding was " \
|
||||
"unable to load " \
|
||||
"(install the python-emaneeventservice bindings)"
|
||||
logger.error(errmsg)
|
||||
logger.error("Warning: EMANE events will not be generated "
|
||||
"because the emaneeventservice\n binding was "
|
||||
"unable to load "
|
||||
"(install the python-emaneeventservice bindings)")
|
||||
return
|
||||
self.doeventloop = True
|
||||
self.eventmonthread = threading.Thread(target=self.eventmonitorloop)
|
||||
|
@ -1019,6 +999,7 @@ class EmaneGlobalModel(EmaneModel):
|
|||
"""
|
||||
Global EMANE configuration options.
|
||||
"""
|
||||
|
||||
_DEFAULT_DEV = "ctrl0"
|
||||
|
||||
name = "emane"
|
||||
|
@ -1033,19 +1014,26 @@ class EmaneGlobalModel(EmaneModel):
|
|||
emulator_config = emanemanifest.parse(emulator_xml, emulator_defaults)
|
||||
emulator_config.insert(
|
||||
0,
|
||||
("platform_id_start", ConfigDataTypes.INT32.value, "1", "", "Starting Platform ID (core)")
|
||||
Configuration(_id="platform_id_start", _type=ConfigDataTypes.INT32, default="1",
|
||||
label="Starting Platform ID (core)")
|
||||
)
|
||||
|
||||
nem_config = [
|
||||
("nem_id_start", ConfigDataTypes.INT32.value, "1", "", "Starting NEM ID (core)"),
|
||||
Configuration(_id="nem_id_start", _type=ConfigDataTypes.INT32, default="1",
|
||||
label="Starting NEM ID (core)")
|
||||
]
|
||||
|
||||
config_matrix_override = emulator_config + nem_config
|
||||
config_groups_override = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % (
|
||||
len(emulator_config), len(emulator_config) + 1, len(config_matrix_override))
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return cls.emulator_config + cls.nem_config
|
||||
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "Platform Attributes:1-%d|NEM Parameters:%d-%d" % (
|
||||
len(cls.emulator_config), len(cls.emulator_config) + 1, len(cls.configurations()))
|
||||
|
||||
def __init__(self, session, object_id=None):
|
||||
EmaneModel.__init__(self, session, object_id)
|
||||
super(EmaneGlobalModel, self).__init__(session, object_id)
|
||||
|
||||
def build_xml_files(self, emane_manager, interface):
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from core import logger
|
||||
from core.conf import Configuration
|
||||
from core.enumerations import ConfigDataTypes
|
||||
|
||||
manifest = None
|
||||
|
@ -23,7 +24,7 @@ def _type_value(config_type):
|
|||
config_type = "FLOAT"
|
||||
elif config_type == "INETADDR":
|
||||
config_type = "STRING"
|
||||
return ConfigDataTypes[config_type].value
|
||||
return ConfigDataTypes[config_type]
|
||||
|
||||
|
||||
def _get_possible(config_type, config_regex):
|
||||
|
@ -36,14 +37,13 @@ def _get_possible(config_type, config_regex):
|
|||
:rtype: str
|
||||
"""
|
||||
if config_type == "bool":
|
||||
return "On,Off"
|
||||
return ["On", "Off"]
|
||||
|
||||
if config_type == "string" and config_regex:
|
||||
possible = config_regex[2:-2]
|
||||
possible = possible.replace("|", ",")
|
||||
return possible
|
||||
return possible.split("|")
|
||||
|
||||
return ""
|
||||
return []
|
||||
|
||||
|
||||
def _get_default(config_type_name, config_value):
|
||||
|
@ -116,7 +116,13 @@ def parse(manifest_path, defaults):
|
|||
if config_name.endswith("uri"):
|
||||
config_descriptions = "%s file" % config_descriptions
|
||||
|
||||
config_tuple = (config_name, config_type_value, config_default, possible, config_descriptions)
|
||||
configurations.append(config_tuple)
|
||||
configuration = Configuration(
|
||||
_id=config_name,
|
||||
_type=config_type_value,
|
||||
default=config_default,
|
||||
options=possible,
|
||||
label=config_descriptions
|
||||
)
|
||||
configurations.append(configuration)
|
||||
|
||||
return configurations
|
||||
|
|
|
@ -34,51 +34,12 @@ def value_to_params(doc, name, value):
|
|||
return xmlutils.add_param_list_to_parent(doc, parent=None, name=name, values=values)
|
||||
|
||||
|
||||
class EmaneModelMetaClass(type):
|
||||
"""
|
||||
Hack into making class level properties to streamline emane model creation, until the Configurable class is
|
||||
removed or refactored.
|
||||
"""
|
||||
|
||||
@property
|
||||
def config_matrix(cls):
|
||||
"""
|
||||
Convenience method for creating the config matrix, allow for a custom override.
|
||||
|
||||
:param EmaneModel cls: emane class
|
||||
:return: config matrix value
|
||||
:rtype: list
|
||||
"""
|
||||
if cls.config_matrix_override:
|
||||
return cls.config_matrix_override
|
||||
else:
|
||||
return cls.mac_config + cls.phy_config
|
||||
|
||||
@property
|
||||
def config_groups(cls):
|
||||
"""
|
||||
Convenience method for creating the config groups, allow for a custom override.
|
||||
|
||||
:param EmaneModel cls: emane class
|
||||
:return: config groups value
|
||||
:rtype: str
|
||||
"""
|
||||
if cls.config_groups_override:
|
||||
return cls.config_groups_override
|
||||
else:
|
||||
mac_len = len(cls.mac_config)
|
||||
config_len = len(cls.config_matrix)
|
||||
return "MAC Parameters:1-%d|PHY Parameters:%d-%d" % (mac_len, mac_len + 1, config_len)
|
||||
|
||||
|
||||
class EmaneModel(WirelessModel):
|
||||
"""
|
||||
EMANE models inherit from this parent class, which takes care of
|
||||
handling configuration messages based on the list of
|
||||
configurable parameters. Helper functions also live here.
|
||||
"""
|
||||
__metaclass__ = EmaneModelMetaClass
|
||||
|
||||
# default mac configuration settings
|
||||
mac_library = None
|
||||
mac_xml = None
|
||||
|
@ -97,10 +58,20 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
config_ignore = set()
|
||||
config_groups_override = None
|
||||
config_matrix_override = None
|
||||
configurations_override = None
|
||||
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return cls.mac_config + cls.phy_config
|
||||
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
mac_len = len(cls.mac_config)
|
||||
config_len = len(cls.configurations())
|
||||
return "MAC Parameters:1-%d|PHY Parameters:%d-%d" % (mac_len, mac_len + 1, config_len)
|
||||
|
||||
def __init__(self, session, object_id=None):
|
||||
WirelessModel.__init__(self, session, object_id)
|
||||
super(EmaneModel, self).__init__(session, object_id)
|
||||
|
||||
def build_xml_files(self, emane_manager, interface):
|
||||
"""
|
||||
|
@ -111,8 +82,8 @@ class EmaneModel(WirelessModel):
|
|||
:return: nothing
|
||||
"""
|
||||
# retrieve configuration values
|
||||
values = emane_manager.getifcconfig(self.object_id, self.name, self.getdefaultvalues(), interface)
|
||||
if values is None:
|
||||
config = emane_manager.getifcconfig(self.object_id, self.name, self.default_values(), interface)
|
||||
if not config:
|
||||
return
|
||||
|
||||
# create document and write to disk
|
||||
|
@ -122,12 +93,12 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
# create mac document and write to disk
|
||||
mac_name = self.mac_name(interface)
|
||||
mac_document = self.create_mac_doc(emane_manager, values)
|
||||
mac_document = self.create_mac_doc(emane_manager, config)
|
||||
emane_manager.xmlwrite(mac_document, mac_name)
|
||||
|
||||
# create phy document and write to disk
|
||||
phy_name = self.phy_name(interface)
|
||||
phy_document = self.create_phy_doc(emane_manager, values)
|
||||
phy_document = self.create_phy_doc(emane_manager, config)
|
||||
emane_manager.xmlwrite(phy_document, phy_name)
|
||||
|
||||
def create_nem_doc(self, emane_manager, interface):
|
||||
|
@ -157,18 +128,15 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
return nem_document
|
||||
|
||||
def create_mac_doc(self, emane_manager, values):
|
||||
def create_mac_doc(self, emane_manager, config):
|
||||
"""
|
||||
Create the mac xml document.
|
||||
|
||||
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
||||
:param tuple values: all current configuration values, mac + phy
|
||||
:param dict config: all current configuration values, mac + phy
|
||||
:return: nem document
|
||||
:rtype: xml.dom.minidom.Document
|
||||
"""
|
||||
names = list(self.getnames())
|
||||
mac_names = names[:len(self.mac_config)]
|
||||
|
||||
mac_document = emane_manager.xmldoc("mac")
|
||||
mac_element = mac_document.getElementsByTagName("mac").pop()
|
||||
mac_element.setAttribute("name", "%s MAC" % self.name)
|
||||
|
@ -177,13 +145,14 @@ class EmaneModel(WirelessModel):
|
|||
raise ValueError("must define emane model library")
|
||||
mac_element.setAttribute("library", self.mac_library)
|
||||
|
||||
for name in mac_names:
|
||||
for mac_configuration in self.mac_config:
|
||||
# ignore custom configurations
|
||||
name = mac_configuration.id
|
||||
if name in self.config_ignore:
|
||||
continue
|
||||
|
||||
# check if value is a multi param
|
||||
value = self.valueof(name, values)
|
||||
value = config[name]
|
||||
param = value_to_params(mac_document, name, value)
|
||||
if not param:
|
||||
param = emane_manager.xmlparam(mac_document, name, value)
|
||||
|
@ -192,18 +161,15 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
return mac_document
|
||||
|
||||
def create_phy_doc(self, emane_manager, values):
|
||||
def create_phy_doc(self, emane_manager, config):
|
||||
"""
|
||||
Create the phy xml document.
|
||||
|
||||
:param core.emane.emanemanager.EmaneManager emane_manager: core emane manager
|
||||
:param tuple values: all current configuration values, mac + phy
|
||||
:param dict config: all current configuration values, mac + phy
|
||||
:return: nem document
|
||||
:rtype: xml.dom.minidom.Document
|
||||
"""
|
||||
names = list(self.getnames())
|
||||
phy_names = names[len(self.mac_config):]
|
||||
|
||||
phy_document = emane_manager.xmldoc("phy")
|
||||
phy_element = phy_document.getElementsByTagName("phy").pop()
|
||||
phy_element.setAttribute("name", "%s PHY" % self.name)
|
||||
|
@ -212,13 +178,14 @@ class EmaneModel(WirelessModel):
|
|||
phy_element.setAttribute("library", self.phy_library)
|
||||
|
||||
# append all phy options
|
||||
for name in phy_names:
|
||||
for phy_configuration in self.phy_config:
|
||||
# ignore custom configurations
|
||||
name = phy_configuration.id
|
||||
if name in self.config_ignore:
|
||||
continue
|
||||
|
||||
# check if value is a multi param
|
||||
value = self.valueof(name, values)
|
||||
value = config[name]
|
||||
param = value_to_params(phy_document, name, value)
|
||||
if not param:
|
||||
param = emane_manager.xmlparam(phy_document, name, value)
|
||||
|
@ -227,16 +194,6 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
return phy_document
|
||||
|
||||
@classmethod
|
||||
def configure_emane(cls, session, config_data):
|
||||
"""
|
||||
Handle configuration messages for configuring an emane model.
|
||||
|
||||
:param core.session.Session session: session to configure emane
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
"""
|
||||
return cls.configure(session.emane, config_data)
|
||||
|
||||
def post_startup(self, emane_manager):
|
||||
"""
|
||||
Logic to execute after the emane manager is finished with startup.
|
||||
|
@ -317,7 +274,7 @@ class EmaneModel(WirelessModel):
|
|||
|
||||
if interface:
|
||||
node_id = interface.node.objid
|
||||
if emane_manager.getifcconfig(node_id, self.name, None, interface) is not None:
|
||||
if emane_manager.getifcconfig(node_id, self.name, {}, interface):
|
||||
name = interface.localname.replace(".", "_")
|
||||
|
||||
return "%s%s" % (name, self.name)
|
||||
|
|
|
@ -174,14 +174,9 @@ class EmaneNode(EmaneNet):
|
|||
trans.setAttribute("library", "trans%s" % transport_type.lower())
|
||||
trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0"))
|
||||
|
||||
flowcontrol = False
|
||||
names = self.model.getnames()
|
||||
values = emane.getconfig(self.objid, self.model.name, self.model.getdefaultvalues())[1]
|
||||
|
||||
if "flowcontrolenable" in names and values:
|
||||
i = names.index("flowcontrolenable")
|
||||
if self.model.booltooffon(values[i]) == "on":
|
||||
flowcontrol = True
|
||||
config = emane.get_configs(self.objid, self.model.name)
|
||||
logger.debug("transport xml config: %s", config)
|
||||
flowcontrol = config.get("flowcontrolenable", "0") == "1"
|
||||
|
||||
if "virtual" in transport_type.lower():
|
||||
if os.path.exists("/dev/net/tun_flowctl"):
|
||||
|
@ -193,11 +188,11 @@ class EmaneNode(EmaneNet):
|
|||
|
||||
emane.xmlwrite(transdoc, self.transportxmlname(transport_type.lower()))
|
||||
|
||||
def transportxmlname(self, type):
|
||||
def transportxmlname(self, _type):
|
||||
"""
|
||||
Return the string name for the Transport XML file, e.g. 'n3transvirtual.xml'
|
||||
"""
|
||||
return "n%strans%s.xml" % (self.objid, type)
|
||||
return "n%strans%s.xml" % (self.objid, _type)
|
||||
|
||||
def installnetifs(self, do_netns=True):
|
||||
"""
|
||||
|
|
|
@ -6,6 +6,7 @@ import os
|
|||
|
||||
from core import constants
|
||||
from core import logger
|
||||
from core.conf import Configuration
|
||||
from core.emane import emanemanifest
|
||||
from core.emane import emanemodel
|
||||
from core.enumerations import ConfigDataTypes
|
||||
|
@ -29,7 +30,12 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
|
|||
default_schedule = os.path.join(constants.CORE_DATA_DIR, "examples", "tdma", "schedule.xml")
|
||||
mac_config.insert(
|
||||
0,
|
||||
(schedule_name, ConfigDataTypes.STRING.value, default_schedule, "", "TDMA schedule file (core)")
|
||||
Configuration(
|
||||
_id=schedule_name,
|
||||
_type=ConfigDataTypes.STRING,
|
||||
default=default_schedule,
|
||||
label="TDMA schedule file (core)"
|
||||
)
|
||||
)
|
||||
config_ignore = {schedule_name}
|
||||
|
||||
|
@ -41,10 +47,10 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
|
|||
:return: nothing
|
||||
"""
|
||||
# get configured schedule
|
||||
values = emane_manager.getconfig(self.object_id, self.name, self.getdefaultvalues())[1]
|
||||
if values is None:
|
||||
config = emane_manager.get_configs()
|
||||
if not config:
|
||||
return
|
||||
schedule = self.valueof(self.schedule_name, values)
|
||||
schedule = config[self.schedule_name]
|
||||
|
||||
event_device = emane_manager.event_device
|
||||
|
||||
|
|
|
@ -378,7 +378,8 @@ class EmuSession(Session):
|
|||
if node_two:
|
||||
node_two.lock.release()
|
||||
|
||||
def update_link(self, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None, link_options=LinkOptions()):
|
||||
def update_link(self, node_one_id, node_two_id, interface_one_id=None, interface_two_id=None,
|
||||
link_options=LinkOptions()):
|
||||
"""
|
||||
Update link information between nodes.
|
||||
|
||||
|
@ -480,7 +481,7 @@ class EmuSession(Session):
|
|||
|
||||
# set node start based on current session state, override and check when rj45
|
||||
start = self.state > EventTypes.DEFINITION_STATE.value
|
||||
enable_rj45 = getattr(self.options, "enablerj45", "0") == "1"
|
||||
enable_rj45 = self.options.get_config("enablerj45") == "1"
|
||||
if _type == NodeTypes.RJ45 and not enable_rj45:
|
||||
start = False
|
||||
|
||||
|
@ -851,7 +852,7 @@ class CoreEmu(object):
|
|||
"""
|
||||
# set umask 0
|
||||
os.umask(0)
|
||||
|
||||
|
||||
# configuration
|
||||
self.config = config
|
||||
|
||||
|
|
|
@ -6,19 +6,15 @@ https://pypi.python.org/pypi/utm (version 0.3.0).
|
|||
"""
|
||||
|
||||
from core import logger
|
||||
from core.conf import ConfigurableManager
|
||||
from core.enumerations import RegisterTlvs
|
||||
from core.misc import utm
|
||||
|
||||
|
||||
class CoreLocation(ConfigurableManager):
|
||||
class CoreLocation(object):
|
||||
"""
|
||||
Member of session class for handling global location data. This keeps
|
||||
track of a latitude/longitude/altitude reference point and scale in
|
||||
order to convert between X,Y and geo coordinates.
|
||||
|
||||
TODO: this could be updated to use more generic
|
||||
Configurable/ConfigurableManager code like other Session objects
|
||||
"""
|
||||
name = "location"
|
||||
config_type = RegisterTlvs.UTILITY.value
|
||||
|
@ -29,7 +25,7 @@ class CoreLocation(ConfigurableManager):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
ConfigurableManager.__init__(self)
|
||||
# ConfigurableManager.__init__(self)
|
||||
self.reset()
|
||||
self.zonemap = {}
|
||||
self.refxyz = (0.0, 0.0, 0.0)
|
||||
|
@ -52,35 +48,6 @@ class CoreLocation(ConfigurableManager):
|
|||
# cached distance to refpt in other zones
|
||||
self.zoneshifts = {}
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Receive configuration message for setting the reference point
|
||||
and scale.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: nothing
|
||||
"""
|
||||
values = config_data.data_values
|
||||
|
||||
if values is None:
|
||||
logger.warn("location data missing")
|
||||
return None
|
||||
values = values.split('|')
|
||||
|
||||
# Cartesian coordinate reference point
|
||||
refx, refy = map(lambda x: float(x), values[0:2])
|
||||
refz = 0.0
|
||||
self.refxyz = (refx, refy, refz)
|
||||
# Geographic reference point
|
||||
lat, lon, alt = map(lambda x: float(x), values[2:5])
|
||||
self.setrefgeo(lat, lon, alt)
|
||||
self.refscale = float(values[5])
|
||||
logger.info("location configured: (%.2f,%.2f,%.2f) = (%.5f,%.5f,%.5f) scale=%.2f" %
|
||||
(self.refxyz[0], self.refxyz[1], self.refxyz[2], self.refgeo[0],
|
||||
self.refgeo[1], self.refgeo[2], self.refscale))
|
||||
logger.info("location configured: UTM(%.5f,%.5f,%.5f)" %
|
||||
(self.refutm[1], self.refutm[2], self.refutm[3]))
|
||||
|
||||
def px2m(self, val):
|
||||
"""
|
||||
Convert the specified value in pixels to meters using the
|
||||
|
|
|
@ -9,10 +9,12 @@ import threading
|
|||
import time
|
||||
|
||||
from core import logger
|
||||
from core.conf import Configurable
|
||||
from core.conf import ConfigurableManager
|
||||
from core.conf import ConfigurableOptions
|
||||
from core.conf import Configuration
|
||||
from core.conf import NewConfigurableManager
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.data import EventData, LinkData
|
||||
from core.data import EventData
|
||||
from core.data import LinkData
|
||||
from core.enumerations import ConfigDataTypes
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import LinkTypes
|
||||
|
@ -24,7 +26,7 @@ from core.misc import utils
|
|||
from core.misc.ipaddress import IpAddress
|
||||
|
||||
|
||||
class MobilityManager(ConfigurableManager):
|
||||
class MobilityManager(NewConfigurableManager):
|
||||
"""
|
||||
Member of session class for handling configuration data for mobility and
|
||||
range models.
|
||||
|
@ -38,20 +40,42 @@ class MobilityManager(ConfigurableManager):
|
|||
|
||||
:param core.session.Session session: session this manager is tied to
|
||||
"""
|
||||
ConfigurableManager.__init__(self)
|
||||
super(MobilityManager, self).__init__()
|
||||
self.session = session
|
||||
# configurations for basic range, indexed by WLAN node number, are
|
||||
# stored in self.configs
|
||||
# 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
|
||||
}
|
||||
|
||||
# dummy node objects for tracking position of nodes on other servers
|
||||
self.phys = {}
|
||||
self.physnets = {}
|
||||
self.session.broker.handlers.add(self.physnodehandlelink)
|
||||
|
||||
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
|
||||
"""
|
||||
configs = self.get_config_types(node.objid)
|
||||
models = []
|
||||
for model_name, config in configs.iteritems():
|
||||
model_class = self._modelclsmap[model_name]
|
||||
models.append((model_class, config))
|
||||
return models
|
||||
|
||||
def startup(self, node_ids=None):
|
||||
"""
|
||||
Session is transitioning from instantiation to runtime state.
|
||||
|
@ -61,7 +85,7 @@ class MobilityManager(ConfigurableManager):
|
|||
:return: nothing
|
||||
"""
|
||||
if node_ids is None:
|
||||
node_ids = self.configs.keys()
|
||||
node_ids = self.nodes()
|
||||
|
||||
for node_id in node_ids:
|
||||
logger.info("checking mobility startup for node: %s", node_id)
|
||||
|
@ -69,22 +93,22 @@ class MobilityManager(ConfigurableManager):
|
|||
try:
|
||||
node = self.session.get_object(node_id)
|
||||
except KeyError:
|
||||
logger.warn("skipping mobility configuration for unknown node %d." % node_id)
|
||||
logger.warn("skipping mobility configuration for unknown node: %s", node_id)
|
||||
continue
|
||||
|
||||
if node_id not in self.configs:
|
||||
logger.warn("missing mobility configuration for node %d." % node_id)
|
||||
node_configs = self.get_config_types(node_id)
|
||||
if not node_configs:
|
||||
logger.warn("missing mobility configuration for node: %s", node_id)
|
||||
continue
|
||||
|
||||
v = self.configs[node_id]
|
||||
|
||||
for model in v:
|
||||
for model_name in node_configs.iterkeys():
|
||||
try:
|
||||
logger.info("setting mobility model to node: %s", model)
|
||||
cls = self._modelclsmap[model[0]]
|
||||
node.setmodel(cls, model[1])
|
||||
clazz = self._modelclsmap[model_name]
|
||||
model_config = self.get_config(node_id, model_name)
|
||||
logger.info("setting mobility model(%s) to node: %s", model_name, model_config)
|
||||
node.setmodel(clazz, model_config)
|
||||
except KeyError:
|
||||
logger.warn("skipping mobility configuration for unknown model '%s'" % model[0])
|
||||
logger.warn("skipping mobility configuration for unknown model: %s", model_name)
|
||||
continue
|
||||
|
||||
if self.session.master:
|
||||
|
@ -99,26 +123,32 @@ class MobilityManager(ConfigurableManager):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
self.clearconfig(nodenum=None)
|
||||
self.config_reset()
|
||||
|
||||
def setconfig(self, node_id, config_type, values):
|
||||
def set_configs(self, config, node_id=None, config_type=None):
|
||||
"""
|
||||
Normal setconfig() with check for run-time updates for WLANs.
|
||||
Adds a check for run-time updates for WLANs after providing normal set configs.
|
||||
|
||||
:param dict config: configuration value
|
||||
:param int node_id: node id
|
||||
:param config_type: configuration type
|
||||
:param values: configuration value
|
||||
:param str config_type: configuration type
|
||||
:return: nothing
|
||||
"""
|
||||
super(MobilityManager, self).setconfig(node_id, config_type, values)
|
||||
if not node_id or not config_type:
|
||||
raise ValueError("mobility manager invalid node id or config type: %s - %s", node_id, config_type)
|
||||
|
||||
super(MobilityManager, self).set_configs(config, node_id, config_type)
|
||||
|
||||
if self.session is None:
|
||||
return
|
||||
|
||||
if self.session.state == EventTypes.RUNTIME_STATE.value:
|
||||
try:
|
||||
node = self.session.get_object(node_id)
|
||||
node.updatemodel(config_type, values)
|
||||
# TODO: this need to be updated
|
||||
node.updatemodel(config_type, config)
|
||||
except KeyError:
|
||||
logger.exception("Skipping mobility configuration for unknown node %d.", node_id)
|
||||
logger.exception("skipping mobility configuration for unknown node %s", node_id)
|
||||
|
||||
def handleevent(self, event_data):
|
||||
"""
|
||||
|
@ -206,13 +236,13 @@ class MobilityManager(ConfigurableManager):
|
|||
:param list moved_netifs: moved network interfaces
|
||||
:return: nothing
|
||||
"""
|
||||
for nodenum in self.configs:
|
||||
for node_id in self.nodes():
|
||||
try:
|
||||
n = self.session.get_object(nodenum)
|
||||
node = self.session.get_object(node_id)
|
||||
except KeyError:
|
||||
continue
|
||||
if n.model:
|
||||
n.model.update(moved, moved_netifs)
|
||||
if node.model:
|
||||
node.model.update(moved, moved_netifs)
|
||||
|
||||
def addphys(self, netnum, node):
|
||||
"""
|
||||
|
@ -222,12 +252,12 @@ class MobilityManager(ConfigurableManager):
|
|||
:param core.coreobj.PyCoreNode node: node to add physical network to
|
||||
:return: nothing
|
||||
"""
|
||||
nodenum = node.objid
|
||||
self.phys[nodenum] = node
|
||||
node_id = node.objid
|
||||
self.phys[node_id] = node
|
||||
if netnum not in self.physnets:
|
||||
self.physnets[netnum] = [nodenum, ]
|
||||
self.physnets[netnum] = [node_id, ]
|
||||
else:
|
||||
self.physnets[netnum].append(nodenum)
|
||||
self.physnets[netnum].append(node_id)
|
||||
|
||||
# TODO: remove need for handling old style message
|
||||
def physnodehandlelink(self, message):
|
||||
|
@ -247,8 +277,7 @@ class MobilityManager(ConfigurableManager):
|
|||
return
|
||||
if nn[1] in self.session.broker.physical_nodes:
|
||||
# record the fact that this PhysicalNode is linked to a net
|
||||
dummy = PyCoreNode(session=self.session, objid=nn[1],
|
||||
name="n%d" % nn[1], start=False)
|
||||
dummy = PyCoreNode(session=self.session, objid=nn[1], name="n%d" % nn[1], start=False)
|
||||
self.addphys(nn[0], dummy)
|
||||
|
||||
# TODO: remove need to handling old style messages
|
||||
|
@ -291,7 +320,7 @@ class MobilityManager(ConfigurableManager):
|
|||
netif.poshook(netif, x, y, z)
|
||||
|
||||
|
||||
class WirelessModel(Configurable):
|
||||
class WirelessModel(ConfigurableOptions):
|
||||
"""
|
||||
Base class used by EMANE models and the basic range model.
|
||||
Used for managing arbitrary configuration parameters.
|
||||
|
@ -308,9 +337,8 @@ class WirelessModel(Configurable):
|
|||
:param int object_id: object id
|
||||
:param values: values
|
||||
"""
|
||||
Configurable.__init__(self, session, object_id)
|
||||
# 'values' can be retrieved from a ConfigurableManager, or used here
|
||||
# during initialization, depending on the model.
|
||||
self.session = session
|
||||
self.object_id = object_id
|
||||
|
||||
def all_link_data(self, flags):
|
||||
"""
|
||||
|
@ -333,12 +361,12 @@ class WirelessModel(Configurable):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def updateconfig(self, values):
|
||||
def updateconfig(self, config):
|
||||
"""
|
||||
For run-time updates of model config. Returns True when position callback and set link
|
||||
parameters should be invoked.
|
||||
|
||||
:param values: value to update
|
||||
:param dict config: value to update
|
||||
:return: False
|
||||
:rtype: bool
|
||||
"""
|
||||
|
@ -353,23 +381,20 @@ class BasicRangeModel(WirelessModel):
|
|||
"""
|
||||
name = "basic_range"
|
||||
|
||||
# configuration parameters are
|
||||
# ( 'name', 'type', 'default', 'possible-value-list', 'caption')
|
||||
config_matrix = [
|
||||
("range", ConfigDataTypes.UINT32.value, '275',
|
||||
'', 'wireless range (pixels)'),
|
||||
("bandwidth", ConfigDataTypes.UINT32.value, '54000',
|
||||
'', 'bandwidth (bps)'),
|
||||
("jitter", ConfigDataTypes.FLOAT.value, '0.0',
|
||||
'', 'transmission jitter (usec)'),
|
||||
("delay", ConfigDataTypes.FLOAT.value, '5000.0',
|
||||
'', 'transmission delay (usec)'),
|
||||
("error", ConfigDataTypes.FLOAT.value, '0.0',
|
||||
'', 'error rate (%)'),
|
||||
]
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return [
|
||||
Configuration(_id="range", _type=ConfigDataTypes.UINT32, default="275", label="wireless range (pixels)"),
|
||||
Configuration(_id="bandwidth", _type=ConfigDataTypes.UINT32, default="54000", label="bandwidth (bps)"),
|
||||
Configuration(_id="jitter", _type=ConfigDataTypes.FLOAT, default="0.0", label="transmission jitter (usec)"),
|
||||
Configuration(_id="delay", _type=ConfigDataTypes.FLOAT, default="5000.0",
|
||||
label="transmission delay (usec)"),
|
||||
Configuration(_id="error", _type=ConfigDataTypes.FLOAT, default="0.0", label="error rate (%)")
|
||||
]
|
||||
|
||||
# value groupings
|
||||
config_groups = "Basic Range Parameters:1-%d" % len(config_matrix)
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "Basic Range Parameters:1-%d" % len(cls.configurations())
|
||||
|
||||
def __init__(self, session, object_id, values=None):
|
||||
"""
|
||||
|
@ -377,57 +402,49 @@ class BasicRangeModel(WirelessModel):
|
|||
|
||||
:param core.session.Session session: related core session
|
||||
:param int object_id: object id
|
||||
:param values: values
|
||||
:param dict values: values
|
||||
"""
|
||||
super(BasicRangeModel, self).__init__(session=session, object_id=object_id)
|
||||
self.session = session
|
||||
self.wlan = session.get_object(object_id)
|
||||
self._netifs = {}
|
||||
self._netifslock = threading.Lock()
|
||||
if values is None:
|
||||
values = session.mobility.getconfig(object_id, self.name, self.getdefaultvalues())[1]
|
||||
self.range = float(self.valueof("range", values))
|
||||
logger.info("Basic range model configured for WLAN %d using range %d", object_id, self.range)
|
||||
self.valuestolinkparams(values)
|
||||
if not values:
|
||||
values = self.default_values()
|
||||
|
||||
# link parameters
|
||||
# TODO: can this be handled in a better spot
|
||||
self.session.mobility.set_configs(values, node_id=object_id, config_type=self.name)
|
||||
|
||||
self.range = None
|
||||
self.bw = None
|
||||
self.delay = None
|
||||
self.loss = None
|
||||
self.jitter = None
|
||||
|
||||
def valuestolinkparams(self, values):
|
||||
self.values_from_config(values)
|
||||
|
||||
def values_from_config(self, config):
|
||||
"""
|
||||
Values to convert to link parameters.
|
||||
|
||||
:param values: values to convert
|
||||
:param dict config: values to convert
|
||||
:return: nothing
|
||||
"""
|
||||
self.bw = int(self.valueof("bandwidth", values))
|
||||
self.range = float(config["range"])
|
||||
logger.info("Basic range model configured for WLAN %d using range %d", self.wlan.objid, self.range)
|
||||
self.bw = int(config["bandwidth"])
|
||||
if self.bw == 0.0:
|
||||
self.bw = None
|
||||
self.delay = float(self.valueof("delay", values))
|
||||
self.delay = float(config["delay"])
|
||||
if self.delay == 0.0:
|
||||
self.delay = None
|
||||
self.loss = float(self.valueof("error", values))
|
||||
self.loss = float(config["error"])
|
||||
if self.loss == 0.0:
|
||||
self.loss = None
|
||||
self.jitter = float(self.valueof("jitter", values))
|
||||
self.jitter = float(config["jitter"])
|
||||
if self.jitter == 0.0:
|
||||
self.jitter = None
|
||||
|
||||
@classmethod
|
||||
def configure_mob(cls, session, config_data):
|
||||
"""
|
||||
Handle configuration messages for setting up a model.
|
||||
Pass the MobilityManager object as the manager object.
|
||||
|
||||
:param core.session.Session session: current session calling function
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: configuration data
|
||||
:rtype: core.data.ConfigData
|
||||
"""
|
||||
return cls.configure(session.mobility, config_data)
|
||||
|
||||
def setlinkparams(self):
|
||||
"""
|
||||
Apply link parameters to all interfaces. This is invoked from
|
||||
|
@ -435,8 +452,7 @@ class BasicRangeModel(WirelessModel):
|
|||
"""
|
||||
with self._netifslock:
|
||||
for netif in self._netifs:
|
||||
self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay,
|
||||
loss=self.loss, duplicate=None,
|
||||
self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay, loss=self.loss, duplicate=None,
|
||||
jitter=self.jitter)
|
||||
|
||||
def get_position(self, netif):
|
||||
|
@ -461,7 +477,6 @@ class BasicRangeModel(WirelessModel):
|
|||
:param z: z position
|
||||
:return: nothing
|
||||
"""
|
||||
# print "set_position(%s, x=%s, y=%s, z=%s)" % (netif.localname, x, y, z)
|
||||
self._netifslock.acquire()
|
||||
self._netifs[netif] = (x, y, z)
|
||||
if x is None or y is None:
|
||||
|
@ -487,7 +502,7 @@ class BasicRangeModel(WirelessModel):
|
|||
with self._netifslock:
|
||||
while len(moved_netifs):
|
||||
netif = moved_netifs.pop()
|
||||
(nx, ny, nz) = netif.node.getposition()
|
||||
nx, ny, nz = netif.node.getposition()
|
||||
if netif in self._netifs:
|
||||
self._netifs[netif] = (nx, ny, nz)
|
||||
for netif2 in self._netifs:
|
||||
|
@ -557,18 +572,17 @@ class BasicRangeModel(WirelessModel):
|
|||
c = p1[2] - p2[2]
|
||||
return math.hypot(math.hypot(a, b), c)
|
||||
|
||||
def updateconfig(self, values):
|
||||
def updateconfig(self, config):
|
||||
"""
|
||||
Configuration has changed during runtime.
|
||||
MobilityManager.setconfig() -> WlanNode.updatemodel() ->
|
||||
WirelessModel.updateconfig()
|
||||
|
||||
:param values: values to update configuration
|
||||
:param dict config: values to update configuration
|
||||
:return: was update successful
|
||||
:rtype: bool
|
||||
"""
|
||||
self.valuestolinkparams(values)
|
||||
self.range = float(self.valueof("range", values))
|
||||
self.values_from_config(config)
|
||||
return True
|
||||
|
||||
def create_link_data(self, interface1, interface2, message_type):
|
||||
|
@ -581,7 +595,6 @@ class BasicRangeModel(WirelessModel):
|
|||
:return: link data
|
||||
:rtype: LinkData
|
||||
"""
|
||||
|
||||
return LinkData(
|
||||
message_type=message_type,
|
||||
node1_id=interface1.node.objid,
|
||||
|
@ -678,6 +691,7 @@ class WayPointMobility(WirelessModel):
|
|||
:return:
|
||||
"""
|
||||
super(WayPointMobility, self).__init__(session=session, object_id=object_id, values=values)
|
||||
|
||||
self.state = self.STATE_STOPPED
|
||||
self.queue = []
|
||||
self.queue_copy = []
|
||||
|
@ -705,7 +719,6 @@ class WayPointMobility(WirelessModel):
|
|||
self.lasttime = time.time()
|
||||
now = self.lasttime - self.timezero
|
||||
dt = self.lasttime - t
|
||||
# print "runround(now=%.2f, dt=%.2f)" % (now, dt)
|
||||
|
||||
# keep current waypoints up-to-date
|
||||
self.updatepoints(now)
|
||||
|
@ -741,7 +754,6 @@ class WayPointMobility(WirelessModel):
|
|||
moved_netifs.append(netif)
|
||||
|
||||
# calculate all ranges after moving nodes; this saves calculations
|
||||
# self.wlan.model.update(moved)
|
||||
self.session.mobility.updatewlans(moved, moved_netifs)
|
||||
|
||||
# TODO: check session state
|
||||
|
@ -806,7 +818,6 @@ class WayPointMobility(WirelessModel):
|
|||
self.endtime = self.lasttime - self.timezero
|
||||
del self.points[node.objid]
|
||||
return False
|
||||
# print "node %s dx,dy= <%s, %d>" % (node.name, dx, dy)
|
||||
if (x1 + dx) < 0.0:
|
||||
dx = 0.0 - x1
|
||||
if (y1 + dy) < 0.0:
|
||||
|
@ -826,7 +837,7 @@ class WayPointMobility(WirelessModel):
|
|||
node = netif.node
|
||||
if node.objid not in self.initial:
|
||||
continue
|
||||
(x, y, z) = self.initial[node.objid].coords
|
||||
x, y, z = self.initial[node.objid].coords
|
||||
self.setnodeposition(node, x, y, z)
|
||||
moved.append(node)
|
||||
moved_netifs.append(netif)
|
||||
|
@ -845,7 +856,6 @@ class WayPointMobility(WirelessModel):
|
|||
:param speed: speed
|
||||
:return: nothing
|
||||
"""
|
||||
# print "addwaypoint: %s %s %s,%s,%s %s" % (time, nodenum, x, y, z, speed)
|
||||
wp = WayPoint(time, nodenum, coords=(x, y, z), speed=speed)
|
||||
heapq.heappush(self.queue, wp)
|
||||
|
||||
|
@ -976,25 +986,22 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
"""
|
||||
name = "ns2script"
|
||||
|
||||
config_matrix = [
|
||||
("file", ConfigDataTypes.STRING.value, '',
|
||||
'', 'mobility script file'),
|
||||
("refresh_ms", ConfigDataTypes.UINT32.value, '50',
|
||||
'', 'refresh time (ms)'),
|
||||
("loop", ConfigDataTypes.BOOL.value, '1',
|
||||
'On,Off', 'loop'),
|
||||
("autostart", ConfigDataTypes.STRING.value, '',
|
||||
'', 'auto-start seconds (0.0 for runtime)'),
|
||||
("map", ConfigDataTypes.STRING.value, '',
|
||||
'', 'node mapping (optional, e.g. 0:1,1:2,2:3)'),
|
||||
("script_start", ConfigDataTypes.STRING.value, '',
|
||||
'', 'script file to run upon start'),
|
||||
("script_pause", ConfigDataTypes.STRING.value, '',
|
||||
'', 'script file to run upon pause'),
|
||||
("script_stop", ConfigDataTypes.STRING.value, '',
|
||||
'', 'script file to run upon stop'),
|
||||
]
|
||||
config_groups = "ns-2 Mobility Script Parameters:1-%d" % len(config_matrix)
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return [
|
||||
Configuration(_id="file", _type=ConfigDataTypes.STRING, label="mobility script file"),
|
||||
Configuration(_id="refresh_ms", _type=ConfigDataTypes.UINT32, default="50", label="mobility script file"),
|
||||
Configuration(_id="loop", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"], label="loop"),
|
||||
Configuration(_id="autostart", _type=ConfigDataTypes.STRING, label="auto-start seconds (0.0 for runtime)"),
|
||||
Configuration(_id="map", _type=ConfigDataTypes.STRING, label="node mapping (optional, e.g. 0:1,1:2,2:3)"),
|
||||
Configuration(_id="script_start", _type=ConfigDataTypes.STRING, label="script file to run upon start"),
|
||||
Configuration(_id="script_pause", _type=ConfigDataTypes.STRING, label="script file to run upon pause"),
|
||||
Configuration(_id="script_stop", _type=ConfigDataTypes.STRING, label="script file to run upon stop")
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "ns-2 Mobility Script Parameters:1-%d" % len(cls.configurations())
|
||||
|
||||
def __init__(self, session, object_id, values=None):
|
||||
"""
|
||||
|
@ -1007,32 +1014,24 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
super(Ns2ScriptedMobility, self).__init__(session=session, object_id=object_id, values=values)
|
||||
self._netifs = {}
|
||||
self._netifslock = threading.Lock()
|
||||
if values is None:
|
||||
values = session.mobility.getconfig(object_id, self.name, self.getdefaultvalues())[1]
|
||||
self.file = self.valueof("file", values)
|
||||
self.refresh_ms = int(self.valueof("refresh_ms", values))
|
||||
self.loop = self.valueof("loop", values).lower() == "on"
|
||||
self.autostart = self.valueof("autostart", values)
|
||||
self.parsemap(self.valueof("map", values))
|
||||
self.script_start = self.valueof("script_start", values)
|
||||
self.script_pause = self.valueof("script_pause", values)
|
||||
self.script_stop = self.valueof("script_stop", values)
|
||||
|
||||
if not values:
|
||||
values = self.default_values()
|
||||
self.session.mobility.set_configs(values, node_id=object_id, config_type=self.name)
|
||||
|
||||
self.file = values["file"]
|
||||
self.refresh_ms = int(values["refresh_ms"])
|
||||
self.loop = values["loop"].lower() == "on"
|
||||
self.autostart = values["autostart"]
|
||||
self.parsemap(values["map"])
|
||||
self.script_start = values["script_start"]
|
||||
self.script_pause = values["script_pause"]
|
||||
self.script_stop = values["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()
|
||||
|
||||
@classmethod
|
||||
def configure_mob(cls, session, config_data):
|
||||
"""
|
||||
Handle configuration messages for setting up a model.
|
||||
Pass the MobilityManager object as the manager object.
|
||||
|
||||
:param core.session.Session session: current session calling function
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
"""
|
||||
return cls.configure(session.mobility, config_data)
|
||||
|
||||
def readscriptfile(self):
|
||||
"""
|
||||
Read in mobility script from a file. This adds waypoints to a
|
||||
|
@ -1234,4 +1233,4 @@ class Ns2ScriptedMobility(WayPointMobility):
|
|||
return
|
||||
filename = self.findfile(filename)
|
||||
args = ["/bin/sh", filename, typestr]
|
||||
utils.check_cmd(args, cwd=self.session.sessiondir, env=self.session.get_environment())
|
||||
utils.check_cmd(args, cwd=self.session.session_dir, env=self.session.get_environment())
|
||||
|
|
|
@ -398,12 +398,12 @@ class WlanNode(LxBrNet):
|
|||
elif model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
self.mobility = model(session=self.session, object_id=self.objid, values=config)
|
||||
|
||||
def updatemodel(self, model_name, values):
|
||||
def updatemodel(self, model_name, config):
|
||||
"""
|
||||
Allow for model updates during runtime (similar to setmodel().)
|
||||
|
||||
:param model_name: model name to update
|
||||
:param values: values to update model with
|
||||
:param str model_name: model name to update
|
||||
:param dict config: values to update model with
|
||||
:return: nothing
|
||||
"""
|
||||
logger.info("updating model %s" % model_name)
|
||||
|
@ -412,14 +412,14 @@ class WlanNode(LxBrNet):
|
|||
|
||||
model = self.model
|
||||
if model.config_type == RegisterTlvs.WIRELESS.value:
|
||||
if not model.updateconfig(values):
|
||||
if not model.updateconfig(config):
|
||||
return
|
||||
|
||||
if self.model.position_callback:
|
||||
for netif in self.netifs():
|
||||
netif.poshook = self.model.position_callback
|
||||
if netif.node is not None:
|
||||
(x, y, z) = netif.node.position.get()
|
||||
x, y, z = netif.node.position.get()
|
||||
netif.poshook(netif, x, y, z)
|
||||
|
||||
self.model.setlinkparams()
|
||||
|
|
|
@ -118,12 +118,7 @@ class Sdt(object):
|
|||
:return: True if enabled, False otherwise
|
||||
:rtype: bool
|
||||
"""
|
||||
if not hasattr(self.session.options, "enablesdt"):
|
||||
return False
|
||||
enabled = self.session.options.enablesdt
|
||||
if enabled in ("1", "true", 1, True):
|
||||
return True
|
||||
return False
|
||||
return self.session.options.get_config("enablesdt") == "1"
|
||||
|
||||
def seturl(self):
|
||||
"""
|
||||
|
@ -132,11 +127,8 @@ class Sdt(object):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
url = None
|
||||
if hasattr(self.session.options, "sdturl"):
|
||||
if self.session.options.sdturl != "":
|
||||
url = self.session.options.sdturl
|
||||
if url is None or url == "":
|
||||
url = self.session.options.get_config("stdurl")
|
||||
if not url:
|
||||
url = self.DEFAULT_SDT_URL
|
||||
self.url = urlparse(url)
|
||||
self.address = (self.url.hostname, self.url.port)
|
||||
|
|
|
@ -7,17 +7,11 @@ a list of available services to the GUI and for configuring individual
|
|||
services.
|
||||
"""
|
||||
import time
|
||||
from itertools import repeat
|
||||
|
||||
from core import CoreCommandError
|
||||
from core import logger
|
||||
from core.conf import Configurable
|
||||
from core.conf import ConfigurableManager
|
||||
from core.data import ConfigData
|
||||
from core.data import EventData
|
||||
from core.data import FileData
|
||||
from core.enumerations import ConfigDataTypes
|
||||
from core.enumerations import ConfigFlags
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import RegisterTlvs
|
||||
|
@ -78,7 +72,7 @@ class ServiceManager(object):
|
|||
cls.add(service)
|
||||
|
||||
|
||||
class CoreServices(ConfigurableManager):
|
||||
class CoreServices(object):
|
||||
"""
|
||||
Class for interacting with a list of available startup services for
|
||||
nodes. Mostly used to convert a CoreService into a Config API
|
||||
|
@ -88,7 +82,6 @@ class CoreServices(ConfigurableManager):
|
|||
"""
|
||||
name = "services"
|
||||
config_type = RegisterTlvs.UTILITY.value
|
||||
|
||||
_invalid_custom_names = ("core", "api", "emane", "misc", "netns", "phys", "services")
|
||||
|
||||
def __init__(self, session):
|
||||
|
@ -98,7 +91,7 @@ class CoreServices(ConfigurableManager):
|
|||
:param core.session.Session session: session this manager is tied to
|
||||
:return: nothing
|
||||
"""
|
||||
ConfigurableManager.__init__(self)
|
||||
# ConfigurableManager.__init__(self)
|
||||
self.session = session
|
||||
# dict of default services tuples, key is node type
|
||||
self.defaultservices = {}
|
||||
|
@ -154,34 +147,31 @@ class CoreServices(ConfigurableManager):
|
|||
return s
|
||||
return service
|
||||
|
||||
def setcustomservice(self, object_id, service, values):
|
||||
def setcustomservice(self, object_id, service, config):
|
||||
"""
|
||||
Store service customizations in an instantiated service object
|
||||
using a list of values that came from a config message.
|
||||
|
||||
:param int object_id: object id to set custom service for
|
||||
:param class service: service to set
|
||||
:param list values: values to
|
||||
:param dict config: values to
|
||||
:return:
|
||||
"""
|
||||
logger.debug("setting custom service(%s) for node(%s): %s", object_id, service, config)
|
||||
if service._custom:
|
||||
s = service
|
||||
else:
|
||||
# instantiate the class, for storing config customization
|
||||
s = service()
|
||||
# values are new key=value format; not all keys need to be present
|
||||
# a missing key means go with the default
|
||||
if Configurable.haskeyvalues(values):
|
||||
for v in values:
|
||||
key, value = v.split('=', 1)
|
||||
s.setvalue(key, value)
|
||||
# old-style config, list of values
|
||||
else:
|
||||
s.fromvaluelist(values)
|
||||
|
||||
# set custom service configuration
|
||||
for name, value in config.iteritems():
|
||||
s.setvalue(name, value)
|
||||
|
||||
# assume custom service already in dict
|
||||
if service._custom:
|
||||
return
|
||||
|
||||
# add the custom service to dict
|
||||
if object_id in self.customservices:
|
||||
self.customservices[object_id] += (s,)
|
||||
|
@ -436,130 +426,6 @@ class CoreServices(ConfigurableManager):
|
|||
status = "-1"
|
||||
return status
|
||||
|
||||
def configure_request(self, config_data):
|
||||
"""
|
||||
Receive configuration message for configuring services.
|
||||
With a request flag set, a list of services has been requested.
|
||||
When the opaque field is present, a specific service is being
|
||||
configured or requested.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: response messages
|
||||
:rtype: ConfigData
|
||||
"""
|
||||
node_id = config_data.node
|
||||
session_id = config_data.session
|
||||
opaque = config_data.opaque
|
||||
|
||||
logger.debug("configuration request: node(%s) session(%s) opaque(%s)", node_id, session_id, opaque)
|
||||
|
||||
# send back a list of available services
|
||||
if opaque is None:
|
||||
type_flag = ConfigFlags.NONE.value
|
||||
data_types = tuple(repeat(ConfigDataTypes.BOOL.value, len(ServiceManager.services)))
|
||||
values = "|".join(repeat('0', len(ServiceManager.services)))
|
||||
names = map(lambda x: x._name, ServiceManager.services)
|
||||
captions = "|".join(names)
|
||||
possible_values = ""
|
||||
for s in ServiceManager.services:
|
||||
if s._custom_needed:
|
||||
possible_values += '1'
|
||||
possible_values += '|'
|
||||
groups = self.buildgroups(ServiceManager.services)
|
||||
# send back the properties for this service
|
||||
else:
|
||||
if node_id is None:
|
||||
return None
|
||||
node = self.session.get_object(node_id)
|
||||
if node is None:
|
||||
logger.warn("Request to configure service for unknown node %s", node_id)
|
||||
return None
|
||||
servicesstring = opaque.split(':')
|
||||
services, unknown = self.servicesfromopaque(opaque, node.objid)
|
||||
for u in unknown:
|
||||
logger.warn("Request for unknown service '%s'" % u)
|
||||
|
||||
if len(services) < 1:
|
||||
return None
|
||||
|
||||
if len(servicesstring) == 3:
|
||||
# a file request: e.g. "service:zebra:quagga.conf"
|
||||
file_data = self.getservicefile(services, node, servicesstring[2])
|
||||
self.session.broadcast_file(file_data)
|
||||
|
||||
# short circuit this request early to avoid returning response below
|
||||
return None
|
||||
|
||||
# the first service in the list is the one being configured
|
||||
svc = services[0]
|
||||
# send back:
|
||||
# dirs, configs, startindex, startup, shutdown, metadata, config
|
||||
type_flag = ConfigFlags.UPDATE.value
|
||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(svc.keys)))
|
||||
values = svc.tovaluelist(node, services)
|
||||
captions = None
|
||||
possible_values = None
|
||||
groups = None
|
||||
|
||||
return ConfigData(
|
||||
message_type=0,
|
||||
node=node_id,
|
||||
object=self.name,
|
||||
type=type_flag,
|
||||
data_types=data_types,
|
||||
data_values=values,
|
||||
captions=captions,
|
||||
possible_values=possible_values,
|
||||
groups=groups,
|
||||
session=session_id,
|
||||
opaque=opaque
|
||||
)
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Receive configuration message for configuring services.
|
||||
With a request flag set, a list of services has been requested.
|
||||
When the opaque field is present, a specific service is being
|
||||
configured or requested.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: None
|
||||
"""
|
||||
data_types = config_data.data_types
|
||||
values = config_data.data_values
|
||||
node_id = config_data.node
|
||||
opaque = config_data.opaque
|
||||
|
||||
error_message = "services config message that I don't know how to handle"
|
||||
if values is None:
|
||||
logger.error(error_message)
|
||||
return None
|
||||
else:
|
||||
values = values.split('|')
|
||||
|
||||
if opaque is None:
|
||||
# store default services for a node type in self.defaultservices[]
|
||||
if data_types is None or data_types[0] != ConfigDataTypes.STRING.value:
|
||||
logger.info(error_message)
|
||||
return None
|
||||
key = values.pop(0)
|
||||
self.defaultservices[key] = values
|
||||
logger.debug("default services for type %s set to %s", key, values)
|
||||
else:
|
||||
# store service customized config in self.customservices[]
|
||||
if node_id is None:
|
||||
return None
|
||||
services, unknown = self.servicesfromopaque(opaque, node_id)
|
||||
for u in unknown:
|
||||
logger.warn("Request for unknown service '%s'" % u)
|
||||
|
||||
if len(services) < 1:
|
||||
return None
|
||||
svc = services[0]
|
||||
self.setcustomservice(node_id, svc, values)
|
||||
|
||||
return None
|
||||
|
||||
def servicesfromopaque(self, opaque, object_id):
|
||||
"""
|
||||
Build a list of services from an opaque data string.
|
||||
|
|
|
@ -11,6 +11,7 @@ import subprocess
|
|||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from itertools import repeat
|
||||
|
||||
import pwd
|
||||
|
||||
|
@ -18,8 +19,10 @@ from core import constants
|
|||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.broker import CoreBroker
|
||||
from core.conf import Configurable
|
||||
from core.conf import ConfigurableManager
|
||||
from core.conf import ConfigShim
|
||||
from core.conf import ConfigurableOptions
|
||||
from core.conf import Configuration
|
||||
from core.conf import NewConfigurableManager
|
||||
from core.data import ConfigData
|
||||
from core.data import EventData
|
||||
from core.data import ExceptionData
|
||||
|
@ -37,11 +40,10 @@ from core.misc import nodeutils
|
|||
from core.misc import utils
|
||||
from core.misc.event import EventLoop
|
||||
from core.misc.ipaddress import MacAddress
|
||||
from core.mobility import BasicRangeModel
|
||||
from core.mobility import MobilityManager
|
||||
from core.mobility import Ns2ScriptedMobility
|
||||
from core.netns import nodes
|
||||
from core.sdt import Sdt
|
||||
from core.service import CoreService
|
||||
from core.service import CoreServices
|
||||
from core.xml.xmlsession import save_session_xml
|
||||
|
||||
|
@ -81,10 +83,6 @@ class Session(object):
|
|||
self.objects = {}
|
||||
self._objects_lock = threading.Lock()
|
||||
|
||||
# dict of configurable objects
|
||||
self.config_objects = {}
|
||||
self._config_objects_lock = threading.Lock()
|
||||
|
||||
# TODO: should the default state be definition?
|
||||
self.state = EventTypes.NONE.value
|
||||
self._state_time = time.time()
|
||||
|
@ -106,60 +104,30 @@ class Session(object):
|
|||
self.config_handlers = []
|
||||
self.shutdown_handlers = []
|
||||
|
||||
# setup broker
|
||||
# initialize feature helpers
|
||||
self.broker = CoreBroker(session=self)
|
||||
self.add_config_object(CoreBroker.name, CoreBroker.config_type, self.broker.configure)
|
||||
|
||||
# setup location
|
||||
self.location = CoreLocation()
|
||||
self.add_config_object(CoreLocation.name, CoreLocation.config_type, self.location.configure)
|
||||
|
||||
# setup mobiliy
|
||||
self.mobility = MobilityManager(session=self)
|
||||
self.add_config_object(MobilityManager.name, MobilityManager.config_type, self.mobility.configure)
|
||||
self.add_config_object(BasicRangeModel.name, BasicRangeModel.config_type, BasicRangeModel.configure_mob)
|
||||
self.add_config_object(Ns2ScriptedMobility.name, Ns2ScriptedMobility.config_type,
|
||||
Ns2ScriptedMobility.configure_mob)
|
||||
|
||||
# setup services
|
||||
self.services = CoreServices(session=self)
|
||||
self.add_config_object(CoreServices.name, CoreServices.config_type, self.services.configure)
|
||||
|
||||
# setup emane
|
||||
self.emane = EmaneManager(session=self)
|
||||
self.add_config_object(EmaneManager.name, EmaneManager.config_type, self.emane.configure)
|
||||
|
||||
# setup sdt
|
||||
self.sdt = Sdt(session=self)
|
||||
|
||||
# future parameters set by the GUI may go here
|
||||
self.options = SessionConfig(session=self)
|
||||
self.add_config_object(SessionConfig.name, SessionConfig.config_type, self.options.configure)
|
||||
self.options = SessionConfig()
|
||||
self.metadata = SessionMetaData()
|
||||
self.add_config_object(SessionMetaData.name, SessionMetaData.config_type, self.metadata.configure)
|
||||
self.sdt = Sdt(session=self)
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Shutdown all emulation objects and remove the session directory.
|
||||
"""
|
||||
|
||||
# shutdown emane
|
||||
# shutdown/cleanup feature helpers
|
||||
self.emane.shutdown()
|
||||
|
||||
# shutdown broker
|
||||
self.broker.shutdown()
|
||||
|
||||
# shutdown NRL's SDT3D
|
||||
self.sdt.shutdown()
|
||||
|
||||
# delete all current objects
|
||||
self.delete_objects()
|
||||
|
||||
preserve = False
|
||||
if hasattr(self.options, "preservedir") and self.options.preservedir == "1":
|
||||
preserve = True
|
||||
|
||||
# remove this sessions working directory
|
||||
preserve = self.options.get_config("preservedir") == "1"
|
||||
if not preserve:
|
||||
shutil.rmtree(self.session_dir, ignore_errors=True)
|
||||
|
||||
|
@ -379,12 +347,7 @@ class Session(object):
|
|||
except:
|
||||
message = "exception occured when running %s state hook: %s" % (coreapi.state_name(state), hook)
|
||||
logger.exception(message)
|
||||
self.exception(
|
||||
ExceptionLevels.ERROR,
|
||||
"Session.run_state_hooks",
|
||||
None,
|
||||
message
|
||||
)
|
||||
self.exception(ExceptionLevels.ERROR, "Session.run_state_hooks", None, message)
|
||||
|
||||
def add_state_hook(self, state, hook):
|
||||
"""
|
||||
|
@ -422,7 +385,7 @@ class Session(object):
|
|||
if state == EventTypes.RUNTIME_STATE.value:
|
||||
self.emane.poststartup()
|
||||
xml_file_version = self.get_config_item("xmlfilever")
|
||||
if xml_file_version in ('1.0',):
|
||||
if xml_file_version in ("1.0",):
|
||||
xml_file_name = os.path.join(self.session_dir, "session-deployed.xml")
|
||||
save_session_xml(self, xml_file_name, xml_file_version)
|
||||
|
||||
|
@ -597,64 +560,6 @@ class Session(object):
|
|||
except IOError:
|
||||
logger.exception("error writing nodes file")
|
||||
|
||||
def add_config_object(self, name, object_type, callback):
|
||||
"""
|
||||
Objects can register configuration objects that are included in
|
||||
the Register Message and may be configured via the Configure
|
||||
Message. The callback is invoked when receiving a Configure Message.
|
||||
|
||||
:param str name: name of configuration object to add
|
||||
:param int object_type: register tlv type
|
||||
:param func callback: callback function for object
|
||||
:return: nothing
|
||||
"""
|
||||
register_tlv = RegisterTlvs(object_type)
|
||||
logger.debug("adding config object callback: %s - %s", name, register_tlv)
|
||||
with self._config_objects_lock:
|
||||
self.config_objects[name] = (object_type, callback)
|
||||
|
||||
def config_object(self, config_data):
|
||||
"""
|
||||
Invoke the callback for an object upon receipt of configuration data for that object.
|
||||
A no-op if the object doesn't exist.
|
||||
|
||||
:param core.data.ConfigData config_data: configuration data to execute against
|
||||
:return: responses to the configuration data
|
||||
:rtype: list
|
||||
"""
|
||||
name = config_data.object
|
||||
logger.info("session(%s) setting config(%s)", self.session_id, name)
|
||||
for key, value in config_data.__dict__.iteritems():
|
||||
logger.debug("%s = %s", key, value)
|
||||
|
||||
replies = []
|
||||
|
||||
if name == "all":
|
||||
with self._config_objects_lock:
|
||||
for name in self.config_objects:
|
||||
config_type, callback = self.config_objects[name]
|
||||
reply = callback(self, config_data)
|
||||
|
||||
if reply:
|
||||
replies.append(reply)
|
||||
|
||||
return replies
|
||||
|
||||
if name in self.config_objects:
|
||||
with self._config_objects_lock:
|
||||
config_type, callback = self.config_objects[name]
|
||||
|
||||
reply = callback(self, config_data)
|
||||
|
||||
if reply:
|
||||
replies.append(reply)
|
||||
|
||||
return replies
|
||||
else:
|
||||
logger.info("session object doesn't own model '%s', ignoring", name)
|
||||
|
||||
return replies
|
||||
|
||||
def dump_session(self):
|
||||
"""
|
||||
Log information about the session in its current state.
|
||||
|
@ -742,10 +647,8 @@ class Session(object):
|
|||
if self.emane.startup() == self.emane.NOT_READY:
|
||||
return
|
||||
|
||||
# startup broker
|
||||
# start feature helpers
|
||||
self.broker.startup()
|
||||
|
||||
# startup mobility
|
||||
self.mobility.startup()
|
||||
|
||||
# boot the services on each node
|
||||
|
@ -901,11 +804,25 @@ class Session(object):
|
|||
:return: control net prefix list
|
||||
:rtype: list
|
||||
"""
|
||||
p = getattr(self.options, "controlnet", self.config.get("controlnet"))
|
||||
p0 = getattr(self.options, "controlnet0", self.config.get("controlnet0"))
|
||||
p1 = getattr(self.options, "controlnet1", self.config.get("controlnet1"))
|
||||
p2 = getattr(self.options, "controlnet2", self.config.get("controlnet2"))
|
||||
p3 = getattr(self.options, "controlnet3", self.config.get("controlnet3"))
|
||||
p = self.options.get_config("controlnet")
|
||||
if not p:
|
||||
p = self.config.get("controlnet")
|
||||
|
||||
p0 = self.options.get_config("controlnet0")
|
||||
if not p0:
|
||||
p0 = self.config.get("controlnet0")
|
||||
|
||||
p1 = self.options.get_config("controlnet1")
|
||||
if not p1:
|
||||
p1 = self.config.get("controlnet1")
|
||||
|
||||
p2 = self.options.get_config("controlnet2")
|
||||
if not p2:
|
||||
p2 = self.config.get("controlnet2")
|
||||
|
||||
p3 = self.options.get_config("controlnet3")
|
||||
if not p3:
|
||||
p3 = self.config.get("controlnet3")
|
||||
|
||||
if not p0 and p:
|
||||
p0 = p
|
||||
|
@ -1000,7 +917,7 @@ class Session(object):
|
|||
logger.warning("controlnet updown script not configured")
|
||||
|
||||
# check if session option set, overwrite if so
|
||||
options_updown_script = getattr(self.options, "controlnet_updown_script", None)
|
||||
options_updown_script = self.options.get_config("controlnet_updown_script")
|
||||
if options_updown_script:
|
||||
updown_script = options_updown_script
|
||||
|
||||
|
@ -1194,6 +1111,7 @@ class Session(object):
|
|||
node = self.get_object(node_id)
|
||||
node.cmd(data, wait=False)
|
||||
|
||||
# TODO: move to core handlers
|
||||
def send_objects(self):
|
||||
"""
|
||||
Return API messages that describe the current session.
|
||||
|
@ -1222,36 +1140,48 @@ class Session(object):
|
|||
logger.info(pprint.pformat(dict(link_data._asdict())))
|
||||
self.broadcast_link(link_data)
|
||||
|
||||
# send model info
|
||||
configs = self.mobility.getallconfigs()
|
||||
configs += self.emane.getallconfigs()
|
||||
logger.info("sending model configs:")
|
||||
for node_number, cls, values in configs:
|
||||
logger.info("config: node(%s) class(%s) values(%s)", node_number, cls, values)
|
||||
config_data = cls.config_data(
|
||||
flags=0,
|
||||
node_id=node_number,
|
||||
type_flags=ConfigFlags.UPDATE.value,
|
||||
values=values
|
||||
)
|
||||
logger.info(pprint.pformat(dict(config_data._asdict())))
|
||||
self.broadcast_config(config_data)
|
||||
# send mobility model info
|
||||
for node_id in self.mobility.nodes():
|
||||
node = self.get_object(node_id)
|
||||
for model_class, config in self.mobility.getmodels(node):
|
||||
logger.info("mobility 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.broadcast_config(config_data)
|
||||
|
||||
# send emane model info
|
||||
for node_id in self.emane.nodes():
|
||||
if node_id not in self.objects:
|
||||
continue
|
||||
|
||||
node = self.get_object(node_id)
|
||||
for model_class, config in self.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.broadcast_config(config_data)
|
||||
|
||||
# service customizations
|
||||
service_configs = self.services.getallconfigs()
|
||||
for node_number, service in service_configs:
|
||||
for node_id, service in service_configs:
|
||||
opaque = "service:%s" % service._name
|
||||
data_types = tuple(repeat(ConfigDataTypes.STRING.value, len(CoreService.keys)))
|
||||
node = self.get_object(node_id)
|
||||
values = CoreService.tovaluelist(node, node.services)
|
||||
config_data = ConfigData(
|
||||
node=node_number,
|
||||
message_type=0,
|
||||
node=node_id,
|
||||
object=self.services.name,
|
||||
type=ConfigFlags.UPDATE.value,
|
||||
data_types=data_types,
|
||||
data_values=values,
|
||||
session=self.session_id,
|
||||
opaque=opaque
|
||||
)
|
||||
config_response = self.services.configure_request(config_data)
|
||||
self.broadcast_config(config_response)
|
||||
self.broadcast_config(config_data)
|
||||
|
||||
for file_name, config_data in self.services.getallfiles(service):
|
||||
file_data = FileData(
|
||||
message_type=MessageFlags.ADD.value,
|
||||
node=node_number,
|
||||
node=node_id,
|
||||
name=str(file_name),
|
||||
type=opaque,
|
||||
data=str(config_data)
|
||||
|
@ -1271,91 +1201,62 @@ class Session(object):
|
|||
)
|
||||
self.broadcast_file(file_data)
|
||||
|
||||
config_data = ConfigData()
|
||||
# send session configuration
|
||||
session_config = self.options.get_configs()
|
||||
config_data = ConfigShim.config_data(0, None, ConfigFlags.UPDATE.value, self.options, session_config)
|
||||
self.broadcast_config(config_data)
|
||||
|
||||
# retrieve session configuration data
|
||||
options_config = self.options.configure_request(config_data, type_flags=ConfigFlags.UPDATE.value)
|
||||
self.broadcast_config(options_config)
|
||||
|
||||
# retrieve session metadata
|
||||
metadata_config = self.metadata.configure_request(config_data, type_flags=ConfigFlags.UPDATE.value)
|
||||
self.broadcast_config(metadata_config)
|
||||
# send session metadata
|
||||
data_values = "|".join(["%s=%s" % item for item in self.metadata.get_configs().iteritems()])
|
||||
data_types = tuple(ConfigDataTypes.STRING.value for _ in self.metadata.get_configs())
|
||||
config_data = ConfigData(
|
||||
message_type=0,
|
||||
object=self.metadata.name,
|
||||
type=ConfigFlags.NONE.value,
|
||||
data_types=data_types,
|
||||
data_values=data_values
|
||||
)
|
||||
self.broadcast_config(config_data)
|
||||
|
||||
logger.info("informed GUI about %d nodes and %d links", len(nodes_data), len(links_data))
|
||||
|
||||
|
||||
class SessionConfig(ConfigurableManager, Configurable):
|
||||
class SessionConfig(NewConfigurableManager, ConfigurableOptions):
|
||||
"""
|
||||
Session configuration object.
|
||||
"""
|
||||
name = "session"
|
||||
config_type = RegisterTlvs.UTILITY.value
|
||||
config_matrix = [
|
||||
("controlnet", ConfigDataTypes.STRING.value, "", "", "Control network"),
|
||||
("controlnet_updown_script", ConfigDataTypes.STRING.value, "", "", "Control network script"),
|
||||
("enablerj45", ConfigDataTypes.BOOL.value, "1", "On,Off", "Enable RJ45s"),
|
||||
("preservedir", ConfigDataTypes.BOOL.value, "0", "On,Off", "Preserve session dir"),
|
||||
("enablesdt", ConfigDataTypes.BOOL.value, "0", "On,Off", "Enable SDT3D output"),
|
||||
("sdturl", ConfigDataTypes.STRING.value, Sdt.DEFAULT_SDT_URL, "", "SDT3D URL"),
|
||||
]
|
||||
config_groups = "Options:1-%d" % len(config_matrix)
|
||||
|
||||
def __init__(self, session):
|
||||
"""
|
||||
Creates a SessionConfig instance.
|
||||
@classmethod
|
||||
def configurations(cls):
|
||||
return [
|
||||
Configuration(_id="controlnet", _type=ConfigDataTypes.STRING, label="Control Network"),
|
||||
Configuration(_id="controlnet0", _type=ConfigDataTypes.STRING, label="Control Network 0"),
|
||||
Configuration(_id="controlnet1", _type=ConfigDataTypes.STRING, label="Control Network 1"),
|
||||
Configuration(_id="controlnet2", _type=ConfigDataTypes.STRING, label="Control Network 2"),
|
||||
Configuration(_id="controlnet3", _type=ConfigDataTypes.STRING, label="Control Network 3"),
|
||||
Configuration(_id="controlnet_updown_script", _type=ConfigDataTypes.STRING, label="Control Network Script"),
|
||||
Configuration(_id="enablerj45", _type=ConfigDataTypes.BOOL, default="1", options=["On", "Off"],
|
||||
label="Enable RJ45s"),
|
||||
Configuration(_id="preservedir", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
|
||||
label="Preserve session dir"),
|
||||
Configuration(_id="enablesdt", _type=ConfigDataTypes.BOOL, default="0", options=["On", "Off"],
|
||||
label="Enable SDT3D output"),
|
||||
Configuration(_id="sdturl", _type=ConfigDataTypes.STRING, default=Sdt.DEFAULT_SDT_URL, label="SDT3D URL")
|
||||
]
|
||||
|
||||
:param core.session.Session session: session this manager is tied to
|
||||
:return: nothing
|
||||
"""
|
||||
ConfigurableManager.__init__(self)
|
||||
self.session = session
|
||||
self.reset()
|
||||
@classmethod
|
||||
def config_groups(cls):
|
||||
return "Options:1-%d" % len(cls.configurations())
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the session configuration.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
defaults = self.getdefaultvalues()
|
||||
for key in self.getnames():
|
||||
# value may come from config file
|
||||
value = self.session.get_config_item(key)
|
||||
if value is None:
|
||||
value = self.valueof(key, defaults)
|
||||
value = self.offontobool(value)
|
||||
setattr(self, key, value)
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Handle configuration values.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: None
|
||||
"""
|
||||
return self.configure_values_keyvalues(config_data, self, self.getnames())
|
||||
|
||||
def configure_request(self, config_data, type_flags=ConfigFlags.NONE.value):
|
||||
"""
|
||||
Handle a configuration request.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:param type_flags:
|
||||
:return:
|
||||
"""
|
||||
node_id = config_data.node
|
||||
values = []
|
||||
|
||||
for key in self.getnames():
|
||||
value = getattr(self, key)
|
||||
if value is None:
|
||||
value = ""
|
||||
values.append("%s" % value)
|
||||
|
||||
return self.config_data(0, node_id, type_flags, values)
|
||||
def __init__(self):
|
||||
super(SessionConfig, self).__init__()
|
||||
config = self.default_values()
|
||||
self.set_configs(config)
|
||||
|
||||
|
||||
class SessionMetaData(ConfigurableManager):
|
||||
class SessionMetaData(NewConfigurableManager):
|
||||
"""
|
||||
Metadata is simply stored in a configs[] dict. Key=value pairs are
|
||||
passed in from configure messages destined to the "metadata" object.
|
||||
|
@ -1363,92 +1264,3 @@ class SessionMetaData(ConfigurableManager):
|
|||
"""
|
||||
name = "metadata"
|
||||
config_type = RegisterTlvs.UTILITY.value
|
||||
|
||||
def configure_values(self, config_data):
|
||||
"""
|
||||
Handle configuration values.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:return: None
|
||||
"""
|
||||
values = config_data.data_values
|
||||
if values is None:
|
||||
return None
|
||||
|
||||
key_values = values.split('|')
|
||||
for key_value in key_values:
|
||||
try:
|
||||
key, value = key_value.split('=', 1)
|
||||
except ValueError:
|
||||
raise ValueError("invalid key in metdata: %s", key_value)
|
||||
|
||||
self.add_item(key, value)
|
||||
|
||||
return None
|
||||
|
||||
def configure_request(self, config_data, type_flags=ConfigFlags.NONE.value):
|
||||
"""
|
||||
Handle a configuration request.
|
||||
|
||||
:param core.conf.ConfigData config_data: configuration data for carrying out a configuration
|
||||
:param int type_flags: configuration request flag value
|
||||
:return: configuration data
|
||||
:rtype: ConfigData
|
||||
"""
|
||||
node_number = config_data.node
|
||||
values_str = "|".join(map(lambda item: "%s=%s" % item, self.items()))
|
||||
return self.config_data(0, node_number, type_flags, values_str)
|
||||
|
||||
def config_data(self, flags, node_id, type_flags, values_str):
|
||||
"""
|
||||
Retrieve configuration data object, leveraging provided data.
|
||||
|
||||
:param flags: configuration data flags
|
||||
:param int node_id: node id
|
||||
:param type_flags: type flags
|
||||
:param values_str: values string
|
||||
:return: configuration data
|
||||
:rtype: ConfigData
|
||||
"""
|
||||
data_types = tuple(map(lambda (k, v): ConfigDataTypes.STRING.value, self.items()))
|
||||
|
||||
return ConfigData(
|
||||
message_type=flags,
|
||||
node=node_id,
|
||||
object=self.name,
|
||||
type=type_flags,
|
||||
data_types=data_types,
|
||||
data_values=values_str
|
||||
)
|
||||
|
||||
def add_item(self, key, value):
|
||||
"""
|
||||
Add configuration key/value pair.
|
||||
|
||||
:param key: configuration key
|
||||
:param value: configuration value
|
||||
:return: nothing
|
||||
"""
|
||||
self.configs[key] = value
|
||||
|
||||
def get_item(self, key):
|
||||
"""
|
||||
Retrieve configuration value.
|
||||
|
||||
:param key: key for configuration value to retrieve
|
||||
:return: configuration value
|
||||
"""
|
||||
try:
|
||||
return self.configs[key]
|
||||
except KeyError:
|
||||
logger.exception("error retrieving item from configs: %s", key)
|
||||
|
||||
return None
|
||||
|
||||
def items(self):
|
||||
"""
|
||||
Retrieve configuration items.
|
||||
|
||||
:return: configuration items iterator
|
||||
"""
|
||||
return self.configs.iteritems()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from xml.dom.minidom import parse
|
||||
|
||||
from core import logger
|
||||
from core.conf import ConfigShim
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodeutils
|
||||
from core.service import ServiceManager
|
||||
|
@ -369,6 +370,7 @@ class CoreDocumentParser0(object):
|
|||
values.append("files=%s" % files)
|
||||
if not bool(service.getAttribute("custom")):
|
||||
return True
|
||||
values = ConfigShim.str_to_dict(values)
|
||||
self.session.services.setcustomservice(n.objid, svc, values)
|
||||
return True
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from xml.dom.minidom import parse
|
|||
|
||||
from core import constants
|
||||
from core import logger
|
||||
from core.conf import ConfigShim
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodeutils
|
||||
from core.misc.ipaddress import MacAddress
|
||||
|
@ -615,6 +616,7 @@ class CoreDocumentParser1(object):
|
|||
values.append('cmddown=%s' % shutdown)
|
||||
if validate:
|
||||
values.append('cmdval=%s' % validate)
|
||||
|
||||
filenames = []
|
||||
files = []
|
||||
for f in xmlutils.iter_children_with_name(service, 'file'):
|
||||
|
@ -629,11 +631,15 @@ class CoreDocumentParser1(object):
|
|||
data = None
|
||||
typestr = 'service:%s:%s' % (name, filename)
|
||||
files.append((typestr, filename, data))
|
||||
|
||||
if filenames:
|
||||
values.append('files=%s' % filenames)
|
||||
|
||||
custom = service.getAttribute('custom')
|
||||
if custom and custom.lower() == 'true':
|
||||
values = ConfigShim.str_to_dict(values)
|
||||
self.session.services.setcustomservice(node.objid, session_service, values)
|
||||
|
||||
# NOTE: if a custom service is used, setservicefile() must be
|
||||
# called after the custom service exists
|
||||
for typestr, filename, data in files:
|
||||
|
@ -812,7 +818,7 @@ class CoreDocumentParser1(object):
|
|||
params = self.parse_parameter_children(options)
|
||||
for name, value in params.iteritems():
|
||||
if name and value:
|
||||
setattr(self.session.options, str(name), str(value))
|
||||
self.session.options.set_config(str(name), str(value))
|
||||
|
||||
def parse_session_hooks(self, session_config):
|
||||
"""
|
||||
|
|
|
@ -217,13 +217,7 @@ class ScenarioPlan(XmlElement):
|
|||
self.last_network_id = 0
|
||||
self.addNetworks()
|
||||
self.addDevices()
|
||||
|
||||
# XXX Do we need these?
|
||||
# self.session.emane.setup() # not during runtime?
|
||||
# self.addorigin()
|
||||
|
||||
self.addDefaultServices()
|
||||
|
||||
self.addSessionConfiguration()
|
||||
|
||||
def addNetworks(self):
|
||||
|
@ -318,10 +312,12 @@ class ScenarioPlan(XmlElement):
|
|||
|
||||
# options
|
||||
options = self.createElement("options")
|
||||
defaults = self.coreSession.options.getdefaultvalues()
|
||||
for i, (k, v) in enumerate(self.coreSession.options.getkeyvaluelist()):
|
||||
if str(v) != str(defaults[i]):
|
||||
XmlElement.add_parameter(self.document, options, k, v)
|
||||
options_config = self.coreSession.options.get_configs()
|
||||
for _id, default_value in self.coreSession.options.default_values().iteritems():
|
||||
value = options_config[_id]
|
||||
if value != default_value:
|
||||
XmlElement.add_parameter(self.document, options, _id, value)
|
||||
|
||||
if options.hasChildNodes():
|
||||
config.appendChild(options)
|
||||
|
||||
|
@ -340,7 +336,7 @@ class ScenarioPlan(XmlElement):
|
|||
|
||||
# metadata
|
||||
meta = self.createElement("metadata")
|
||||
for k, v in self.coreSession.metadata.items():
|
||||
for k, v in self.coreSession.metadata.get_configs().iteritems():
|
||||
XmlElement.add_parameter(self.document, meta, k, v)
|
||||
if meta.hasChildNodes():
|
||||
config.appendChild(meta)
|
||||
|
@ -482,6 +478,7 @@ class NetworkElement(NamedXmlElement):
|
|||
modelconfigs = network_object.session.mobility.getmodels(network_object)
|
||||
modelconfigs += network_object.session.emane.getmodels(network_object)
|
||||
chan = None
|
||||
|
||||
for model, conf in modelconfigs:
|
||||
# Handle mobility parameters below
|
||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
|
@ -496,10 +493,9 @@ class NetworkElement(NamedXmlElement):
|
|||
channel_domain="CORE")
|
||||
|
||||
# Add wireless model parameters
|
||||
for i, key in enumerate(model.getnames()):
|
||||
value = conf[i]
|
||||
for key, value in conf.iteritems():
|
||||
if value is not None:
|
||||
chan.addParameter(key, model.valueof(key, conf))
|
||||
chan.addParameter(key, value)
|
||||
|
||||
for model, conf in modelconfigs:
|
||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
|
@ -509,8 +505,8 @@ class NetworkElement(NamedXmlElement):
|
|||
type_element = self.createElement("type")
|
||||
type_element.appendChild(self.createTextNode(model.name))
|
||||
mobility.appendChild(type_element)
|
||||
for i, key in enumerate(model.getnames()):
|
||||
value = conf[i]
|
||||
|
||||
for key, value in conf.iteritems():
|
||||
if value is not None:
|
||||
mobility.addParameter(key, value)
|
||||
|
||||
|
|
Loading…
Reference in a new issue