From c033343acb6c0585a839afef71a0972f61257e38 Mon Sep 17 00:00:00 2001 From: Pelayo Torres Date: Thu, 24 Oct 2024 12:26:33 +0200 Subject: [PATCH 1/2] apiStatusMonitoring event --- .../core/apiinvokerenrolmentdetails.py | 6 +- .../capif_acl/core/internal_service_ops.py | 2 +- .../capif_events/core/notifications.py | 20 ++++- .../capif_events/models/event_subscription.py | 12 +++ .../core/invocationlogs.py | 2 +- .../core/serviceapidescriptions.py | 90 ++++++++++++++----- 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py index bcf1905..80988ca 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py @@ -96,7 +96,7 @@ class InvokerManagementOperations(Resource): if res.status_code == 201: current_app.logger.info("Invoker Created") - RedisEvent("API_INVOKER_ONBOARDED", "apiInvokerIds", [str(api_invoker_id)]).send_event() + RedisEvent("API_INVOKER_ONBOARDED", ["apiInvokerIds"], [[str(api_invoker_id)]]).send_event() return res def update_apiinvokerenrolmentdetail(self, onboard_id, apiinvokerenrolmentdetail): @@ -133,7 +133,7 @@ class InvokerManagementOperations(Resource): res = make_response(object=serialize_clean_camel_case(invoker_updated), status=200) if res.status_code == 200: current_app.logger.info("Invoker Updated") - RedisEvent("API_INVOKER_UPDATED", "apiInvokerIds", [onboard_id]).send_event() + RedisEvent("API_INVOKER_UPDATED", ["apiInvokerIds"], [[onboard_id]]).send_event() return res except Exception as e: @@ -160,7 +160,7 @@ class InvokerManagementOperations(Resource): res = make_response(out, status=204) if res.status_code == 204: current_app.logger.info("Invoker Removed") - RedisEvent("API_INVOKER_OFFBOARDED", "apiInvokerIds", [onboard_id]).send_event() + RedisEvent("API_INVOKER_OFFBOARDED", ["apiInvokerIds"], [[onboard_id]]).send_event() publisher_ops.publish_message("internal-messages", f"invoker-removed:{onboard_id}") return res diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py index 1e5aa20..924ea9e 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py @@ -59,7 +59,7 @@ class InternalServiceOps(Resource): "apiInvokerPolicies": inserted_service_acls_camel['apiInvokerPolicies'] } RedisEvent("ACCESS_CONTROL_POLICY_UPDATE", - "accCtrlPolList", accCtrlPolListExt).send_event() + ["accCtrlPolList"], [accCtrlPolListExt]).send_event() current_app.logger.info( f"Invoker ACL added for invoker: {invoker_id} for service: {service_id}") diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py index c9ac79e..8ac124e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py @@ -4,6 +4,7 @@ from .internal_event_ops import InternalEventOperations from models.event_notification import EventNotification from models.access_control_policy_list_ext import AccessControlPolicyListExt from models.capif_event_detail import CAPIFEventDetail +from models.event_subscription import EventSubscription from encoder import CustomJSONEncoder import sys import json @@ -29,11 +30,22 @@ class Notifications(): for sub in subscriptions: url = sub["notification_destination"] current_app.logger.debug(url) - event_detail=None + data = EventNotification(sub["subscription_id"], events=redis_event.get('event')) if redis_event.get('key', None) != None and redis_event.get('information', None) != None: - event_detail={redis_event.get('key'):redis_event.get('information')} - current_app.logger.debug(event_detail) - data = EventNotification(sub["subscription_id"], events=redis_event.get('event'), event_detail=event_detail) + event_detail={} + for pos, key in enumerate(redis_event.get('key', None)): + current_app.logger.debug(sub["supported_features"]) + current_app.logger.debug("AQUI") + if sub["supported_features"] is not None: + if redis_event.get('event', None) in ["SERVICE_API_AVAILABLE", "SERVICE_API_UNAVAILABLE"] and key == "serviceAPIDescriptions" and not EventSubscription.return_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]: + current_app.logger.debug("ApiStatusMonitoring not supported.") + else: + event_detail[key]=redis_event.get('information', None)[pos] + else: + event_detail[key]=redis_event.get('information', None)[pos] + current_app.logger.debug(event_detail) + data.event_detail=event_detail + current_app.logger.debug(json.dumps(data.to_dict(),cls=CustomJSONEncoder)) asyncio.run(self.send(url, serialize_clean_camel_case(data))) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py index 6660c33..a5f49e2 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py @@ -68,6 +68,18 @@ class EventSubscription(Model): self._websock_notif_config = websock_notif_config self._supported_features = supported_features + @classmethod + def return_supp_feat_dict(cls, supp_feat): + supp_feat_in_hex = int(supp_feat, 16) + supp_feat_in_bin = bin(supp_feat_in_hex)[2:] + + return { + "NotificationTestEvent": True if supp_feat_in_bin[0] == "1" else False, + "NotificationWebsocket": True if supp_feat_in_bin[1] == "1" else False, + "EnhancedEventReport": True if supp_feat_in_bin[2] == "1" else False, + "ApiStatusMonitoring": True if supp_feat_in_bin[3] == "1" else False + } + @classmethod def from_dict(cls, dikt) -> 'EventSubscription': """Returns the dict as a model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py index d2ba9ea..6629022 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py @@ -99,7 +99,7 @@ class LoggingInvocationOperations(Resource): current_app.logger.info(event) invocation_log_base['logs']=[log.to_dict()] invocationLogs=[invocation_log_base] - RedisEvent(event,"invocation_logs",invocationLogs).send_event() + RedisEvent(event,["invocation_logs"],[invocationLogs]).send_event() current_app.logger.debug("After log check") diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py index c1792b4..67851b5 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py @@ -9,7 +9,9 @@ from .responses import internal_server_error, forbidden_error, not_found_error, from .auth_manager import AuthManager from .redis_event import RedisEvent from .publisher import Publisher - +from ..models.service_api_description import ServiceAPIDescription +import json +from ..encoder import CustomJSONEncoder publisher_ops = Publisher() @@ -123,13 +125,34 @@ class PublishServiceOperations(Resource): if res.status_code == 201: current_app.logger.info("Service published") if serviceapidescription.api_status is None or len(serviceapidescription.api_status.aef_ids) > 0: - current_app.logger.info("Service available") - RedisEvent("SERVICE_API_AVAILABLE", "apiIds", - [str(api_id)]).send_event() + if serviceapidescription.supported_features is not None: + if serviceapidescription.return_supp_feat_dict(serviceapidescription.supported_features)["ApiStatusMonitoring"]: + current_app.logger.info(f"Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["serviceAPIDescriptions", "apiIds"], + [[serviceapidescription.to_dict()],[str(api_id)]]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], + [str(api_id)]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], + [str(api_id)]).send_event() else: - current_app.logger.info("Service unavailable") - RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds", - [str(api_id)]).send_event() + if serviceapidescription.supported_features is not None: + if serviceapidescription.return_supp_feat_dict(serviceapidescription.supported_features)["ApiStatusMonitoring"]: + current_app.logger.info(f"Service unavailable") + RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], + [[serviceapidescription.to_dict()],[str(api_id)]]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], + [str(api_id)]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], + [str(api_id)]).send_event() + return res except Exception as e: @@ -182,7 +205,7 @@ class PublishServiceOperations(Resource): return result my_query = {'apf_id': apf_id, 'api_id': service_api_id} - serviceapidescription = mycol.find_one(my_query) + serviceapidescription = mycol.find_one(my_query, {"_id": 0}) if serviceapidescription is None: current_app.logger.error(service_api_not_found_message) @@ -197,10 +220,14 @@ class PublishServiceOperations(Resource): res = make_response(out, status=204) if res.status_code == 204: current_app.logger.info("Removed service published") - RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds", - [service_api_id]).send_event() - publisher_ops.publish_message( - "internal-messages", f"service-removed:{service_api_id}") + if ServiceAPIDescription.return_supp_feat_dict(serviceapidescription["supported_features"])["ApiStatusMonitoring"]: + current_app.logger.info(f"Service unavailable") + RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], + [[serviceapidescription],[str(service_api_id)]]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], + [str(service_api_id)]).send_event() return res except Exception as e: @@ -244,17 +271,38 @@ class PublishServiceOperations(Resource): response = make_response( object=service_api_description_updated, status=200) + service_api_description = ServiceAPIDescription.from_dict(json.dumps(service_api_description_updated, cls=CustomJSONEncoder)) if response.status_code == 200: - RedisEvent("SERVICE_API_UPDATE", "serviceAPIDescriptions", [ - service_api_description_updated]).send_event() - if "apiStatus" not in service_api_description_updated or len(service_api_description_updated["apiStatus"]["aefIds"]) > 0: - current_app.logger.info("Service available") - RedisEvent("SERVICE_API_AVAILABLE", "apiIds", - [str(service_api_id)]).send_event() + RedisEvent("SERVICE_API_UPDATE", ["serviceAPIDescriptions"], [[ + service_api_description_updated]]).send_event() + if service_api_description.api_status is None or len(service_api_description.api_status.aef_ids) > 0: + if service_api_description.supported_features is not None: + if service_api_description.return_supp_feat_dict(service_api_description.supported_features)["ApiStatusMonitoring"]: + current_app.logger.info(f"Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["serviceAPIDescriptions", "apiIds"], + [[service_api_description_updated],[str(service_api_id)]]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], + [str(service_api_id)]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], + [str(service_api_id)]).send_event() else: - current_app.logger.info("Service unavailable") - RedisEvent("SERVICE_API_UNAVAILABLE", "apiIds", - [str(service_api_id)]).send_event() + if service_api_description.supported_features is not None: + if service_api_description.return_supp_feat_dict(service_api_description.supported_features)["ApiStatusMonitoring"]: + current_app.logger.info(f"Service unavailable") + RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], + [[service_api_description_updated],[str(service_api_id)]]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], + [str(service_api_id)]).send_event() + else: + current_app.logger.info("Service available") + RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], + [str(service_api_id)]).send_event() return response -- GitLab From d4ce713233a10a5d1b9b485238dd82d0f8b45520 Mon Sep 17 00:00:00 2001 From: Pelayo Torres Date: Thu, 31 Oct 2024 11:50:16 +0100 Subject: [PATCH 2/2] events logic and apiStatus --- .../capif_events/core/notifications.py | 14 +++---- .../capif_events/util.py | 16 +++++++- .../core/serviceapidescriptions.py | 40 ++++++++++++------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py index 8ac124e..c1c7db1 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py @@ -5,6 +5,7 @@ from models.event_notification import EventNotification from models.access_control_policy_list_ext import AccessControlPolicyListExt from models.capif_event_detail import CAPIFEventDetail from models.event_subscription import EventSubscription +from models.service_api_description import ServiceAPIDescription from encoder import CustomJSONEncoder import sys import json @@ -34,15 +35,14 @@ class Notifications(): if redis_event.get('key', None) != None and redis_event.get('information', None) != None: event_detail={} for pos, key in enumerate(redis_event.get('key', None)): - current_app.logger.debug(sub["supported_features"]) - current_app.logger.debug("AQUI") - if sub["supported_features"] is not None: - if redis_event.get('event', None) in ["SERVICE_API_AVAILABLE", "SERVICE_API_UNAVAILABLE"] and key == "serviceAPIDescriptions" and not EventSubscription.return_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]: - current_app.logger.debug("ApiStatusMonitoring not supported.") - else: + + if sub["supported_features"] is None: + if not (key == "serviceAPIDescriptions" and redis_event.get('event', None) in ["SERVICE_API_AVAILABLE", "SERVICE_API_UNAVAILABLE"]): event_detail[key]=redis_event.get('information', None)[pos] else: - event_detail[key]=redis_event.get('information', None)[pos] + if not (redis_event.get('event', None) in ["SERVICE_API_AVAILABLE", "SERVICE_API_UNAVAILABLE"] and key == "serviceAPIDescriptions" and not EventSubscription.return_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]): + event_detail[key]=redis_event.get('information', None)[pos] + current_app.logger.debug(event_detail) data.event_detail=event_detail diff --git a/services/TS29222_CAPIF_Events_API/capif_events/util.py b/services/TS29222_CAPIF_Events_API/capif_events/util.py index 2ce4382..d8f55b6 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/util.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/util.py @@ -24,25 +24,39 @@ def clean_empty(d): def dict_to_camel_case(my_dict): + + result = {} + for attr, value in my_dict.items(): + if len(attr.split('_')) != 1: my_key = ''.join(word.title() for word in attr.split('_')) - my_key= ''.join([my_key[0].lower(), my_key[1:]]) + my_key = ''.join([my_key[0].lower(), my_key[1:]]) else: my_key = attr + + if my_key == "serviceApiCategory": + my_key = "serviceAPICategory" + elif my_key == "serviceApiDescriptions": + my_key = "serviceAPIDescriptions" + if isinstance(value, list): result[my_key] = list(map( lambda x: dict_to_camel_case(x) if isinstance(x, dict) else x, value )) + elif hasattr(value, "to_dict"): result[my_key] = dict_to_camel_case(value) + elif isinstance(value, dict): value = dict_to_camel_case(value) result[my_key] = value else: result[my_key] = value + return result + def _deserialize(data, klass): """Deserializes dict, list, str into an object. diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py index 67851b5..cddfcea 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py @@ -129,7 +129,7 @@ class PublishServiceOperations(Resource): if serviceapidescription.return_supp_feat_dict(serviceapidescription.supported_features)["ApiStatusMonitoring"]: current_app.logger.info(f"Service available") RedisEvent("SERVICE_API_AVAILABLE", ["serviceAPIDescriptions", "apiIds"], - [[serviceapidescription.to_dict()],[str(api_id)]]).send_event() + [[clean_n_camel_case(serviceapidescription.to_dict())],[str(api_id)]]).send_event() else: current_app.logger.info("Service available") RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], @@ -143,7 +143,7 @@ class PublishServiceOperations(Resource): if serviceapidescription.return_supp_feat_dict(serviceapidescription.supported_features)["ApiStatusMonitoring"]: current_app.logger.info(f"Service unavailable") RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], - [[serviceapidescription.to_dict()],[str(api_id)]]).send_event() + [[clean_n_camel_case(serviceapidescription.to_dict())],[str(api_id)]]).send_event() else: current_app.logger.info("Service available") RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], @@ -205,9 +205,9 @@ class PublishServiceOperations(Resource): return result my_query = {'apf_id': apf_id, 'api_id': service_api_id} - serviceapidescription = mycol.find_one(my_query, {"_id": 0}) + serviceapidescription_dict = mycol.find_one(my_query, {"_id": 0, "onboarding_date": 0, "apf_id": 0}) - if serviceapidescription is None: + if serviceapidescription_dict is None: current_app.logger.error(service_api_not_found_message) return not_found_error(detail="Service API not existing", cause="Service API id not found") @@ -218,16 +218,28 @@ class PublishServiceOperations(Resource): current_app.logger.debug("Removed service from database") out = "The service matching api_id " + service_api_id + " was deleted." res = make_response(out, status=204) + serviceapidescription= clean_empty(dict_to_camel_case(serviceapidescription_dict)) if res.status_code == 204: - current_app.logger.info("Removed service published") - if ServiceAPIDescription.return_supp_feat_dict(serviceapidescription["supported_features"])["ApiStatusMonitoring"]: - current_app.logger.info(f"Service unavailable") - RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], - [[serviceapidescription],[str(service_api_id)]]).send_event() + is_supported = serviceapidescription.get("supportedFeatures") and \ + ServiceAPIDescription.return_supp_feat_dict(serviceapidescription["supportedFeatures"]).get("ApiStatusMonitoring") + + if is_supported: + current_app.logger.info("Service unavailable") + RedisEvent( + "SERVICE_API_UNAVAILABLE", + ["serviceAPIDescriptions", "apiIds"], + [[serviceapidescription], [str(service_api_id)]] + ).send_event() + else: - current_app.logger.info("Service available") - RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], - [str(service_api_id)]).send_event() + status_message = "Service available" if serviceapidescription.get("supportedFeatures") is None else "Service unavailable" + current_app.logger.info(status_message) + RedisEvent( + "SERVICE_API_UNAVAILABLE", + ["apiIds"], + [str(service_api_id)] + ).send_event() + return res except Exception as e: @@ -280,7 +292,7 @@ class PublishServiceOperations(Resource): if service_api_description.return_supp_feat_dict(service_api_description.supported_features)["ApiStatusMonitoring"]: current_app.logger.info(f"Service available") RedisEvent("SERVICE_API_AVAILABLE", ["serviceAPIDescriptions", "apiIds"], - [[service_api_description_updated],[str(service_api_id)]]).send_event() + [[service_api_description],[str(service_api_id)]]).send_event() else: current_app.logger.info("Service available") RedisEvent("SERVICE_API_AVAILABLE", ["apiIds"], @@ -294,7 +306,7 @@ class PublishServiceOperations(Resource): if service_api_description.return_supp_feat_dict(service_api_description.supported_features)["ApiStatusMonitoring"]: current_app.logger.info(f"Service unavailable") RedisEvent("SERVICE_API_UNAVAILABLE", ["serviceAPIDescriptions", "apiIds"], - [[service_api_description_updated],[str(service_api_id)]]).send_event() + [[service_api_description],[str(service_api_id)]]).send_event() else: current_app.logger.info("Service available") RedisEvent("SERVICE_API_UNAVAILABLE", ["apiIds"], -- GitLab