Skip to content

Commit

Permalink
Squished commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Shastick committed Oct 10, 2023
1 parent b171492 commit c128249
Show file tree
Hide file tree
Showing 7 changed files with 283 additions and 82 deletions.
13 changes: 13 additions & 0 deletions monitoring/uss_qualifier/configurations/dev/dss_probing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.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:
Expand Down Expand Up @@ -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:
Expand Down
34 changes: 32 additions & 2 deletions monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Tuple, List
from typing import Tuple, List, Optional
from urllib.parse import urlparse

from implicitdict import ImplicitDict
Expand All @@ -24,6 +24,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:
Expand All @@ -34,16 +37,20 @@ def __init__(self, *args, **kwargs):

class DSSInstance(object):
participant_id: 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
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(
Expand Down Expand Up @@ -92,5 +99,28 @@ 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
]
1 change: 1 addition & 0 deletions monitoring/uss_qualifier/scenarios/astm/utm/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO DSS0300 comes in here somewhere
Original file line number Diff line number Diff line change
@@ -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.
119 changes: 119 additions & 0 deletions monitoring/uss_qualifier/scenarios/astm/utm/dss_interoperability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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 monitoring.monitorlib.fetch.rid import ISA
from monitoring.uss_qualifier.common_data_definitions import Severity
from monitoring.uss_qualifier.resources.astm.f3411.dss import (
DSSInstancesResource,
DSSInstanceResource,
)
from monitoring.uss_qualifier.scenarios.astm.netrid.dss_wrapper import DSSWrapper
from monitoring.uss_qualifier.scenarios.scenario import GenericTestScenario

VERTICES: List[s2sphere.LatLng] = [
s2sphere.LatLng.from_degrees(lng=130.6205, lat=-23.6558),
s2sphere.LatLng.from_degrees(lng=130.6301, lat=-23.6898),
s2sphere.LatLng.from_degrees(lng=130.6700, lat=-23.6709),
s2sphere.LatLng.from_degrees(lng=130.6466, lat=-23.6407),
]
SHORT_WAIT_SEC = 5


class EntityType(str, Enum):
ISA = "ISA"
Sub = "Sub"


@dataclass
class TestEntity(object):
type: EntityType
uuid: str
version: Optional[str] = None


class DSSInteroperability(GenericTestScenario):
_dss_primary: DSSWrapper
_dss_others: List[DSSWrapper]
_context: Dict[str, TestEntity]

def __init__(
self,
primary_dss_instance: DSSInstanceResource,
all_dss_instances: DSSInstancesResource,
):
super().__init__()
self._dss_primary = DSSWrapper(self, primary_dss_instance.dss_instance)
self._dss_others = [
DSSWrapper(self, dss)
for dss in all_dss_instances.dss_instances
if not dss.is_same_as(primary_dss_instance.dss_instance)
]
self._context: Dict[str, TestEntity] = {}

def _new_isa(self, name: str) -> TestEntity:
self._context[name] = TestEntity(EntityType.ISA, str(uuid.uuid4()))
return self._context[name]

def _new_sub(self, name: str) -> TestEntity:
self._context[name] = TestEntity(EntityType.Sub, str(uuid.uuid4()))
return self._context[name]

def _get_entities_by_prefix(self, prefix: str) -> Dict[str, TestEntity]:
all_entities = dict()
for name, entity in self._context.items():
if name.startswith(prefix):
all_entities[entity.uuid] = entity
return all_entities

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.search_subs(check, VERTICES)

def cleanup(self):
self.begin_cleanup()
self.end_cleanup()
Loading

0 comments on commit c128249

Please sign in to comment.