From 85c5ad22e4ca728ce521fe5957943f2656b1114b Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 7 May 2021 22:49:58 -0700 Subject: [PATCH] daemon: adjustments to load local emane models and config services better using a full import --- daemon/core/configservice/manager.py | 26 ++++++++++++++++--- daemon/core/emane/modelmanager.py | 37 +++++++++++++++++++++++++--- daemon/core/emulator/coreemu.py | 15 +++++------ daemon/core/utils.py | 29 +++++++++++++--------- 4 files changed, 80 insertions(+), 27 deletions(-) diff --git a/daemon/core/configservice/manager.py b/daemon/core/configservice/manager.py index 02812ea2..1fd26e43 100644 --- a/daemon/core/configservice/manager.py +++ b/daemon/core/configservice/manager.py @@ -1,9 +1,10 @@ import logging import pathlib +import pkgutil from pathlib import Path from typing import Dict, List, Type -from core import utils +from core import configservices, utils from core.configservice.base import ConfigService from core.errors import CoreError @@ -61,12 +62,31 @@ class ConfigServiceManager: # make service available self.services[name] = service + def load_locals(self) -> List[str]: + """ + Search and add config service from local core module. + + :return: list of errors when loading services + """ + errors = [] + for module_info in pkgutil.walk_packages( + configservices.__path__, f"{configservices.__name__}." + ): + services = utils.load_module(module_info.name, ConfigService) + for service in services: + try: + self.add(service) + except CoreError as e: + errors.append(service.name) + logger.debug("not loading config service(%s): %s", service.name, e) + return errors + def load(self, path: Path) -> List[str]: """ - Search path provided for configurable services and add them for being managed. + Search path provided for config services and add them for being managed. :param path: path to search configurable services - :return: list errors when loading and adding services + :return: list errors when loading services """ path = pathlib.Path(path) subdirs = [x for x in path.iterdir() if x.is_dir()] diff --git a/daemon/core/emane/modelmanager.py b/daemon/core/emane/modelmanager.py index 94ced08b..989802c4 100644 --- a/daemon/core/emane/modelmanager.py +++ b/daemon/core/emane/modelmanager.py @@ -1,8 +1,10 @@ import logging +import pkgutil from pathlib import Path from typing import Dict, List, Type from core import utils +from core.emane import models as emane_models from core.emane.emanemodel import EmaneModel from core.errors import CoreError @@ -13,9 +15,36 @@ class EmaneModelManager: models: Dict[str, Type[EmaneModel]] = {} @classmethod - def load(cls, path: Path, prefix: Path) -> List[str]: + def load_locals(cls, emane_prefix: Path) -> List[str]: """ - Load EMANE models and make them available. + Load local core emane models and make them available. + + :param emane_prefix: installed emane prefix + :return: list of errors encountered loading emane models + """ + errors = [] + for module_info in pkgutil.walk_packages( + emane_models.__path__, f"{emane_models.__name__}." + ): + models = utils.load_module(module_info.name, EmaneModel) + for model in models: + logger.debug("loading emane model: %s", model.name) + try: + model.load(emane_prefix) + cls.models[model.name] = model + except CoreError as e: + errors.append(model.name) + logger.debug("not loading emane model(%s): %s", model.name, e) + return errors + + @classmethod + def load(cls, path: Path, emane_prefix: Path) -> List[str]: + """ + Search and load custom emane models and make them available. + + :param path: path to search for custom emane models + :param emane_prefix: installed emane prefix + :return: list of errors encountered loading emane models """ subdirs = [x for x in path.iterdir() if x.is_dir()] subdirs.append(path) @@ -26,11 +55,11 @@ class EmaneModelManager: for model in models: logger.debug("loading emane model: %s", model.name) try: - model.load(prefix) + model.load(emane_prefix) cls.models[model.name] = model except CoreError as e: errors.append(model.name) - logger.debug("not loading service(%s): %s", model.name, e) + logger.debug("not loading emane model(%s): %s", model.name, e) return errors @classmethod diff --git a/daemon/core/emulator/coreemu.py b/daemon/core/emulator/coreemu.py index 0fd46626..179faf9c 100644 --- a/daemon/core/emulator/coreemu.py +++ b/daemon/core/emulator/coreemu.py @@ -7,9 +7,8 @@ from pathlib import Path from typing import Dict, List, Type import core.services -from core import configservices, utils +from core import utils from core.configservice.manager import ConfigServiceManager -from core.emane import models from core.emane.modelmanager import EmaneModelManager from core.emulator.session import Session from core.executables import get_requirements @@ -103,8 +102,7 @@ class CoreEmu: custom_service_errors = ServiceManager.add_services(service_path) self.service_errors.extend(custom_service_errors) # load default config services - config_services_path = Path(configservices.__file__).resolve().parent - self.service_manager.load(config_services_path) + self.service_manager.load_locals() # load custom config services custom_dir = self.config.get("custom_config_services_dir") if custom_dir is not None: @@ -126,16 +124,15 @@ class CoreEmu: # get version emane_version = utils.cmd("emane --version") logger.info("using emane: %s", emane_version) - prefix = self.config.get("emane_prefix", DEFAULT_EMANE_PREFIX) - prefix = Path(prefix) - default_path = Path(models.__file__).resolve().parent - EmaneModelManager.load(default_path, prefix) + emane_prefix = self.config.get("emane_prefix", DEFAULT_EMANE_PREFIX) + emane_prefix = Path(emane_prefix) + EmaneModelManager.load_locals(emane_prefix) # load custom models custom_path = self.config.get("emane_models_dir") if custom_path is not None: logger.info("loading custom emane models: %s", custom_path) custom_path = Path(custom_path) - EmaneModelManager.load(custom_path, prefix) + EmaneModelManager.load(custom_path, emane_prefix) def shutdown(self) -> None: """ diff --git a/daemon/core/utils.py b/daemon/core/utils.py index 201797e1..b7ef1e5c 100644 --- a/daemon/core/utils.py +++ b/daemon/core/utils.py @@ -328,7 +328,22 @@ def load_config(file_path: Path, d: Dict[str, str]) -> None: logger.exception("error reading file to dict: %s", file_path) -def load_classes(path: Path, clazz: Generic[T]) -> T: +def load_module(import_statement: str, clazz: Generic[T]) -> List[T]: + classes = [] + try: + module = importlib.import_module(import_statement) + members = inspect.getmembers(module, lambda x: _is_class(module, x, clazz)) + for member in members: + valid_class = member[1] + classes.append(valid_class) + except Exception: + logger.exception( + "unexpected error during import, skipping: %s", import_statement + ) + return classes + + +def load_classes(path: Path, clazz: Generic[T]) -> List[T]: """ Dynamically load classes for use within CORE. @@ -352,16 +367,8 @@ def load_classes(path: Path, clazz: Generic[T]) -> T: continue import_statement = f"{path.name}.{p.stem}" logger.debug("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: - valid_class = member[1] - classes.append(valid_class) - except Exception: - logger.exception( - "unexpected error during import, skipping: %s", import_statement - ) + loaded = load_module(import_statement, clazz) + classes.extend(loaded) return classes