-
Notifications
You must be signed in to change notification settings - Fork 33
[benchmarker] Add SCD subscription actions #1666
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
Open
BenjaminPelletier
wants to merge
4
commits into
interuss:main
Choose a base branch
from
BenjaminPelletier:benchmarker-scd-subscription-actions
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| from typing import Optional | ||
|
|
||
| from implicitdict import ImplicitDict, StringBasedTimeDelta | ||
| from uas_standards.astm.f3548.v21.api import SubscriptionID | ||
|
|
||
| from monitoring.benchmarker.configurations.actions.astm import ( | ||
| SubscriptionCreationMode, | ||
| SubscriptionDeletionMode, | ||
| ) | ||
| from monitoring.monitorlib.geo import Altitude, LatLngBoundingBox | ||
|
|
||
|
|
||
| class Subscription(ImplicitDict): | ||
| subscription_id: SubscriptionID | ||
| """ID of the single subscription to create.""" | ||
|
|
||
| duration: StringBasedTimeDelta | ||
| """Duration of the subscription, from the time it is created.""" | ||
|
|
||
| area: LatLngBoundingBox | ||
| """Horizontal area this subscription should cover.""" | ||
|
|
||
| min_alt: Altitude | ||
| """Altitude below which this subscription should not apply.""" | ||
|
|
||
| max_alt: Altitude | ||
| """Altitude above which this subscription should not apply.""" | ||
|
|
||
| notify_for_op_intents: Optional[bool] | ||
| """Whether to receive notifications for operational intents. Defaults to True if not specified.""" | ||
|
|
||
| notify_for_constraints: Optional[bool] | ||
| """Whether to receive notifications for constraints. Defaults to False if not specified.""" | ||
|
|
||
|
|
||
| class CreateSubscription(ImplicitDict): | ||
| """Create a subscription.""" | ||
|
|
||
| subscription: Subscription | ||
| """Characteristics of subscription to create.""" | ||
|
|
||
| mode: SubscriptionCreationMode | ||
| """Desired creation behavior.""" | ||
|
|
||
|
|
||
| class DeleteSubscription(ImplicitDict): | ||
| subscription_id: SubscriptionID | ||
| """ID of the subscription to delete.""" | ||
|
|
||
| mode: SubscriptionDeletionMode | ||
| """Desired deletion behavior.""" | ||
|
|
||
|
|
||
| class F3548ActionSpecification(ImplicitDict): | ||
| """Actions pertaining to ASTM F3548 SCD.""" | ||
|
|
||
| create_subscription: Optional[CreateSubscription] | ||
| delete_subscription: Optional[DeleteSubscription] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| from datetime import UTC, datetime | ||
| from typing import Any | ||
|
|
||
| from loguru import logger | ||
| from uas_standards.astm.f3548.v21.constants import Scope | ||
|
|
||
| from monitoring.benchmarker.configurations.actions.action import BenchmarkActionName | ||
| from monitoring.benchmarker.configurations.actions.astm import ( | ||
| SubscriptionCreationMode, | ||
| SubscriptionDeletionMode, | ||
| ) | ||
| from monitoring.benchmarker.configurations.actions.f3548 import ( | ||
| CreateSubscription, | ||
| DeleteSubscription, | ||
| F3548ActionSpecification, | ||
| ) | ||
| from monitoring.monitorlib.testing import make_fake_url | ||
| from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import ( | ||
| DSSInstance, | ||
| DSSInstanceResource, | ||
| DSSInstancesResource, | ||
| ) | ||
| from monitoring.uss_qualifier.resources.definitions import ResourceID | ||
|
|
||
|
|
||
| def get_dss_instances(resource_pool: dict[ResourceID, Any]) -> list[DSSInstance]: | ||
| """Retrieve all F3548 DSS instances from the resource pool.""" | ||
| scopes_required = { | ||
| Scope.StrategicCoordination.value: "managing subscriptions for strategic conflict detection", | ||
| } | ||
| dss_instances: list[DSSInstance] = [] | ||
| for res in resource_pool.values(): | ||
| if isinstance(res, DSSInstanceResource): | ||
| dss_instances.append(res.get_instance(scopes_required)) | ||
| elif isinstance(res, DSSInstancesResource): | ||
| for dss_instance_res in res.dss_instances: | ||
| dss_instances.append(dss_instance_res.get_instance(scopes_required)) | ||
| return dss_instances | ||
|
|
||
|
|
||
| def create_subscription( | ||
| spec: CreateSubscription, | ||
| resource_pool: dict[ResourceID, Any], | ||
| ) -> None: | ||
| dss_instances = get_dss_instances(resource_pool) | ||
| if not dss_instances: | ||
| raise ValueError("No ASTM F3548 DSS instances found in resource pool") | ||
| sub = spec.subscription | ||
| dss_instance = dss_instances[0] | ||
|
|
||
| if spec.mode == SubscriptionCreationMode.GetDeleteCreate: | ||
| logger.info( | ||
| f"F3548 Action: Checking if subscription '{sub.subscription_id}' exists before creating..." | ||
| ) | ||
| fetched_sub = dss_instance.get_subscription(sub.subscription_id) | ||
| if fetched_sub.status_code == 200 and fetched_sub.subscription is not None: | ||
| logger.info( | ||
| f"F3548 Action: Existing subscription '{sub.subscription_id}' found (version {fetched_sub.subscription.version}); deleting it..." | ||
| ) | ||
| del_result = dss_instance.delete_subscription( | ||
| sub_id=sub.subscription_id, | ||
| sub_version=fetched_sub.subscription.version, | ||
| ) | ||
| if not del_result.success: | ||
| raise RuntimeError( | ||
| f"Failed to delete existing subscription '{sub.subscription_id}' during GetDeleteCreate: {del_result.errors}" | ||
| ) | ||
| elif fetched_sub.status_code == 404: | ||
| logger.info( | ||
| f"F3548 Action: Subscription '{sub.subscription_id}' does not exist; proceeding to create." | ||
| ) | ||
| else: | ||
| raise RuntimeError( | ||
| f"Failed to query subscription '{sub.subscription_id}' during GetDeleteCreate: {fetched_sub.errors}" | ||
| ) | ||
|
|
||
| logger.info(f"F3548 Action: Creating subscription '{sub.subscription_id}'...") | ||
| uss_base_url = make_fake_url() | ||
| t0 = datetime.now(UTC) | ||
| notify_for_op_intents = ( | ||
| sub.notify_for_op_intents | ||
| if "notify_for_op_intents" in sub and sub.notify_for_op_intents is not None | ||
| else True | ||
| ) | ||
| notify_for_constraints = ( | ||
| sub.notify_for_constraints | ||
| if "notify_for_constraints" in sub | ||
| and sub.notify_for_constraints is not None | ||
| else False | ||
| ) | ||
| create_result = dss_instance.upsert_subscription( | ||
| area_vertices=sub.area.to_latlngrect(), | ||
| start_time=t0, | ||
| end_time=t0 + sub.duration.timedelta, | ||
| base_url=uss_base_url, | ||
| sub_id=sub.subscription_id, | ||
| notify_for_op_intents=notify_for_op_intents, | ||
| notify_for_constraints=notify_for_constraints, | ||
| min_alt_m=sub.min_alt.to_w84_m(), | ||
| max_alt_m=sub.max_alt.to_w84_m(), | ||
| ) | ||
| if not create_result.success: | ||
| raise RuntimeError( | ||
| f"Failed to create subscription '{sub.subscription_id}': {create_result.errors}" | ||
| ) | ||
| logger.info( | ||
| f"F3548 Action: Successfully created subscription '{sub.subscription_id}'." | ||
| ) | ||
| else: | ||
| raise NotImplementedError( | ||
| f"Unsupported subscription creation mode '{spec.mode}'" | ||
| ) | ||
|
|
||
|
|
||
| def delete_subscription( | ||
| spec: DeleteSubscription, | ||
| resource_pool: dict[ResourceID, Any], | ||
| ) -> None: | ||
| dss_instances = get_dss_instances(resource_pool) | ||
| if not dss_instances: | ||
| raise ValueError("No ASTM F3548 DSS instances found in resource pool") | ||
|
|
||
| if spec.mode == SubscriptionDeletionMode.GetDeleteIfExist: | ||
| logger.info( | ||
| f"F3548 Action: Checking if subscription '{spec.subscription_id}' exists before deleting..." | ||
| ) | ||
| deleted = False | ||
| for dss_instance in dss_instances: | ||
| fetched_sub = dss_instance.get_subscription(spec.subscription_id) | ||
| if fetched_sub.status_code == 200 and fetched_sub.subscription is not None: | ||
| logger.info( | ||
| f"F3548 Action: Existing subscription '{spec.subscription_id}' found (version {fetched_sub.subscription.version}); deleting it..." | ||
| ) | ||
| del_result = dss_instance.delete_subscription( | ||
| sub_id=spec.subscription_id, | ||
| sub_version=fetched_sub.subscription.version, | ||
| ) | ||
| if not del_result.success: | ||
| raise RuntimeError( | ||
| f"Failed to delete subscription '{spec.subscription_id}': {del_result.errors}" | ||
| ) | ||
| logger.info( | ||
| f"F3548 Action: Successfully deleted subscription '{spec.subscription_id}'." | ||
| ) | ||
| deleted = True | ||
| break | ||
| elif fetched_sub.status_code == 404: | ||
| continue | ||
| else: | ||
| raise RuntimeError( | ||
| f"Failed to query subscription '{spec.subscription_id}' during GetDeleteIfExist: {fetched_sub.errors}" | ||
| ) | ||
|
|
||
| if not deleted: | ||
| logger.info( | ||
| f"F3548 Action: Subscription '{spec.subscription_id}' did not exist; nothing to delete." | ||
| ) | ||
| else: | ||
| raise NotImplementedError( | ||
| f"Unsupported subscription deletion mode '{spec.mode}'" | ||
| ) | ||
|
|
||
|
|
||
| def run_f3548_action( | ||
| action_name: BenchmarkActionName, | ||
| f3548_spec: F3548ActionSpecification, | ||
| resource_pool: dict[ResourceID, Any], | ||
| ) -> None: | ||
| action_performed = False | ||
| if ( | ||
| "create_subscription" in f3548_spec | ||
| and f3548_spec.create_subscription is not None | ||
| ): | ||
| logger.info(f"Action '{action_name}': Creating F3548 subscription...") | ||
| create_subscription(f3548_spec.create_subscription, resource_pool) | ||
| action_performed = True | ||
| if ( | ||
| "delete_subscription" in f3548_spec | ||
| and f3548_spec.delete_subscription is not None | ||
| ): | ||
| logger.info(f"Action '{action_name}': Deleting F3548 subscription...") | ||
| delete_subscription(f3548_spec.delete_subscription, resource_pool) | ||
| action_performed = True | ||
| if not action_performed: | ||
| raise ValueError( | ||
| f"Action '{action_name}' F3548ActionSpecification did not specify any supported action" | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
schemas/monitoring/benchmarker/configurations/actions/f3548/CreateSubscription.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| { | ||
| "$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/benchmarker/configurations/actions/f3548/CreateSubscription.json", | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "description": "Create a subscription.\n\nmonitoring.benchmarker.configurations.actions.f3548.CreateSubscription, as defined in monitoring/benchmarker/configurations/actions/f3548.py", | ||
| "properties": { | ||
| "$ref": { | ||
| "description": "Path to content that replaces the $ref", | ||
| "type": "string" | ||
| }, | ||
| "mode": { | ||
| "description": "Desired creation behavior.", | ||
| "enum": [ | ||
| "GetDeleteCreate" | ||
| ], | ||
| "type": "string" | ||
| }, | ||
| "subscription": { | ||
| "$ref": "Subscription.json", | ||
| "description": "Characteristics of subscription to create." | ||
| } | ||
| }, | ||
| "required": [ | ||
| "mode", | ||
| "subscription" | ||
| ], | ||
| "type": "object" | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit