| garciadeblas | 3a5d204 | 2024-11-21 01:12:53 +0100 | [diff] [blame] | 1 | #!/usr/bin/python3 |
| 2 | # Copyright ETSI Contributors and Others. |
| 3 | # All Rights Reserved. |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 6 | # not use this file except in compliance with the License. You may obtain |
| 7 | # a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 14 | # License for the specific language governing permissions and limitations |
| 15 | # under the License. |
| 16 | |
| 17 | |
| 18 | # generate_osm_test.py --config test_config.yaml |
| 19 | |
| 20 | import argparse |
| 21 | import logging |
| 22 | import os |
| 23 | import yaml |
| 24 | |
| 25 | # from jinja2 import Environment, FileSystemLoader, select_autoescape |
| 26 | from jinja2 import Template |
| 27 | |
| 28 | |
| 29 | #################################### |
| 30 | # Global functions |
| 31 | #################################### |
| 32 | def set_logger(verbose): |
| 33 | global logger |
| 34 | log_format_simple = "%(levelname)s %(message)s" |
| 35 | log_format_complete = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(funcName)s(): %(message)s" |
| 36 | log_formatter_simple = logging.Formatter( |
| 37 | log_format_simple, datefmt="%Y-%m-%dT%H:%M:%S" |
| 38 | ) |
| 39 | handler = logging.StreamHandler() |
| 40 | handler.setFormatter(log_formatter_simple) |
| 41 | logger = logging.getLogger("generate_osm_test") |
| 42 | logger.setLevel(level=logging.WARNING) |
| 43 | logger.addHandler(handler) |
| 44 | if verbose == 1: |
| 45 | logger.setLevel(level=logging.INFO) |
| 46 | elif verbose > 1: |
| 47 | log_formatter = logging.Formatter( |
| 48 | log_format_complete, datefmt="%Y-%m-%dT%H:%M:%S" |
| 49 | ) |
| 50 | handler.setFormatter(log_formatter) |
| 51 | logger.setLevel(level=logging.DEBUG) |
| 52 | |
| 53 | |
| 54 | def exit_with_error(message, code=1): |
| 55 | logger.error(message) |
| 56 | exit(code) |
| 57 | |
| 58 | |
| 59 | def render_template(template_file, test_data, output_file=None): |
| 60 | logger.info(f"Rendering {template_file} with test data") |
| 61 | |
| 62 | # Load Jinja template |
| 63 | with open(template_file, "r") as template_stream: |
| 64 | template = Template(template_stream.read()) |
| 65 | |
| 66 | # Render template with test_data and store it in output_file |
| 67 | output = template.render(test_data) |
| 68 | if output_file: |
| 69 | if os.path.exists(output_file): |
| 70 | exit_with_error( |
| 71 | f"Output file '{output_file}' already exists. Use a different filename or remove it." |
| 72 | ) |
| 73 | with open(output_file, "w") as output_stream: |
| 74 | output_stream.write(output) |
| 75 | else: |
| 76 | print(output) |
| 77 | |
| 78 | |
| 79 | def validate_data(test_data): |
| 80 | required_keys = {"nspkg", "ns"} |
| 81 | missing_keys = required_keys - test_data.keys() |
| 82 | if missing_keys: |
| 83 | logger.error(f"Missing required keys in YAML: {', '.join(missing_keys)}") |
| 84 | raise ValueError(f"Invalid test data structure: missing keys {missing_keys}") |
| 85 | |
| 86 | |
| 87 | def complete_data(test_data): |
| 88 | nspkg_indexes = {nspkg["name"]: i + 1 for i, nspkg in enumerate(test_data["nspkg"])} |
| 89 | ns_indexes = {ns["name"]: i + 1 for i, ns in enumerate(test_data["ns"])} |
| 90 | for ns in test_data["ns"]: |
| 91 | if ns["nspkg"] not in nspkg_indexes: |
| 92 | logger.error( |
| 93 | f"nspkg '{ns['nspkg']}' referenced in 'ns' not found in 'nspkg'" |
| 94 | ) |
| 95 | raise ValueError(f"Invalid nspkg name: {ns['nspkg']}") |
| 96 | ns["nspkg_index"] = nspkg_indexes[ns["nspkg"]] |
| 97 | for vnf in test_data["vnf"]: |
| 98 | if vnf["ns"] not in ns_indexes: |
| 99 | logger.error(f"ns '{vnf['ns']}' referenced in 'vnf' not found in 'ns'") |
| 100 | raise ValueError(f"Invalid ns name: {vnf['ns']}") |
| 101 | vnf["ns_index"] = ns_indexes[vnf["ns"]] |
| 102 | |
| 103 | |
| 104 | #################################### |
| 105 | # Main |
| 106 | #################################### |
| 107 | if __name__ == "__main__": |
| 108 | # Argument parse |
| 109 | parser = argparse.ArgumentParser( |
| 110 | description="Generate OSM tests from YAML configuration file." |
| 111 | ) |
| 112 | parser.add_argument( |
| 113 | "-v", "--verbose", action="count", default=0, help="increase output verbosity" |
| 114 | ) |
| 115 | # parser.add_argument("--basedir", default=".", help="basedir for the test") |
| 116 | parser.add_argument( |
| 117 | "--config", required=True, help="yaml configuration file to create the test" |
| 118 | ) |
| 119 | parser.add_argument( |
| 120 | "--template", |
| 121 | default="test_template.j2", |
| 122 | help="template file for rendering the test (default: test_template.j2)", |
| 123 | ) |
| 124 | parser.add_argument( |
| 125 | "--output", default=None, help="output file (default: standard output)" |
| 126 | ) |
| 127 | args = parser.parse_args() |
| 128 | |
| 129 | # Calculate paths relative to the script directory |
| 130 | script_dir = os.path.dirname(os.path.abspath(__file__)) |
| 131 | config_path = os.path.abspath(args.config) |
| 132 | template_path = os.path.join(script_dir, args.template) |
| 133 | |
| 134 | # Initialize logger |
| 135 | set_logger(args.verbose) |
| 136 | |
| 137 | # Load test_data |
| 138 | try: |
| 139 | with open(config_path, "r") as yaml_stream: |
| 140 | test_data = yaml.safe_load(yaml_stream) |
| 141 | except FileNotFoundError: |
| 142 | exit_with_error(f"Configuration file '{args.config}' not found.") |
| 143 | except yaml.YAMLError as e: |
| 144 | exit_with_error(f"Error parsing YAML file '{args.config}': {e}") |
| 145 | validate_data(test_data) |
| 146 | complete_data(test_data) |
| 147 | logger.debug(f"Test data:\n{yaml.safe_dump(test_data)}") |
| 148 | if not os.path.exists(template_path): |
| 149 | exit_with_error(f"Template file '{template_path}' not found.") |
| 150 | render_template(template_path, test_data, args.output) |