attempt to better support dynamic emane models
This commit is contained in:
parent
6f4ef0e193
commit
45e82f05b2
2 changed files with 106 additions and 1 deletions
|
@ -29,6 +29,8 @@ from core.misc import utils
|
||||||
from core.misc.ipaddress import MacAddress
|
from core.misc.ipaddress import MacAddress
|
||||||
from core.xml import xmlutils
|
from core.xml import xmlutils
|
||||||
|
|
||||||
|
_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
# EMANE 0.7.4/0.8.1
|
# EMANE 0.7.4/0.8.1
|
||||||
try:
|
try:
|
||||||
import emaneeventservice
|
import emaneeventservice
|
||||||
|
@ -91,7 +93,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
self._modelclsmap = {
|
self._modelclsmap = {
|
||||||
self.emane_config.name: self.emane_config
|
self.emane_config.name: self.emane_config
|
||||||
}
|
}
|
||||||
self.loadmodels()
|
self.load_models(_PATH)
|
||||||
|
|
||||||
def logversion(self):
|
def logversion(self):
|
||||||
"""
|
"""
|
||||||
|
@ -192,6 +194,21 @@ class EmaneManager(ConfigurableManager):
|
||||||
self.session.add_config_object(emane_model.name, emane_model.config_type,
|
self.session.add_config_object(emane_model.name, emane_model.config_type,
|
||||||
emane_model.configure_emane)
|
emane_model.configure_emane)
|
||||||
|
|
||||||
|
def load_models(self, path):
|
||||||
|
"""
|
||||||
|
Loads EMANE models into the manager for usage within CORE.
|
||||||
|
|
||||||
|
:param str path: path to retrieve model from
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
emane_models = utils.load_classes(path, EmaneModel)
|
||||||
|
for emane_model in emane_models:
|
||||||
|
logger.info("loading emane model: (%s) %s - %s",
|
||||||
|
emane_model, emane_model.name, RegisterTlvs(emane_model.config_type))
|
||||||
|
self._modelclsmap[emane_model.name] = emane_model
|
||||||
|
self.session.add_config_object(emane_model.name, emane_model.config_type,
|
||||||
|
emane_model.configure_emane)
|
||||||
|
|
||||||
def addobj(self, obj):
|
def addobj(self, obj):
|
||||||
"""
|
"""
|
||||||
add a new EmaneNode object to this Emane controller object
|
add a new EmaneNode object to this Emane controller object
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
Miscellaneous utility functions, wrappers around some subprocess procedures.
|
Miscellaneous utility functions, wrappers around some subprocess procedures.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import resource
|
import resource
|
||||||
|
@ -445,3 +448,88 @@ def checkforkernelmodule(name):
|
||||||
if line.startswith(name + " "):
|
if line.startswith(name + " "):
|
||||||
return line.rstrip()
|
return line.rstrip()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _valid_module(path, file_name):
|
||||||
|
"""
|
||||||
|
Check if file is a valid python module.
|
||||||
|
|
||||||
|
:param str path: path to file
|
||||||
|
:param str file_name: file name to check
|
||||||
|
:return: True if a valid python module file, False otherwise
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
file_path = os.path.join(path, file_name)
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if file_name.startswith("_"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not file_name.endswith(".py"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _is_class(module, member, clazz):
|
||||||
|
"""
|
||||||
|
Validates if a module member is a class and an instance of a CoreService.
|
||||||
|
|
||||||
|
:param module: module to validate for service
|
||||||
|
:param member: member to validate for service
|
||||||
|
:param clazz: clazz type to check for validation
|
||||||
|
:return: True if a valid service, False otherwise
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
if not inspect.isclass(member):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not issubclass(member, clazz):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if member.__module__ != module.__name__:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def load_classes(path, clazz):
|
||||||
|
"""
|
||||||
|
Dynamically load classes for use within CORE.
|
||||||
|
|
||||||
|
:param path: path to load classes from
|
||||||
|
:param clazz: class type expected to be inherited from for loading
|
||||||
|
:return: list of classes loaded
|
||||||
|
"""
|
||||||
|
# validate path exists
|
||||||
|
logger.info("attempting to load modules from path: %s", path)
|
||||||
|
if not os.path.isdir(path):
|
||||||
|
logger.warn("invalid custom module directory specified" ": %s" % path)
|
||||||
|
# check if path is in sys.path
|
||||||
|
parent_path = os.path.dirname(path)
|
||||||
|
if parent_path not in sys.path:
|
||||||
|
logger.info("adding parent path to allow imports: %s", parent_path)
|
||||||
|
sys.path.append(parent_path)
|
||||||
|
|
||||||
|
# retrieve potential service modules, and filter out invalid modules
|
||||||
|
base_module = os.path.basename(path)
|
||||||
|
module_names = os.listdir(path)
|
||||||
|
module_names = filter(lambda x: _valid_module(path, x), module_names)
|
||||||
|
module_names = map(lambda x: x[:-3], module_names)
|
||||||
|
|
||||||
|
# import and add all service modules in the path
|
||||||
|
classes = []
|
||||||
|
for module_name in module_names:
|
||||||
|
import_statement = "%s.%s" % (base_module, module_name)
|
||||||
|
logger.info("importing custom module: %s", import_statement)
|
||||||
|
try:
|
||||||
|
module = importlib.import_module(import_statement)
|
||||||
|
members = inspect.getmembers(module, lambda x: _is_class(module, x, clazz))
|
||||||
|
for member in members:
|
||||||
|
clazz = member[1]
|
||||||
|
classes.append(clazz)
|
||||||
|
except:
|
||||||
|
logger.exception("unexpected error during import, skipping: %s", import_statement)
|
||||||
|
|
||||||
|
return classes
|
||||||
|
|
Loading…
Reference in a new issue