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

add https port only when different from default, improve concecutive Publish...

add https port only when different from default, improve concecutive Publish requests, add GET request to interconection APIs
parent 8a9bb7ac
Loading
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -220,8 +220,6 @@ class PublishServiceOperations(Resource):
                                rec.update({"pub_api_path": {"ccf_ids": ccf_list}})
                        else:
                            rec['shareable_info']['capif_prov_doms'].remove(dom)
                            if "CCF" in apf_id:
                                rec['pub_api_path']['ccf_ids'].remove(apf_id)

            if "CCF" in apf_id:
                if rec.get("pub_api_path") is None:
+87 −0
Original line number Diff line number Diff line
@@ -12,6 +12,44 @@ servers:
# 1. PATHS: Where you define your endpoints
paths:
  /request:
    get:
      summary: Retrieve the interconnection information of every CCF
      operationId: get_interconnect_requests  # <--- Becomes 'def get_interconnect_requests():' in Python
      responses:
        "200":
          description: Interconnection information of every interconnected CCF
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CcfInstanceDetails'
        "401":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Unauthorized
        "403":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Forbidden
        "500":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Internal Server Error
        "503":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Service Unavailable
        default:
          description: Generic Error
    post:
      summary: Send a new interconnection request
      operationId: interconnect_request  # <--- Becomes 'def interconnect_request(body):' in Python
@@ -122,6 +160,55 @@ paths:
        default:
          description: Generic Error
  /request/{ccf_id}:
    get:
      summary: Retrieve the interconnection information of a single CCF
      operationId: get_interconnect_request  # <--- Becomes 'def get_interconnect_request(ccf_id):' in Python
      parameters:
      - description: CCF identifier of the interconnection to retrieve
        in: path
        name: ccf_id
        required: true
        schema:
          type: string
      responses:
        "200":
          description: Interconnection information of the requested CCF
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CcfInstanceDetails'
        "401":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Unauthorized
        "403":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Forbidden
        "404":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Not Found
        "500":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Internal Server Error
        "503":
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDetails'
          description: Service Unavailable
        default:
          description: Generic Error
    delete:
      summary: Remove an interconnection request
      operationId: delete_interconnect_request  # <--- Becomes 'def delete_interconnect_request(ccf_id):' in Python
+27 −0
Original line number Diff line number Diff line
@@ -48,6 +48,33 @@ def delete_connected_ccf(ccf_id): # noqa: E501
    return res


def get_interconnect_requests():  # noqa: E501
    """Retrieve the interconnection information of every CCF

     # noqa: E501

    :rtype: Union[List[CcfInstanceDetails], Tuple[List[CcfInstanceDetails], int], Tuple[List[CcfInstanceDetails], int, Dict[str, str]]
    """
    res = capif_domain_operations.get_capifdomains()

    return res


def get_interconnect_request(ccf_id):  # noqa: E501
    """Retrieve the interconnection information of a single CCF

     # noqa: E501

    :param ccf_id: CCF identifier of the interconnection to retrieve
    :type ccf_id: str

    :rtype: Union[CcfInstanceDetails, Tuple[CcfInstanceDetails, int], Tuple[CcfInstanceDetails, int, Dict[str, str]]
    """
    res = capif_domain_operations.get_capifdomain(ccf_id)

    return res


def interconnect_request(body):  # noqa: E501
    """Send a new interconnection request

+34 −5
Original line number Diff line number Diff line
@@ -39,6 +39,35 @@ class CapifDomainOperations(Resource):
        self.db = get_mongo()
        self.ccf_operations = CcfInstanceOperations()

    def get_capifdomains(self):
        """Return the interconnection details of every interconnected CCF."""
        current_app.logger.debug("Interconnection: Get domains")

        interconnected_col = self.db.get_col_by_name(self.db.interconnected)
        interconnected_ccfs = interconnected_col.find({}, {"_id": 0})

        ccfinstances = [
            serialize_clean_camel_case(CcfInstanceDetails().from_dict(dict_to_camel_case(interconnected_ccf)))
            for interconnected_ccf in interconnected_ccfs
        ]

        return make_response(object=ccfinstances, status=200)

    def get_capifdomain(self, ccf_id):
        """Return the interconnection details of a single interconnected CCF."""
        current_app.logger.debug("Interconnection: Get domain")

        interconnected_col = self.db.get_col_by_name(self.db.interconnected)
        interconnected_ccf = interconnected_col.find_one({"ccf_id": ccf_id}, {"_id": 0})
        if interconnected_ccf is None:
            return not_found_error(
                detail="CAPIF domain with ccf_id {} not found".format(ccf_id),
                cause="NOT_FOUND")

        ccfinstancedetails_new = CcfInstanceDetails().from_dict(dict_to_camel_case(interconnected_ccf))

        return make_response(object=serialize_clean_camel_case(ccfinstancedetails_new), status=200)

    def add_capifdomain(self, capifdomaindetails):
        current_app.logger.debug("Interconnection: Add domain")

@@ -57,13 +86,12 @@ class CapifDomainOperations(Resource):
            server_pub = server_cert.read()
            server_cert.close()

        config_col = self.db.get_col_by_name(self.db.capif_configuration)
        config = config_col.find_one({}, {"_id": 0})
        local_ccf_id, local_dom = self.ccf_operations.local_ccf_identity()

        payload = json.dumps({
            "caRoot": server_ca.decode("utf-8"),
            "ccfId": config['ccf_id'],
            "dstProvDom": "{}:{}".format(os.getenv("CAPIF_HOSTNAME"), os.getenv("CAPIF_HTTPS_PORT")),
            "ccfId": local_ccf_id,
            "dstProvDom": local_dom,
            "publicKey": server_pub.decode("utf-8")
        })
        headers = {
@@ -87,7 +115,8 @@ class CapifDomainOperations(Resource):
        if response.status_code in (200, 201):
            if isinstance(inter_ccf, dict):
                interconnected_col.insert_one(inter_ccf)
                self.ccf_operations.sync_with_ccf(capifdomaindetails.dst_prov_dom)
                # The peer reports the domain it is reachable at, which is what got stored
                self.ccf_operations.sync_with_ccf(inter_ccf.get("dst_prov_dom", capifdomaindetails.dst_prov_dom))
                ccfinstancedetails_new = CcfInstanceDetails().from_dict(dict_to_camel_case(inter_ccf))
                return make_response(object=ccfinstancedetails_new, status=response.status_code)

+43 −32
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ publisher_ops = Publisher()

service_api_not_found_message = "Service API not found"

# Seconds allowed for a single publish request towards a peer CCF
publish_timeout = 30


class CcfInstanceOperations(Resource):

@@ -64,13 +67,12 @@ class CcfInstanceOperations(Resource):
            interconnected_col.insert_one(clean_empty(ccfinstancedetails_dict))
            status = 201

        config_col = self.db.get_col_by_name(self.db.capif_configuration)
        config = config_col.find_one({}, {"_id": 0})
        local_ccf_id, local_dom = self.local_ccf_identity()

        ccfinstancedetails_dict['ca_root'] = server_ca.decode("utf-8")
        ccfinstancedetails_dict['public_key'] = server_pub.decode("utf-8")
        ccfinstancedetails_dict['ccf_id'] = config['ccf_id']
        ccfinstancedetails_dict['dst_prov_dom'] = "{}:{}".format(os.getenv("CAPIF_HOSTNAME"), os.getenv("CAPIF_HTTPS_PORT"))
        ccfinstancedetails_dict['ccf_id'] = local_ccf_id
        ccfinstancedetails_dict['dst_prov_dom'] = local_dom

        ccfinstancedetails_new = CcfInstanceDetails().from_dict(dict_to_camel_case(ccfinstancedetails_dict))
        res = make_response(object=serialize_clean(ccfinstancedetails_new), status=status)
@@ -80,7 +82,11 @@ class CcfInstanceOperations(Resource):
        """Return the CCF identifier and the provider domain of this CAPIF instance."""
        config_col = self.db.get_col_by_name(self.db.capif_configuration)
        config = config_col.find_one({}, {"_id": 0})
        dst_prov_dom = "{}:{}".format(os.getenv("CAPIF_HOSTNAME"), os.getenv("CAPIF_HTTPS_PORT"))

        hostname = os.getenv("CAPIF_HOSTNAME")
        https_port = os.getenv("CAPIF_HTTPS_PORT")
        
        dst_prov_dom = hostname if https_port in (None, "", "443") else "{}:{}".format(hostname, https_port)

        return config['ccf_id'], dst_prov_dom

@@ -104,12 +110,18 @@ class CcfInstanceOperations(Resource):
        })

        url = "https://{}/published-apis/v1/{}/service-apis".format(peer_dom, local_ccf_id)
        headers = {

        published = 0
        # A single session keeps the connection alive, so the mTLS handshake with the peer
        # is paid once for the whole batch instead of once per service API
        with requests.Session() as session:
            session.cert = ('certs/server.crt', 'certs/server.key')
            session.verify = 'certs/ca.crt'
            session.headers.update({
                'accept': 'application/json',
                'Content-Type': 'application/json'
        }
            })

        published = 0
            for service_api in shareable_apis:
                payload = {
                    key: value for key, value in service_api.items()
@@ -119,10 +131,9 @@ class CcfInstanceOperations(Resource):
                payload['shareable_info'] = {"is_shareable": False}

                try:
                response = requests.request("POST", url, headers=headers,
                    response = session.post(url,
                                            data=json.dumps(clean_n_camel_case(payload), cls=CustomJSONEncoder),
                                            cert=('certs/server.crt', 'certs/server.key'),
                                            verify='certs/ca.crt')
                                            timeout=publish_timeout)
                except requests.exceptions.RequestException as exc:
                    current_app.logger.error("Interconnection: publish to {} failed: {}".format(peer_dom, str(exc)))
                    continue
Loading