From 9167288ae5aa1451e5f02cbcb94dd71602423bb8 Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Wed, 8 May 2024 20:31:36 -0700 Subject: [PATCH] Add lint for topology and workflow --- .github/workflows/lint.yml | 16 +++++++++++ framework/lint.py | 55 +++++++++++++++++++++++++++++++------- host_vars/WU | 2 ++ 3 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..7afd8ac --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,16 @@ +name: Lint +on: [push] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3 + uses: actions/setup-python@v5 + with: + python-version: 3.x + + - name: Install dependencies + run: python -m pip install PyYAML \ No newline at end of file diff --git a/framework/lint.py b/framework/lint.py index a01139d..96fa3dc 100644 --- a/framework/lint.py +++ b/framework/lint.py @@ -1,3 +1,5 @@ +import os +import sys import yaml import internal.utils as utils @@ -8,6 +10,16 @@ # Read config file config = conf.get() +# Validation of links +NEIGHBORS = {} + +# Configuration has errors +HAS_ERRORS = False +def log_error(message: str): + print(message, file=sys.stderr) + global HAS_ERRORS + HAS_ERRORS = True + def check_type(key: str, value: Any, typ: str, path: str): """ Validate a value against a type. @@ -27,19 +39,23 @@ def check_type(key: str, value: Any, typ: str, path: str): elif typ == 'dict': valid_type = isinstance(value, dict) else: - print(f"WARNING: Unknown type '{typ}' for key '{key}'") + log_error(f"WARNING: Unknown type '{typ}' for key '{key}'") if not valid_type: - print(f"WARNING: Key '{key}' has invalid type (got '{type(value).__name__}', epxected '{typ}') in file: {path}") + log_error(f"WARNING: Key '{key}' has invalid type (got '{type(value).__name__}', epxected '{typ}') in file: {path}") def lint(path: str): + node_name = os.path.basename(path) + # Read YAML file + raw_content = None content = None with open(path, 'r') as stream: try: - content = yaml.safe_load(stream) + raw_content = stream.read() + content = yaml.safe_load(raw_content) except yaml.YAMLError as exc: - print("Error reading YAML file: ", path, exc) + log_error("Error reading YAML file: ", path, exc) return # Create an ordered dict with the same order as the config file @@ -56,18 +72,39 @@ def lint(path: str): check_type(key, content[key], typ, path) ordered_content[key] = content[key] elif not is_optional: - print(f"WARNING: Missing key '{key}' in file: {path}") + log_error(f"WARNING: Missing key '{key}' in file: {path}") # Check for any unknown keys for key in content: if key not in config.variables: - print(f"WARNING: Unknown key '{key}' in file: {path}") + log_error(f"WARNING: Unknown key '{key}' in file: {path}") ordered_content[key] = content[key] - # Sort keys by name and write the file back + # Sort keys by name and check file + raw_ordered_content = yaml.dump(ordered_content, sort_keys=False) + if raw_content != raw_ordered_content: + log_error(f"WARNING: File '{path}' was incorrectly formatted or last errors.") + + # Write the file back with open(path, 'w') as stream: - yaml.dump(ordered_content, stream, sort_keys=False) + stream.write(raw_ordered_content) + + # Validate neighbor pairs + for name, params in ordered_content['neighbors'].items(): + flip = name + ':' + node_name + if flip in NEIGHBORS: + if NEIGHBORS[flip] != params: + log_error(f"ERROR: Parameter mismatch in link '{flip}' ({path})") + del NEIGHBORS[name + ':' + node_name] + continue + NEIGHBORS[node_name + ':' + name] = params if __name__ == '__main__': for file in utils.get_files(config.host_vars_path): - lint(file) \ No newline at end of file + lint(file) + + # Any entries that remain are incomplete + for invalid in NEIGHBORS: + log_error(f"ERROR: Neighbor '{invalid}' is not symmetric") + + sys.exit(1 if HAS_ERRORS else 0) \ No newline at end of file diff --git a/host_vars/WU b/host_vars/WU index 98a5ffb..e8ef6b0 100644 --- a/host_vars/WU +++ b/host_vars/WU @@ -38,6 +38,8 @@ neighbors: link_cost: 33 MEMPHIS: link_cost: 17 + BERN: + link_cost: 60 hr_angle: 4.31067 hr_radius: 19.4268 ethernet_device: eth0