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 Diff line number Diff line
@@ -10,6 +10,8 @@ from logging.handlers import RotatingFileHandler
import os
from fluent import sender
from flask_executor import Executor
from flask_apscheduler import APScheduler
from datetime import datetime
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry import trace
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
@@ -137,16 +139,11 @@ if monitoring_value == "true":

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

first = True

@app.app.before_request
def create_listener_message():
    global first
    if first:
        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
scheduler = APScheduler()
scheduler.init_app(app.app)
scheduler.start()

@scheduler.task('date', id='listener', next_run_time=datetime.now())
def up_listener():
    with scheduler.app.app_context():
        executor.submit(subscriber.listen())
+55 −32
Original line number Diff line number Diff line
@@ -3,18 +3,22 @@ from pymongo import ReturnDocument
import secrets
import requests
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
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 .resources import Resource
from ..config import Config
from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails
from .redis_event import RedisEvent
from .redis_internal_event import RedisInternalEvent
from .publisher import Publisher
import os

publisher_ops = Publisher()


class InvokerManagementOperations(Resource):

    def __check_api_invoker_id(self, api_invoker_id):
@@ -41,7 +45,8 @@ class InvokerManagementOperations(Resource):
            '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)
        response_payload = json.loads(response.text)

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


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

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

        # try:
        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:
            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")

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

        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
        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
        invoker_dict = apiinvokerenrolmentdetail.to_dict()
@@ -89,14 +97,17 @@ class InvokerManagementOperations(Resource):
        current_app.logger.debug("Invoker inserted in database")
        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.headers['Location'] = "/api-invoker-management/v1/onboardedInvokers/" + str(api_invoker_id)
        res = make_response(object=serialize_clean_camel_case(
            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:
            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

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

            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"])
                apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert['data']['certificate']
                self.auth_manager.update_auth_invoker(cert['data']["certificate"], onboard_id)
                cert = self.__sign_cert(
                    apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_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 = {
                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 = {
                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))

            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:
                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

        except Exception as e:
@@ -160,13 +180,16 @@ 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()
                publisher_ops.publish_message("internal-messages", f"invoker-removed:{onboard_id}")
                RedisEvent("API_INVOKER_OFFBOARDED",
                           api_invoker_ids=[onboard_id]).send_event()
                RedisInternalEvent("INVOKER-REMOVED",
                                   "invokerId",
                                   {
                                       "api_invoker_id": onboard_id
                                   }).send_event()
            return res

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

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


class Subscriber():

@@ -14,13 +16,38 @@ class Subscriber():
    def listen(self):
        for raw_message in self.p.listen():
            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(":")
                if message == "security-context-created":
                    current_app.logger.debug("Internal message received, updating Api list on invoker")
                    self.invoker_ops.update_services_list(invoker_id, api_id)
                if message == "security-context-removed":
                    current_app.logger.debug("Internal message received, removing service in  Api list of invoker")
                    self.invoker_ops.remove_services_list(invoker_id, api_id)


                current_app.logger.info("New internal event received")
                internal_redis_event = json.loads(
                    raw_message["data"].decode('utf-8'))
                if internal_redis_event.get('event') == "SECURITY-CONTEXT-CREATED":
                    current_app.logger.debug(
                        "Internal message received, updating Api list on 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.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 Diff line number Diff line
@@ -6,7 +6,14 @@ publisher_ops = Publisher()


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 = [
            'SERVICE_API_AVAILABLE',
            'SERVICE_API_UNAVAILABLE',
@@ -27,9 +34,23 @@ class RedisEvent():
        self.redis_event = {
            "event": event
        }
        if event_detail_key != None and information != None:
            self.redis_event['key'] = event_detail_key
            self.redis_event['information'] = information
        # Add event filter keys to an auxiliary object
        event_detail = {
            "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):
        return json.dumps(self.redis_event, cls=JSONEncoder)
+35 −0
Original line number 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