From db4a74e29fd435d6791b926721fd49d96acec1e4 Mon Sep 17 00:00:00 2001 From: Julien Perrochet Date: Tue, 10 Oct 2023 11:08:20 +0200 Subject: [PATCH] Squished commit --- .../configurations/dev/dss_probing.yaml | 13 +++ .../configurations/dev/f3548.yaml | 1 + .../dev/library/environment.yaml | 14 +++ .../resources/astm/f3548/v21/__init__.py | 2 +- .../resources/astm/f3548/v21/dss.py | 48 ++++++++- .../scenarios/astm/utm/__init__.py | 1 + .../astm/utm/dss_interoperability.md | 31 ++++++ .../astm/utm/dss_interoperability.py | 97 +++++++++++++++++++ .../uss_qualifier/suites/astm/utm/f3548_21.md | 14 ++- .../suites/astm/utm/f3548_21.yaml | 7 ++ .../suites/faa/uft/message_signing.md | 7 +- .../suites/interuss/dss/all_tests.yaml | 1 + .../suites/uspace/flight_auth.md | 7 +- .../suites/uspace/required_services.md | 7 +- 14 files changed, 239 insertions(+), 11 deletions(-) create mode 100644 monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.md create mode 100644 monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.py diff --git a/monitoring/uss_qualifier/configurations/dev/dss_probing.yaml b/monitoring/uss_qualifier/configurations/dev/dss_probing.yaml index 6ef5c7f17b..c83118d283 100644 --- a/monitoring/uss_qualifier/configurations/dev/dss_probing.yaml +++ b/monitoring/uss_qualifier/configurations/dev/dss_probing.yaml @@ -39,6 +39,18 @@ v1: rid_version: F3411-22a base_url: http://dss.uss2.localutm/rid/v2 has_private_address: true + utm_dss_instances_v21: # TODO discuss if this is the right place for this? The rest seems netrid specific + resource_type: resources.astm.f3548.v21.DSSInstancesResource + dependencies: + auth_adapter: utm_auth + specification: + dss_instances: + - participant_id: uss1 + base_url: http://dss.uss1.localutm/rid/v2 # TODO: probably different base urls here? + has_private_address: true + - participant_id: uss2 + base_url: http://dss.uss2.localutm/rid/v2 + has_private_address: true id_generator: resource_type: resources.interuss.IDGeneratorResource dependencies: @@ -70,6 +82,7 @@ v1: resources: f3411v19_dss_instances: netrid_dss_instances_v19 f3411v22a_dss_instances: netrid_dss_instances_v22a + f3548v21_dss_instances: utm_dss_instances_v21 id_generator: id_generator service_area: service_area artifacts: diff --git a/monitoring/uss_qualifier/configurations/dev/f3548.yaml b/monitoring/uss_qualifier/configurations/dev/f3548.yaml index 257a49d4fc..067c5b7113 100644 --- a/monitoring/uss_qualifier/configurations/dev/f3548.yaml +++ b/monitoring/uss_qualifier/configurations/dev/f3548.yaml @@ -13,6 +13,7 @@ v1: priority_preemption_flights: priority_preemption_flights invalid_flight_intents: invalid_flight_intents dss: dss + all_dss_instances: dss_instances artifacts: tested_roles: report_path: output/tested_roles_f3548 diff --git a/monitoring/uss_qualifier/configurations/dev/library/environment.yaml b/monitoring/uss_qualifier/configurations/dev/library/environment.yaml index ab16eec8aa..28f0ff8361 100644 --- a/monitoring/uss_qualifier/configurations/dev/library/environment.yaml +++ b/monitoring/uss_qualifier/configurations/dev/library/environment.yaml @@ -11,6 +11,7 @@ non_baseline_inputs: - v1.test_run.resources.resource_declarations.netrid_dss_instances_v22a - v1.test_run.resources.resource_declarations.netrid_dss_instance_v19 - v1.test_run.resources.resource_declarations.netrid_dss_instance_v22a + - v1.test_run.resources.resource_declarations.utm_dss_instance_v21 - v1.test_run.resources.resource_declarations.flight_planners - v1.test_run.resources.resource_declarations.dss - v1.test_run.resources.resource_declarations.uss1 @@ -147,6 +148,19 @@ f3548: participant_id: uss1 base_url: http://dss.uss1.localutm has_private_address: true + dss_instances: + $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json + resource_type: resources.astm.f3548.v21.DSSInstancesResource + dependencies: + auth_adapter: utm_auth + specification: + dss_instances: + - participant_id: uss1 + base_url: http://dss.uss1.localutm + has_private_address: true + - participant_id: uss2 + base_url: http://dss.uss2.localutm + has_private_address: true f3548_single_scenario: uss1: diff --git a/monitoring/uss_qualifier/resources/astm/f3548/v21/__init__.py b/monitoring/uss_qualifier/resources/astm/f3548/v21/__init__.py index c0c50ca3fe..6da048f501 100644 --- a/monitoring/uss_qualifier/resources/astm/f3548/v21/__init__.py +++ b/monitoring/uss_qualifier/resources/astm/f3548/v21/__init__.py @@ -1 +1 @@ -from .dss import DSSInstanceResource +from .dss import DSSInstanceResource, DSSInstancesResource diff --git a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py index ed937b0694..c040db8126 100644 --- a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py +++ b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py @@ -1,4 +1,5 @@ -from typing import Tuple, List +from __future__ import annotations +from typing import Tuple, List, Optional from urllib.parse import urlparse from implicitdict import ImplicitDict @@ -24,6 +25,9 @@ class DSSInstanceSpecification(ImplicitDict): base_url: str """Base URL for the DSS instance according to the ASTM F3548-21 API""" + has_private_address: Optional[bool] + """Whether this DSS instance is expected to have a private address that is not publicly addressable.""" + def __init__(self, *args, **kwargs): super().__init__(**kwargs) try: @@ -34,16 +38,21 @@ def __init__(self, *args, **kwargs): class DSSInstance(object): participant_id: str + base_url: str + has_private_address: bool = False client: infrastructure.UTMClientSession def __init__( self, participant_id: str, base_url: str, + has_private_address: Optional[bool], auth_adapter: infrastructure.AuthAdapter, ): self.participant_id = participant_id - self._base_url = base_url + self.base_url = base_url + if has_private_address is not None: + self.has_private_address = has_private_address self.client = infrastructure.UTMClientSession(base_url, auth_adapter) def find_op_intent( @@ -82,6 +91,13 @@ def get_full_op_intent( ).operational_intent return result, query + def is_same_as(self, other: DSSInstance) -> bool: + return ( + self.participant_id == other.participant_id + and self.base_url == other.base_url + and self.has_private_address == other.has_private_address + ) + class DSSInstanceResource(Resource[DSSInstanceSpecification]): dss: DSSInstance @@ -92,5 +108,31 @@ def __init__( auth_adapter: AuthAdapterResource, ): self.dss = DSSInstance( - specification.participant_id, specification.base_url, auth_adapter.adapter + specification.participant_id, + specification.base_url, + specification.has_private_address, + auth_adapter.adapter, ) + + +class DSSInstancesSpecification(ImplicitDict): + dss_instances: List[DSSInstanceSpecification] + + +class DSSInstancesResource(Resource[DSSInstancesSpecification]): + dss_instances: List[DSSInstance] + + def __init__( + self, + specification: DSSInstancesSpecification, + auth_adapter: AuthAdapterResource, + ): + self.dss_instances = [ + DSSInstance( + s.participant_id, + s.base_url, + s.has_private_address, + auth_adapter.adapter, + ) + for s in specification.dss_instances + ] diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/__init__.py b/monitoring/uss_qualifier/scenarios/astm/utm/__init__.py index 007c2a8358..9317644cb6 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/__init__.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/__init__.py @@ -5,3 +5,4 @@ from .nominal_planning.conflict_equal_priority_not_permitted.conflict_equal_priority_not_permitted import ( ConflictEqualPriorityNotPermitted, ) +from .dss_interoperability import DSSInteroperability diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.md b/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.md new file mode 100644 index 0000000000..16ff85c363 --- /dev/null +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.md @@ -0,0 +1,31 @@ +# ASTM F3548-21 UTM DSS interoperability test scenario + +## Overview + +TODO: Complete with details once we check more than the prerequisites. + +This scenario currently only checks that all specified DSS instances are publicly addressable and reachable. + +## Resources + +### primary_dss_instance + +A resources.astm.f3548.v21.DSSInstanceResource containing the "primary" DSS instance for this scenario. + +### all_dss_instances + +A resources.astm.f3548.v21.DSSInstancesResource containing at least two DSS instances complying with ASTM F3548-21. + +## Prerequisites test case + +### Test environment requirements test step + +#### DSS instance is publicly addressable check + +As per **[astm.f3548.v21.DSS0300](../../../requirements/astm/f3548/v21.md)** the DSS instance should be publicly addressable. +As such, this check will fail if the resolved IP of the DSS host is a private IP address, unless that is explicitly +expected. + +#### DSS instance is reachable check +As per **[astm.f3548.v21.DSS0300](../../../requirements/astm/f3548/v21.md)** the DSS instance should be publicly addressable. +As such, this check will fail if the DSS is not reachable with a dummy query. diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.py b/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.py new file mode 100644 index 0000000000..fcb4cec287 --- /dev/null +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.py @@ -0,0 +1,97 @@ +import ipaddress +import socket +import time +import uuid +from dataclasses import dataclass +import datetime +from enum import Enum +from typing import List, Dict, Optional +from urllib.parse import urlparse + +import s2sphere +from uas_standards.astm.f3548.v21.api import Volume4D, Volume3D, Polygon, LatLngPoint + +from monitoring.monitorlib.fetch.rid import ISA +from monitoring.uss_qualifier.common_data_definitions import Severity +from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import ( + DSSInstancesResource, + DSSInstanceResource, + DSSInstance, +) +from monitoring.uss_qualifier.scenarios.astm.netrid.dss_wrapper import DSSWrapper +from monitoring.uss_qualifier.scenarios.scenario import TestScenario + +VERTICES: List[LatLngPoint] = [ + LatLngPoint(lng=130.6205, lat=-23.6558), + LatLngPoint(lng=130.6301, lat=-23.6898), + LatLngPoint(lng=130.6700, lat=-23.6709), + LatLngPoint(lng=130.6466, lat=-23.6407), +] +SHORT_WAIT_SEC = 5 + + +class DSSInteroperability( + TestScenario +): # TODO needed to extend TestScenario instead of GenericTestScenario otherwise `make format` is unhappy + _dss_primary: DSSInstance + _dss_others: List[DSSInstance] + + def __init__( + self, + primary_dss_instance: DSSInstanceResource, + all_dss_instances: DSSInstancesResource, + ): + super().__init__() + self._dss_primary = primary_dss_instance.dss + self._dss_others = [ + dss + for dss in all_dss_instances.dss_instances + if not dss.is_same_as(primary_dss_instance.dss) + ] + + def run(self): + + # self.record_note( + # "dss_instances", + # f"Provided DSS instances: {[self._dss_primary] + self._dss_others}", + # ) + self.begin_test_scenario() + + self.begin_test_case("Prerequisites") + + self.begin_test_step("Test environment requirements") + self._test_env_reqs() + self.end_test_step() + + self.end_test_case() + + self.end_test_scenario() + + def _test_env_reqs(self): + for dss in [self._dss_primary] + self._dss_others: + with self.check( + "DSS instance is publicly addressable", [dss.participant_id] + ) as check: + parsed_url = urlparse(dss.base_url) + ip_addr = socket.gethostbyname(parsed_url.hostname) + + if dss.has_private_address: + self.record_note( + f"{dss.participant_id}_private_address", + f"DSS instance (URL: {dss.base_url}, netloc: {parsed_url.netloc}, resolved IP: {ip_addr}) is declared as explicitly having a private address, skipping check", + ) + elif ipaddress.ip_address(ip_addr).is_private: + check.record_failed( + summary=f"DSS host {parsed_url.netloc} is not publicly addressable", + severity=Severity.Medium, + participants=[dss.participant_id], + details=f"DSS (URL: {dss.base_url}, netloc: {parsed_url.netloc}, resolved IP: {ip_addr}) is not publicly addressable", + ) + + with self.check("DSS instance is reachable", [dss.participant_id]) as check: + # dummy search query + dss.find_op_intent( + extent=Volume4D( + volume=Volume3D(outline_polygon=Polygon(vertices=VERTICES)) + ) + ) diff --git a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md index 9b83332c44..91c251e487 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md +++ b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md @@ -4,11 +4,12 @@ ## [Actions](../../README.md#actions) -1. Action generator: [`action_generators.flight_planning.FlightPlannerCombinations`](../../../action_generators/flight_planning/planner_combinations.py) - 1. Scenario: [Validation of operational intents](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.md) ([`scenarios.astm.utm.FlightIntentValidation`](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.py)) +1. Scenario: [ASTM F3548-21 UTM DSS interoperability](../../../scenarios/astm/utm/dss_interoperability.md) ([`scenarios.astm.utm.DSSInteroperability`](../../../scenarios/astm/utm/dss_interoperability.py)) 2. Action generator: [`action_generators.flight_planning.FlightPlannerCombinations`](../../../action_generators/flight_planning/planner_combinations.py) - 1. Scenario: [Nominal planning: conflict with higher priority](../../../scenarios/astm/utm/nominal_planning/conflict_higher_priority/conflict_higher_priority.md) ([`scenarios.astm.utm.ConflictHigherPriority`](../../../scenarios/astm/utm/nominal_planning/conflict_higher_priority/conflict_higher_priority.py)) + 1. Scenario: [Validation of operational intents](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.md) ([`scenarios.astm.utm.FlightIntentValidation`](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.py)) 3. Action generator: [`action_generators.flight_planning.FlightPlannerCombinations`](../../../action_generators/flight_planning/planner_combinations.py) + 1. Scenario: [Nominal planning: conflict with higher priority](../../../scenarios/astm/utm/nominal_planning/conflict_higher_priority/conflict_higher_priority.md) ([`scenarios.astm.utm.ConflictHigherPriority`](../../../scenarios/astm/utm/nominal_planning/conflict_higher_priority/conflict_higher_priority.py)) +4. Action generator: [`action_generators.flight_planning.FlightPlannerCombinations`](../../../action_generators/flight_planning/planner_combinations.py) 1. Scenario: [Nominal planning: not permitted conflict with equal priority](../../../scenarios/astm/utm/nominal_planning/conflict_equal_priority_not_permitted/conflict_equal_priority_not_permitted.md) ([`scenarios.astm.utm.ConflictEqualPriorityNotPermitted`](../../../scenarios/astm/utm/nominal_planning/conflict_equal_priority_not_permitted/conflict_equal_priority_not_permitted.py)) ## [Checked requirements](../../README.md#checked-requirements) @@ -21,11 +22,16 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005 Implemented Nominal planning: conflict with higher priority
Nominal planning: not permitted conflict with equal priority
Validation of operational intents + + DSS0300 + Implemented + ASTM F3548-21 UTM DSS interoperability + GEN0310 Implemented diff --git a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml index 51380c2746..1a0448ad90 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml +++ b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml @@ -2,12 +2,19 @@ name: ASTM F3548-21 resources: flight_planners: resources.flight_planning.FlightPlannersResource dss: resources.astm.f3548.v21.DSSInstanceResource + all_dss_instances: resources.astm.f3548.v21.DSSInstancesResource? conflicting_flights: resources.flight_planning.FlightIntentsResource priority_preemption_flights: resources.flight_planning.FlightIntentsResource invalid_flight_intents: resources.flight_planning.FlightIntentsResource nominal_planning_selector: resources.flight_planning.FlightPlannerCombinationSelectorResource? priority_planning_selector: resources.flight_planning.FlightPlannerCombinationSelectorResource? actions: +- test_scenario: # TODO confirm this should go here + scenario_type: scenarios.astm.utm.DSSInteroperability + resources: + primary_dss_instance: dss + all_dss_instances: all_dss_instances + on_failure: Continue - action_generator: generator_type: action_generators.flight_planning.FlightPlannerCombinations resources: diff --git a/monitoring/uss_qualifier/suites/faa/uft/message_signing.md b/monitoring/uss_qualifier/suites/faa/uft/message_signing.md index 050dde31a4..4296159689 100644 --- a/monitoring/uss_qualifier/suites/faa/uft/message_signing.md +++ b/monitoring/uss_qualifier/suites/faa/uft/message_signing.md @@ -18,11 +18,16 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005 Implemented Nominal planning: conflict with higher priority
Nominal planning: not permitted conflict with equal priority
Validation of operational intents + + DSS0300 + Implemented + ASTM F3548-21 UTM DSS interoperability + GEN0310 Implemented diff --git a/monitoring/uss_qualifier/suites/interuss/dss/all_tests.yaml b/monitoring/uss_qualifier/suites/interuss/dss/all_tests.yaml index b8fad053be..0c33ce19c7 100644 --- a/monitoring/uss_qualifier/suites/interuss/dss/all_tests.yaml +++ b/monitoring/uss_qualifier/suites/interuss/dss/all_tests.yaml @@ -2,6 +2,7 @@ name: ASTM DSS tests resources: f3411v19_dss_instances: resources.astm.f3411.DSSInstancesResource f3411v22a_dss_instances: resources.astm.f3411.DSSInstancesResource + f3548v21_dss_instances: resources.astm.f3548.v21.DSSInstancesResource id_generator: resources.interuss.IDGeneratorResource service_area: resources.netrid.ServiceAreaResource actions: diff --git a/monitoring/uss_qualifier/suites/uspace/flight_auth.md b/monitoring/uss_qualifier/suites/uspace/flight_auth.md index f7dd88ba0a..659b1a805d 100644 --- a/monitoring/uss_qualifier/suites/uspace/flight_auth.md +++ b/monitoring/uss_qualifier/suites/uspace/flight_auth.md @@ -18,11 +18,16 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005 Implemented Nominal planning: conflict with higher priority
Nominal planning: not permitted conflict with equal priority
Validation of operational intents + + DSS0300 + Implemented + ASTM F3548-21 UTM DSS interoperability + GEN0310 Implemented diff --git a/monitoring/uss_qualifier/suites/uspace/required_services.md b/monitoring/uss_qualifier/suites/uspace/required_services.md index a690bb7ab8..7997e33f9c 100644 --- a/monitoring/uss_qualifier/suites/uspace/required_services.md +++ b/monitoring/uss_qualifier/suites/uspace/required_services.md @@ -388,11 +388,16 @@ ASTM NetRID DSS: Simple ISA - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005 Implemented Nominal planning: conflict with higher priority
Nominal planning: not permitted conflict with equal priority
Validation of operational intents + + DSS0300 + Implemented + ASTM F3548-21 UTM DSS interoperability + GEN0310 Implemented