From 880b8d427f18c615a9d5ae76954f002fa511c05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Misbach?= Date: Fri, 9 Feb 2024 19:06:01 +0100 Subject: [PATCH] [uss_qualifier/resources/f3548/dss/put_op_intent] Use QueryError for error handling (#502) --- .../resources/astm/f3548/v21/dss.py | 35 ++--- .../astm/utm/off_nominal_planning/down_uss.py | 29 +++-- .../astm/utm/op_intent_ref_access_control.py | 120 +++++++++++------- 3 files changed, 108 insertions(+), 76 deletions(-) diff --git a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py index d1f4e77485..e22227af82 100644 --- a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py +++ b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py @@ -240,16 +240,20 @@ def put_op_intent( key: List[EntityOVN], state: OperationalIntentState, base_url: UssBaseURL, - id: Optional[str] = None, + oi_id: Optional[str] = None, ovn: Optional[str] = None, - ) -> Tuple[ - Optional[OperationalIntentReference], - Optional[List[SubscriberToNotify]], - Query, - ]: + ) -> Tuple[OperationalIntentReference, List[SubscriberToNotify], Query,]: + """ + Create or update an operational intent. + Returns: + the operational intent reference created or updated, the subscribers to notify, the query + Raises: + * QueryError: if request failed, if HTTP status code is different than 200 or 201, or if the parsing of the response failed. + """ self._uses_scope(Scope.StrategicCoordination) - oi_uuid = str(uuid.uuid4()) if id is None else id - if ovn is None: + oi_uuid = str(uuid.uuid4()) if oi_id is None else oi_id + create = ovn is None + if create: op = OPERATIONS[OperationID.CreateOperationalIntentReference] url = op.path.format(entityid=oi_uuid) query_type = QueryType.F3548v21DSSCreateOperationalIntentReference @@ -274,15 +278,16 @@ def put_op_intent( scope=Scope.StrategicCoordination, json=req, ) - if query.status_code != 200 and query.status_code != 201: - return None, None, query + if (create and query.status_code == 201) or ( + not create and query.status_code == 200 + ): + result = query.parse_json_result(ChangeOperationalIntentReferenceResponse) + return result.operational_intent_reference, result.subscribers, query else: - result = ChangeOperationalIntentReferenceResponse( - ImplicitDict.parse( - query.response.json, ChangeOperationalIntentReferenceResponse - ) + raise QueryError( + f"Received code {query.status_code} when attempting to {'create' if create else 'update'} operational intent with ID {oi_uuid}{f'; error message: `{query.error_message}`' if query.error_message is not None else ''}", + query, ) - return result.operational_intent_reference, result.subscribers, query def delete_op_intent( self, diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.py b/monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.py index f67ec24fd2..6e67b3c94b 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.py @@ -193,25 +193,28 @@ def _put_conflicting_op_intent_step( raise ValueError(f"Invalid state {target_state}") self.begin_test_step(f"Virtual USS {msg_action} conflicting operational intent") - oi_ref, _, query = self.dss.put_op_intent( - Volume4DCollection.from_interuss_scd_api( - conflicting_intent.request.operational_intent.volumes - ).to_f3548v21(), - key, - target_state, - "https://fake.uss/down", - oi_id, - oi_ovn, - ) - self.record_query(query) with self.check( f"Operational intent successfully {msg_action_past}", [self.dss.participant_id], ) as check: - if oi_ref is None: + try: + oi_ref, _, query = self.dss.put_op_intent( + Volume4DCollection.from_interuss_scd_api( + conflicting_intent.request.operational_intent.volumes + ).to_f3548v21(), + key, + target_state, + "https://fake.uss/down", + oi_id, + oi_ovn, + ) + self.record_query(query) + except QueryError as e: + self.record_queries(e.queries) + query = e.queries[0] check.record_failed( f"Operational intent not successfully {msg_action_past}", - details=f"DSS responded code {query.status_code}; error message: {query.error_message}", + details=f"DSS responded code {query.status_code}; {e}", query_timestamps=[query.request.timestamp], ) self.end_test_step() diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/op_intent_ref_access_control.py b/monitoring/uss_qualifier/scenarios/astm/utm/op_intent_ref_access_control.py index 7f861f0a48..72de07a64c 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/op_intent_ref_access_control.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/op_intent_ref_access_control.py @@ -341,41 +341,46 @@ def _ensure_clean_workspace(self) -> bool: return True def _create_op_intents(self): - (self._current_ref_1, subscribers1, q1) = self._dss.put_op_intent( - id=self._oid_1, - extents=self._volumes1.to_f3548v21(), - key=[], - state=OperationalIntentState.Accepted, - base_url=DUMMY_USS_BASE_URL, - ) - self.record_query(q1) - with self.check( "Can create an operational intent with valid credentials", self._pid ) as check: - if q1.response.status_code != 201: + try: + (self._current_ref_1, subscribers1, q1) = self._dss.put_op_intent( + oi_id=self._oid_1, + extents=self._volumes1.to_f3548v21(), + key=[], + state=OperationalIntentState.Accepted, + base_url=DUMMY_USS_BASE_URL, + ) + self.record_query(q1) + except QueryError as e: + self.record_queries(e.queries) + q1 = e.queries[0] check.record_failed( f"Could not create operational intent using main credentials", - details=f"DSS responded with {q1.response.status_code} to attempt to create OI {self._oid_1}", + details=f"DSS responded with {q1.response.status_code} to attempt to create OI {self._oid_1}; {e}", query_timestamps=[q1.request.timestamp], ) - ( - self._current_ref_2, - subscribers2, - q2, - ) = self._dss_separate_creds.put_op_intent( - id=self._oid_2, - extents=self._volumes2.to_f3548v21(), - key=[self._current_ref_1.ovn], - state=OperationalIntentState.Accepted, - base_url=DUMMY_USS_BASE_URL, - ) - self.record_query(q2) with self.check( "Can create an operational intent with valid credentials", self._pid ) as check: - if q2.response.status_code != 201: + try: + ( + self._current_ref_2, + subscribers2, + q2, + ) = self._dss_separate_creds.put_op_intent( + oi_id=self._oid_2, + extents=self._volumes2.to_f3548v21(), + key=[self._current_ref_1.ovn], + state=OperationalIntentState.Accepted, + base_url=DUMMY_USS_BASE_URL, + ) + self.record_query(q2) + except QueryError as e: + self.record_queries(e.queries) + q2 = e.queries[0] check.record_failed( f"Could not create operational intent using second credentials", details=f"DSS responded with {q2.response.status_code} to attempt to create OI {self._oid_2}", @@ -400,46 +405,65 @@ def _ensure_credentials_are_different(self): ) def _check_mutation_on_non_owned_intent_fails(self): - # Attempt to update the state of the intent created with the main credentials using the second credentials - (ref, notif, q) = self._dss_separate_creds.put_op_intent( - id=self._oid_1, - extents=self._volumes1.to_f3548v21(), - key=[self._current_ref_2.ovn], - state=OperationalIntentState.Accepted, - base_url=self._current_ref_1.uss_base_url, - ovn=self._current_ref_1.ovn, - ) - self.record_query(q) with self.check( "Non-owning credentials cannot modify operational intent", self._pid, ) as check: - if q.response.status_code != 403: + try: + # Attempt to update the state of the intent created with the main credentials using the second credentials + (ref, notif, q) = self._dss_separate_creds.put_op_intent( + oi_id=self._oid_1, + extents=self._volumes1.to_f3548v21(), + key=[self._current_ref_2.ovn], + state=OperationalIntentState.Accepted, + base_url=self._current_ref_1.uss_base_url, + ovn=self._current_ref_1.ovn, + ) + self.record_query(q) check.record_failed( - f"Could update operational intent using second credentials", + "Could update operational intent using second credentials", details=f"DSS responded with {q.response.status_code} to attempt to update OI {self._oid_1}", query_timestamps=[q.request.timestamp], ) - # Attempt to update the base_url of the intent created with the main credentials using the second credentials - (ref, notif, q) = self._dss_separate_creds.put_op_intent( - id=self._oid_1, - extents=self._volumes1.to_f3548v21(), - key=[self._current_ref_2.ovn], - state=self._current_ref_1.state, - base_url="https://another-url.uss/down", - ovn=self._current_ref_1.ovn, - ) - self.record_query(q) + except QueryError as e: + self.record_queries(e.queries) + q = e.queries[0] + if q.response.status_code != 403: + check.record_failed( + "Attempt to update operational intent using second credentials failed with an unexpected status code (expected 403)", + details=f"DSS responded with {q.response.status_code} to attempt to update OI {self._oid_1}; {e}", + query_timestamps=[q.request.timestamp], + ) + with self.check( "Non-owning credentials cannot modify operational intent", self._pid, ) as check: - if q.response.status_code != 403: + try: + # Attempt to update the base_url of the intent created with the main credentials using the second credentials + (ref, notif, q) = self._dss_separate_creds.put_op_intent( + oi_id=self._oid_1, + extents=self._volumes1.to_f3548v21(), + key=[self._current_ref_2.ovn], + state=self._current_ref_1.state, + base_url="https://another-url.uss/down", + ovn=self._current_ref_1.ovn, + ) + self.record_query(q) check.record_failed( - f"Could update operational intent using second credentials", + "Could update operational intent using second credentials", details=f"DSS responded with {q.response.status_code} to attempt to update OI {self._oid_1}", query_timestamps=[q.request.timestamp], ) + except QueryError as e: + self.record_queries(e.queries) + q = e.queries[0] + if q.response.status_code != 403: + check.record_failed( + "Attempt to update operational intent using second credentials failed with an unexpected status code (expected 403)", + details=f"DSS responded with {q.response.status_code} to attempt to update OI {self._oid_1}; {e}", + query_timestamps=[q.request.timestamp], + ) # Try to delete with self.check(