Skip to content

Commit

Permalink
Merge branch 'main' into dss0210-sub-manager-synced
Browse files Browse the repository at this point in the history
  • Loading branch information
Shastick authored Mar 19, 2024
2 parents 7dbf130 + 46c020a commit 9dcb897
Show file tree
Hide file tree
Showing 23 changed files with 1,303 additions and 39 deletions.
53 changes: 40 additions & 13 deletions monitoring/monitorlib/mutate/scd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import s2sphere
import yaml
from implicitdict import ImplicitDict
from uas_standards.astm.f3548.v21.api import OPERATIONS, OperationID, Subscription
from uas_standards.astm.f3548.v21.api import (
OPERATIONS,
OperationID,
Subscription,
PutSubscriptionParameters,
)
from yaml.representer import Representer

from monitoring.monitorlib import fetch
Expand Down Expand Up @@ -74,18 +79,16 @@ def upsert_subscription(
path = op.path.format(subscriptionid=subscription_id, version=version)
query_type = QueryType.F3548v21DSSUpdateSubscription

body = {
"extents": Volume4D.from_values(
start_time,
end_time,
min_alt_m,
max_alt_m,
polygon=Polygon.from_latlng_rect(latlngrect=area),
).to_f3548v21(),
"uss_base_url": base_url,
"notify_for_operational_intents": notify_for_op_intents,
"notify_for_constraints": notify_for_constraints,
}
body = build_upsert_subscription_params(
area_vertices=area,
start_time=start_time,
end_time=end_time,
base_url=base_url,
notify_for_op_intents=notify_for_op_intents,
notify_for_constraints=notify_for_constraints,
min_alt_m=min_alt_m,
max_alt_m=max_alt_m,
)

result = MutatedSubscription(
fetch.query_and_describe(
Expand All @@ -102,6 +105,30 @@ def upsert_subscription(
return result


def build_upsert_subscription_params(
area_vertices: s2sphere.LatLngRect,
start_time: datetime.datetime,
end_time: datetime.datetime,
base_url: str,
notify_for_op_intents: bool,
notify_for_constraints: bool,
min_alt_m: float,
max_alt_m: float,
) -> PutSubscriptionParameters:
return PutSubscriptionParameters(
extents=Volume4D.from_values(
start_time,
end_time,
min_alt_m,
max_alt_m,
polygon=Polygon.from_latlng_rect(latlngrect=area_vertices),
).to_f3548v21(),
uss_base_url=base_url,
notify_for_operational_intents=notify_for_op_intents,
notify_for_constraints=notify_for_constraints,
)


def delete_subscription(
utm_client: infrastructure.UTMClientSession,
subscription_id: str,
Expand Down
1 change: 1 addition & 0 deletions monitoring/monitorlib/schema_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class F3411_22a(str, Enum):

class F3548_21(str, Enum):
OpenAPIPath = "interfaces/astm-utm/Protocol/utm.yaml"
ErrorResponse = "components.schemas.ErrorResponse"
GetOperationalIntentDetailsResponse = (
"components.schemas.GetOperationalIntentDetailsResponse"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ v1:
# ASTM F3548-21 USS emulation roles
- utm.strategic_coordination
- utm.availability_arbitration
# For authentication test purposes.
# Remove if the authentication provider pointed to by AUTH_SPEC does not support it.
- ""

# Means by which uss_qualifier can discover which subscription ('sub' claim of its tokes) it is described by
utm_client_identity:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ utm_auth:
- utm.availability_arbitration
# InterUSS versioning automated testing
- interuss.versioning.read_system_versions
# For authentication test purposes.
# Remove if the authentication provider pointed to by AUTH_SPEC does not support it.
- ""

second_utm_auth:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ utm_auth:
- utm.availability_arbitration
# InterUSS versioning automated testing
- interuss.versioning.read_system_versions
# For authentication test purposes
- ""

second_utm_auth:
$content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json
Expand Down
67 changes: 67 additions & 0 deletions monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
OperationID,
GetOperationalIntentTelemetryResponse,
VehicleTelemetry,
ExchangeRecord,
ErrorReport,
)
from uas_standards.astm.f3548.v21.constants import Scope

Expand Down Expand Up @@ -104,6 +106,16 @@ def _uses_scope(self, *scopes: Tuple[str]) -> None:
f"{fullname(type(self))} client called {calling_function_name(1)} which requires the use of the scope `{scope}`, but this DSSInstance is only authorized to perform actions with the scopes {' or '.join(self._scopes_authorized)}"
)

def _uses_any_scope(self, *scopes: str) -> str:
"""Validates that at least a required scope is authorized for a request.
Additionally, returns a valid scope that may be used for the request."""
for scope in scopes:
if scope in self._scopes_authorized:
return scope
raise ValueError(
f"{fullname(type(self))} client called {calling_function_name(1)} which requires the use of any of the scopes `{', '.join(scopes)}`, but this DSSInstance is only authorized to perform actions with the scopes {' or '.join(self._scopes_authorized)}"
)

def can_use_scope(self, scope: str) -> bool:
return scope in self._scopes_authorized

Expand Down Expand Up @@ -369,6 +381,58 @@ def set_uss_availability(
result = query.parse_json_result(UssAvailabilityStatusResponse)
return result.version, query

def make_report(
self,
exchange: ExchangeRecord,
) -> Tuple[Optional[str], Query]:
"""
Make a DSS report.
Returns:
A tuple composed of
1) the report ID;
2) the query.
Raises:
* QueryError: if request failed, if HTTP status code is different than 201, or if the parsing of the response failed.
"""
use_scope = self._uses_any_scope(
Scope.ConstraintManagement,
Scope.ConstraintProcessing,
Scope.StrategicCoordination,
Scope.ConformanceMonitoringForSituationalAwareness,
Scope.AvailabilityArbitration,
)

req = ErrorReport(exchange=exchange)
op = OPERATIONS[OperationID.MakeDssReport]
query = query_and_describe(
self.client,
op.verb,
op.path,
QueryType.F3548v21DSSMakeDssReport,
self.participant_id,
scope=use_scope,
json=req,
)

# TODO: this is a temporary hack: the endpoint is currently not implemented in the DSS, as such we expect the
# DSS to respond with a 400 and a specific error message. This must be updated once this endpoint is actually
# implemented in the DSS.
# if query.status_code != 201:
# raise QueryError(
# f"Received code {query.status_code} when attempting to make DSS report{f'; error message: `{query.error_message}`' if query.error_message is not None else ''}",
# query,
# )
# else:
# result = query.parse_json_result(ErrorReport)
# return result.report_id, query
if query.status_code != 400 or "Not yet implemented" not in query.error_message:
raise QueryError(
f"Received code {query.status_code} when attempting to make DSS report{f'; error message: `{query.error_message}`' if query.error_message is not None else ''}",
query,
)
else:
return "dummy_report_id", query

def query_subscriptions(
self,
volume: Volume4D,
Expand Down Expand Up @@ -446,6 +510,9 @@ def __init__(
def can_use_scope(self, scope: str) -> bool:
return scope in self._auth_adapter.scopes

def get_authorized_scopes(self) -> Set[str]:
return self._auth_adapter.scopes.copy()

def get_instance(self, scopes_required: Dict[str, str]) -> DSSInstance:
"""Get a client object ready to be used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,18 @@ def get_new_operational_intent_ref_params(
uss_base_url: UssBaseURL,
time_start: datetime.datetime,
time_end: datetime.datetime,
subscription_id: Optional[EntityID] = None,
subscription_id: Optional[EntityID],
implicit_sub_base_url: Optional[UssBaseURL] = None,
implicit_sub_for_constraints: Optional[bool] = None,
) -> PutOperationalIntentReferenceParameters:
"""
Builds a PutOperationalIntentReferenceParameters object that can be used against the DSS OIR API.
The extents contained in these parameters contain a single 4DVolume, which may not be entirely realistic,
but is sufficient in situations where the content of the OIR is irrelevant as long as it is valid, such
as for testing authentication or parameter validation.
Note that this method allows building inconsistent parameters.
Note that this method allows building inconsistent parameters:
"""
return PutOperationalIntentReferenceParameters(
extents=[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import datetime
from typing import List, Optional, Self

import s2sphere
from implicitdict import ImplicitDict
from uas_standards.astm.f3548.v21.api import PutSubscriptionParameters

from monitoring.monitorlib.geo import LatLngPoint
from monitoring.monitorlib.mutate import scd as mutate


class SubscriptionParams(ImplicitDict):
Expand Down Expand Up @@ -44,3 +47,28 @@ class SubscriptionParams(ImplicitDict):

def copy(self) -> Self:
return SubscriptionParams(super().copy())

def to_upsert_subscription_params(
self, area: s2sphere.LatLngRect
) -> PutSubscriptionParameters:
"""
Prepares the subscription parameters to be used in the body of an HTTP request
to create or update a subscription on the DSS in the SCD context.
Args:
area: area to include in the subscription parameters
Returns:
A dict to be passed as the request body when calling the subscription creation or update API.
"""
return mutate.build_upsert_subscription_params(
area_vertices=area,
start_time=self.start_time,
end_time=self.end_time,
base_url=self.base_url,
notify_for_op_intents=self.notify_for_op_intents,
notify_for_constraints=self.notify_for_constraints,
min_alt_m=self.min_alt_m,
max_alt_m=self.max_alt_m,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .authentication_validation import AuthenticationValidation
Loading

0 comments on commit 9dcb897

Please sign in to comment.