attempt to better support dynamic emane models

This commit is contained in:
Blake J. Harnden 2018-02-05 09:01:49 -08:00
parent 6f4ef0e193
commit 45e82f05b2
2 changed files with 106 additions and 1 deletions

View file

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

View file

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