diff --git a/src/containernet/config.py b/src/containernet/config.py index d0dcf08..20e0b6a 100644 --- a/src/containernet/config.py +++ b/src/containernet/config.py @@ -77,48 +77,79 @@ class TopologyConfig: json_description: Optional[str] = field(default=None) +supported_config_keys = ["node", "topology"] + + class INodeConfig(ABC): @staticmethod - def load_node_config(yaml_config_file: str, - config_name: str) -> NodeConfig: + def is_supported_config_key(config_key: str): + return config_key in supported_config_keys + + @staticmethod + def load_config_reference(yaml_config_file: str, + config_name: str, config_key: str): + if not INodeConfig.is_supported_config_key(config_key): + logging.error( + f"load_config_reference: key %s is not supported.", + config_key) + return None if not os.path.exists(yaml_config_file): logging.error( - f"load_node_config: file %s does not exist.", + f"load_config_reference: file %s does not exist.", yaml_config_file) return None - node_config = [] + loaded_yaml_config = [] with open(yaml_config_file, 'r', encoding='utf-8') as stream: try: - node_config = yaml.safe_load(stream) + loaded_yaml_config = yaml.safe_load(stream) except yaml.YAMLError as exc: logging.error(exc) return None - if node_config is None or "node" not in node_config: + # check key 'config_key' in the yaml content + if loaded_yaml_config is None or config_key not in loaded_yaml_config: logging.error( - f"load_node_config: node config is not defined in %s", - yaml_config_file) + f"load_config_reference: %s is not defined in %s", + config_key, yaml_config_file) return None + loaded_config = None # Find it by 'name' in `node_config`, for example "linear_network" - for topology in node_config['node']: - if topology['name'] == config_name: - loaded_node_config = topology + for conf in loaded_yaml_config[config_key]: + if conf['name'] == config_name: + loaded_config = conf + logging.info('load_config_reference: loaded %s', loaded_config) break - logging.info('load_node_config: loaded %s', loaded_node_config) - return NodeConfig(**loaded_node_config) + if loaded_config is None: + logging.error( + f"load_config_reference: %s is not defined in %s", + config_name, yaml_config_file) + return None + if config_key == "node": + return NodeConfig(**loaded_config) + if config_key == "topology": + return TopologyConfig(**loaded_config) + return None @staticmethod - def load_yaml_config(yaml_description: str): + def load_yaml_config(yaml_description: str, config_key: str): # load it directly from the yaml_description or # load it from another yaml file. - node_config = None + if not INodeConfig.is_supported_config_key(config_key): + logging.error( + f"load_yaml_config: key %s is not supported.", + config_key) + return None + config_data = None is_load_from_file = ["config_file", "config_name"] if all(key in yaml_description for key in is_load_from_file): # load from the yaml file `config_file` - node_config = INodeConfig.load_node_config( + config_data = INodeConfig.load_config_reference( yaml_description['config_file'], - yaml_description['config_name']) + yaml_description['config_name'], config_key) else: # load directly from the yaml_description logging.info('load_yaml_config: %s', yaml_description) - node_config = NodeConfig(**yaml_description) - return node_config + if config_key == "node": + config_data = NodeConfig(**yaml_description) + if config_key == "topology": + config_data = TopologyConfig(**yaml_description) + return config_data diff --git a/src/containernet/topology.py b/src/containernet/topology.py index 2b4206f..f92f97b 100644 --- a/src/containernet/topology.py +++ b/src/containernet/topology.py @@ -3,8 +3,6 @@ import logging import os import json -import yaml - from .config import (TopologyConfig, MatrixType) @@ -28,10 +26,9 @@ class LinkAttr(IntEnum): class ITopology(ABC): def __init__(self, top: TopologyConfig) -> None: self.all_mats = {} - self.top_config = None self.adj_matrix = None self.top_config = top - self.init_all_matrices() + self.init_all_mats() @abstractmethod def generate_adj_matrix(self, num_of_nodes: int): @@ -49,7 +46,7 @@ def get_matrix(self, mat_type: MatrixType): return None return self.all_mats[mat_type] - def init_all_matrices(self): + def init_all_mats(self): # init from json_description or array_description if self.top_config.json_description is not None: logging.info( @@ -63,63 +60,6 @@ def init_all_matrices(self): self.all_mats[MatrixType.ADJACENCY_MATRIX] = self.adj_matrix self.generate_other_matrices(self.adj_matrix) - @staticmethod - def load_topology_config(yaml_config_file: str, - config_name: str) -> TopologyConfig: - ''' - Load the topology configuration from a yaml file. The configuration - contains the following fields: - - name of the topology - - number of nodes - - topology type - - one of the following: - - array_description: the array description of the topology - - json_description: the json description of the topology; - if json_description is provided, need load the topology - from the json file. - ''' - if not os.path.exists(yaml_config_file): - logging.error( - f"load_topology_config: file %s does not exist.", - yaml_config_file) - return None - topology_config = [] - with open(yaml_config_file, 'r', encoding='utf-8') as stream: - try: - topology_config = yaml.safe_load(stream) - except yaml.YAMLError as exc: - logging.error(exc) - return None - if topology_config is None or "topology" not in topology_config: - logging.error( - f"load_topology_config: topology is not defined in %s", - yaml_config_file) - return None - # Find it by 'name' in `topology_config`, for example "linear_network" - for topology in topology_config['topology']: - if topology['name'] == config_name: - loaded_topology = topology - break - logging.info('load_topology_config: loaded %s', loaded_topology) - return TopologyConfig(**loaded_topology) - - @staticmethod - def load_yaml_config(yaml_description: str): - # load it directly from the yaml_description or - # load it from another yaml file. - topology = None - is_load_from_file = ["config_file", "config_name"] - if all(key in yaml_description for key in is_load_from_file): - # load from the yaml file `config_file` - topology = ITopology.load_topology_config( - yaml_description['config_file'], - yaml_description['config_name']) - else: - # load directly from the yaml_description - logging.info('load_yaml_config: %s', yaml_description) - topology = TopologyConfig(**yaml_description) - return topology - def load_all_mats(self, json_file_path): """Load all matrices from the Json file. Args: diff --git a/src/run_test.py b/src/run_test.py index 1a8ce7c..7e886db 100755 --- a/src/run_test.py +++ b/src/run_test.py @@ -7,7 +7,6 @@ # from mininet.cli import CLI from mininet.log import setLogLevel from containernet.linear_topology import LinearTopology -from containernet.topology import ITopology from containernet.network import Network from containernet.config import ( INodeConfig, NodeConfig, TopologyConfig) @@ -61,8 +60,8 @@ def load_config(test_case_yaml) -> Tuple[NodeConfig, TopologyConfig]: if local_net_top_yaml is None or local_node_conf_yaml is None: logging.error("Error: top_yaml or node_conf_yaml is None.") return None, None - node_config = INodeConfig.load_yaml_config(local_node_conf_yaml) - top_config = ITopology.load_yaml_config(local_net_top_yaml) + node_config = INodeConfig.load_yaml_config(local_node_conf_yaml, 'node') + top_config = INodeConfig.load_yaml_config(local_net_top_yaml, 'topology') if top_config is None or node_config is None: logging.error("Error: topology/node configuration is None.") return None, None