Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[uss_qualifier] Enable execution of multiple configurations in the same container #266

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions monitoring/uss_qualifier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The `uss_qualifier` tool is a synchronous executable built into the `interuss/mo

The primary input accepted by uss_qualifier is the "configuration" specified with the `--config` option. This option should be a [reference to a configuration file](configurations/README.md) that the user has constructed or been provided to test the desired system for the desired characteristics. If testing a standard local system (DSS + dummy auth + mock USSs), the user can specify an alternate configuration reference as a single argument to `run_locally.sh` (the default configuration is `configurations.dev.local_test`).

Several comma-separated "configurations" may be passed via the `--config` option. If specified, the `--report` and `--config-output` options must have the same number of comma-separated values, which may be empty.

When building a custom configuration file, consider starting from [`configurations.dev.f3548_self_contained`](configurations/dev/f3548_self_contained.yaml), as it contains all information necessary to run the test without the usage of sometimes-configuring `$ref`s and `allOf`s. See [configurations documentation](configurations/README.md) for more information.

### Quick start
Expand Down
89 changes: 67 additions & 22 deletions monitoring/uss_qualifier/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,20 @@ def parseArgs() -> argparse.Namespace:

parser.add_argument(
"--config",
help="Configuration string according to monitoring/uss_qualifier/configurations/README.md",
help="Configuration string according to monitoring/uss_qualifier/configurations/README.md; Several comma-separated strings may be specified",
required=True,
)

parser.add_argument(
"--report",
default=None,
help="(Overrides setting in artifacts configuration) File name of the report to write (if test configuration provided) or read (if test configuration not provided)",
help="(Overrides setting in artifacts configuration) File name of the report to write (if test configuration provided) or read (if test configuration not provided); Several comma-separated file names matching the configurations may be specified",
)

parser.add_argument(
"--config-output",
default=None,
help="If specified, write the configuration as parsed (potentially from multiple files) to the single file specified by this path",
help="If specified, write the configuration as parsed (potentially from multiple files) to the single file specified by this path; Several comma-separated file names matching the configurations may be specified",
)

parser.add_argument(
Expand Down Expand Up @@ -115,12 +115,16 @@ def execute_test_run(
)


def main() -> int:
args = parseArgs()

config_src = load_dict_with_references(args.config)
def run_config(
config_name: str,
config_output: str,
report_path: str,
skip_validation: bool,
exit_before_execution: bool,
):
config_src = load_dict_with_references(config_name)

if not args.skip_validation:
if not skip_validation:
logger.info("Validating configuration...")
validation_errors = validate_config(config_src)
if validation_errors:
Expand All @@ -132,33 +136,33 @@ def main() -> int:

whole_config = ImplicitDict.parse(config_src, USSQualifierConfiguration)

if args.config_output:
logger.info("Writing flattened configuration to {}", args.config_output)
if args.config_output.lower().endswith(".json"):
with open(args.config_output, "w") as f:
if config_output:
logger.info("Writing flattened configuration to {}", config_output)
if config_output.lower().endswith(".json"):
with open(config_output, "w") as f:
json.dump(whole_config, f, indent=2, sort_keys=True)
elif args.config_output.lower().endswith(".yaml"):
with open(args.config_output, "w") as f:
elif config_output.lower().endswith(".yaml"):
with open(config_output, "w") as f:
yaml.dump(json.loads(json.dumps(whole_config)), f, sort_keys=True)
else:
raise ValueError(
"Unsupported extension for --config-output; only .json or .yaml file paths may be specified"
)

if args.exit_before_execution:
if exit_before_execution:
logger.info("Exiting because --exit-before-execution specified.")
return os.EX_OK
return

config: USSQualifierConfigurationV1 = whole_config.v1
if args.report:
if report_path:
if not config.artifacts:
config.artifacts = ArtifactsConfiguration(
ReportConfiguration(report_path=args.report)
ReportConfiguration(report_path=report_path)
)
elif not config.artifacts.report:
config.artifacts.report = ReportConfiguration(report_path=args.report)
config.artifacts.report = ReportConfiguration(report_path=report_path)
else:
config.artifacts.report.report_path = args.report
config.artifacts.report.report_path = report_path

do_not_save_report = False
if config.test_run:
Expand Down Expand Up @@ -215,15 +219,56 @@ def main() -> int:
generate_sequence_view(report, config.artifacts.sequence_view)

if "validation" in config and config.validation:
logger.info(f"Validating test run report for configuration '{args.config}'")
logger.info(f"Validating test run report for configuration '{config_name}'")
if not validate_report(report, config.validation):
logger.error(
f"Validation failed on test run report for configuration '{args.config}'"
f"Validation failed on test run report for configuration '{config_name}'"
)
return -1

return os.EX_OK


def main() -> int:
args = parseArgs()

config_names = str(args.config).split(",")

if args.config_output:
config_outputs = str(args.config_output).split(",")
if len(config_outputs) != len(config_names):
raise ValueError(
f"Need matching number of config_output, expected {len(config_names)}, got {len(config_outputs)}"
)
else:
config_outputs = ["" for _ in config_names]

if args.report:
report_paths = str(args.report).split(",")
if len(report_paths) != len(config_names):
raise ValueError(
f"Need matching number of report, expected {len(config_names)}, got {len(report_paths)}"
)
else:
report_paths = ["" for _ in config_names]

for idx, config_name in enumerate(config_names):
logger.info(
f"========== Running uss_qualifier for configuration {config_name} =========="
)
run_config(
config_name,
config_outputs[idx],
report_paths[idx],
args.skip_validation,
args.exit_before_execution,
)
logger.info(
f"========== Completed uss_qualifier for configuration {config_name} =========="
)

return os.EX_OK


if __name__ == "__main__":
sys.exit(main())
101 changes: 55 additions & 46 deletions monitoring/uss_qualifier/run_locally.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,57 +24,66 @@ CONFIG_NAME="${1:-ALL}"
OTHER_ARGS=${@:2}

if [ "$CONFIG_NAME" == "ALL" ]; then
declare -a all_configurations=( \
"configurations.dev.noop" \
"configurations.dev.dss_probing" \
"configurations.dev.geoawareness_cis" \
"configurations.dev.generate_rid_test_data" \
"configurations.dev.geospatial_comprehension" \
"configurations.dev.general_flight_auth" \
"configurations.dev.f3548" \
"configurations.dev.f3548_self_contained" \
"configurations.dev.netrid_v22a" \
"configurations.dev.uspace" \
)
# TODO: Add configurations.dev.netrid_v19
echo "Running configurations: ${all_configurations[*]}"
for configuration_name in "${all_configurations[@]}"; do
monitoring/uss_qualifier/run_locally.sh "$configuration_name"
done
else
CONFIG_FLAG="--config ${CONFIG_NAME}"
CONFIG_NAME="\
configurations.dev.noop,\
configurations.dev.dss_probing,\
configurations.dev.geoawareness_cis,\
configurations.dev.generate_rid_test_data,\
configurations.dev.geospatial_comprehension,\
configurations.dev.general_flight_auth,\
configurations.dev.f3548,\
configurations.dev.f3548_self_contained,\
configurations.dev.netrid_v22a,\
configurations.dev.uspace"
fi
# TODO: Add configurations.dev.netrid_v19

AUTH_SPEC='DummyOAuth(http://oauth.authority.localutm:8085/token,uss_qualifier)'
echo "Running configuration(s): ${CONFIG_NAME}"

QUALIFIER_OPTIONS="$CONFIG_FLAG $OTHER_ARGS"
CONFIG_FLAG="--config ${CONFIG_NAME}"

OUTPUT_DIR="monitoring/uss_qualifier/output"
mkdir -p "$OUTPUT_DIR"
AUTH_SPEC='DummyOAuth(http://oauth.authority.localutm:8085/token,uss_qualifier)'

CACHE_DIR="monitoring/uss_qualifier/.templates_cache"
mkdir -p "$CACHE_DIR"
QUALIFIER_OPTIONS="$CONFIG_FLAG $OTHER_ARGS"

if [ "$CI" == "true" ]; then
docker_args="--add-host host.docker.internal:host-gateway" # Required to reach other containers in Ubuntu (used for Github Actions)
else
docker_args="-it"
fi
OUTPUT_DIR="monitoring/uss_qualifier/output"
mkdir -p "$OUTPUT_DIR"

CACHE_DIR="monitoring/uss_qualifier/.templates_cache"
mkdir -p "$CACHE_DIR"

echo "========== Running uss_qualifier for configuration ${CONFIG_NAME} =========="
# shellcheck disable=SC2086
docker run ${docker_args} --name uss_qualifier \
--rm \
--network interop_ecosystem_network \
-u "$(id -u):$(id -g)" \
-e PYTHONBUFFERED=1 \
-e AUTH_SPEC=${AUTH_SPEC} \
-e USS_QUALIFIER_STOP_FAST=${USS_QUALIFIER_STOP_FAST:-} \
-e MONITORING_GITHUB_ROOT=${MONITORING_GITHUB_ROOT:-} \
-v "$(pwd)/$OUTPUT_DIR:/app/$OUTPUT_DIR" \
-v "$(pwd)/$CACHE_DIR:/app/$CACHE_DIR" \
-w /app/monitoring/uss_qualifier \
interuss/monitoring \
python main.py $QUALIFIER_OPTIONS
echo "========== Completed uss_qualifier for configuration ${CONFIG_NAME} =========="
if [ "$CI" == "true" ]; then
docker_args="--add-host host.docker.internal:host-gateway" # Required to reach other containers in Ubuntu (used for Github Actions)
else
docker_args="-it"
fi

start_time=$(date +%Y-%m-%dT%H:%M:%S)
# shellcheck disable=SC2086
docker run ${docker_args} --name uss_qualifier \
--rm \
--network interop_ecosystem_network \
-u "$(id -u):$(id -g)" \
-e PYTHONBUFFERED=1 \
-e AUTH_SPEC=${AUTH_SPEC} \
-e USS_QUALIFIER_STOP_FAST=${USS_QUALIFIER_STOP_FAST:-} \
-e MONITORING_GITHUB_ROOT=${MONITORING_GITHUB_ROOT:-} \
-v "$(pwd)/$OUTPUT_DIR:/app/$OUTPUT_DIR" \
-v "$(pwd)/$CACHE_DIR:/app/$CACHE_DIR" \
-w /app/monitoring/uss_qualifier \
interuss/monitoring \
python main.py $QUALIFIER_OPTIONS

# Set return code according to whether the test run was fully successful
reports_generated=$(find ./monitoring/uss_qualifier/output/report*.json -newermt "$start_time")
# shellcheck disable=SC2068
for REPORT in ${reports_generated[@]}; do
successful=$(python build/dev/extract_json_field.py report.*.successful "$REPORT")
if echo "${successful}" | grep -iqF true; then
echo "Full success indicated by $REPORT"
else
echo "Could not establish that all uss_qualifier tests passed in $REPORT"
exit 1
fi
done

Loading