|
| 1 | +""" |
| 2 | +Script Name: run_simulation.py |
| 3 | +Description: Runs a simulation command based on provided arguments and support config. |
| 4 | +
|
| 5 | +Usage: python script.py <env> <sim> |
| 6 | +
|
| 7 | +<env> - The environment argument. |
| 8 | +<sim> - The simulation argument. |
| 9 | +
|
| 10 | +The script relies on two config files which it consults to build the simulation command. |
| 11 | +* env.txt |
| 12 | +* sim.txt |
| 13 | +
|
| 14 | +""" |
| 15 | +import argparse |
| 16 | +import logging |
| 17 | +import os |
| 18 | +import subprocess |
| 19 | +import sys |
| 20 | +import yaml |
| 21 | + |
| 22 | + |
| 23 | +def print_usage(parser): |
| 24 | + parser.print_help() |
| 25 | + logging.error("Please provide the 'env' and 'sim' arguments.") |
| 26 | + |
| 27 | + |
| 28 | +def check_file_exists(file_path): |
| 29 | + """check file actually exists""" |
| 30 | + if not os.path.isfile(file_path): |
| 31 | + logging.error(f"File not found: {file_path}") |
| 32 | + return False |
| 33 | + return True |
| 34 | + |
| 35 | + |
| 36 | +def read_env_properties(env_value): |
| 37 | + """read and return the env properties""" |
| 38 | + logging.info(f"Environment: {env_value}") |
| 39 | + env_file = os.path.join("config", "env.yml") |
| 40 | + if not check_file_exists(env_file): |
| 41 | + return False |
| 42 | + |
| 43 | + with open(env_file, "r") as file: |
| 44 | + env_data = yaml.safe_load(file) |
| 45 | + for env in env_data: |
| 46 | + if env == env_value: |
| 47 | + return env_data[env_value] |
| 48 | + logging.info(f"Unknown environment: {env_value}") |
| 49 | + |
| 50 | + |
| 51 | +def read_sim_properties(sim_value): |
| 52 | + """read and return simulation properties""" |
| 53 | + logging.info(f"Simulaton: {sim_value}") |
| 54 | + sim_file = os.path.join("config", "sim.yml") |
| 55 | + if not check_file_exists(sim_file): |
| 56 | + return False |
| 57 | + |
| 58 | + with open(sim_file, "r") as file: |
| 59 | + sim_data = yaml.safe_load(file) |
| 60 | + for sim in sim_data: |
| 61 | + if sim == sim_value: |
| 62 | + return sim_data[sim_value] |
| 63 | + logging.info(f"Unknown simulation: {sim_value}") |
| 64 | + |
| 65 | + |
| 66 | +def write_properties_file( |
| 67 | + env: str, sim: str, env_props: dict, sim_props: dict, file_path: str |
| 68 | +): |
| 69 | + """write properties file""" |
| 70 | + with open(file_path, "w") as file: |
| 71 | + file.write(f"\n# TEST PROPERTIES. ENV {env}, SIM {sim}\n") |
| 72 | + for name, value in env_props["properties"].items(): |
| 73 | + if "$" in value: |
| 74 | + logging.info(f"Substituting in environment variable for {value}") |
| 75 | + value = os.environ.get(value[1:]) |
| 76 | + if value is None: |
| 77 | + logging.warning(f"Environment variable {value} is None") |
| 78 | + file.write(f"{name}={value}\n") |
| 79 | + for name, value in sim_props["properties"].items(): |
| 80 | + file.write(f"{name}={value}\n") |
| 81 | + with open(file_path, "r") as file: |
| 82 | + contents = file.read() |
| 83 | + logging.info(contents) |
| 84 | + |
| 85 | + |
| 86 | +### MAIN ### |
| 87 | + |
| 88 | +# Configure logging |
| 89 | +log_file = "output.log" |
| 90 | +logging.basicConfig( |
| 91 | + filename=log_file, |
| 92 | + level=logging.INFO, |
| 93 | + format="%(asctime)s - %(levelname)s - %(message)s", |
| 94 | +) |
| 95 | +console = logging.StreamHandler(sys.stdout) |
| 96 | +console.setLevel(logging.INFO) |
| 97 | +formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") |
| 98 | +console.setFormatter(formatter) |
| 99 | +logging.getLogger().addHandler(console) |
| 100 | + |
| 101 | +# Create the argument parser |
| 102 | +parser = argparse.ArgumentParser( |
| 103 | + description="Runs a simulation command based on the provided arguments " |
| 104 | + + "and support config" |
| 105 | +) |
| 106 | + |
| 107 | +# Add the mandatory arguments |
| 108 | +parser.add_argument("env", type=str, help="Environment argument") |
| 109 | +parser.add_argument("sim", type=str, help="Simulation argument") |
| 110 | + |
| 111 | +# Parse the command-line arguments |
| 112 | +args = parser.parse_args() |
| 113 | + |
| 114 | +# Check if the arguments are empty |
| 115 | +if not args.env or not args.sim: |
| 116 | + print_usage(parser) |
| 117 | + exit(1) |
| 118 | + |
| 119 | +# Check if the env.yml file exists and if the provided env argument exists within it |
| 120 | +env_props = read_env_properties(args.env) |
| 121 | +logging.info(f"Environment properties: {env_props}") |
| 122 | + |
| 123 | +# Check if the sim.yml file exists and if the provided sim argument exists within it |
| 124 | +sim_props = read_sim_properties(args.sim) |
| 125 | +logging.info("Simulation properties: {sim_props}") |
| 126 | + |
| 127 | +if env_props is None or sim_props is None: |
| 128 | + logging.error("Environment or Simulation is not defined") |
| 129 | + exit(2) |
| 130 | + |
| 131 | +# Building test.properties file |
| 132 | +logging.info("Building test.properties file") |
| 133 | +file_path = "test.properties" |
| 134 | +write_properties_file(args.env, args.sim, env_props, sim_props, file_path) |
| 135 | + |
| 136 | +try: |
| 137 | + # Execute command |
| 138 | + command = sim_props["command"] |
| 139 | + logging.info(f"Executing simulation command: {command}") |
| 140 | + output = subprocess.check_output(command, shell=True, universal_newlines=True) |
| 141 | + logging.info(f"Output: ${output}") |
| 142 | +except subprocess.CalledProcessError as e: |
| 143 | + logging.error(f"Command failed with return code {e.returncode}. Error output:") |
| 144 | + logging.error(e.output) |
0 commit comments