Commit adf45d6b authored by Stavros-Anastasios Charismiadis's avatar Stavros-Anastasios Charismiadis
Browse files

Merge with latest staging

parents e865c5b2 6775b068
Loading
Loading
Loading
Loading
Loading
+10 −13
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@ from logging.handlers import RotatingFileHandler
import os
import os
from fluent import sender
from fluent import sender
from flask_executor import Executor
from flask_executor import Executor
from flask_apscheduler import APScheduler
from datetime import datetime
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry import trace
from opentelemetry import trace
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
@@ -137,16 +139,11 @@ if monitoring_value == "true":


executor = Executor(app.app)
executor = Executor(app.app)
subscriber = Subscriber()
subscriber = Subscriber()

scheduler = APScheduler()
first = True
scheduler.init_app(app.app)

scheduler.start()
@app.app.before_request

def create_listener_message():
@scheduler.task('date', id='listener', next_run_time=datetime.now())
    global first
def up_listener():
    if first:
    with scheduler.app.app_context():
        executor.submit(subscriber.listen)
        executor.submit(subscriber.listen())
        first = False

# @app.app.before_first_request
# def create_listener_message():
#     executor.submit(subscriber.listen)
 No newline at end of file
+55 −32
Original line number Original line Diff line number Diff line
@@ -3,18 +3,22 @@ from pymongo import ReturnDocument
import secrets
import secrets
import requests
import requests
from .responses import bad_request_error, not_found_error, forbidden_error, internal_server_error, make_response
from .responses import bad_request_error, not_found_error, forbidden_error, internal_server_error, make_response
from flask import current_app, Flask, Response
from flask import current_app, Response
import json
import json
from datetime import datetime
from datetime import datetime
from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case
from ..util import dict_to_camel_case, serialize_clean_camel_case
from .auth_manager import AuthManager
from .auth_manager import AuthManager
from .resources import Resource
from .resources import Resource
from ..config import Config
from ..config import Config
from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails
from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails
from .redis_event import RedisEvent
from .redis_event import RedisEvent
from .redis_internal_event import RedisInternalEvent
from .publisher import Publisher
from .publisher import Publisher
import os


publisher_ops = Publisher()
publisher_ops = Publisher()


class InvokerManagementOperations(Resource):
class InvokerManagementOperations(Resource):


    def __check_api_invoker_id(self, api_invoker_id):
    def __check_api_invoker_id(self, api_invoker_id):
@@ -41,7 +45,8 @@ class InvokerManagementOperations(Resource):
            'common_name': invoker_id
            'common_name': invoker_id
        }
        }


        response = requests.request("POST", url, headers=headers, data=data, verify = self.config["ca_factory"].get("verify", False))
        response = requests.request("POST", url, headers=headers, data=data,
                                    verify=self.config["ca_factory"].get("verify", False))
        print(response)
        print(response)
        response_payload = json.loads(response.text)
        response_payload = json.loads(response.text)


@@ -52,17 +57,18 @@ class InvokerManagementOperations(Resource):
        self.auth_manager = AuthManager()
        self.auth_manager = AuthManager()
        self.config = Config().get_config()
        self.config = Config().get_config()



    def add_apiinvokerenrolmentdetail(self, apiinvokerenrolmentdetail, username, uuid):
    def add_apiinvokerenrolmentdetail(self, apiinvokerenrolmentdetail, username, uuid):


        mycol = self.db.get_col_by_name(self.db.invoker_enrolment_details)
        mycol = self.db.get_col_by_name(self.db.invoker_enrolment_details)


        # try:
        # try:
        current_app.logger.debug("Creating invoker resource")
        current_app.logger.debug("Creating invoker resource")
        res = mycol.find_one({'onboarding_information.api_invoker_public_key': apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key})
        res = mycol.find_one({'onboarding_information.api_invoker_public_key':
                             apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key})


        if res is not None:
        if res is not None:
            current_app.logger.error("Generating forbbiden error, invoker registered")
            current_app.logger.error(
                "Generating forbbiden error, invoker registered")
            return forbidden_error(detail="Invoker already registered", cause="Identical invoker public key")
            return forbidden_error(detail="Invoker already registered", cause="Identical invoker public key")


        if rfc3987.match(apiinvokerenrolmentdetail.notification_destination, rule="URI") is None:
        if rfc3987.match(apiinvokerenrolmentdetail.notification_destination, rule="URI") is None:
@@ -72,11 +78,13 @@ class InvokerManagementOperations(Resource):
        current_app.logger.debug("Signing Certificate")
        current_app.logger.debug("Signing Certificate")


        api_invoker_id = 'INV'+str(secrets.token_hex(15))
        api_invoker_id = 'INV'+str(secrets.token_hex(15))
        cert = self.__sign_cert(apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, api_invoker_id)
        cert = self.__sign_cert(
            apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, api_invoker_id)


        apiinvokerenrolmentdetail.api_invoker_id = api_invoker_id
        apiinvokerenrolmentdetail.api_invoker_id = api_invoker_id
        current_app.logger.debug(cert)
        current_app.logger.debug(cert)
        apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert['data']['certificate']
        apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[
            'data']['certificate']


        # Onboarding Date Record
        # Onboarding Date Record
        invoker_dict = apiinvokerenrolmentdetail.to_dict()
        invoker_dict = apiinvokerenrolmentdetail.to_dict()
@@ -89,14 +97,17 @@ class InvokerManagementOperations(Resource):
        current_app.logger.debug("Invoker inserted in database")
        current_app.logger.debug("Invoker inserted in database")
        current_app.logger.debug("Netapp onboarded sucessfuly")
        current_app.logger.debug("Netapp onboarded sucessfuly")


        self.auth_manager.add_auth_invoker(cert['data']['certificate'], api_invoker_id)
        self.auth_manager.add_auth_invoker(
            cert['data']['certificate'], api_invoker_id)


        res = make_response(object=serialize_clean_camel_case(apiinvokerenrolmentdetail), status=201)
        res = make_response(object=serialize_clean_camel_case(
        res.headers['Location'] = "/api-invoker-management/v1/onboardedInvokers/" + str(api_invoker_id)
            apiinvokerenrolmentdetail), status=201)
        res.headers['Location'] = f"https://{os.getenv("CAPIF_HOSTNAME")}/api-invoker-management/v1/onboardedInvokers/{str(api_invoker_id)}"


        if res.status_code == 201:
        if res.status_code == 201:
            current_app.logger.info("Invoker Created")
            current_app.logger.info("Invoker Created")
            RedisEvent("API_INVOKER_ONBOARDED", ["apiInvokerIds"], [[str(api_invoker_id)]]).send_event()
            RedisEvent("API_INVOKER_ONBOARDED",
                       api_invoker_ids=[str(api_invoker_id)]).send_event()
        return res
        return res


    def update_apiinvokerenrolmentdetail(self, onboard_id, apiinvokerenrolmentdetail):
    def update_apiinvokerenrolmentdetail(self, onboard_id, apiinvokerenrolmentdetail):
@@ -111,16 +122,23 @@ class InvokerManagementOperations(Resource):
                return result
                return result


            if apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key != result["onboarding_information"]["api_invoker_public_key"]:
            if apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key != result["onboarding_information"]["api_invoker_public_key"]:
                cert = self.__sign_cert(apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_id"])
                cert = self.__sign_cert(
                apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert['data']['certificate']
                    apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_id"])
                self.auth_manager.update_auth_invoker(cert['data']["certificate"], onboard_id)
                apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[
                    'data']['certificate']
                self.auth_manager.update_auth_invoker(
                    cert['data']["certificate"], onboard_id)


            apiinvokerenrolmentdetail_update = apiinvokerenrolmentdetail.to_dict()
            apiinvokerenrolmentdetail_update = apiinvokerenrolmentdetail.to_dict()
            apiinvokerenrolmentdetail_update = {
            apiinvokerenrolmentdetail_update = {
                key: value for key, value in apiinvokerenrolmentdetail_update.items() if value is not None
                key: value for key, value in apiinvokerenrolmentdetail_update.items() if value is not None
            }
            }


            result = mycol.find_one_and_update(result, {"$set":apiinvokerenrolmentdetail_update}, projection={'_id': 0},return_document=ReturnDocument.AFTER ,upsert=False)
            result = mycol.find_one_and_update(result,
                                               {"$set": apiinvokerenrolmentdetail_update},
                                               projection={'_id': 0},
                                               return_document=ReturnDocument.AFTER,
                                               upsert=False)


            result = {
            result = {
                key: value for key, value in result.items() if value is not None
                key: value for key, value in result.items() if value is not None
@@ -130,10 +148,12 @@ class InvokerManagementOperations(Resource):


            invoker_updated = APIInvokerEnrolmentDetails().from_dict(dict_to_camel_case(result))
            invoker_updated = APIInvokerEnrolmentDetails().from_dict(dict_to_camel_case(result))


            res = make_response(object=serialize_clean_camel_case(invoker_updated), status=200)
            res = make_response(object=serialize_clean_camel_case(
                invoker_updated), status=200)
            if res.status_code == 200:
            if res.status_code == 200:
                current_app.logger.info("Invoker Updated")
                current_app.logger.info("Invoker Updated")
                RedisEvent("API_INVOKER_UPDATED", ["apiInvokerIds"], [[onboard_id]]).send_event()
                RedisEvent("API_INVOKER_UPDATED",
                           api_invoker_ids=[onboard_id]).send_event()
            return res
            return res


        except Exception as e:
        except Exception as e:
@@ -160,13 +180,16 @@ class InvokerManagementOperations(Resource):
            res = make_response(out, status=204)
            res = make_response(out, status=204)
            if res.status_code == 204:
            if res.status_code == 204:
                current_app.logger.info("Invoker Removed")
                current_app.logger.info("Invoker Removed")
                RedisEvent("API_INVOKER_OFFBOARDED", ["apiInvokerIds"], [[onboard_id]]).send_event()
                RedisEvent("API_INVOKER_OFFBOARDED",
                publisher_ops.publish_message("internal-messages", f"invoker-removed:{onboard_id}")
                           api_invoker_ids=[onboard_id]).send_event()
                RedisInternalEvent("INVOKER-REMOVED",
                                   "invokerId",
                                   {
                                       "api_invoker_id": onboard_id
                                   }).send_event()
            return res
            return res


        except Exception as e:
        except Exception as e:
            exception = "An exception occurred in remove invoker"
            exception = "An exception occurred in remove invoker"
            current_app.logger.error(exception + "::" + str(e))
            current_app.logger.error(exception + "::" + str(e))
            return internal_server_error(detail=exception, cause=str(e))
            return internal_server_error(detail=exception, cause=str(e))

+37 −10
Original line number Original line Diff line number Diff line
@@ -2,6 +2,8 @@
import redis
import redis
from .invoker_internal_ops import InvokerInternalOperations
from .invoker_internal_ops import InvokerInternalOperations
from flask import current_app
from flask import current_app
import json



class Subscriber():
class Subscriber():


@@ -14,13 +16,38 @@ class Subscriber():
    def listen(self):
    def listen(self):
        for raw_message in self.p.listen():
        for raw_message in self.p.listen():
            if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages":
            if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages":
                message, invoker_id, api_id = raw_message["data"].decode('utf-8').split(":")
                current_app.logger.info("New internal event received")
                if message == "security-context-created":
                internal_redis_event = json.loads(
                    current_app.logger.debug("Internal message received, updating Api list on invoker")
                    raw_message["data"].decode('utf-8'))
                    self.invoker_ops.update_services_list(invoker_id, api_id)
                if internal_redis_event.get('event') == "SECURITY-CONTEXT-CREATED":
                if message == "security-context-removed":
                    current_app.logger.debug(
                    current_app.logger.debug("Internal message received, removing service in  Api list of invoker")
                        "Internal message received, updating Api list on invoker")
                    self.invoker_ops.remove_services_list(invoker_id, api_id)
                    security_context_information = internal_redis_event.get(

                        'information', None)

                    if security_context_information is not None:
                        api_invoker_id = security_context_information.get(
                            'api_invoker_id')
                        api_id = security_context_information.get('api_id')
                        self.invoker_ops.update_services_list(
                            api_invoker_id, api_id)
                elif internal_redis_event.get('event') == "SECURITY-CONTEXT-REMOVED":
                    current_app.logger.debug(
                        "Internal message received, removing service in  Api list of invoker")
                    security_context_information = internal_redis_event.get(
                        'information', None)
                    if security_context_information is not None:
                        api_invoker_id = security_context_information.get(
                            'api_invoker_id')
                        api_id = security_context_information.get('api_id')
                        self.invoker_ops.remove_services_list(
                            api_invoker_id, api_id)
                # elif internal_redis_event.get('event') == "INVOKER-REMOVED":
                #     api_invoker_id = internal_redis_event.get(
                #         'information', {"api_invoker_id": None}).get('api_invoker_id')
                #     if api_invoker_id is not None:
                #         self.acls_ops.remove_invoker_acl(api_invoker_id)
                # elif internal_redis_event.get('event') == "PROVIDER-REMOVED":
                #     aef_ids = internal_redis_event.get(
                #         'information', {"aef_ids": []}).get('aef_ids')
                #     if len(aef_ids) > 0:
                #         self.acls_ops.remove_provider_acls(aef_ids[0])
+25 −4
Original line number Original line Diff line number Diff line
@@ -6,7 +6,14 @@ publisher_ops = Publisher()




class RedisEvent():
class RedisEvent():
    def __init__(self, event, event_detail_key=None, information=None) -> None:
    def __init__(self,
                 event,
                 service_api_descriptions=None,
                 api_ids=None,
                 api_invoker_ids=None,
                 acc_ctrl_pol_list=None,
                 invocation_logs=None,
                 api_topo_hide=None) -> None:
        self.EVENTS_ENUM = [
        self.EVENTS_ENUM = [
            'SERVICE_API_AVAILABLE',
            'SERVICE_API_AVAILABLE',
            'SERVICE_API_UNAVAILABLE',
            'SERVICE_API_UNAVAILABLE',
@@ -27,9 +34,23 @@ class RedisEvent():
        self.redis_event = {
        self.redis_event = {
            "event": event
            "event": event
        }
        }
        if event_detail_key != None and information != None:
        # Add event filter keys to an auxiliary object
            self.redis_event['key'] = event_detail_key
        event_detail = {
            self.redis_event['information'] = information
            "serviceAPIDescriptions": service_api_descriptions,
            "apiIds": api_ids,
            "apiInvokerIds": api_invoker_ids,
            "accCtrlPolList": acc_ctrl_pol_list,
            "invocationLogs": invocation_logs,
            "apiTopoHide": api_topo_hide
        }

        # Filter keys with not None values
        filtered_event_detail = {k: v for k,
                                 v in event_detail.items() if v is not None}

        # If there are valid values then add to redis event.
        if filtered_event_detail:
            self.redis_event["event_detail"] = filtered_event_detail


    def to_string(self):
    def to_string(self):
        return json.dumps(self.redis_event, cls=JSONEncoder)
        return json.dumps(self.redis_event, cls=JSONEncoder)
+35 −0
Original line number Original line Diff line number Diff line
from ..encoder import JSONEncoder
from .publisher import Publisher
import json

publisher_ops = Publisher()


class RedisInternalEvent():
    def __init__(self, event, event_detail_key=None, information=None) -> None:
        self.INTERNAL_MESSAGES = [
            'INVOKER-REMOVED',
            'PROVIDER-REMOVED',
            'SECURITY-CONTEXT-CREATED',
            'SECURITY-CONTEXT-REMOVED',
            'create-acl',
            'remove-acl',
        ]
        if event not in self.INTERNAL_MESSAGES:
            raise Exception(
                "Internal Message (" + event + ") is not on INTERNAL_MESSAGES enum (" + ','.join(self.INTERNAL_MESSAGES) + ")")
        self.redis_event = {
            "event": event
        }
        if event_detail_key is not None and information is not None:
            self.redis_event['key'] = event_detail_key
            self.redis_event['information'] = information

    def to_string(self):
        return json.dumps(self.redis_event, cls=JSONEncoder)

    def send_event(self):
        publisher_ops.publish_message("internal-messages", self.to_string())

    def __call__(self):
        return self.redis_event
Loading