From d2a07e910d2da5f7cdab2b13d960f76f2b02c334 Mon Sep 17 00:00:00 2001 From: garciay <yann.garcia@fscom.fr> Date: Sat, 15 Mar 2025 08:06:53 +0100 Subject: [PATCH] Add CAPIF_And_ETSI_MEC_Tutorial.ipynb --- .../CAPIF_And_ETSI_MEC_Tutorial.ipynb | 2384 +++++++++++++++++ 1 file changed, 2384 insertions(+) create mode 100644 examples/demo6/python/notebook/CAPIF_And_ETSI_MEC_Tutorial.ipynb diff --git a/examples/demo6/python/notebook/CAPIF_And_ETSI_MEC_Tutorial.ipynb b/examples/demo6/python/notebook/CAPIF_And_ETSI_MEC_Tutorial.ipynb new file mode 100644 index 000000000..22c03d22f --- /dev/null +++ b/examples/demo6/python/notebook/CAPIF_And_ETSI_MEC_Tutorial.ipynb @@ -0,0 +1,2384 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "44TomlvPCGTe" + }, + "source": [ + "# Using ETSI MEC profile of CAPIF in CAPIF application\n", + "\n", + "## Introduction\n", + "\n", + "3GPP CAPIF (Common API Framework) is a standardized API management framework designed to enable a unified northbound API approach across 3GPP network functions (see 3GPP TS 23.222 version 18.6.0 Release 18/ETSI TS 123 222 V18.6.0 (2024-06) and 3GPP TS 29.222 version 18.6.0 Release 18/ETSI TS 129 222 V18.6.0 (2022-06)).\n", + "\n", + "This tutorial introduces the step by step procedure to create a basic CAPIF application to exploit the ETSI MEC CAPIF profile as described in ETSI GS MEC 011 (V3.2.1) Clause 9.\n", + "It uses the ETSI MEC Sandbox simulator.\n", + "\n", + "<div class=\"alert alert-block alert-danger\">\n", + " <b>Note:</b> These source code examples are simplified and ignore return codes and error checks to a large extent. We do this to highlight how to use the MEC Sandbox API and the different MEC satndards and reduce unrelated code.\n", + "A real-world application will of course properly check every return value and exit correctly at the first serious error.\n", + "</div>\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4DpxwmiomELg" + }, + "source": [ + "## The basics of developing a MEC application\n", + "\n", + "\n", + "<div class=\"alert alert-warning\" role=\"alert\">\n", + " <b>Note:</b> The sub-paragraph 'Putting everything together' is a specific paragraph where all the newly features introduced in the main paragraph are put together to create an executable block of code. It is possible to skip this block of code by removing the comment character (#) on first line of this block of code.\n", + "</div>\n", + "\n", + "Before going to create our CAPIF application skeleton, the following steps shall be done:\n", + "\n", + "1) Apply the python imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "1gjo-NM6hD1k" + }, + "outputs": [], + "source": [ + "from __future__ import division # Import floating-point division (1/4=0.25) instead of Euclidian division (1/4=0)\n", + "\n", + "import os\n", + "import sys\n", + "import re\n", + "import logging\n", + "import threading\n", + "import time\n", + "import json\n", + "import uuid\n", + "import base64\n", + "\n", + "import pprint\n", + "\n", + "import requests\n", + "\n", + "from http import HTTPStatus\n", + "from http.server import BaseHTTPRequestHandler, HTTPServer\n", + "\n", + "try:\n", + " import urllib3\n", + "except ImportError:\n", + " raise ImportError('Swagger python client requires urllib3.')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j9wDIe9IEUQz" + }, + "source": [ + "The following imports are required to support the security aspects such as certificates management, signatures..." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "xb4ReBZZEVLB" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pyOpenSSL==25.0.0 in /opt/conda/lib/python3.11/site-packages (25.0.0)\n", + "Requirement already satisfied: cryptography<45,>=41.0.5 in /opt/conda/lib/python3.11/site-packages (from pyOpenSSL==25.0.0) (43.0.1)\n", + "Requirement already satisfied: typing-extensions>=4.9 in /opt/conda/lib/python3.11/site-packages (from pyOpenSSL==25.0.0) (4.12.2)\n", + "Requirement already satisfied: cffi>=1.12 in /opt/conda/lib/python3.11/site-packages (from cryptography<45,>=41.0.5->pyOpenSSL==25.0.0) (1.17.1)\n", + "Requirement already satisfied: pycparser in /opt/conda/lib/python3.11/site-packages (from cffi>=1.12->cryptography<45,>=41.0.5->pyOpenSSL==25.0.0) (2.22)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3714172/2658395025.py:5: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.\n", + " from OpenSSL.crypto import (dump_certificate_request, dump_privatekey, load_publickey, PKey, TYPE_RSA, X509Req, dump_publickey)\n" + ] + } + ], + "source": [ + "!pip3 install pyOpenSSL==25.0.0\n", + "\n", + "try:\n", + " from OpenSSL.SSL import FILETYPE_PEM\n", + " from OpenSSL.crypto import (dump_certificate_request, dump_privatekey, load_publickey, PKey, TYPE_RSA, X509Req, dump_publickey)\n", + "except ImportError:\n", + " raise ImportError('OpenSSL package not found.')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DrPJzD14nLas" + }, + "source": [ + "2) Initialize of the global constants (cell 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "id": "rNibZWiBitPE" + }, + "outputs": [], + "source": [ + "REGISTER_HOSTNAME = 'lab-oai.etsi.org' # capif-prev.mobilesandbox.cloud\n", + "REGISTER_PORT = 31120 # 31120\n", + "REGISTER_USER = 'admin' # Basic AUTH for registration\n", + "REGISTER_PASSWORD = 'password123' # Basic AUTH for registration\n", + "\n", + "CAPIF_HOSTNAME = 'lab-oai.etsi.org' # capif-prev.mobilesandbox.cloud\n", + "CAPIF_PORT = 443\n", + "\n", + "USER_PASSWORD = 'password123'\n", + "\n", + "TRY_MEC_URL = 'try-mec.etsi.org' # MEC Sandbox URL\n", + "TRY_MEC_SESSION_ID = 'sbxx3i4jhr' # MEC Sandbox identifier\n", + "TRY_MEC_PLTF = 'mep1' # MEC Platform identifier (depending of the network scenario loaded)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MOa9g-NMnpod" + }, + "source": [ + "3) Setup the logger instance and the HTTP REST API (cell 4)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "-cuxWhfantSw" + }, + "outputs": [], + "source": [ + "# Initialize the logger\n", + "logger = logging.getLogger(__name__)\n", + "logger.setLevel(logging.DEBUG)\n", + "logging.basicConfig(filename='/tmp/' + time.strftime('%Y%m%d-%H%M%S') + '.log')\n", + "l = logging.StreamHandler()\n", + "l.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))\n", + "logger.addHandler(l)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "D67Aq0vujB0q" + }, + "source": [ + "4) Setup the global variables (cell 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "7RC7UY-0oACq" + }, + "outputs": [], + "source": [ + "# Initialize the global variables\n", + "ca_root = \"\" # The CAPIF root certificate\n", + "ccf_api_onboarding_url = \"\" #\n", + "ccf_publish_url = \"\" # The CAPIF publish API endpoint\n", + "ccf_discover_url = \"\" # The CAPIF discovery endpoint\n", + "ccf_security_url = \"\" # The CAPIF security endpoint\n", + "ccf_onboarding_url = \"\" # The CAPIF onboarding endpoint\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2YvSVMClhPJT" + }, + "source": [ + "To enable the Automatic Debugger Calling, uncomment the code bellow." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "OQjYWHgnYM4G" + }, + "outputs": [], + "source": [ + "#!pip3 install ipdb\n", + "#import ipdb\n", + "#%pdb on\n", + "# Use the command ipdb.set_trace() to set a breakpoint" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1fMmXWk9jLDX" + }, + "source": [ + "## Create our first CAPIF application\n", + "\n", + "The first step to develop a MEC application is to create the application skeleton which contains the minimum steps below:\n", + "\n", + "- Login to instanciate a MEC Sandbox\n", + "- Logout to delete a existing MEC Sandbox" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rtAVXZayoQRx" + }, + "source": [ + "#### Login\n", + "\n", + "The login operation is required by ETSI TS 123 222 V18.6.0 (2024-06) Clause 4.5 Operations, Administration and Maintenance but is out of the scope of ETSI TS 129 222 V18.6.0 (2022-06)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "Ad8g1no-pH7i" + }, + "outputs": [], + "source": [ + "def process_login() -> tuple:\n", + " \"\"\"\n", + " Logs in to the CAPIF server.\n", + " :return A dictionary containing the login response, or None if login fails\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> process_login')\n", + "\n", + " try:\n", + " url = 'https://' + REGISTER_HOSTNAME + ':' + str(REGISTER_PORT) + '/login'\n", + " logger.debug('process_login: url=' + url)\n", + " auth_string = f\"{REGISTER_USER}:{REGISTER_PASSWORD}\"\n", + " encoded_auth = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8')\n", + " headers = {'Content-Type': 'application/json', 'Authorization': f'Basic {encoded_auth}'}\n", + " logger.debug('process_login (step1): headers: ' + str(headers))\n", + " response = requests.post(url, headers=headers, verify=False)\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('process_login (step2): result: ' + str(response.json()))\n", + " if response.status_code != 200:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return None, None\n", + " tokens = json.loads(response.text)\n", + " return tokens['refresh_token'], tokens['access_token']\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"Login failed: {e}\")\n", + "\n", + " return None, None\n", + " # End of function process_login" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8Cw5MBc-st1e" + }, + "source": [ + "### Logout\n", + "\n", + "The logout operation is required by ETSI TS 123 222 V18.6.0 (2024-06) Clause 4.5 Operations, Administration and Maintenance but is out of the scope of ETSI TS 129 222 V18.6.0 (2022-06)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "XmyLOuFasuvU" + }, + "outputs": [], + "source": [ + "def process_logout():\n", + " \"\"\"\n", + " Logs out from the CAPIF server\n", + " Nothing to do\n", + " \"\"\"\n", + " pass\n", + " # End of function process_logout" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mCKT-ntspnsM" + }, + "source": [ + "### Putting everything together\n", + "Now, it is time now to create the our first iteration of our CAPIF/MEC application. Here the logic is:\n", + "* Login\n", + "* Print obtained tokens\n", + "* Logout\n", + "* Check that logout is effective" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "XYC8PnDUpvui" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the first sprint of our CAPIF application:\n", + " - Login\n", + " - Print obtained tokens\n", + " - Logout\n", + " - Check that logout is effective\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Login\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " return\n", + "\n", + " # Print obtained tokens\n", + " logger.debug(\"Login successful: admin_token=\" + admin_token)\n", + "\n", + " # Logout\n", + " process_logout()\n", + "\n", + " # Check that logout is effective\n", + " logger.debug('To check that logout is effective')\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rTcvGY5T1pZJ" + }, + "source": [ + "## Create the API Provider\n", + "\n", + "The next step is to create a new user associated to our CAPIF application to obtain a user UUID. It will be used to genereate ceertificates to be used during TLS mutual authentication and API onboarding and offboarding for instance.\n", + "\n", + "**Note:** It is required by ETSI TS 123 222 V18.6.0 (2024-06) Clause 4.5 Operations, Administration and Maintenance but is out of the scope of ETSI TS 129 222 V18.6.0 (2022-06).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ysxZ8sIiLLgw" + }, + "source": [ + "### Creating a new user\n", + "\n", + "The cell below provides an implementation for this user creation.\n", + "\n", + "**Note:** To improve this code, the user profile shlould be fully parametrized." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "Jq-9_sLI8WgW" + }, + "outputs": [], + "source": [ + "def create_user(p_admin_token: str) -> tuple:\n", + " \"\"\"\n", + " Creates a new user.\n", + " :return: The user UUID on success, None otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> create_user')\n", + "\n", + " try:\n", + " user_name = str(uuid.uuid1())\n", + " url = 'https://' + REGISTER_HOSTNAME + ':' + str(REGISTER_PORT) + '/createUser'\n", + " logger.debug('create_user: url=' + url)\n", + " headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + p_admin_token}\n", + " logger.debug('create_user (step1): headers: ' + str(headers))\n", + " data = {\n", + " 'username': user_name,\n", + " 'password': USER_PASSWORD,\n", + " 'enterprise': 'ETSI',\n", + " 'country': 'France',\n", + " 'email': 'ocf@etsi.org',\n", + " 'purpose': 'Tutorial on MEC/OpenCAPIF',\n", + " 'phone_number': \"+330405060708\",\n", + " 'company_web': 'www.etsi.org',\n", + " 'description': 'A step by step procedure to create a basic CAPIF application to exploit the ETSI MEC CAPIF profile'\n", + " }\n", + " response = requests.post(url, headers=headers, data=json.dumps(data), verify=False)\n", + " logger.debug('create_user (step2): response=' + str(response))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " if response.status_code != 201:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return ()\n", + " tokens = json.loads(response.text)\n", + " return (user_name, tokens['uuid'])\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"Error creating user: {e}\")\n", + "\n", + " return ()\n", + " # End of function create_user" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ut3CLrRUFT5o" + }, + "source": [ + "### Deleting an existing User\n", + "\n", + "Before to terminate our CAPIF application, we have to clean up the resources. So, a function to delete a created user is required." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "WRIdwNMNFrdC" + }, + "outputs": [], + "source": [ + "def delete_user(p_user_uuid: str, p_admin_token: str) -> int:\n", + " \"\"\"\n", + " Deletes a user.\n", + " :param p_user_uuid: The user UUID\n", + " :return: 0 on success, -1 otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> delete_user')\n", + "\n", + " try:\n", + " url = 'https://' + REGISTER_HOSTNAME + ':' + str(REGISTER_PORT) + '/deleteUser/' + p_user_uuid\n", + " logger.debug('delete_user: url=' + url)\n", + " headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + p_admin_token}\n", + " response = requests.delete(url, headers=headers, verify=False)\n", + " logger.debug('delete_user: response=' + str(response))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " return 0\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"Error creating user: {e}\")\n", + "\n", + " return -1\n", + " # End of function delete_user" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IAh9tN25-82V" + }, + "source": [ + "### Putting everything together\n", + "It is time now to create the our second iteration of our CAPIF/MEC application.\n", + "\n", + "The sequence is the following:\n", + "* Login\n", + "* Print obtained tokens\n", + "* Create a new user\n", + "* Print the user UUID\n", + "* Delete the newly created user\n", + "* Logout\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "1M_x2I1B_Crp" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the second sprint of our CAPIF/MEC application:\n", + " - Login\n", + " - Print obtained tokens\n", + " - Create a new user\n", + " - Print the user UUID\n", + " - Delete the newly created user\n", + " - Logout\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Login\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " return\n", + "\n", + " # Print obtained tokens\n", + " logger.debug(\"Login successful: admin_token=\" + admin_token)\n", + "\n", + " # Create a new user\n", + " user_name, user_uuid = create_user(admin_token)\n", + " if len(user_uuid) == 0:\n", + " return\n", + "\n", + " # Print User UUID\n", + " logger.debug(\"User successfully created: user_uuid=\" + user_uuid)\n", + "\n", + " time.sleep(5) # Sleep for 5 seconds\n", + "\n", + " # Delete the newly created user\n", + " delete_user(user_uuid, admin_token)\n", + "\n", + " # Logout\n", + " process_logout()\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f896qBJOjMuz" + }, + "source": [ + "## Getting security materials\n", + "\n", + "The purpose is to retrieves peer certificates for the TLS mutual authentication purpose and the JWT token to onboarding and offboarding APIs.\n", + "The following information is retrived:\n", + "- The root certificate\n", + "- An access token which will be used for onboarding and offboarding APIs\n", + "- The URLs for the different CAPIF endpoints:\n", + " * API onbording endpoint\n", + " * API discovery endpoint\n", + " * API publish endpoint\n", + " * Security endpoint\n", + "\n", + "This operation needs the user name and the user password used in previous [chapter](#create_the_invoker_/_provider).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lC2JAah7LWLp" + }, + "source": [ + "### Getting certificates" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "1glmqNSRK1cH" + }, + "outputs": [], + "source": [ + "def get_auth(p_user_name: str, p_user_password: str) -> dict:\n", + " \"\"\"\n", + " Gets the authentication information.\n", + " :param The user name\n", + " :param The user password\n", + " :return A dictionary containing the authentication information on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> get_auth')\n", + "\n", + " try:\n", + " url = 'https://' + REGISTER_HOSTNAME + ':' + str(REGISTER_PORT) + '/getauth'\n", + " logger.debug('get_auth: url=' + url)\n", + " auth_string = f\"{p_user_name}:{p_user_password}\"\n", + " encoded_auth = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8')\n", + " headers = {'Content-Type': 'application/json', 'Authorization': f'Basic {encoded_auth}'}\n", + " logger.debug('get_auth (step1): headers: ' + str(headers))\n", + " response = requests.get(url, headers=headers, verify=False)\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('get_auth (step2): result: ' + str(response.json()))\n", + " if response.status_code != 200:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return dict()\n", + " auth = json.loads(response.text)\n", + " return auth\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"get_auth failed: {e}\")\n", + "\n", + " return dict()\n", + " # End of function get_auth" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BUw-VS1WLb7i" + }, + "source": [ + "### Putting everything together\n", + "\n", + "Now, it is time now to create the our third iteration of our MEC application. Here the logic is:\n", + "\n", + "- Login\n", + "- Create the user\n", + "- Get the information to use CAPIF (security materials & URLs)\n", + "- Print the information to use CAPI\n", + "- Delete the user\n", + "- Logout\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "J002Vuz2OIKl" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the first sprint of our skeleton of our CAPIF application:\n", + " - Login\n", + " - Print obtained tokens\n", + " - Create a new user\n", + " - Get the information to use CAPIF (security materials & URLs)\n", + " - Print the information to use CAPI\n", + " - Delete the newly created user\n", + " - Logout\n", + " \"\"\"\n", + " global logger, ca_root, ccf_api_onboarding_url, ccf_publish_url, ccf_discover_url, ccf_security_url, ccf_onboarding_url\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Login\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " return\n", + "\n", + " # Create a new user\n", + " user_name, user_uuid = create_user(admin_token)\n", + " if len(user_uuid) == 0:\n", + " return\n", + "\n", + " auth = get_auth(user_name, USER_PASSWORD)\n", + " if len(auth) == 0:\n", + " return\n", + "\n", + " # Print the authentication information\n", + " logger.debug(\"Authentication information=\" + str(auth))\n", + " access_token = auth['access_token']\n", + " ca_root = auth['ca_root']\n", + " ccf_api_onboarding_url = auth['ccf_api_onboarding_url']\n", + " ccf_discover_url = auth['ccf_discover_url']\n", + " ccf_onboarding_url = auth['ccf_onboarding_url']\n", + " ccf_publish_url = auth['ccf_publish_url']\n", + " ccf_security_url = auth['ccf_security_url']\n", + "\n", + " time.sleep(5) # Sleep for 5 seconds\n", + "\n", + " # Delete the newly created user\n", + " delete_user(user_uuid, admin_token)\n", + "\n", + " # Logout\n", + " process_logout()\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oNhnnDhjjOd7" + }, + "source": [ + "## Onboarding and offboarding APIs\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "K6i4ktfM1xFQ" + }, + "source": [ + "### Generate certificates\n", + "\n", + "Until now, all HTTPS exchanges were done with the the 'verify' attribute of the HTTP reques set to False. It means that the TLS mutual authentication was disabled.\n", + "\n", + "Fo the process of onboarding and offboarding APIs, the TLS mutual authentication is required. We already got the peer certificate to verify peer but we need to generate our own certificate to be verified by the CAPIF server. This is the purpose of the following functions to generate the public/private keys and generate a CSR and request certificates for each of the three functions AMF, AEF and APF.\n", + "\n", + "**Refer to:** ETSI TS 129 222 V18.6.0 (2022-06) Clauses 5.11 CAPIF_API_Provider_Management and 8.9 CAPIF_API_Provider_Management_API\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "gEIS3iAH2D4t" + }, + "outputs": [], + "source": [ + "def generate_csr(p_cn: str, p_org: str, p_country: str) -> tuple:\n", + " \"\"\"\n", + " To generate the CSR and generate the dumps\n", + " :param p_cn: The common name\n", + " :param p_org: The organization\n", + " :param p_country: The country\n", + " :return: The CSR and the private keys on success, None otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> generate_csr')\n", + "\n", + " # Generate the public/private key\n", + " key = PKey()\n", + " key.generate_key(TYPE_RSA, 2048)\n", + "\n", + " # Generate the CSR\n", + " req = X509Req()\n", + " req.get_subject().CN = p_cn\n", + " req.get_subject().O = p_org\n", + " req.get_subject().C = p_country\n", + " req.set_pubkey(key)\n", + " req.sign(key, 'sha256')\n", + "\n", + " # Generate the dumps\n", + " csr_request = dump_certificate_request(FILETYPE_PEM, req)\n", + " private_key = dump_privatekey(FILETYPE_PEM, key)\n", + " logger.debug('generate_csr: PrivKey: ' + str(private_key))\n", + "\n", + " return (csr_request, private_key)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F2-W0a5S3snI" + }, + "source": [ + "**Note:** The function above can be improved using parameter for the SHA, and the signature/encryption algorithm." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1HyqrdUz-uzn" + }, + "source": [ + "### Onboard the API provider\n", + "\n", + "The purpose here is to get certificates from CAPIF in order to export our APIs for the different functions:\n", + "- AMF: API Management Function\n", + "- AEF: API Exposing Function\n", + "- APF: API Publishing Function" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "6cCn1vKLGe0k" + }, + "outputs": [], + "source": [ + "def onboard_provider(p_name: str, p_access_token: str) -> dict:\n", + " \"\"\"\n", + " To onboard the provider.\n", + " :param p_name: The name of the provider\n", + " :return: A dictionary containing security material for each CAPIF endpoint on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger, ccf_api_onboarding_url, access_token\n", + "\n", + " logger.debug('>>> onboard_provider')\n", + "\n", + " try:\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_api_onboarding_url\n", + " logger.debug('onboard_provider: url=' + url)\n", + " headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + p_access_token}\n", + " logger.debug('onboard_provider (step1): headers: ' + str(headers))\n", + " # Build the list of certificate request for the three endpoints\n", + " l = []\n", + " amf_csr_request, amf_private_key = generate_csr(\"AMF\", \"ETSI\", \"Fr\")\n", + " amf_entry = {\n", + " 'regInfo': {\n", + " 'apiProvPubKey': amf_csr_request.decode(\"utf-8\")\n", + " },\n", + " 'apiProvFuncRole': 'AMF'\n", + " }\n", + " l.append(amf_entry)\n", + " aef_csr_request, aef_private_key = generate_csr(\"AEF\", \"ETSI\", \"Fr\")\n", + " aef_entry = {\n", + " 'regInfo': {\n", + " 'apiProvPubKey': aef_csr_request.decode(\"utf-8\")\n", + " },\n", + " 'apiProvFuncRole': 'AEF'\n", + " }\n", + " l.append(aef_entry)\n", + " apf_csr_request, apf_private_key = generate_csr(\"APF\", \"ETSI\", \"Fr\")\n", + " apf_entry = {\n", + " 'regInfo': {\n", + " 'apiProvPubKey': apf_csr_request.decode(\"utf-8\")\n", + " },\n", + " 'apiProvFuncRole': 'APF'\n", + " }\n", + " l.append(apf_entry)\n", + " # Build the request body\n", + " data = {\n", + " 'apiProvFuncs': l,\n", + " 'apiProvDomInfo': p_name,\n", + " 'suppFeat': 'fff',\n", + " 'failReason': 'string',\n", + " 'regSec': p_access_token\n", + " }\n", + " logger.debug('onboard_provider (step2): body: ' + str(data))\n", + " response = requests.post(url, headers=headers, data=json.dumps(data), verify=False)\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('onboard_provider (step3): result: ' + str(response.json()))\n", + " if response.status_code != 201:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return dict()\n", + " res = json.loads(response.text)\n", + " # Add an entry for CSRs and private keys for future usage\n", + " res['csr'] = {\n", + " 'amf': [amf_csr_request, amf_private_key],\n", + " 'aef': [aef_csr_request, aef_private_key],\n", + " 'apf': [apf_csr_request, apf_private_key]\n", + " }\n", + " return res\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"onboard_provider failed: {e}\")\n", + "\n", + " return dict()\n", + " # End of function onboard_provider" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yP6ZytijFxKG" + }, + "source": [ + "### Offboard the API provider\n", + "\n", + "The purpose is to offboard the API provider from the CAPIF server. Here, the certificate and the private key of the AMF endpoint are required (TLS mutual authentication)." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "rbpNr26tF2gr" + }, + "outputs": [], + "source": [ + "def offboard_provider(p_api_provider_id: str, p_bundle: tuple) -> list:\n", + " \"\"\"\n", + " To offboard the API provider.\n", + " :param p_api_provider_id: The identifier of the API provider\n", + " :param p_bundle: The bundle of certificates and keys for the TLS mutual authentication operations\n", + " :return: A list containing the files created for the TLS mutual authentication operations on success, or an empty list otherwise\n", + " \"\"\"\n", + " global logger, ccf_api_onboarding_url, ca_root\n", + "\n", + " logger.debug('>>> offboard_provider')\n", + "\n", + " try:\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_api_onboarding_url + '/' + p_api_provider_id\n", + " logger.debug('offboard_provider: url=' + url)\n", + " headers = {'Content-Type': 'application/json'}\n", + " logger.debug('offboard_provider (step1): headers: ' + str(headers))\n", + " bundle = store_certificate_2_files(p_bundle[0], p_bundle[1], ca_root) # Use CA certificate for verif\n", + " if len(bundle) != 3:\n", + " logger.error(f\"Error converting in-memory bundle into files\")\n", + " return []\n", + " logger.debug('offboard_provider (step2): bundle: ' + str(bundle))\n", + " response = requests.delete(url, headers=headers, cert=(bundle[0], bundle[1]), verify=bundle[2])\n", + " logger.debug('offboard_provider (step3): response=' + str(response))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " if response.status_code != 204:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return []\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"offboard_provider failed: {e}\")\n", + " return []\n", + "\n", + " return bundle\n", + " # End of function offboard_provider\n", + "\n", + "def store_certificate_2_files(p_certificate, p_private_key, p_ca_root) -> list:\n", + " \"\"\"\n", + " Save certificate and key into files\n", + " :param p_certificate:\n", + " :param p_private_key:\n", + " :param p_ca_root:\n", + " :return: A list of file paths on success, an empty list otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> store_certificate_2_files')\n", + " try:\n", + " with open(\"p_crt.crt\", \"w\") as f:\n", + " f.write(p_certificate)\n", + " with open(\"p_key.key\", \"w\") as f:\n", + " f.write(p_private_key.decode('utf-8'))\n", + " with open(\"ca_root.pem\", \"w\") as f:\n", + " f.write(p_ca_root)\n", + " return [\"p_crt.crt\", \"p_key.key\", \"ca_root.pem\"]\n", + " except Exception as e:\n", + " logger.error(f\"An error occurred: {e}\")\n", + "\n", + " return []\n", + " # End of function store_certificate_2_files\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wmvJSK8I13XD" + }, + "source": [ + "### Putting everything together\n", + "\n", + "Now, it is time now to create the our third iteration of our CAPIF/MEC application. Here the logic is:\n", + "\n", + "- Login\n", + "- Create the user\n", + "- Get the information to use CAPIF (security materials & URLs)\n", + "- Onboard the provider\n", + "- Print certificates for each function\n", + "- Delete the user\n", + "- Logout\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "id": "EDcPUuNEM26H" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the third sprint of our CAPIF/MEC application:\n", + " - Login\n", + " - Print obtained tokens\n", + " - Create a new user\n", + " - Get the information to use CAPIF (security materials & URLs)\n", + " - Onboard the provider\n", + " - Print certificates for each function\n", + " - Delete the newly created user\n", + " - Logout\n", + " \"\"\"\n", + " global logger, ca_root, ccf_api_onboarding_url, ccf_publish_url, ccf_discover_url, ccf_security_url, ccf_onboarding_url\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Login\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " return\n", + "\n", + " # Create a new user\n", + " user_name, user_uuid = create_user(admin_token)\n", + " if len(user_uuid) == 0:\n", + " return\n", + "\n", + " auth = get_auth(user_name, USER_PASSWORD)\n", + " if len(auth) == 0:\n", + " return\n", + "\n", + " # Set the CAPIF access information\n", + " access_token = auth['access_token']\n", + " ca_root = auth['ca_root']\n", + " ccf_api_onboarding_url = auth['ccf_api_onboarding_url']\n", + " ccf_discover_url = auth['ccf_discover_url']\n", + " ccf_onboarding_url = auth['ccf_onboarding_url']\n", + " ccf_publish_url = auth['ccf_publish_url']\n", + " ccf_security_url = auth['ccf_security_url']\n", + " logger.debug(\"ccf_api_onboarding_url:\" + ccf_api_onboarding_url)\n", + " logger.debug(\"ccf_discover_url:\" + ccf_discover_url)\n", + " logger.debug(\"ccf_publish_url:\" + ccf_publish_url)\n", + " logger.debug(\"ccf_security_url:\" + ccf_security_url)\n", + "\n", + " # Onboard the provider\n", + " prov = onboard_provider(\"MECSandbox_to_CAPIF_Provider\", access_token)\n", + " if len(prov) == 0:\n", + " return\n", + "\n", + " # Print certificates for each function\n", + " logger.debug(\"API Provider Id:\" + prov['apiProvDomId'])\n", + " logger.debug(\"AMF: \" + prov['apiProvFuncs'][0]['regInfo']['apiProvCert'])\n", + " logger.debug(\"AEF: \" + prov['apiProvFuncs'][1]['regInfo']['apiProvCert'])\n", + " logger.debug(\"APF: \" + prov['apiProvFuncs'][2]['regInfo']['apiProvCert'])\n", + " logger.debug(\"csr: \" + str(prov['csr']))\n", + "\n", + " time.sleep(5) # Sleep for 5 seconds\n", + "\n", + " # Offboard the API profider\n", + " certs_bundle = (prov['apiProvFuncs'][0]['regInfo']['apiProvCert'], prov['csr']['amf'][1]) # Use AMF certificate and AMF private key\n", + " file_bundle = offboard_provider(prov['apiProvDomId'], certs_bundle)\n", + " if len(file_bundle) == 0:\n", + " for file in file_bundle:\n", + " os.remove(file)\n", + "\n", + " # Delete the newly created user\n", + " delete_user(user_uuid, admin_token)\n", + "\n", + " # Logout\n", + " process_logout()\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0wHI1ooMbCy3" + }, + "source": [ + "## Using ETSI MEC profile for CAPIF\n", + "\n", + "The purpose is to export the MEC Profile for CAPIF API into our CAPIF application. To achieve it, we need to fulfill the following requirements:\n", + "1. Create an instance of a MEC Sandbox using the '4g-5g-macri-v2x' network scenario\n", + "2. Set TRY_MEC_URL, TRY_MEC_SESSION_ID, TRY_MEC_PLTF constants accordingly\n", + "3. Build the ServiceAPIDescription as described in ETSI TS 129 222 V18.6.0 (2022-06) Table 8.2.4.2.2-1: Definition of type ServiceAPIDescription. This is the role of the function below" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "id": "S7InJDD1_g-v" + }, + "outputs": [], + "source": [ + "def build_publish_api_from_mec_services(p_aefId: str) -> dict:\n", + " \"\"\"\n", + " This function builds the Publish API request body data structure which will be used todo the request for publish API\n", + " :param p_aefId: The AEF ID\n", + " :return The request body data structure on success, an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger, TRY_MEC_URL, TRY_MEC_SESSION_ID, TRY_MEC_PLTF\n", + "\n", + " logger.debug('>>> build_publish_api_from_mec_services: p_aefId=' + p_aefId)\n", + "\n", + " # Sanity checks\n", + " if len(p_aefId) == 0:\n", + " logger.error('build_publish_api_from_mec_services: p_aefId is empty')\n", + " return dict()\n", + "\n", + " # Build the service-apis data structure\n", + " publish_api_req_body = {\n", + " \"apiName\": \"MEC Profile for CAPIF\",\n", + " \"aefProfiles\": [\n", + " {\n", + " \"aefId\": p_aefId,\n", + " \"versions\": [\n", + " {\n", + " \"apiVersion\": \"v1\",\n", + " \"expiry\": \"2025-11-30T10:32:02.004Z\",\n", + " \"resources\": [\n", + " {\n", + " \"resourceName\": \"MEC Profile of CAPIF\",\n", + " \"commType\": \"REQUEST_RESPONSE\",\n", + " \"uri\": f\"/{TRY_MEC_SESSION_ID}/{TRY_MEC_PLTF}/service-apis/v1/allServiceAPIs\",\n", + " \"custOpName\": \"string\",\n", + " \"operations\": [\n", + " \"GET\"\n", + " ],\n", + " \"description\": \"Endpoint to access MEC services\"\n", + " }\n", + " ],\n", + " \"custOperations\": [\n", + " {\n", + " \"commType\": \"REQUEST_RESPONSE\",\n", + " \"custOpName\": \"string\",\n", + " \"operations\": [\n", + " \"GET\"\n", + " ],\n", + " \"description\": \"string\"\n", + " }\n", + " ]\n", + " }\n", + " ],\n", + " \"protocol\": \"HTTP_1_1\",\n", + " \"dataFormat\": \"JSON\",\n", + " \"securityMethods\": [\"OAUTH\"],\n", + " \"interfaceDescriptions\": [\n", + " {\n", + " \"ipv4Addr\": TRY_MEC_URL,\n", + " \"securityMethods\": [\"OAUTH\"]\n", + " }\n", + " ]\n", + " }\n", + " ],\n", + " \"description\": \"MEC Profile of CAPIF\",\n", + " \"supportedFeatures\": \"fffff\",\n", + " \"shareableInfo\": {\n", + " \"isShareable\": True,\n", + " \"capifProvDoms\": [\n", + " \"string\"\n", + " ]\n", + " },\n", + " \"serviceAPICategory\": \"string\",\n", + " \"apiSuppFeats\": \"fffff\",\n", + " \"pubApiPath\": {\n", + " \"ccfIds\": [\n", + " \"string\"\n", + " ]\n", + " },\n", + " \"ccfId\": \"string\",\n", + " \"apiStatus\":{\n", + " \"aefIds\": [\n", + " p_aefId\n", + " ]\n", + " }\n", + " }\n", + "\n", + " logger.debug('<<< build_publish_api_from_mec_services: ' + str(publish_api_req_body))\n", + " return publish_api_req_body\n", + " # End of build_publish_api_from_mec_services function" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PRAie110_r8P" + }, + "source": [ + "Having built the ServiceAPIDescription data structure, the next step is to implement the CAPIF publish API.\n", + "\n", + "To proceed, we need to enable the TLS mutual authentication using the security material obtained during the onboarding APIs operation ([Onboarding APIs](#onboarding_apis)), i.e. the AEF certificate and the AEF private key ([Generate certificates](#Generate_certificates)).\n", + "\n", + "\n", + "**Refer to:** ETSI TS 129 222 V18.6.0 (2022-06) Clauses 5.3 CAPIF_Publish_Service_API and 8.2 CAPIF_Publish_Service_API\n", + "\n", + "Before to proceed with the steps above, let's create 2 helper functions to simpily the implemantation of the CAPIF publish API. These helper functions cover the following operations:\n", + "- Onboarding operations\n", + "- Offboarding operations" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IreHiSXs2U65" + }, + "source": [ + "#### Onboarding operations\n", + "\n", + "The Onboarding operations include th following steps:\n", + "- login\n", + "- create a new user\n", + "- Get the information to use CAPIF (security materials & URLs)\n", + "- onboard the provider\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "id": "nu-tEA6n2TpI" + }, + "outputs": [], + "source": [ + "def onboarding_provider() -> dict:\n", + " \"\"\"\n", + " To onboard the provider using CAPIF endpoint. It includes:\n", + " - login\n", + " - create a new user\n", + " - Get the information to use CAPIF (security materials & URLs)\n", + " - onboard the provider\n", + " :return: A dictionary containing security material and additional context information on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger, ca_root, ccf_api_onboarding_url, ccf_publish_url, ccf_discover_url, ccf_security_url, ccf_onboarding_url\n", + "\n", + " # Login\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " return dict()\n", + "\n", + " # Create a new user\n", + " user_name, user_uuid = create_user(admin_token)\n", + " if len(user_uuid) == 0:\n", + " return dict()\n", + "\n", + " auth = get_auth(user_name, USER_PASSWORD)\n", + " if len(auth) == 0:\n", + " return dict()\n", + "\n", + " # Set the CAPIF access information\n", + " access_token = auth['access_token']\n", + " ca_root = auth['ca_root']\n", + " ccf_api_onboarding_url = auth['ccf_api_onboarding_url']\n", + " ccf_discover_url = auth['ccf_discover_url']\n", + " ccf_onboarding_url = auth['ccf_onboarding_url']\n", + " ccf_publish_url = auth['ccf_publish_url']\n", + " ccf_security_url = auth['ccf_security_url']\n", + "\n", + " # Onboard the provider\n", + " prov = onboard_provider(\"MECSandbox_to_CAPIF_Provider\", access_token)\n", + " if len(prov) == 0:\n", + " return dict()\n", + "\n", + " # Add context data\n", + " prov['refresh_token'] = refresh_token\n", + " prov['admin_token'] = admin_token\n", + " prov['user_uuid'] = user_uuid\n", + " prov['access_token'] = access_token\n", + "\n", + " return prov\n", + " # End of onboarding_provider function" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e940bUcf2deu" + }, + "source": [ + "#### Offboarding operations\n", + "\n", + "The Offboarding operations include th following steps:\n", + "- Offboard the API provide\n", + "- Delete the user\n", + "- Logout\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "id": "hEnFLfPI2hms" + }, + "outputs": [], + "source": [ + "def offboarding_provider(p_user_uuid: str, p_api_provider_id: str, p_bundle: tuple, p_admin_token: str) -> int:\n", + " \"\"\"\n", + " To offboard the provider. It includes:\n", + " - Offboard the API provider\n", + " - Delete the user\n", + " - Logout\n", + " :return: 0 on success, or -1 otherwise\n", + " \"\"\"\n", + " global logger, ccf_api_onboarding_url, access_token\n", + "\n", + " logger.debug('>>> offboarding_provider: ' + p_user_uuid)\n", + "\n", + " # Offboard the API profider\n", + " file_bundle = offboard_provider(p_api_provider_id, p_bundle)\n", + " if len(file_bundle) == 0: # Remove cert files if any\n", + " for file in file_bundle:\n", + " os.remove(file)\n", + "\n", + " # Delete the newly created user\n", + " delete_user(p_user_uuid, p_admin_token)\n", + "\n", + " # Logout\n", + " process_logout()\n", + "\n", + " return 0\n", + " # End of offboarding_provider function" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9TSYztWMcaOA" + }, + "source": [ + "#### Publish CAPIF API function\n", + "\n", + "As mentionned above , the prupose of this function is to publish an API, using the TLS mutual authentication. To do so, we need the APF certificate (public keys) and its private key for the signature and the encription processes, and the CA certificate for the verification of the peer certifcate.\n", + "\n", + "**Note**: The http.request function required taht the cerficates and the keys are stored on files, not in memory. So, when our CAPIF applicate terminates, these files shall be removed (freeing resource step). This is the reason the publish_capif_api() function return a tuple containing the files created for the TLS mutual authentication operation.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "z_Cwazjl_xGJ" + }, + "outputs": [], + "source": [ + "def publish_capif_api(p_apfId: str, p_body: dict, p_bundle: tuple) -> list:\n", + " \"\"\"\n", + " This function is to publish an API on CAPIF server\n", + " :param p_apfId: The APF identifier\n", + " :param p_body: The request body\n", + " :param p_bundle: The bundle of certificates and keys for the TLS mutual authentication operations\n", + " :return: A list containing the files created for the TLS mutual authentication operations on success, or an empty list otherwise\n", + " \"\"\"\n", + " global logger, ccf_publish_url, ca_root\n", + "\n", + " logger.debug('>>> publish_capif_api')\n", + "\n", + " # Sanity checks\n", + " if len(p_bundle) != 2:\n", + " logger.error('publish_capif_api: p_bundle is malformed')\n", + " return []\n", + "\n", + " try:\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_publish_url.replace('<apfId>', p_apfId)\n", + " logger.debug('publish_capif_api: url=' + url)\n", + " headers = {'Content-Type': 'application/json'}\n", + " logger.debug('publish_capif_api (step1): headers: ' + str(headers))\n", + " logger.debug('publish_capif_api (step2): body: ' + str(p_body))\n", + " bundle = store_certificate_2_files(p_bundle[0], p_bundle[1], ca_root) # Use CA certificate for verif\n", + " if len(bundle) != 3:\n", + " logger.error(f\"Error converting in-memory bundle into files\")\n", + " return []\n", + " logger.debug('publish_capif_api (step3): bundle: ' + str(bundle))\n", + " response = requests.post(url, headers=headers, data=json.dumps(p_body), cert=(bundle[0], bundle[1]), verify=bundle[2])\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('publish_capif_api (step4): result: ' + str(response.json()))\n", + " if response.status_code != 201:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return []\n", + " res = json.loads(response.text)\n", + " logger.debug('publish_capif_api (step5): res: ' + str(res))\n", + " api_id = res['apiId']\n", + " return bundle\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"publish_capif_api failed: {e}\")\n", + "\n", + " return []\n", + " # End of function publish_capif_api\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-TzvBVLM1fIc" + }, + "source": [ + "### Putting everything together\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "CRtfJ6cm3V6b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the fourth sprint of our CAPIF/MEC application:\n", + " - Onboarding operations\n", + " - Offboarding operations\n", + " \"\"\"\n", + " global logger, ca_root\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " prov = onboarding_provider()\n", + " if len(prov) == 0:\n", + " return\n", + " user_uuid = prov['user_uuid']\n", + "\n", + " # Build the publish_api body request\n", + " aefId = prov['apiProvFuncs'][1]['apiProvFuncId']\n", + " apfId = prov['apiProvFuncs'][2]['apiProvFuncId']\n", + " publish_api_req_body = build_publish_api_from_mec_services(aefId)\n", + " if len(publish_api_req_body) == 0:\n", + " offboarding_provider(user_uuid, prov['apiProvDomId'], (prov['apiProvFuncs'][0]['regInfo']['apiProvCert'], prov['csr']['amf'][1]), prov['admin_token']) # Use AMF certificate and AMF private key\n", + " return\n", + " logger.debug(\"publish_api_req_body: \" + str(publish_api_req_body))\n", + " certs_bundle = (prov['apiProvFuncs'][2]['regInfo']['apiProvCert'], prov['csr']['apf'][1]) # Use APF certificate and APF private key\n", + "\n", + " # Publish the APIs\n", + " #ipdb.set_trace()\n", + " files_bundle = publish_capif_api(apfId, publish_api_req_body, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + " offboarding_provider(user_uuid, prov['apiProvDomId'], (prov['apiProvFuncs'][0]['regInfo']['apiProvCert'], prov['csr']['amf'][1]), prov['admin_token']) # Use AMF certificate and AMF private key\n", + " return\n", + "\n", + " # Terminate the application\n", + " offboarding_provider(\n", + " user_uuid,\n", + " prov['apiProvDomId'],\n", + " (prov['apiProvFuncs'][0]['regInfo']['apiProvCert'], prov['csr']['amf'][1]), # Use AMF certificate and AMF private key\n", + " prov['admin_token']\n", + " )\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aABBc4Hizy88" + }, + "source": [ + "## Build an helper function to publish the ETSI MEC profile for CAPIF API\n", + "\n", + "To simply the API invoker process, let's create two helpers functions:\n", + "- One to publish the ETSI MEC profile for CAPIF API\n", + "- One to remove the previously published API" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r-gZe6mQ4yHH" + }, + "source": [ + "### Helper to publish API" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "ozCMG8jh0UMd" + }, + "outputs": [], + "source": [ + "def publish_api() -> tuple:\n", + " \"\"\"\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> publish_api')\n", + "\n", + " prov = onboarding_provider()\n", + " if len(prov) == 0:\n", + " return ()\n", + " amf_cert_bundle = (prov['apiProvFuncs'][0]['regInfo']['apiProvCert'], prov['csr']['amf'][1]) # Use AMF certificate and AMF private key\n", + "\n", + " # Build the publish_api body request\n", + " aefId = prov['apiProvFuncs'][1]['apiProvFuncId']\n", + " apfId = prov['apiProvFuncs'][2]['apiProvFuncId']\n", + " apiId = prov['apiProvDomId']\n", + " publish_api_req_body = build_publish_api_from_mec_services(aefId)\n", + " if len(publish_api_req_body) == 0:\n", + " offboarding_provider(prov['user_uuid'], apiId, amf_cert_bundle, prov['admin_token'])\n", + " return ()\n", + " logger.debug(\"publish_api_req_body: \" + str(publish_api_req_body))\n", + " certs_bundle = (prov['apiProvFuncs'][2]['regInfo']['apiProvCert'], prov['csr']['apf'][1]) # Use APF certificate and APF private key\n", + "\n", + " # Publish the APIs\n", + " files_bundle = publish_capif_api(apfId, publish_api_req_body, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + " offboarding_provider(prov['user_uuid'], apiId, amf_cert_bundle, prov['admin_token']) # Use AMF certificate and AMF private key\n", + " return ()\n", + "\n", + " logger.debug('publish_api: ' + str((apiId, amf_cert_bundle)))\n", + " return (apiId, amf_cert_bundle, prov['user_uuid'], prov['admin_token'])\n", + " # End of function publish_api\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lrnfAlrZ1-TB" + }, + "source": [ + "### Helper to remove published API" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "Ql9dC3P41_nO" + }, + "outputs": [], + "source": [ + "def remove_publish_api(p_user_uuid: str, p_api_id: str, p_bundle: tuple, p_admin_token: str):\n", + " \"\"\"\n", + " To remove published API.\n", + " :param p_user_uuid: The user identifier\n", + " :param p_api_id: The API identifier\n", + " :param p_bundle: The bundle of certificates and keys for the TLS mutual authentication operations\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> remove_publish_api ')\n", + "\n", + " # Terminate the application\n", + " offboarding_provider(p_user_uuid, p_api_id, p_bundle, p_admin_token)\n", + "\n", + " return\n", + " # End of function reove_publish_api\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UNN73-Zg4WZ-" + }, + "source": [ + "### Putting everything together\n", + "\n", + "Let's test these two helpers functions before to go ahead" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "bVYS13iV4-s8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " To test both helpers functions:\n", + " - publish_api\n", + " - remove_publish_api\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Publish the MEC profile for CAPIF API\n", + " res = publish_api()\n", + " if len(res) == 0:\n", + " return\n", + "\n", + " api_id, bundle, user_uuid, admin_token = res\n", + "\n", + " time.sleep(5) # Sleep for 5 seconds\n", + "\n", + " # Remove the MEC profile for CAPIF API\n", + " remove_publish_api(user_uuid, api_id, bundle, admin_token)\n", + "\n", + " logger.debug('Stopped at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " # End of function process_main\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9W2SvVdx6fxk" + }, + "source": [ + "## Using the published API: The CAPIF Invoker side\n", + "\n", + "Now that we are able to publish an API on the CAPIF server, the next step is to use it in order to invoke some MEC Services API. To achieve this goal, we have to implement the CAPI Invoker, following these steps:\n", + "- Onboard an API invoker\n", + "- Discover the published APIs\n", + "- Get a MEC Service API (this step requires that a MEC Sandox platform is already running)\n", + "- Offboard an API invoker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YasCvixW7E4o" + }, + "source": [ + "### Onboard an API invoker\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "id": "f11_uMS67I9J" + }, + "outputs": [], + "source": [ + "def onboard_invoker(p_name: str, p_access_token: str) -> dict:\n", + " \"\"\"\n", + " To onboard the API invoker.\n", + " :param p_name: The name of the invoker\n", + " :return: A dictionary containing security material for each CAPIF endpoint on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger, ccf_api_onboarding_url, ccf_onboarding_url\n", + "\n", + " logger.debug('>>> onboard_invoker: ' + p_name)\n", + " logger.debug('>>> onboard_invoker: ' + p_access_token)\n", + "\n", + " try:\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_onboarding_url\n", + " logger.debug('onboard_invoker: url=' + url)\n", + " headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + p_access_token}\n", + " logger.debug('onboard_invoker (step1): headers: ' + str(headers))\n", + " # Request body for onboarding the invoker\n", + " invoker_csr_request, invoker_private_key = generate_csr(\"API Invoker\", \"ETSI\", \"Fr\")\n", + " data = {\n", + " \"notificationDestination\" : \"http://host.docker.internal:8086/netapp_callback\",\n", + " \"supportedFeatures\" : \"fffffff\",\n", + " \"apiInvokerInformation\" : \"dummy\",\n", + " \"websockNotifConfig\" : {\n", + " \"requestWebsocketUri\" : True,\n", + " \"websocketUri\" : \"websocketUri\"\n", + " },\n", + " \"onboardingInformation\" : {\n", + " \"apiInvokerPublicKey\" : invoker_csr_request.decode(\"utf-8\"),\n", + " },\n", + " \"requestTestNotification\" : True\n", + " }\n", + " logger.debug('onboard_invoker (step2): body: ' + str(data))\n", + " response = requests.post(url, headers=headers, data=json.dumps(data), verify=\"ca_root.pem\")\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('onboard_invoker (step3): result: ' + str(response.json()))\n", + " if response.status_code != 201:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return dict()\n", + " res = json.loads(response.text)\n", + " # Add an entry for CSRs and private keys for future usage\n", + " res['csr'] = [invoker_csr_request, invoker_private_key]\n", + " return res\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"onboard_invoker failed: {e}\")\n", + "\n", + " return dict()\n", + " # End of function onboard_invoker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kQmJW-d99cGo" + }, + "source": [ + "### Offboard an API invoker" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "id": "KRC_xkGO9hEY" + }, + "outputs": [], + "source": [ + "def offboard_invoker(p_invoker_id: str, p_bundle: tuple) -> list:\n", + " \"\"\"\n", + " To offboard the API invoker.\n", + " :param p_invoker_id: The API invoker identifier\n", + " :param p_bundle: The bundle of certificates and keys for the TLS mutual authentication operations\n", + " :return: 0 on success, -1 otherwise\n", + " \"\"\"\n", + " global logger, ccf_onboarding_url, ca_root\n", + "\n", + " logger.debug('>>> offboard_invoker: ' + p_invoker_id)\n", + "\n", + " try:\n", + " # Delete the newly created user\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_onboarding_url + '/' + p_invoker_id\n", + " logger.debug('offboard_invoker: url=' + url)\n", + " headers = {'Content-Type': 'application/json'}\n", + " logger.debug('offboard_invoker (step1): headers: ' + str(headers))\n", + " bundle = store_certificate_2_files(p_bundle[0], p_bundle[1], ca_root) # Use CA certificate for verif\n", + " if len(bundle) != 3:\n", + " logger.error(f\"Error converting in-memory bundle into files\")\n", + " return []\n", + " logger.debug('offboard_invoker (step2): bundle: ' + str(bundle))\n", + " response = requests.delete(url, headers=headers, cert=(bundle[0], bundle[1]), verify=bundle[2])\n", + " logger.debug('offboard_invoker (step3): response=' + str(response))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " if response.status_code != 204:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return []\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"offboard_invoker failed: {e}\")\n", + " return []\n", + "\n", + " return bundle\n", + " # End of function offboard_invoker" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-h0zz7ocxtyv" + }, + "source": [ + "### Discover published APIs" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "id": "ofUuploUxuhn" + }, + "outputs": [], + "source": [ + "def discover(p_invoker_id: str, p_bundle: tuple, p_access_token: str) -> dict:\n", + " \"\"\"\n", + " To discover the APIs published by capif core.\n", + " :param p_invoker_id: The API invoker identifier\n", + " :return: A dictionary containing the APIs published by capif core on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger, ca_root, ccf_discover_url\n", + "\n", + " logger.debug('>>> Discover APIs published by capif core')\n", + "\n", + " try:\n", + " url = 'https://' + CAPIF_HOSTNAME + ':' + str(CAPIF_PORT) + '/' + ccf_discover_url + p_invoker_id\n", + " logger.debug('Discover: url=' + url)\n", + " headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + p_access_token}\n", + " logger.debug('Discover (step1): headers: ' + str(headers))\n", + " bundle = store_certificate_2_files(p_bundle[0], p_bundle[1], ca_root) # Use CA certificate for verif\n", + " if len(bundle) != 3:\n", + " logger.error(f\"Error converting in-memory bundle into files\")\n", + " return dict()\n", + " logger.debug('Discover (step2): bundle: ' + str(bundle))\n", + " response = requests.get(url, headers=headers, cert=(bundle[0], bundle[1]), verify=bundle[2])\n", + " logger.debug('Discover (step3): response=' + str(response))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " logger.debug('Discover : result: ' + str(response.json()))\n", + " if response.status_code != 200:\n", + " logger.error(f\"Discovery failed: {response.status_code} - {response.text}\")\n", + " return dict()\n", + " res = json.loads(response.text)\n", + " return res\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"Discovery failed: {e}\")\n", + "\n", + " return dict()\n", + " # End of function discover\n", + "\n", + "def extract_ipv4_and_uri(p_response_data: json.loads) -> dict:\n", + " # Extract ipv4Addr using a list comprehension\n", + " ipv4_addrs = [\n", + " desc.get(\"ipv4Addr\")\n", + " for profile in p_response_data.get(\"serviceAPIDescriptions\", [])\n", + " for aef in profile.get(\"aefProfiles\", [])\n", + " for desc in aef.get(\"interfaceDescriptions\", [])\n", + " ]\n", + "\n", + " # Extract uri using a list comprehension\n", + " uris = [\n", + " resource.get(\"uri\")\n", + " for profile in p_response_data.get(\"serviceAPIDescriptions\", [])\n", + " for aef in profile.get(\"aefProfiles\", [])\n", + " for version in aef.get(\"versions\", [])\n", + " for resource in version.get(\"resources\", [])\n", + " ]\n", + "\n", + " return {\"ipv4Addr\": ipv4_addrs, \"uri\": uris}\n", + " # End of function extract_ipv4_and_uri" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RElS9XFZ9hvQ" + }, + "source": [ + "### Putting everything together" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "QPZPYJZM9mNr" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "skipping\n" + ] + } + ], + "source": [ + "%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the fiveth sprint of our CAPIF/MEC application:\n", + " - Publish the MEC profile for CAPIF API\n", + " - Create a new user for the invoker\n", + " - Get certificates\n", + " - Onboad the API invoker\n", + " - Do the discovery\n", + " - Offboard the API invoker\n", + " - Delete the\n", + " - Logout the invoker user\n", + " - Remove the MEC profile for CAPIF API\n", + " \"\"\"\n", + " global logger, ca_root, ccf_api_onboarding_url, ccf_discover_url, ccf_onboarding_url, ccf_publish_url, ccf_security_url\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Publish the MEC profile for CAPIF API\n", + " res = publish_api()\n", + " if len(res) == 0:\n", + " return\n", + " api_id, bundle, prov_user_uuid, prov_admin_token = res\n", + "\n", + " # Login for the new user for the invoker\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Create a new user for the invoker\n", + " res = create_user(admin_token)\n", + " if len(res) == 0:\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + " user_name, user_uuid = res\n", + "\n", + " # Get certificates\n", + " auth = get_auth(user_name, USER_PASSWORD)\n", + " if len(auth) == 0:\n", + " delete_user(user_name, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Sanity checks\n", + " if auth['ca_root'] != ca_root:\n", + " raise Exception('CA root mismatch')\n", + " if auth['ccf_api_onboarding_url'] != ccf_api_onboarding_url:\n", + " raise Exception('CCF API onboarding URL mismatch')\n", + " if auth['ccf_discover_url'] != ccf_discover_url:\n", + " raise Exception('CCF discover URL mismatch')\n", + " if auth['ccf_onboarding_url'] != ccf_onboarding_url:\n", + " raise Exception('CCF onboarding URL mismatch')\n", + " if auth['ccf_publish_url'] != ccf_publish_url:\n", + " raise Exception('CCF publish URL mismatch')\n", + " if auth['ccf_security_url'] != ccf_security_url:\n", + " raise Exception('CCF security URL mismatch')\n", + " access_token = auth['access_token']\n", + "\n", + " # Onboad the API invoker\n", + " res = onboard_invoker('API Invoker', access_token)\n", + " if len(res) == 0:\n", + " delete_user(user_uuid, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Do the discovery\n", + " invoker_id = res['apiInvokerId']\n", + " certs_bundle = (res['onboardingInformation']['apiInvokerCertificate'], res['csr'][1])\n", + " mec_api = discover(invoker_id, certs_bundle, access_token)\n", + " if len(mec_api) == 0:\n", + " files_bundle = offboard_invoker(invoker_id, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + " delete_user(user_uuid, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Extract the URL to access to the MEC Sandbox platform\n", + " addrs = extract_ipv4_and_uri(mec_api)\n", + " logger.debug('addrs: ' + str(addrs))\n", + "\n", + " time.sleep(5) # Sleep for 5 seconds\n", + "\n", + " # Offboard the API invoker\n", + " files_bundle = offboard_invoker(invoker_id, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + "\n", + " # Delete the invoker user\n", + " delete_user(user_uuid, admin_token)\n", + "\n", + " # Logout the invoker user\n", + " process_logout()\n", + "\n", + " # Remove the MEC profile for CAPIF API\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6tJWDz4woyz1" + }, + "source": [ + "## Discoverig MEC services\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Uy-XNKA9pN5h" + }, + "source": [ + "### Invoking the MEC profile for CAPIF\n", + "\n", + "After discovering the published API, we have the information (see content of addrs data structure in previous execution) to do a request to an existing MEC Sandbox platform to get the list of the MEC services exposed (see TRY_MEC_SESSION_ID)." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "id": "ZL8Gyo0Ao2_u" + }, + "outputs": [], + "source": [ + "def discovering_mec_services(p_url: str) -> dict:\n", + " \"\"\"\n", + " To discover MEC services API\n", + " :param p_url: The URL to access to the MEC Sandbox platform\n", + " :return: A dictionary containing the MEC services on success, or an empty dictionary otherwise\n", + " \"\"\"\n", + " global logger\n", + "\n", + " logger.debug('>>> discovering_mec_services: ' + p_url)\n", + "\n", + " try:\n", + " headers = {'Content-Type': 'application/json', 'accept': 'application/json',}\n", + " logger.debug('discovering_mec_services (step1): headers: ' + str(headers))\n", + " response = requests.get(p_url, headers=headers)\n", + " logger.debug('discovering_mec_services (step2): result: ' + str(response.json()))\n", + " response.raise_for_status() # Raise an exception for bad status codes\n", + " if response.status_code != 200:\n", + " logger.error(f\"Error creating user: {response.status_code} - {response.text}\")\n", + " return dict()\n", + " res = json.loads(response.text)\n", + " return res\n", + " except requests.exceptions.RequestException as e:\n", + " logger.error(f\"discovering_mec_services failed: {e}\")\n", + "\n", + " return dict()\n", + " # End of function discovering_mec_services" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wa_8khiGpTAa" + }, + "source": [ + "### Putting everything together\n", + "\n", + "Here is the last and complete version of our CAPIF application achieving the main objective of this tutorial: __Retrieve the MEC services exposed by an existing MEC Sandbox platform.__\n", + "\n", + "The process involves following steps:\n", + "- Create new User (API Provider)\n", + "- Onboard API Provider\n", + "- Publish MEC APIs on CCF\n", + "- Create new User (API Invoker)\n", + "- Onboard API Invoker\n", + "- Discovery of APIs by API Invoker\n", + "- Request Discovered API (Get MEC Services)\n", + "- Offboard API Invoker/API Provider\n", + "- Delete Users" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "id": "aTllbmoUpXKx", + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-03-14 06:31:39,150 - __main__ - DEBUG - Starting at 20250314-063139\n", + "2025-03-14 06:31:39,151 - __main__ - DEBUG - \t pwd= /home/jovyan/work/notebook\n", + "2025-03-14 06:31:39,152 - __main__ - DEBUG - >>> publish_api\n", + "2025-03-14 06:31:39,153 - __main__ - DEBUG - >>> process_login\n", + "2025-03-14 06:31:39,154 - __main__ - DEBUG - process_login: url=https://lab-oai.etsi.org:31120/login\n", + "2025-03-14 06:31:39,154 - __main__ - DEBUG - process_login (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Basic YWRtaW46cGFzc3dvcmQxMjM='}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,208 - __main__ - DEBUG - process_login (step2): result: {'access_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQxOTM0NDk5fQ.wNjsuLgh61j0G_6rtN6vxqfbJGMgtaetJd1xPUOoBb4', 'refresh_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQ0NTI1ODk5fQ.lgD4IZCAVJ3-smu1nFBjTtdhTW_trraua1OppvQd4rc'}\n", + "2025-03-14 06:31:39,209 - __main__ - DEBUG - >>> create_user\n", + "2025-03-14 06:31:39,210 - __main__ - DEBUG - create_user: url=https://lab-oai.etsi.org:31120/createUser\n", + "2025-03-14 06:31:39,210 - __main__ - DEBUG - create_user (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQxOTM0NDk5fQ.wNjsuLgh61j0G_6rtN6vxqfbJGMgtaetJd1xPUOoBb4'}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,245 - __main__ - DEBUG - create_user (step2): response=<Response [201]>\n", + "2025-03-14 06:31:39,246 - __main__ - DEBUG - >>> get_auth\n", + "2025-03-14 06:31:39,247 - __main__ - DEBUG - get_auth: url=https://lab-oai.etsi.org:31120/getauth\n", + "2025-03-14 06:31:39,247 - __main__ - DEBUG - get_auth (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Basic ZmM1OWU4YWUtMDA5ZC0xMWYwLWI3MDYtMDI0MmFjMTEwMDAyOnBhc3N3b3JkMTIz'}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,331 - __main__ - DEBUG - get_auth (step2): result: {'access_token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiYjI0N2YyNzQtMDIxMC00ZDY4LTgwYzktMTAxNjliNTdiNzcyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjNTllOGFlLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA1ODg3NzE2YS0zNWVmLTVmOTktYmQ5NC0zOGQxZmEzZDAzMTciLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiJjNzNjNDJkYy0zOTJhLTQzNzQtOTQyNS1hODY0OTIzNjE1OTciLCJleHAiOjE3NDE5MzQ3OTl9.cQFJ7UfYr_8Fm7eG2hrazmBFqHn7z0WVtvEPmZxLqjUs27MiUmMhd-la89EZ9y_CL4ncZr68N6TCvLfhW6ZReEzdzUCivPJ6iOmw2UTsr1McAnaqf_bmExEIwz3746kYzO2BOPjja15JvaC4d8UiJSzHSW4PNTc3GrtEe2OuuOgsi1mmUH5zCYluyyBzykwZuM7N-mclarQbnmsacSCsMSlFeWVsa-fR560C8uXe0nEMdP9VBBq5O5zwol2ZNGOn3tTYTTibZTv9zZ4Qmay4KXCpQxbIKA_N5fhqSR6P6uQVJ9ihWB0lYXfmnEVlGu4H_IR4oZNs0TxNFNAZkjgROQ', 'ca_root': '-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n', 'ccf_api_onboarding_url': 'api-provider-management/v1/registrations', 'ccf_discover_url': 'service-apis/v1/allServiceAPIs?api-invoker-id=', 'ccf_onboarding_url': 'api-invoker-management/v1/onboardedInvokers', 'ccf_publish_url': 'published-apis/v1/<apfId>/service-apis', 'ccf_security_url': 'capif-security/v1/trustedInvokers/<apiInvokerId>', 'message': 'Token and CA root returned successfully'}\n", + "2025-03-14 06:31:39,332 - __main__ - DEBUG - >>> onboard_provider\n", + "2025-03-14 06:31:39,333 - __main__ - DEBUG - onboard_provider: url=https://lab-oai.etsi.org:443/api-provider-management/v1/registrations\n", + "2025-03-14 06:31:39,333 - __main__ - DEBUG - onboard_provider (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiYjI0N2YyNzQtMDIxMC00ZDY4LTgwYzktMTAxNjliNTdiNzcyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjNTllOGFlLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA1ODg3NzE2YS0zNWVmLTVmOTktYmQ5NC0zOGQxZmEzZDAzMTciLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiJjNzNjNDJkYy0zOTJhLTQzNzQtOTQyNS1hODY0OTIzNjE1OTciLCJleHAiOjE3NDE5MzQ3OTl9.cQFJ7UfYr_8Fm7eG2hrazmBFqHn7z0WVtvEPmZxLqjUs27MiUmMhd-la89EZ9y_CL4ncZr68N6TCvLfhW6ZReEzdzUCivPJ6iOmw2UTsr1McAnaqf_bmExEIwz3746kYzO2BOPjja15JvaC4d8UiJSzHSW4PNTc3GrtEe2OuuOgsi1mmUH5zCYluyyBzykwZuM7N-mclarQbnmsacSCsMSlFeWVsa-fR560C8uXe0nEMdP9VBBq5O5zwol2ZNGOn3tTYTTibZTv9zZ4Qmay4KXCpQxbIKA_N5fhqSR6P6uQVJ9ihWB0lYXfmnEVlGu4H_IR4oZNs0TxNFNAZkjgROQ'}\n", + "2025-03-14 06:31:39,334 - __main__ - DEBUG - >>> generate_csr\n", + "/tmp/ipykernel_3714172/1257919564.py:18: DeprecationWarning: CSR support in pyOpenSSL is deprecated. You should use the APIs in cryptography.\n", + " req = X509Req()\n", + "2025-03-14 06:31:39,373 - __main__ - DEBUG - generate_csr: PrivKey: b'-----BEGIN PRIVATE KEY-----\\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwGYlsHsmrt0wN\\nZ+0Tn7kVnf+ovdqnS07Yasvj3eAgoJWjl0pmMfX3Grqb5hAeF3DoaHZe5yMZq9eN\\nPGyMhtK7PozWWv7HQVaPQLRAW9yJ4vzzjYgyEOWXape3rGH1xhCGOvlXHyYIztMl\\npEWVmIPtOHx978WrD8i4oQrjVNO0ivYW4fCLFqv7L6uLT1rY/wns+7REtaTZopWI\\nNswZm2Upc/CBp8+mP8PCk0LWnUNeeG9J/tZNSQour5eRaadwCxPD58af2oq8fZ4L\\nHJ8W2UGYBVfLV0Gn9vzn0GGinu3qvdwKeKO+/MBlc4wcQFU2EBEBWpVFpjD09PvA\\n0dqQ+t6hAgMBAAECggEARIx8QPkvGcfNM/67e4MWQgLx7RaSUcLv2zCfU4Ef6LN5\\n7GdND8Ds9RaTg3In3f7T9bQMN98Te7+3tYPK4VzuFPNBUYO0X43givzt7YuUqpwQ\\nSSJT3OFU7f8RNe9FZq2F6ypzuuUmIhGYgbOTXqsy15nAZCl8sZ0ATlZp7Zosmr9C\\nxgHNJtBlieTsb40unETw097OKqvJV4JEWQQsvLgnsrIuKFC21d7efid09uy7O/Dm\\nYOAQI+zupQrtBWCZlxNdB0KDAFX1xjisVnunq4fPmp1uQQ+CUgDHZaTlRJ6awKjM\\ns20SP2eg9YYiygwV/6luWsB6OZOKyQe2x6JbGEnejQKBgQDs8ZyBtvSDomENiD1t\\niSq/DwExoaAB5+2a2kCwDPqIAITswgZqXTgQUK+LkFCZqj6brZ+TQaDRQCLhR+WU\\n23XET3OdywMex/fwH8URaOAdAXtsgQXqi92ZSDb9Y0h5mPE5QHFR8S4Z2rBpTjvc\\nDaHvRQW6LpTG9U/XpN8Nsa6Z8wKBgQC+Qzg3I43Wo9LCIgBaspZLwxlJdBdz4zsE\\nQpAROQYXds47bVsPQqaerCR9a259KZUhfmxwAxEH86lmsot6iPktMIWtg6O7G8jB\\nyWyVxA4f4J2t2g9RIkUG4HOkJ4lG/9QwRM7GtzMqlu8BXd5rp0wF5aWToZJmG/+o\\nWv8LqgNWGwKBgA8wObES8j+R5BjC9/USitvucUwmKSSWImP/w4/FdTXMmri2g0TE\\nLvjUwzv2B0SiZhsCmS0OUum268V3H19YZgcsdKPTxKJvfRQ2ZSKFj4AsfSXqa1+q\\nkYzm1SeO+rFYvXXHDLyM8kCUBSTq7+leMlgtG33gyIasaO7Q0b+F+URDAoGAJQeK\\nIlkeGt8pfrUFYqGNVNN00XHxupFIBC08Qs3ZXKm3u6Mt7MtpCEqyk2JcT6nPJ4Sm\\ncCp4nxaSKrWnJcMQ0/W0nq+XJyxiJy0foApXQWcC6Toebwj/bDY064byVcomrvpF\\nUDGJmMllXNu7FTKrPh6S2ifBCXR7jnWfW9LL8W8CgYAkItXeo5t/cbXjtp87WdIV\\nU+AXb4hbXdm++WQjV+m3PxkPAukHYaxZzHSxVv64urW5YdA9Xv9seJE++KRlpD+a\\nXvELsyJ/lScLp5YQoWcuNpisqkKn72dJWcGZHhfvd8GaFtIaxJ/Krtn2FO39lxjX\\nLdIp77vh3SB7KlsV7AKqwQ==\\n-----END PRIVATE KEY-----\\n'\n", + "2025-03-14 06:31:39,374 - __main__ - DEBUG - >>> generate_csr\n", + "2025-03-14 06:31:39,442 - __main__ - DEBUG - generate_csr: PrivKey: b'-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDN1nWrOlD9eyG+\\nx150iAbwsfVOGeRW0bgkZD935jI+ydF5mNpiJnRAfmdGflGDqDWDhDaCcZSjwH1t\\nX+ga0/FtUs/zHdUBGrNj1bwxFUZxL8LRMrqrkrJhH7JfcxmSSSNe7qJbLrTE3Ykg\\nldHjcZRMEkuK5zlQLycdTZQvPuBorUeMesuU+pG5+9F00QsCNVzZl/zqTQEAgkxe\\nLRBkyttqwSCENt9V9rycDCP9Q1m5uWwtE/zYyu9C36gvSGSGiM7xTv9HNTnts80j\\ngL/jsVzOyqJKPnT7ILs1TPA8rD8YrLWOL3p0mzTDBH3gFAzqCXOiOcv13WfEBom7\\nOFWMxH3vAgMBAAECggEAGs+y/w03DHVz9U4xyvsG8GY1vikYOYjStAbMz5jP9abD\\nHtQeqgc5QEdWu3Nrubr40XswwHf79QJ3M/54lLoDqgpN5Ox/WMf6Euh9vWT4ini+\\npxI1B3Exw/3ldZJgA9J8BXsO8dKZIEV8/Z4WO0qJlwkRBvRMXlnt/d6jjS3i/C9O\\nFLd/YhzUjDwwYdaSiMcQ/sgcOI5an/LouIPnbOAZFw6294bZu/MaEdr0OdeUCyjK\\nrPT2IBlP9RdEwTfZBnfCRcZ4nLHAyEKhcKB8/LLXNg2Cm6YnB3lN+2sUaaDChupy\\ndChtYsKz4mhKdjdWsO9S5CACT6T7w/GocxOGGYJbNQKBgQDv/JDffe9pTrKJm98b\\n20lLXUIenRIhOgmcQOIGnK8eTn0dugMU+TyDzKmyA97+ET/GGdAaDuV7O/f/tKkO\\nMImX/DTzoYqHpMoANo+TWMl8Jqaqu/LSp5G+y75tUlyDWR6iGIulq/Cfoo2mCzYS\\nc9exLafahogluWZTLMBdklcyFQKBgQDbkpC/UDYB1iEm6zmBpvTkT9+uoR8hBaCC\\nEZvUe6qAdAixMqi1kihTUlC0UNDBmSA2PUKvEi+0OJb2c1Ep+RFhdzN+kxPl6QbH\\nWtp75w0/FHf53Da2JS+MN5+UgzRdKHjJrwrPyPqDdcb+Bao8P8OdnZU2vAz8zKQh\\nPg3ki2Ek8wKBgQChHiCpWyRDwAkPZ+1nB1by2P6ODQfh9NQE6m6U39aV8z3+miZ9\\ni0L8fYgkMoMgcbYuKqBTDlM05DMAomqpUx7dQf7O3lJh9NmFQRwtYXuL9WsJzzsc\\nAFJSFPmY7aWcrVVqoC4JISFgG0McCgTYaJuToUJC7PU01n8DMlVHvPr7bQKBgERM\\n6R25s7MKirFyhibgalkCx4+oqug4ud773z9PYJAoh/Om0Hf6iPSyLEyKvwUZvr1g\\nfPe8bn5fBAaRhHPL+C4bSDddRNlFjUhB6KiWDLbMhS2B5LrwAkRZoRgvYACCcGA8\\nRN6xo8t0vXuTA4tOQmkq9ZlbEacpePymMugeuw8lAoGANKB5VXA1/pt2nSV1Bt0u\\nTDd8VdcXE+1oxnQ0Rt4+jHhSSVNZd7OBH4qxBkmaQSgkKC+IOqjfFYs6PTbgUI9Y\\npXyc6dMwAqvNZyP88unbooEZYQwm0ynK878pav2wiKOAZaypGkNmiRgzYKuYdZ1n\\nLSUBxB62CticCewzFLBkMnY=\\n-----END PRIVATE KEY-----\\n'\n", + "2025-03-14 06:31:39,443 - __main__ - DEBUG - >>> generate_csr\n", + "2025-03-14 06:31:39,498 - __main__ - DEBUG - generate_csr: PrivKey: b'-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC1u+4cipJsRh7M\\nT5psEHv/2mCDanU7/EyqMfGah/GX3rb66XQiqNuqktihif0x5qULo3aEm6nZQ1Ed\\n2W3iO+TMo+KYnHanQZig+wXDyHyh3aJfKwuu3/aNolc1PXlcoM6qxY5PAppZoTmb\\nlEcDTPvNG8ZatYkyTQZgsfDRnL3owuiM3XTBQ0hNoBNXFHHs+cEpPzqr5y+LL5LU\\nyKLGNNNmtYpggjhWns9koCgYbJrkowhSsQOTCiCiIP+nBZ472GeEyxr4I2AM85qK\\niYHVgQ3JkaJbJmg+Ompz65uW587EDaiK3ssePj59gF0KiSraTFlzg2H0mTsoJsB7\\nlsQqQsULAgMBAAECggEALikmkaRXDd5/uyirEjDbtkC7TBYR4iMzO/XEpxpJsOg2\\ntSPwRk96wGhdUybQI8kwefTSyVsauN9i7sCIKzNIafxktZvkfZZpVNZ9/91gXuMD\\nd8XgyVIE97PZD+Jl/bOw2uqkO4hvOT38+noe0YVP3ijkaKz8xMSQzqXUBAIasNDH\\nOXw4Zep5appuTtzllhxlt79c6lywtfjWg5NWAg7Gkutm3ZGYV1KjmCcphpqVwoAH\\nxgU4PODA41k2eio99iMmIZxYGPrddTD77slTGlVzCsZCpOqoL9Ho5YKLhidpug1Q\\nmUc54eaZncTnRmW7OQMm3/sppbEGG/Ac2XLcVW0SXQKBgQDqamhnxZQKeM+jCiqe\\n8LQ6nFTgUOEM5Wwt0OYxuhGA9O6+d0gVt2DXYUAb28xj1qoRM7LRlhdVg+zv4V3O\\nf/afJW5wJGBWPmn1yv6Rpca1KrW3xk0PQ3MwrF1pIjmla1E1kO7m4q1RqaBnBO7U\\nBBfxz1zeZM5yKFfNImIItsOwvwKBgQDGd7mKiDFydKlsrJx+XVGL7kS7A6v+FRaX\\n09Ita+9FaHcVtqPHrJlD4wHIKMkltsGHZwLV7Cuk4KQosevgD2bHzKxq5LG9A0mF\\nQaBcwckStrD1GvoCmSsw5kxWckRP+HUstcQyzM9FDI1qaQaGnzxdcXJUFxUyluBy\\nb7Of3X6ytQKBgC2Hl1m4dWWHS4T2P4r5Y3gSzyV2cA+qK9XGQj+cTTQH3qsdzeFx\\n6ZxLpkEC8vLdSdDngq7UgRm58vYwhqDKF+OXSJj9Z7y4iKoV0FYHpc2gSwUzvdne\\nFux4PfhijmHDs1U9Hjm4A0PeN2pq+dwyI1hzFy2W1MY1ccBFEldw8BdPAoGBAMGD\\naWEfDH+aKrxwzaIUoXd8Gn3yxZfXvhDKE4wASuv1QO/mBmmh7EsaI9mjkwV33dmF\\nYmltftyjwMyBNwlgWwoDkjYjyP4QH3aUF6V5ufHKOl6zMASqjkd+tf4wKlWDX9T5\\nYlVaB9s+swCHaTqINtax0BUX8K5EGJLcQVtmH6xlAoGBALu15n4ueD2x/QBwTYWX\\nYwawwPHckuuXxc1c2qJcJ1VAULrcJl0FCYWza4hIqmtdAZ6uzLsiRb/Qoh66tufP\\n2bCxvKO4aSjXQcGLbY4n4dmFjp0X/vl/isb/xGWk4GqVev3CCEsVzseVXCIiWax5\\nC5F9a0df0nPSTuCSn5cAlkjl\\n-----END PRIVATE KEY-----\\n'\n", + "2025-03-14 06:31:39,499 - __main__ - DEBUG - onboard_provider (step2): body: {'apiProvFuncs': [{'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQU1GMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAZiWweyau3\\nTA1n7ROfuRWd/6i92qdLTthqy+Pd4CCglaOXSmYx9fcaupvmEB4XcOhodl7nIxmr\\n1408bIyG0rs+jNZa/sdBVo9AtEBb3Ini/PONiDIQ5Zdql7esYfXGEIY6+VcfJgjO\\n0yWkRZWYg+04fH3vxasPyLihCuNU07SK9hbh8IsWq/svq4tPWtj/Cez7tES1pNmi\\nlYg2zBmbZSlz8IGnz6Y/w8KTQtadQ154b0n+1k1JCi6vl5Fpp3ALE8Pnxp/airx9\\nngscnxbZQZgFV8tXQaf2/OfQYaKe7eq93Ap4o778wGVzjBxAVTYQEQFalUWmMPT0\\n+8DR2pD63qECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQChwyyD3Rcxidm0SK9f\\nJwyrEcTwr5an1H5EuDWpvQnKFGiePEcQF1vVzRotMazWHHT6sgJNVZO+bJqkugvS\\nC9Pc/TnocB4lFYB3iZBT7rhrC8JnjufnZfkBeaJFx1AUJnu/DxEBc9lij5acpcJB\\nD+TMOfDNy/VVa7/2RJakwmHdlwAc8WKGaSUvJw9rFpMEYGQC+HljXtByvLyBne1H\\nOZTuayTZtDHGqM7tKOFsCP0ajLEW4BuVioMh8Ge+NozUl+zLbD8CA89M/PAotANV\\nKZl+EexnS/+c3N8p+7x8Lk/8A0AsW98Ktf+MQAA20Tab5FmWSPrg/X+XjSHvHdSw\\n1qgA\\n-----END CERTIFICATE REQUEST-----\\n'}, 'apiProvFuncRole': 'AMF'}, {'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQUVGMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM3Wdas6UP17\\nIb7HXnSIBvCx9U4Z5FbRuCRkP3fmMj7J0XmY2mImdEB+Z0Z+UYOoNYOENoJxlKPA\\nfW1f6BrT8W1Sz/Md1QEas2PVvDEVRnEvwtEyuquSsmEfsl9zGZJJI17uolsutMTd\\niSCV0eNxlEwSS4rnOVAvJx1NlC8+4GitR4x6y5T6kbn70XTRCwI1XNmX/OpNAQCC\\nTF4tEGTK22rBIIQ231X2vJwMI/1DWbm5bC0T/NjK70LfqC9IZIaIzvFO/0c1Oe2z\\nzSOAv+OxXM7Koko+dPsguzVM8DysPxistY4venSbNMMEfeAUDOoJc6I5y/XdZ8QG\\nibs4VYzEfe8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBDGmtyvcLOgeMKH5yK\\nKXIAhV3gkWT8PP/cM49jh7wsy5CJ1Sa++tki8xo1OHmwG8WZkp8AhlCmRCAhqa4d\\nWKNJMR/2baFbdj3CIPsKciOacoe+0fwA+rPqT4JKzCiZ0LtAtf4+YZn5tOMQcVhA\\nd/o16jugqLU5Cvdyf5iz42p67bCKInaR+JQNkJQv99cjJbLxHkOdke9HGL3YcZYY\\nqCJ4YY/UQbfUZGQr6gXxuYIqyIwHUOhVRdlakFQESVOz8lbgvkFhs5xKETgg/6A1\\nYQSyCgYt/r6W0YarDGW9TTTnOT1/bioGxaMs4jHtCF6quUpJ2lWiY25MXlNvKa9v\\nCvdM\\n-----END CERTIFICATE REQUEST-----\\n'}, 'apiProvFuncRole': 'AEF'}, {'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQVBGMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALW77hyKkmxG\\nHsxPmmwQe//aYINqdTv8TKox8ZqH8ZfetvrpdCKo26qS2KGJ/THmpQujdoSbqdlD\\nUR3ZbeI75Myj4picdqdBmKD7BcPIfKHdol8rC67f9o2iVzU9eVygzqrFjk8Cmlmh\\nOZuURwNM+80bxlq1iTJNBmCx8NGcvejC6IzddMFDSE2gE1cUcez5wSk/OqvnL4sv\\nktTIosY002a1imCCOFaez2SgKBhsmuSjCFKxA5MKIKIg/6cFnjvYZ4TLGvgjYAzz\\nmoqJgdWBDcmRolsmaD46anPrm5bnzsQNqIreyx4+Pn2AXQqJKtpMWXODYfSZOygm\\nwHuWxCpCxQsCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQApUoo3ZXsqvfPVeGFz\\nwPuG8oUTmcPzRT9jt27zsxPl02wVNU+ah5r6gENKUWF1YNHus1YOCEwkypFlTje2\\nlM1XnrGZ16kGmJOHs/K+CUCaRBOvQNJNCdhF6O56u0cT99p6E1MBtNARdITrC1Pf\\no2UE81ixqNmbYvUUTf6HfvLwMj7y9/ZflW777dY8/X4JqP8b7EcBQj26LcnfZSo8\\nbyVj9Dqm1aFAhqKg5z4/DNnTVWKo+hioK6/ML37aQqwCjHGtYhv5onB/tV5UVAHj\\n/XSjBDEkZuGntuQHJfGy82S2W+8sWQlY/DY+UbuLehPpDJQljj0AO4P6FIltbupo\\nYAyl\\n-----END CERTIFICATE REQUEST-----\\n'}, 'apiProvFuncRole': 'APF'}], 'apiProvDomInfo': 'MECSandbox_to_CAPIF_Provider', 'suppFeat': 'fff', 'failReason': 'string', 'regSec': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiYjI0N2YyNzQtMDIxMC00ZDY4LTgwYzktMTAxNjliNTdiNzcyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjNTllOGFlLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA1ODg3NzE2YS0zNWVmLTVmOTktYmQ5NC0zOGQxZmEzZDAzMTciLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiJjNzNjNDJkYy0zOTJhLTQzNzQtOTQyNS1hODY0OTIzNjE1OTciLCJleHAiOjE3NDE5MzQ3OTl9.cQFJ7UfYr_8Fm7eG2hrazmBFqHn7z0WVtvEPmZxLqjUs27MiUmMhd-la89EZ9y_CL4ncZr68N6TCvLfhW6ZReEzdzUCivPJ6iOmw2UTsr1McAnaqf_bmExEIwz3746kYzO2BOPjja15JvaC4d8UiJSzHSW4PNTc3GrtEe2OuuOgsi1mmUH5zCYluyyBzykwZuM7N-mclarQbnmsacSCsMSlFeWVsa-fR560C8uXe0nEMdP9VBBq5O5zwol2ZNGOn3tTYTTibZTv9zZ4Qmay4KXCpQxbIKA_N5fhqSR6P6uQVJ9ihWB0lYXfmnEVlGu4H_IR4oZNs0TxNFNAZkjgROQ'}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,556 - __main__ - DEBUG - onboard_provider (step3): result: {'apiProvDomId': '7d1e7acfc6bb19a31614da0968a8f8', 'regSec': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiYjI0N2YyNzQtMDIxMC00ZDY4LTgwYzktMTAxNjliNTdiNzcyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjNTllOGFlLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA1ODg3NzE2YS0zNWVmLTVmOTktYmQ5NC0zOGQxZmEzZDAzMTciLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiJjNzNjNDJkYy0zOTJhLTQzNzQtOTQyNS1hODY0OTIzNjE1OTciLCJleHAiOjE3NDE5MzQ3OTl9.cQFJ7UfYr_8Fm7eG2hrazmBFqHn7z0WVtvEPmZxLqjUs27MiUmMhd-la89EZ9y_CL4ncZr68N6TCvLfhW6ZReEzdzUCivPJ6iOmw2UTsr1McAnaqf_bmExEIwz3746kYzO2BOPjja15JvaC4d8UiJSzHSW4PNTc3GrtEe2OuuOgsi1mmUH5zCYluyyBzykwZuM7N-mclarQbnmsacSCsMSlFeWVsa-fR560C8uXe0nEMdP9VBBq5O5zwol2ZNGOn3tTYTTibZTv9zZ4Qmay4KXCpQxbIKA_N5fhqSR6P6uQVJ9ihWB0lYXfmnEVlGu4H_IR4oZNs0TxNFNAZkjgROQ', 'apiProvFuncs': [{'apiProvFuncId': 'AMF4b2ceb2ce84148aa56a88a07d9ab9c', 'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQU1GMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAZiWweyau3\\nTA1n7ROfuRWd/6i92qdLTthqy+Pd4CCglaOXSmYx9fcaupvmEB4XcOhodl7nIxmr\\n1408bIyG0rs+jNZa/sdBVo9AtEBb3Ini/PONiDIQ5Zdql7esYfXGEIY6+VcfJgjO\\n0yWkRZWYg+04fH3vxasPyLihCuNU07SK9hbh8IsWq/svq4tPWtj/Cez7tES1pNmi\\nlYg2zBmbZSlz8IGnz6Y/w8KTQtadQ154b0n+1k1JCi6vl5Fpp3ALE8Pnxp/airx9\\nngscnxbZQZgFV8tXQaf2/OfQYaKe7eq93Ap4o778wGVzjBxAVTYQEQFalUWmMPT0\\n+8DR2pD63qECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQChwyyD3Rcxidm0SK9f\\nJwyrEcTwr5an1H5EuDWpvQnKFGiePEcQF1vVzRotMazWHHT6sgJNVZO+bJqkugvS\\nC9Pc/TnocB4lFYB3iZBT7rhrC8JnjufnZfkBeaJFx1AUJnu/DxEBc9lij5acpcJB\\nD+TMOfDNy/VVa7/2RJakwmHdlwAc8WKGaSUvJw9rFpMEYGQC+HljXtByvLyBne1H\\nOZTuayTZtDHGqM7tKOFsCP0ajLEW4BuVioMh8Ge+NozUl+zLbD8CA89M/PAotANV\\nKZl+EexnS/+c3N8p+7x8Lk/8A0AsW98Ktf+MQAA20Tab5FmWSPrg/X+XjSHvHdSw\\n1qgA\\n-----END CERTIFICATE REQUEST-----\\n', 'apiProvCert': '-----BEGIN CERTIFICATE-----\\nMIIDgjCCAmqgAwIBAgIUXWNSwZhcDK6gbO6bers6UlaK+kkwDQYJKoZIhvcNAQEL\\nBQAwJzElMCMGA1UEAxMcY2FwaWYgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTAeFw0y\\nNTAzMTQwNjMxMDlaFw0yNTA5MDkxMDMxMzlaMCwxKjAoBgNVBAMTIUFNRjRiMmNl\\nYjJjZTg0MTQ4YWE1NmE4OGEwN2Q5YWI5YzCCASIwDQYJKoZIhvcNAQEBBQADggEP\\nADCCAQoCggEBALAZiWweyau3TA1n7ROfuRWd/6i92qdLTthqy+Pd4CCglaOXSmYx\\n9fcaupvmEB4XcOhodl7nIxmr1408bIyG0rs+jNZa/sdBVo9AtEBb3Ini/PONiDIQ\\n5Zdql7esYfXGEIY6+VcfJgjO0yWkRZWYg+04fH3vxasPyLihCuNU07SK9hbh8IsW\\nq/svq4tPWtj/Cez7tES1pNmilYg2zBmbZSlz8IGnz6Y/w8KTQtadQ154b0n+1k1J\\nCi6vl5Fpp3ALE8Pnxp/airx9ngscnxbZQZgFV8tXQaf2/OfQYaKe7eq93Ap4o778\\nwGVzjBxAVTYQEQFalUWmMPT0+8DR2pD63qECAwEAAaOBoDCBnTAOBgNVHQ8BAf8E\\nBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQf\\n6A3W+VuniqRJYpMK89aTSeVPVDAfBgNVHSMEGDAWgBRyWzJdjOmGfJFOwo6wJiup\\nYnm00jAsBgNVHREEJTAjgiFBTUY0YjJjZWIyY2U4NDE0OGFhNTZhODhhMDdkOWFi\\nOWMwDQYJKoZIhvcNAQELBQADggEBAKxQV3StdM8orcqILKtomgcot9ieq+4ijyRm\\nD86Y7pKLSPRAtVgR5IAfQHmGH1/OSOskXL2JW+4EL3qHAmLuka3pnCj8d8etgxKb\\nSKD4yUTRZ/yiIcd2gB5/ykUIOeTdghzzf2yI0x5SYHtpYupmi+FP6twhMxnP8IFh\\nZ3qaYMq1rx4g8riBQz7i9yVby5kc4Na6eUG7V/J/qBL/ONrsvVYW9YBRn6uaFNJJ\\nEAHsRZWAcBy+6NaMToqzp7lC4Pslwfv9YtaythQCguGGz5P7QTc2CrAFO/MDDoM/\\nDvkdUs0skrY+VBjInWpML6e+DJ2sRRC8PJTIjAk1Qgeoxlqnaqo=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----'}, 'apiProvFuncRole': 'AMF'}, {'apiProvFuncId': 'AEFb7a696201b577f7c0233923e4b5839', 'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQUVGMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM3Wdas6UP17\\nIb7HXnSIBvCx9U4Z5FbRuCRkP3fmMj7J0XmY2mImdEB+Z0Z+UYOoNYOENoJxlKPA\\nfW1f6BrT8W1Sz/Md1QEas2PVvDEVRnEvwtEyuquSsmEfsl9zGZJJI17uolsutMTd\\niSCV0eNxlEwSS4rnOVAvJx1NlC8+4GitR4x6y5T6kbn70XTRCwI1XNmX/OpNAQCC\\nTF4tEGTK22rBIIQ231X2vJwMI/1DWbm5bC0T/NjK70LfqC9IZIaIzvFO/0c1Oe2z\\nzSOAv+OxXM7Koko+dPsguzVM8DysPxistY4venSbNMMEfeAUDOoJc6I5y/XdZ8QG\\nibs4VYzEfe8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBDGmtyvcLOgeMKH5yK\\nKXIAhV3gkWT8PP/cM49jh7wsy5CJ1Sa++tki8xo1OHmwG8WZkp8AhlCmRCAhqa4d\\nWKNJMR/2baFbdj3CIPsKciOacoe+0fwA+rPqT4JKzCiZ0LtAtf4+YZn5tOMQcVhA\\nd/o16jugqLU5Cvdyf5iz42p67bCKInaR+JQNkJQv99cjJbLxHkOdke9HGL3YcZYY\\nqCJ4YY/UQbfUZGQr6gXxuYIqyIwHUOhVRdlakFQESVOz8lbgvkFhs5xKETgg/6A1\\nYQSyCgYt/r6W0YarDGW9TTTnOT1/bioGxaMs4jHtCF6quUpJ2lWiY25MXlNvKa9v\\nCvdM\\n-----END CERTIFICATE REQUEST-----\\n', 'apiProvCert': '-----BEGIN CERTIFICATE-----\\nMIIDgjCCAmqgAwIBAgIULl5w9Xdg+aoq0YvbrhTXrpB6pIIwDQYJKoZIhvcNAQEL\\nBQAwJzElMCMGA1UEAxMcY2FwaWYgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTAeFw0y\\nNTAzMTQwNjMxMDlaFw0yNTA5MDkxMDMxMzlaMCwxKjAoBgNVBAMTIUFFRmI3YTY5\\nNjIwMWI1NzdmN2MwMjMzOTIzZTRiNTgzOTCCASIwDQYJKoZIhvcNAQEBBQADggEP\\nADCCAQoCggEBAM3Wdas6UP17Ib7HXnSIBvCx9U4Z5FbRuCRkP3fmMj7J0XmY2mIm\\ndEB+Z0Z+UYOoNYOENoJxlKPAfW1f6BrT8W1Sz/Md1QEas2PVvDEVRnEvwtEyuquS\\nsmEfsl9zGZJJI17uolsutMTdiSCV0eNxlEwSS4rnOVAvJx1NlC8+4GitR4x6y5T6\\nkbn70XTRCwI1XNmX/OpNAQCCTF4tEGTK22rBIIQ231X2vJwMI/1DWbm5bC0T/NjK\\n70LfqC9IZIaIzvFO/0c1Oe2zzSOAv+OxXM7Koko+dPsguzVM8DysPxistY4venSb\\nNMMEfeAUDOoJc6I5y/XdZ8QGibs4VYzEfe8CAwEAAaOBoDCBnTAOBgNVHQ8BAf8E\\nBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSj\\nU/uJ2mE3Vy2+cTPwR2uLYsQvkzAfBgNVHSMEGDAWgBRyWzJdjOmGfJFOwo6wJiup\\nYnm00jAsBgNVHREEJTAjgiFBRUZiN2E2OTYyMDFiNTc3ZjdjMDIzMzkyM2U0YjU4\\nMzkwDQYJKoZIhvcNAQELBQADggEBAG2+v/AB4L8ruUwo7jrb5l7ska4DlXWstx2O\\n8VOECWa7fXuqvptIW3I/ny4BVS0365SPbr4HdimH4b4G9Im2DBNHzgOgvptPOeUy\\nWBkn9tcdUkISiwdiqlLT4jDgbD+1/ptTVEfdg8Q5xr51NnNPz+XLZjnuAr85/7me\\nxZroCJ4flALdJIJIcBxusQCiQf2TOes3IKK94bTrrq4bAwgzUsQESONwgTinzGa/\\nsQvPD84LtD1RsCmXVbNZsbEHPU9aEiZMHyV7OtObQbrG6GVqEL9lfAexTG3U3um6\\n3lm5L5LxrPXM4CFcgIFUWWd2z7fhuUvOJ1zLY0mV77m3bagw0hA=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----'}, 'apiProvFuncRole': 'AEF'}, {'apiProvFuncId': 'APF5590794dcb278ebcf3d9325f547bee', 'regInfo': {'apiProvPubKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICbzCCAVcCAQAwKjEMMAoGA1UEAwwDQVBGMQ0wCwYDVQQKDARFVFNJMQswCQYD\\nVQQGEwJGcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALW77hyKkmxG\\nHsxPmmwQe//aYINqdTv8TKox8ZqH8ZfetvrpdCKo26qS2KGJ/THmpQujdoSbqdlD\\nUR3ZbeI75Myj4picdqdBmKD7BcPIfKHdol8rC67f9o2iVzU9eVygzqrFjk8Cmlmh\\nOZuURwNM+80bxlq1iTJNBmCx8NGcvejC6IzddMFDSE2gE1cUcez5wSk/OqvnL4sv\\nktTIosY002a1imCCOFaez2SgKBhsmuSjCFKxA5MKIKIg/6cFnjvYZ4TLGvgjYAzz\\nmoqJgdWBDcmRolsmaD46anPrm5bnzsQNqIreyx4+Pn2AXQqJKtpMWXODYfSZOygm\\nwHuWxCpCxQsCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQApUoo3ZXsqvfPVeGFz\\nwPuG8oUTmcPzRT9jt27zsxPl02wVNU+ah5r6gENKUWF1YNHus1YOCEwkypFlTje2\\nlM1XnrGZ16kGmJOHs/K+CUCaRBOvQNJNCdhF6O56u0cT99p6E1MBtNARdITrC1Pf\\no2UE81ixqNmbYvUUTf6HfvLwMj7y9/ZflW777dY8/X4JqP8b7EcBQj26LcnfZSo8\\nbyVj9Dqm1aFAhqKg5z4/DNnTVWKo+hioK6/ML37aQqwCjHGtYhv5onB/tV5UVAHj\\n/XSjBDEkZuGntuQHJfGy82S2W+8sWQlY/DY+UbuLehPpDJQljj0AO4P6FIltbupo\\nYAyl\\n-----END CERTIFICATE REQUEST-----\\n', 'apiProvCert': '-----BEGIN CERTIFICATE-----\\nMIIDgjCCAmqgAwIBAgIUVIf6wTIfDvMffnpLaSGeVqXrujAwDQYJKoZIhvcNAQEL\\nBQAwJzElMCMGA1UEAxMcY2FwaWYgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTAeFw0y\\nNTAzMTQwNjMxMDlaFw0yNTA5MDkxMDMxMzlaMCwxKjAoBgNVBAMTIUFQRjU1OTA3\\nOTRkY2IyNzhlYmNmM2Q5MzI1ZjU0N2JlZTCCASIwDQYJKoZIhvcNAQEBBQADggEP\\nADCCAQoCggEBALW77hyKkmxGHsxPmmwQe//aYINqdTv8TKox8ZqH8ZfetvrpdCKo\\n26qS2KGJ/THmpQujdoSbqdlDUR3ZbeI75Myj4picdqdBmKD7BcPIfKHdol8rC67f\\n9o2iVzU9eVygzqrFjk8CmlmhOZuURwNM+80bxlq1iTJNBmCx8NGcvejC6IzddMFD\\nSE2gE1cUcez5wSk/OqvnL4svktTIosY002a1imCCOFaez2SgKBhsmuSjCFKxA5MK\\nIKIg/6cFnjvYZ4TLGvgjYAzzmoqJgdWBDcmRolsmaD46anPrm5bnzsQNqIreyx4+\\nPn2AXQqJKtpMWXODYfSZOygmwHuWxCpCxQsCAwEAAaOBoDCBnTAOBgNVHQ8BAf8E\\nBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRB\\nOpj37DyD3EoqrOLAqK5ti6avPjAfBgNVHSMEGDAWgBRyWzJdjOmGfJFOwo6wJiup\\nYnm00jAsBgNVHREEJTAjgiFBUEY1NTkwNzk0ZGNiMjc4ZWJjZjNkOTMyNWY1NDdi\\nZWUwDQYJKoZIhvcNAQELBQADggEBAGFhndkgIC2WYjbOpXI83HYtz+DaOCN1b2FQ\\nCfTYPU7+UlMqY7gokEZXaQPsABpV+T/iZDuAGyDbhJLQ8qtk4e6Zpa+d/J83AhyU\\n3b8qauPSWpTVh6TWH9+Io2WlAhLSFqREHCrBWdcbij0nTfT4MmkTHRj6uTf45RQb\\nKrnA5vYNtauJ9Pt/lLUHQd5YcVxGK2vCGTEzmoZn5L28SQLZB6dnA6mEZd/hdfYC\\nbEDGOxfq5Mhoxygzu1N+cF0F6ykI2fTpwM2xKkOyvmaEAoHRRXSgpZFXN7NZxCWM\\nxSFNtGN3UwveVmJfIQENQAxX7YVOKVYarrtnUt9Xn/Da4HiZVis=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----'}, 'apiProvFuncRole': 'APF'}], 'apiProvDomInfo': 'MECSandbox_to_CAPIF_Provider', 'suppFeat': 'fff', 'failReason': 'string'}\n", + "2025-03-14 06:31:39,558 - __main__ - DEBUG - >>> build_publish_api_from_mec_services: p_aefId=AEFb7a696201b577f7c0233923e4b5839\n", + "2025-03-14 06:31:39,559 - __main__ - DEBUG - <<< build_publish_api_from_mec_services: {'apiName': 'MEC Profile for CAPIF', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004Z', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string', 'apiStatus': {'aefIds': ['AEFb7a696201b577f7c0233923e4b5839']}}\n", + "2025-03-14 06:31:39,559 - __main__ - DEBUG - publish_api_req_body: {'apiName': 'MEC Profile for CAPIF', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004Z', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string', 'apiStatus': {'aefIds': ['AEFb7a696201b577f7c0233923e4b5839']}}\n", + "2025-03-14 06:31:39,560 - __main__ - DEBUG - >>> publish_capif_api\n", + "2025-03-14 06:31:39,560 - __main__ - DEBUG - publish_capif_api: url=https://lab-oai.etsi.org:443/published-apis/v1/APF5590794dcb278ebcf3d9325f547bee/service-apis\n", + "2025-03-14 06:31:39,561 - __main__ - DEBUG - publish_capif_api (step1): headers: {'Content-Type': 'application/json'}\n", + "2025-03-14 06:31:39,561 - __main__ - DEBUG - publish_capif_api (step2): body: {'apiName': 'MEC Profile for CAPIF', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004Z', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string', 'apiStatus': {'aefIds': ['AEFb7a696201b577f7c0233923e4b5839']}}\n", + "2025-03-14 06:31:39,561 - __main__ - DEBUG - >>> store_certificate_2_files\n", + "2025-03-14 06:31:39,562 - __main__ - DEBUG - publish_capif_api (step3): bundle: ['p_crt.crt', 'p_key.key', 'ca_root.pem']\n", + "2025-03-14 06:31:39,592 - __main__ - DEBUG - publish_capif_api (step4): result: {'apiName': 'MEC Profile for CAPIF', 'apiId': 'a55b2ecc0ee7a2ff0d5b7da3a63dd2', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004000+00:00', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string'}\n", + "2025-03-14 06:31:39,593 - __main__ - DEBUG - publish_capif_api (step5): res: {'apiName': 'MEC Profile for CAPIF', 'apiId': 'a55b2ecc0ee7a2ff0d5b7da3a63dd2', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004000+00:00', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string'}\n", + "2025-03-14 06:31:39,594 - __main__ - DEBUG - publish_api: ('7d1e7acfc6bb19a31614da0968a8f8', ('-----BEGIN CERTIFICATE-----\\nMIIDgjCCAmqgAwIBAgIUXWNSwZhcDK6gbO6bers6UlaK+kkwDQYJKoZIhvcNAQEL\\nBQAwJzElMCMGA1UEAxMcY2FwaWYgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTAeFw0y\\nNTAzMTQwNjMxMDlaFw0yNTA5MDkxMDMxMzlaMCwxKjAoBgNVBAMTIUFNRjRiMmNl\\nYjJjZTg0MTQ4YWE1NmE4OGEwN2Q5YWI5YzCCASIwDQYJKoZIhvcNAQEBBQADggEP\\nADCCAQoCggEBALAZiWweyau3TA1n7ROfuRWd/6i92qdLTthqy+Pd4CCglaOXSmYx\\n9fcaupvmEB4XcOhodl7nIxmr1408bIyG0rs+jNZa/sdBVo9AtEBb3Ini/PONiDIQ\\n5Zdql7esYfXGEIY6+VcfJgjO0yWkRZWYg+04fH3vxasPyLihCuNU07SK9hbh8IsW\\nq/svq4tPWtj/Cez7tES1pNmilYg2zBmbZSlz8IGnz6Y/w8KTQtadQ154b0n+1k1J\\nCi6vl5Fpp3ALE8Pnxp/airx9ngscnxbZQZgFV8tXQaf2/OfQYaKe7eq93Ap4o778\\nwGVzjBxAVTYQEQFalUWmMPT0+8DR2pD63qECAwEAAaOBoDCBnTAOBgNVHQ8BAf8E\\nBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQf\\n6A3W+VuniqRJYpMK89aTSeVPVDAfBgNVHSMEGDAWgBRyWzJdjOmGfJFOwo6wJiup\\nYnm00jAsBgNVHREEJTAjgiFBTUY0YjJjZWIyY2U4NDE0OGFhNTZhODhhMDdkOWFi\\nOWMwDQYJKoZIhvcNAQELBQADggEBAKxQV3StdM8orcqILKtomgcot9ieq+4ijyRm\\nD86Y7pKLSPRAtVgR5IAfQHmGH1/OSOskXL2JW+4EL3qHAmLuka3pnCj8d8etgxKb\\nSKD4yUTRZ/yiIcd2gB5/ykUIOeTdghzzf2yI0x5SYHtpYupmi+FP6twhMxnP8IFh\\nZ3qaYMq1rx4g8riBQz7i9yVby5kc4Na6eUG7V/J/qBL/ONrsvVYW9YBRn6uaFNJJ\\nEAHsRZWAcBy+6NaMToqzp7lC4Pslwfv9YtaythQCguGGz5P7QTc2CrAFO/MDDoM/\\nDvkdUs0skrY+VBjInWpML6e+DJ2sRRC8PJTIjAk1Qgeoxlqnaqo=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----', b'-----BEGIN PRIVATE KEY-----\\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwGYlsHsmrt0wN\\nZ+0Tn7kVnf+ovdqnS07Yasvj3eAgoJWjl0pmMfX3Grqb5hAeF3DoaHZe5yMZq9eN\\nPGyMhtK7PozWWv7HQVaPQLRAW9yJ4vzzjYgyEOWXape3rGH1xhCGOvlXHyYIztMl\\npEWVmIPtOHx978WrD8i4oQrjVNO0ivYW4fCLFqv7L6uLT1rY/wns+7REtaTZopWI\\nNswZm2Upc/CBp8+mP8PCk0LWnUNeeG9J/tZNSQour5eRaadwCxPD58af2oq8fZ4L\\nHJ8W2UGYBVfLV0Gn9vzn0GGinu3qvdwKeKO+/MBlc4wcQFU2EBEBWpVFpjD09PvA\\n0dqQ+t6hAgMBAAECggEARIx8QPkvGcfNM/67e4MWQgLx7RaSUcLv2zCfU4Ef6LN5\\n7GdND8Ds9RaTg3In3f7T9bQMN98Te7+3tYPK4VzuFPNBUYO0X43givzt7YuUqpwQ\\nSSJT3OFU7f8RNe9FZq2F6ypzuuUmIhGYgbOTXqsy15nAZCl8sZ0ATlZp7Zosmr9C\\nxgHNJtBlieTsb40unETw097OKqvJV4JEWQQsvLgnsrIuKFC21d7efid09uy7O/Dm\\nYOAQI+zupQrtBWCZlxNdB0KDAFX1xjisVnunq4fPmp1uQQ+CUgDHZaTlRJ6awKjM\\ns20SP2eg9YYiygwV/6luWsB6OZOKyQe2x6JbGEnejQKBgQDs8ZyBtvSDomENiD1t\\niSq/DwExoaAB5+2a2kCwDPqIAITswgZqXTgQUK+LkFCZqj6brZ+TQaDRQCLhR+WU\\n23XET3OdywMex/fwH8URaOAdAXtsgQXqi92ZSDb9Y0h5mPE5QHFR8S4Z2rBpTjvc\\nDaHvRQW6LpTG9U/XpN8Nsa6Z8wKBgQC+Qzg3I43Wo9LCIgBaspZLwxlJdBdz4zsE\\nQpAROQYXds47bVsPQqaerCR9a259KZUhfmxwAxEH86lmsot6iPktMIWtg6O7G8jB\\nyWyVxA4f4J2t2g9RIkUG4HOkJ4lG/9QwRM7GtzMqlu8BXd5rp0wF5aWToZJmG/+o\\nWv8LqgNWGwKBgA8wObES8j+R5BjC9/USitvucUwmKSSWImP/w4/FdTXMmri2g0TE\\nLvjUwzv2B0SiZhsCmS0OUum268V3H19YZgcsdKPTxKJvfRQ2ZSKFj4AsfSXqa1+q\\nkYzm1SeO+rFYvXXHDLyM8kCUBSTq7+leMlgtG33gyIasaO7Q0b+F+URDAoGAJQeK\\nIlkeGt8pfrUFYqGNVNN00XHxupFIBC08Qs3ZXKm3u6Mt7MtpCEqyk2JcT6nPJ4Sm\\ncCp4nxaSKrWnJcMQ0/W0nq+XJyxiJy0foApXQWcC6Toebwj/bDY064byVcomrvpF\\nUDGJmMllXNu7FTKrPh6S2ifBCXR7jnWfW9LL8W8CgYAkItXeo5t/cbXjtp87WdIV\\nU+AXb4hbXdm++WQjV+m3PxkPAukHYaxZzHSxVv64urW5YdA9Xv9seJE++KRlpD+a\\nXvELsyJ/lScLp5YQoWcuNpisqkKn72dJWcGZHhfvd8GaFtIaxJ/Krtn2FO39lxjX\\nLdIp77vh3SB7KlsV7AKqwQ==\\n-----END PRIVATE KEY-----\\n'))\n", + "2025-03-14 06:31:39,594 - __main__ - DEBUG - >>> process_login\n", + "2025-03-14 06:31:39,595 - __main__ - DEBUG - process_login: url=https://lab-oai.etsi.org:31120/login\n", + "2025-03-14 06:31:39,595 - __main__ - DEBUG - process_login (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Basic YWRtaW46cGFzc3dvcmQxMjM='}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,639 - __main__ - DEBUG - process_login (step2): result: {'access_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQxOTM0NDk5fQ.wNjsuLgh61j0G_6rtN6vxqfbJGMgtaetJd1xPUOoBb4', 'refresh_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQ0NTI1ODk5fQ.lgD4IZCAVJ3-smu1nFBjTtdhTW_trraua1OppvQd4rc'}\n", + "2025-03-14 06:31:39,640 - __main__ - DEBUG - >>> create_user\n", + "2025-03-14 06:31:39,640 - __main__ - DEBUG - create_user: url=https://lab-oai.etsi.org:31120/createUser\n", + "2025-03-14 06:31:39,641 - __main__ - DEBUG - create_user (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzQxOTM0NDk5fQ.wNjsuLgh61j0G_6rtN6vxqfbJGMgtaetJd1xPUOoBb4'}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,673 - __main__ - DEBUG - create_user (step2): response=<Response [201]>\n", + "2025-03-14 06:31:39,674 - __main__ - DEBUG - >>> get_auth\n", + "2025-03-14 06:31:39,674 - __main__ - DEBUG - get_auth: url=https://lab-oai.etsi.org:31120/getauth\n", + "2025-03-14 06:31:39,675 - __main__ - DEBUG - get_auth (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Basic ZmM5YjlhZWMtMDA5ZC0xMWYwLWI3MDYtMDI0MmFjMTEwMDAyOnBhc3N3b3JkMTIz'}\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:39,760 - __main__ - DEBUG - get_auth (step2): result: {'access_token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiNmEwYzAwMGMtODM1OS00Zjk2LTg2YmYtZWM0NmU0MWI4ZWVlIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjOWI5YWVjLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA0MTFiOWM0MC1mZTUwLTUyN2EtOWU5OS1kMjU1ZWVkODg1OWIiLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiIxMzkyN2UyMC1mYzA3LTQwYTgtYTM1Ni1lNjBmOTRmN2NmYzgiLCJleHAiOjE3NDE5MzQ3OTl9.ajpnFHBQdSMKmy1s5NZVFaYP6ST3e54MpG_6-ExKIvuZ3vnbqae7Y4kRMOOh4wO6NEEoZcAkb7et4spws16q_r4uuonyh5lmXFJIp63wcF1x94Yw4P51y6Qu9lSpAhZuznF-AhgVoFhtK7BI5z37iqiiTywI9HgrEHfbpll2AD5HaB5MVbmjCiFsADdixK4gisf8FRpxdBUdaCpX1pDJsEAIPhRtWt-6ZYBZhrXffNVSoRyA_Pda8fglLiKMk8lWMPYgePYQ4LntE5Hr3K-_OdxstjLyMkHtnmFHlU02fOLSQxbqJEcCBBcTZfxPHLlGbltcXkt8iHeqFKMuK5-h7w', 'ca_root': '-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n', 'ccf_api_onboarding_url': 'api-provider-management/v1/registrations', 'ccf_discover_url': 'service-apis/v1/allServiceAPIs?api-invoker-id=', 'ccf_onboarding_url': 'api-invoker-management/v1/onboardedInvokers', 'ccf_publish_url': 'published-apis/v1/<apfId>/service-apis', 'ccf_security_url': 'capif-security/v1/trustedInvokers/<apiInvokerId>', 'message': 'Token and CA root returned successfully'}\n", + "2025-03-14 06:31:39,761 - __main__ - DEBUG - >>> onboard_invoker: API Invoker\n", + "2025-03-14 06:31:39,761 - __main__ - DEBUG - >>> onboard_invoker: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiNmEwYzAwMGMtODM1OS00Zjk2LTg2YmYtZWM0NmU0MWI4ZWVlIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjOWI5YWVjLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA0MTFiOWM0MC1mZTUwLTUyN2EtOWU5OS1kMjU1ZWVkODg1OWIiLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiIxMzkyN2UyMC1mYzA3LTQwYTgtYTM1Ni1lNjBmOTRmN2NmYzgiLCJleHAiOjE3NDE5MzQ3OTl9.ajpnFHBQdSMKmy1s5NZVFaYP6ST3e54MpG_6-ExKIvuZ3vnbqae7Y4kRMOOh4wO6NEEoZcAkb7et4spws16q_r4uuonyh5lmXFJIp63wcF1x94Yw4P51y6Qu9lSpAhZuznF-AhgVoFhtK7BI5z37iqiiTywI9HgrEHfbpll2AD5HaB5MVbmjCiFsADdixK4gisf8FRpxdBUdaCpX1pDJsEAIPhRtWt-6ZYBZhrXffNVSoRyA_Pda8fglLiKMk8lWMPYgePYQ4LntE5Hr3K-_OdxstjLyMkHtnmFHlU02fOLSQxbqJEcCBBcTZfxPHLlGbltcXkt8iHeqFKMuK5-h7w\n", + "2025-03-14 06:31:39,762 - __main__ - DEBUG - onboard_invoker: url=https://lab-oai.etsi.org:443/api-invoker-management/v1/onboardedInvokers\n", + "2025-03-14 06:31:39,763 - __main__ - DEBUG - onboard_invoker (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiNmEwYzAwMGMtODM1OS00Zjk2LTg2YmYtZWM0NmU0MWI4ZWVlIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjOWI5YWVjLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA0MTFiOWM0MC1mZTUwLTUyN2EtOWU5OS1kMjU1ZWVkODg1OWIiLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiIxMzkyN2UyMC1mYzA3LTQwYTgtYTM1Ni1lNjBmOTRmN2NmYzgiLCJleHAiOjE3NDE5MzQ3OTl9.ajpnFHBQdSMKmy1s5NZVFaYP6ST3e54MpG_6-ExKIvuZ3vnbqae7Y4kRMOOh4wO6NEEoZcAkb7et4spws16q_r4uuonyh5lmXFJIp63wcF1x94Yw4P51y6Qu9lSpAhZuznF-AhgVoFhtK7BI5z37iqiiTywI9HgrEHfbpll2AD5HaB5MVbmjCiFsADdixK4gisf8FRpxdBUdaCpX1pDJsEAIPhRtWt-6ZYBZhrXffNVSoRyA_Pda8fglLiKMk8lWMPYgePYQ4LntE5Hr3K-_OdxstjLyMkHtnmFHlU02fOLSQxbqJEcCBBcTZfxPHLlGbltcXkt8iHeqFKMuK5-h7w'}\n", + "2025-03-14 06:31:39,763 - __main__ - DEBUG - >>> generate_csr\n", + "2025-03-14 06:31:39,833 - __main__ - DEBUG - generate_csr: PrivKey: b'-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGj82/J4u6FSpP\\nSVh1FyO5gjjWJOlT3C9f+z1ZrC3QDSILgHiQlVOBVpaBnw4QWpIwFRnX+nHlL5N0\\njfDWvtqfxp1m3y4PGMv4DV9MRVXSITEnLA/V6hV7FzQkabYdaS4FDGWh7U5Gc2KJ\\n1Sddo5RlYxaH+NIiV9rCvu2frWJ8Ol+2EJwRJgXoBHNtEKkGm+P7IeT+UuPPUiF/\\nRRwgYDd530stLMqYCMTpxFwnxHuLpB1ylPgh7Qdvfg9qylTFndETKpUKkFbn4rvE\\nV939ekBor/Q0nAYXgkhOrbJqLk7LGspFNqC4fFBKgEueeVScIsWll57EDNb/UVAF\\nSYvsvS7NAgMBAAECggEAMEM83cUlc834MjxgKVm9/7W0zew74HvI8hn1sAmnOwYu\\nK8CGzZHWMb5Tp976wqPZG6HNXc9Mhsn5G9/yVagfKK3UjXAa2GWNElZhvv6tXP1f\\nXqeZk8Opg/lAXcdqEh0CKAz62RB+saYTIfBy+JItnDUpAVTL8rgK/sH8rQ6uPQZf\\ngUjXUKpLYrb79IrdYq1qrR6wfNDjru+OrFum/2HpQMDg4abo1whwWsp5nlK/tryj\\nQHN8oieZghg02SpiMwuYkAtAPuQFgN6ENSva08iddxUavO5pHf5BqyUhW2bjaVoo\\nYLT7sr5gx8vhn9h7/+s3H33/Lw+RCvKwdVYueGBOywKBgQDt8DBEIQhHZbSf81Mz\\nCvJpS5DioBQIiw3fmsIToE33bLD19LJNP1IqEilYvnUvC5ctXB9rM3WJ4Fx7uHo2\\ndQMq+/HyGKJNz38pK03/k6ABb+ZNbdI3Qq+4t5SDDwtEui3tGdTGzFFTvNrWuYGg\\n4yIkv0w9gr3STTn4+0MGELf3kwKBgQDVomsnTr1HP1StPh7JcCeMkGIYyW6J4wrZ\\nx3uUI5XR2/xyaaqjToUZu9BUZ0l261mGAsru8fNMIVT46Z3vekVeBuVzBxMg8CW3\\nANKmRqJfLr6MpyBdUyIRkpHUGvx9CnazGSbx+hWB7BNoBqyjRIiow05uNx2hjfnw\\noKONzCl8HwKBgQCJ8rNJDI2sNz8dbQlTkokwmusJOR3kRhppBWR31Hzfcli2gIPP\\nXWLZmWX3WZS/Dc08MyjUEiWXJkj4QeA5KmYHycJgRf/zdNWYnM6/2mrt6l5vjbhO\\n6Y7PXT/xLAuwcPCngk5mY5bTIa8OxsZs7MKi43XkQ6SiBLwTqjkVjyPZmQKBgHJ1\\nr+WCiWTn6I1dcA9LONVV8kkHe2MDMygVef+XxUiIDcybEqKmiieMegUOxcyiMffb\\n/TBij5EldqpaOJU7NHk5RqwHiVcnc32GQlZ2F77Zg5xGWs/Fn8Y8ekdjIg44kfpJ\\nKpWRAP74JjmhAdQD/xg0dAwXGZgaQmSLHLX3Qe7PAoGBANvuaZcN0umxqEYfq8mA\\nhmQ0WJuxaJw42Y2qLnx492kKA4aTODAVzUfkmuWFoIrw+0ivmXS6GUpz1iejSXce\\n3CNw/7Z8b40lnbZN9gVD3YiWLhFZMV7FUtYk5uNuOuXAeoKP9ydFtWANShrtIqFJ\\nyW94au/ArID/+5GvRJt7Taz/\\n-----END PRIVATE KEY-----\\n'\n", + "2025-03-14 06:31:39,834 - __main__ - DEBUG - onboard_invoker (step2): body: {'notificationDestination': 'http://host.docker.internal:8086/netapp_callback', 'supportedFeatures': 'fffffff', 'apiInvokerInformation': 'dummy', 'websockNotifConfig': {'requestWebsocketUri': True, 'websocketUri': 'websocketUri'}, 'onboardingInformation': {'apiInvokerPublicKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICdzCCAV8CAQAwMjEUMBIGA1UEAwwLQVBJIEludm9rZXIxDTALBgNVBAoMBEVU\\nU0kxCzAJBgNVBAYTAkZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\\nxo/NvyeLuhUqT0lYdRcjuYI41iTpU9wvX/s9Wawt0A0iC4B4kJVTgVaWgZ8OEFqS\\nMBUZ1/px5S+TdI3w1r7an8adZt8uDxjL+A1fTEVV0iExJywP1eoVexc0JGm2HWku\\nBQxloe1ORnNiidUnXaOUZWMWh/jSIlfawr7tn61ifDpfthCcESYF6ARzbRCpBpvj\\n+yHk/lLjz1Ihf0UcIGA3ed9LLSzKmAjE6cRcJ8R7i6QdcpT4Ie0Hb34PaspUxZ3R\\nEyqVCpBW5+K7xFfd/XpAaK/0NJwGF4JITq2yai5OyxrKRTaguHxQSoBLnnlUnCLF\\npZeexAzW/1FQBUmL7L0uzQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAAnTqKJS\\n5JCzYIHQ4J31iZzwq5Omg4z4SbowzQl41AnQmPDt5zRkZzhwM1HjAus4Qt0v8M/7\\nwe8BPlYQyRZbHF9HN0Gvqe61E7IAVtftfGdmEMwZigRUJ3wfwxF92a66JMg2IcV0\\nsHzsApr8XxEy7slzjINEDWHUmVEBrLsO9HTE7otGBPdbUQ+NheOYTQKxXUkcDKf5\\nmC1OG4xHWqm1vuxcnbXi1Bc7PHNbiSBckPyPgrGwMYrmSimVeSIJA6YzKGbSozdG\\n73b3ZPO6mCV3qXElgeq+igBC7pCo5EbsSOD0lyJX1Tu3EMo2Rvix5xwI5yx3MpQ2\\nC1iHUqsOd0yNbic=\\n-----END CERTIFICATE REQUEST-----\\n'}, 'requestTestNotification': True}\n", + "2025-03-14 06:31:39,867 - __main__ - DEBUG - onboard_invoker (step3): result: {'apiInvokerId': 'INV87e7a6dbc97d1fd9478862f6bd2ce5', 'onboardingInformation': {'apiInvokerPublicKey': '-----BEGIN CERTIFICATE REQUEST-----\\nMIICdzCCAV8CAQAwMjEUMBIGA1UEAwwLQVBJIEludm9rZXIxDTALBgNVBAoMBEVU\\nU0kxCzAJBgNVBAYTAkZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\\nxo/NvyeLuhUqT0lYdRcjuYI41iTpU9wvX/s9Wawt0A0iC4B4kJVTgVaWgZ8OEFqS\\nMBUZ1/px5S+TdI3w1r7an8adZt8uDxjL+A1fTEVV0iExJywP1eoVexc0JGm2HWku\\nBQxloe1ORnNiidUnXaOUZWMWh/jSIlfawr7tn61ifDpfthCcESYF6ARzbRCpBpvj\\n+yHk/lLjz1Ihf0UcIGA3ed9LLSzKmAjE6cRcJ8R7i6QdcpT4Ie0Hb34PaspUxZ3R\\nEyqVCpBW5+K7xFfd/XpAaK/0NJwGF4JITq2yai5OyxrKRTaguHxQSoBLnnlUnCLF\\npZeexAzW/1FQBUmL7L0uzQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAAnTqKJS\\n5JCzYIHQ4J31iZzwq5Omg4z4SbowzQl41AnQmPDt5zRkZzhwM1HjAus4Qt0v8M/7\\nwe8BPlYQyRZbHF9HN0Gvqe61E7IAVtftfGdmEMwZigRUJ3wfwxF92a66JMg2IcV0\\nsHzsApr8XxEy7slzjINEDWHUmVEBrLsO9HTE7otGBPdbUQ+NheOYTQKxXUkcDKf5\\nmC1OG4xHWqm1vuxcnbXi1Bc7PHNbiSBckPyPgrGwMYrmSimVeSIJA6YzKGbSozdG\\n73b3ZPO6mCV3qXElgeq+igBC7pCo5EbsSOD0lyJX1Tu3EMo2Rvix5xwI5yx3MpQ2\\nC1iHUqsOd0yNbic=\\n-----END CERTIFICATE REQUEST-----\\n', 'apiInvokerCertificate': '-----BEGIN CERTIFICATE-----\\nMIIDgjCCAmqgAwIBAgIUbRfvEE4B2gIGKB4FwwQWAKNT/rowDQYJKoZIhvcNAQEL\\nBQAwJzElMCMGA1UEAxMcY2FwaWYgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTAeFw0y\\nNTAzMTQwNjMxMDlaFw0yNTA5MDkxMDMxMzlaMCwxKjAoBgNVBAMTIUlOVjg3ZTdh\\nNmRiYzk3ZDFmZDk0Nzg4NjJmNmJkMmNlNTCCASIwDQYJKoZIhvcNAQEBBQADggEP\\nADCCAQoCggEBAMaPzb8ni7oVKk9JWHUXI7mCONYk6VPcL1/7PVmsLdANIguAeJCV\\nU4FWloGfDhBakjAVGdf6ceUvk3SN8Na+2p/GnWbfLg8Yy/gNX0xFVdIhMScsD9Xq\\nFXsXNCRpth1pLgUMZaHtTkZzYonVJ12jlGVjFof40iJX2sK+7Z+tYnw6X7YQnBEm\\nBegEc20QqQab4/sh5P5S489SIX9FHCBgN3nfSy0sypgIxOnEXCfEe4ukHXKU+CHt\\nB29+D2rKVMWd0RMqlQqQVufiu8RX3f16QGiv9DScBheCSE6tsmouTssaykU2oLh8\\nUEqAS555VJwixaWXnsQM1v9RUAVJi+y9Ls0CAwEAAaOBoDCBnTAOBgNVHQ8BAf8E\\nBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQ2\\nOXQyNZNJpml3Xyv+rWt333ETmTAfBgNVHSMEGDAWgBRyWzJdjOmGfJFOwo6wJiup\\nYnm00jAsBgNVHREEJTAjgiFJTlY4N2U3YTZkYmM5N2QxZmQ5NDc4ODYyZjZiZDJj\\nZTUwDQYJKoZIhvcNAQELBQADggEBAEAL/HW76QNK6eQsomekoYQA2mxlZQ+k216s\\nSxuE6wl+WEgi6SEZyAx3/ZhELLF2SUtURQvfm+RuDbgUMK1kWX4RBRm/8hXgwKyu\\n0H450FF+FwKhE08qMpfbDf4uv5yrGpTdtuLt+g90iXV6Dq2IzJeWiQ7dzXhqVxfX\\nfX/f81S0mbjbnaTSum/OZjJDf+p1lacTdcNLVKgP1YjJkt8qtLJz5UO4rNza4mka\\nSDwyVKyIEgz0OEnc5SuA6A99L4YMI0oZ4vpicvWEERzybyfOHn4M1TG1yHFM+dUJ\\nBv6pbo4mQhNsJ0AIUOgQmoVO2gnW/zNclmLmN3dh8Vknz4gWWRE=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDKDCCAhCgAwIBAgIUDUrJG3QedRyOQ5suvo1eB0WThr0wDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzAwMzA0MDcy\\nMzMxWjAnMSUwIwYDVQQDExxjYXBpZiBJbnRlcm1lZGlhdGUgQXV0aG9yaXR5MIIB\\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzxRlEt2FkvKfjxqiq5uFhgyx\\nqNQ0Lct/0CksmQQaR4CZjebZPF2MAnz56L4O8dtqGOFPOYjBY2I0XZ7+hlNBJMwA\\nPC4Ea/q7yPOBzTlJ0gRtIdW/2kiUzxt5TX4LBJsEtn7mZw9KRTSubDfXAt6X5LMA\\ndmG/IYiXERtd/sx3Qya8Hv6L4O9H+RGe2tOd3oVrpbX8QDOlNFHNWdALWFq1vB28\\nUwZ6bmW4ZU8xakc0s8TMFhIKNi3zNVSLyEQlkZ2o3tzSDsjevOJ6iiJWfArObLY+\\ncNaCJYk5g6MsfCp+kTP0TZ4DO5Z9Xwi+xNKM2BoYU3xBfzB9ULF+ZCCoZxnSnQID\\nAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\nFgQUclsyXYzphnyRTsKOsCYrqWJ5tNIwHwYDVR0jBBgwFoAUkzuK1gy5rzhMq0ax\\nZ4aulK6HzMgwDQYJKoZIhvcNAQELBQADggEBAJx2XwG2+EB6kL0hHFnTEuuiXiqH\\nCOzTbNAMswFsgHb6K7pWJ9d3ZCp1Tm96+4+Q1tN8pj4ZVlps6bOxosznJxdWsMGm\\ncGT4Oxdw11tX5oOk8eTlYkmzwBsv1rXlBsyNxqnOO/z6OCjG0o14mOWEgL/cNC+0\\niZ0AAr1dSobOfe2bOvfcUjTwMfsHq5iqs6scIsMfghKxhUKreRFNsvMwIZGWHSxm\\nn8jpbgVKYl5jw4PbbEHnvWB2PupFGn3omxuFM14gT5SSHKizHqqjnc9xbVbo94ps\\nEFv/+YwAx+cy3q8khdgWfp5so8LR2s1fBA1YcFJMxig6ozbSelDcRadMvPM=\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\nMIIDIzCCAgugAwIBAgIUY/66jK16pFsGagTpZLjVW2ow40QwDQYJKoZIhvcNAQEL\\nBQAwEDEOMAwGA1UEAxMFY2FwaWYwHhcNMjUwMzA1MDcyMzAxWhcNMzUwMzAzMDcy\\nMzMxWjAQMQ4wDAYDVQQDEwVjYXBpZjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\nAQoCggEBAKHM8mtKDtJdwE0ZSr+CD+u0jY6GrWMJ1rhZsXltiLbPOGBIOqioGyZ2\\nR9YEfWnrChznY9vFST95PU53gUO1GtnHpNqbXUGlsmQ0KwTeE6MzKflXbq3b0RQG\\nHMO6hw9Juqllmv3FDwCjVl4ZNJyrF2ekoqqBoFlSUeNI8V7cZF5sMPDe3rljzeRb\\njkmv+63FEAaOX1VcUMx6PWHSpGPQsY7jskVoLO60yJurq6qWz598wyZMc9hUj3Al\\nF9H2YaxqU+tfuQyjt9x3qeI1xNT293jBldvI2Xvh0+eJ0niCzjuCLHGU2WJ4OOE3\\nUtCVE0sDpLViUB7KMH8PO4Te4cu5XHMCAwEAAaN1MHMwDgYDVR0PAQH/BAQDAgEG\\nMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJM7itYMua84TKtGsWeGrpSuh8zI\\nMB8GA1UdIwQYMBaAFJM7itYMua84TKtGsWeGrpSuh8zIMBAGA1UdEQQJMAeCBWNh\\ncGlmMA0GCSqGSIb3DQEBCwUAA4IBAQCHCtL6PE+xrCCKL8B6W5RZP0whBftjrtfd\\nb/w7Lwq7/XmFeDrMdve12p0tjJ3Bo2EpJqgoTLHrVnd8THcOiFZS6zb2dDX3CKA/\\nMYMqc5+7qzH+0ts9Pi/+L3CsWMvCY2OUT0ojUGdpUmjQhSZqLKofTSBe5H2UzQmT\\n/3vilDHoICKNCE7ob8BJzHQJfvGk/XRtxmuySz+LuK/JOm4auL0IjsWtpqPR0SKJ\\nunNsmjPt7E012kYkmvcwbgDvN7JbK3Frwm32R4hYpETH6pnTEx6YNxbMZXGB50lS\\nnHiEj9eM3AvpecMNVlBJanetzoHfV+mYSoVGJEvuvn4QWXMzrVD4\\n-----END CERTIFICATE-----'}, 'notificationDestination': 'http://host.docker.internal:8086/netapp_callback', 'requestTestNotification': True, 'websockNotifConfig': {'websocketUri': 'websocketUri', 'requestWebsocketUri': True}, 'apiInvokerInformation': 'dummy', 'supportedFeatures': 'fffffff'}\n", + "2025-03-14 06:31:39,868 - __main__ - DEBUG - >>> Discover APIs published by capif core\n", + "2025-03-14 06:31:39,869 - __main__ - DEBUG - Discover: url=https://lab-oai.etsi.org:443/service-apis/v1/allServiceAPIs?api-invoker-id=INV87e7a6dbc97d1fd9478862f6bd2ce5\n", + "2025-03-14 06:31:39,869 - __main__ - DEBUG - Discover (step1): headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTkzMzg5OSwianRpIjoiNmEwYzAwMGMtODM1OS00Zjk2LTg2YmYtZWM0NmU0MWI4ZWVlIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImZjOWI5YWVjLTAwOWQtMTFmMC1iNzA2LTAyNDJhYzExMDAwMiA0MTFiOWM0MC1mZTUwLTUyN2EtOWU5OS1kMjU1ZWVkODg1OWIiLCJuYmYiOjE3NDE5MzM4OTksImNzcmYiOiIxMzkyN2UyMC1mYzA3LTQwYTgtYTM1Ni1lNjBmOTRmN2NmYzgiLCJleHAiOjE3NDE5MzQ3OTl9.ajpnFHBQdSMKmy1s5NZVFaYP6ST3e54MpG_6-ExKIvuZ3vnbqae7Y4kRMOOh4wO6NEEoZcAkb7et4spws16q_r4uuonyh5lmXFJIp63wcF1x94Yw4P51y6Qu9lSpAhZuznF-AhgVoFhtK7BI5z37iqiiTywI9HgrEHfbpll2AD5HaB5MVbmjCiFsADdixK4gisf8FRpxdBUdaCpX1pDJsEAIPhRtWt-6ZYBZhrXffNVSoRyA_Pda8fglLiKMk8lWMPYgePYQ4LntE5Hr3K-_OdxstjLyMkHtnmFHlU02fOLSQxbqJEcCBBcTZfxPHLlGbltcXkt8iHeqFKMuK5-h7w'}\n", + "2025-03-14 06:31:39,870 - __main__ - DEBUG - >>> store_certificate_2_files\n", + "2025-03-14 06:31:39,871 - __main__ - DEBUG - Discover (step2): bundle: ['p_crt.crt', 'p_key.key', 'ca_root.pem']\n", + "2025-03-14 06:31:39,900 - __main__ - DEBUG - Discover (step3): response=<Response [200]>\n", + "2025-03-14 06:31:39,901 - __main__ - DEBUG - Discover : result: {'serviceAPIDescriptions': [{'apiName': 'MEC Profile for CAPIF', 'apiId': 'a55b2ecc0ee7a2ff0d5b7da3a63dd2', 'aefProfiles': [{'aefId': 'AEFb7a696201b577f7c0233923e4b5839', 'versions': [{'apiVersion': 'v1', 'expiry': '2025-11-30T10:32:02.004000+00:00', 'resources': [{'resourceName': 'MEC Profile of CAPIF', 'commType': 'REQUEST_RESPONSE', 'uri': '/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs', 'custOpName': 'string', 'operations': ['GET'], 'description': 'Endpoint to access MEC services'}], 'custOperations': [{'commType': 'REQUEST_RESPONSE', 'custOpName': 'string', 'operations': ['GET'], 'description': 'string'}]}], 'protocol': 'HTTP_1_1', 'dataFormat': 'JSON', 'securityMethods': ['OAUTH'], 'interfaceDescriptions': [{'ipv4Addr': 'try-mec.etsi.org', 'securityMethods': ['OAUTH']}]}], 'description': 'MEC Profile of CAPIF', 'supportedFeatures': 'fffff', 'shareableInfo': {'isShareable': True, 'capifProvDoms': ['string']}, 'serviceAPICategory': 'string', 'apiSuppFeats': 'fffff', 'pubApiPath': {'ccfIds': ['string']}, 'ccfId': 'string'}]}\n", + "2025-03-14 06:31:39,902 - __main__ - DEBUG - addrs: {'ipv4Addr': ['try-mec.etsi.org'], 'uri': ['/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs']}\n", + "2025-03-14 06:31:39,902 - __main__ - DEBUG - >>> discovering_mec_services: https://try-mec.etsi.org/sbxx3i4jhr/mep1/service-apis/v1/allServiceAPIs\n", + "2025-03-14 06:31:39,903 - __main__ - DEBUG - discovering_mec_services (step1): headers: {'Content-Type': 'application/json', 'accept': 'application/json'}\n", + "2025-03-14 06:31:39,930 - __main__ - DEBUG - discovering_mec_services (step2): result: {'serviceAPIDescriptions': [{'apiName': 'mec016-1', 'apiId': 'fa5b0b09-c2e6-4bf6-b7f2-8853132a50da', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/dev_app/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'daiId', 'name': 'DAI', 'version': 'v1'}}}, {'apiName': 'mec015-1', 'apiId': '70ff5514-1479-4746-a867-406b904962fe', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/bwm/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'bwmId', 'name': 'BWM', 'version': 'v1'}}}, {'apiName': 'mec013-1', 'apiId': 'fb18ea66-b93c-4b4d-9d6f-9ed197355ad6', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['3.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/location/v3/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'locationId', 'name': 'Location', 'version': 'v2'}}}, {'apiName': 'mec028-1', 'apiId': '9c69f4b0-77e8-4cb3-ad8f-b666f38f2560', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/wai/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'waiId', 'name': 'WAI', 'version': 'v2'}}}, {'apiName': 'mec012-1', 'apiId': '89e1b639-0780-4fd1-9c12-fe771e0cbafb', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/rni/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'rniId', 'name': 'RNI', 'version': 'v2'}}}, {'apiName': 'mec015-1', 'apiId': '9ee651cc-2eb5-4db8-8c57-40036889835f', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/mts/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'mtsId', 'name': 'MTS', 'version': 'v1'}}}, {'apiName': 'mec030-1', 'apiId': 'f304467b-a269-4647-9aca-67df18b3b5b2', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['3.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/vis/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'visId', 'name': 'V2XI', 'version': 'v2'}}}]}\n", + "2025-03-14 06:31:39,932 - __main__ - DEBUG - ===> The list of the MEC services exposed by try-mec.etsi.org is: {'serviceAPIDescriptions': [{'apiName': 'mec016-1', 'apiId': 'fa5b0b09-c2e6-4bf6-b7f2-8853132a50da', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/dev_app/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'daiId', 'name': 'DAI', 'version': 'v1'}}}, {'apiName': 'mec015-1', 'apiId': '70ff5514-1479-4746-a867-406b904962fe', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/bwm/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'bwmId', 'name': 'BWM', 'version': 'v1'}}}, {'apiName': 'mec013-1', 'apiId': 'fb18ea66-b93c-4b4d-9d6f-9ed197355ad6', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['3.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/location/v3/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'locationId', 'name': 'Location', 'version': 'v2'}}}, {'apiName': 'mec028-1', 'apiId': '9c69f4b0-77e8-4cb3-ad8f-b666f38f2560', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/wai/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'waiId', 'name': 'WAI', 'version': 'v2'}}}, {'apiName': 'mec012-1', 'apiId': '89e1b639-0780-4fd1-9c12-fe771e0cbafb', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/rni/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'rniId', 'name': 'RNI', 'version': 'v2'}}}, {'apiName': 'mec015-1', 'apiId': '9ee651cc-2eb5-4db8-8c57-40036889835f', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['2.2.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/mts/v1/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'mtsId', 'name': 'MTS', 'version': 'v1'}}}, {'apiName': 'mec030-1', 'apiId': 'f304467b-a269-4647-9aca-67df18b3b5b2', 'aefProfiles': [{'aefId': 'sandboxTransport', 'versions': ['3.1.1'], 'interfaceDescriptions': {'uris': ['https://try-mec.etsi.org/sbxx3i4jhr/mep1/vis/v2/'], 'fqdn': None, 'addresses': None, 'alternative': None}, 'vendorSpecific-urn:etsi:mec:capifext:transport-info': {'name': 'REST', 'type': 'REST_HTTP', 'protocol': 'HTTP', 'version': '2.0'}}], 'vendorSpecific-urn:etsi:mec:capifext:service-info': {'serializer': 'JSON', 'state': 'ACTIVE', 'scopeOfLocality': 'MEC_SYSTEM', 'consumedLocalOnly': True, 'isLocal': True, 'category': {'href': 'catalogueHref', 'id': 'visId', 'name': 'V2XI', 'version': 'v2'}}}]}\n", + "2025-03-14 06:31:39,932 - __main__ - DEBUG - >>> offboard_invoker: INV87e7a6dbc97d1fd9478862f6bd2ce5\n", + "2025-03-14 06:31:39,933 - __main__ - DEBUG - offboard_invoker: url=https://lab-oai.etsi.org:443/api-invoker-management/v1/onboardedInvokers/INV87e7a6dbc97d1fd9478862f6bd2ce5\n", + "2025-03-14 06:31:39,933 - __main__ - DEBUG - offboard_invoker (step1): headers: {'Content-Type': 'application/json'}\n", + "2025-03-14 06:31:39,933 - __main__ - DEBUG - >>> store_certificate_2_files\n", + "2025-03-14 06:31:39,934 - __main__ - DEBUG - offboard_invoker (step2): bundle: ['p_crt.crt', 'p_key.key', 'ca_root.pem']\n", + "2025-03-14 06:31:39,967 - __main__ - DEBUG - offboard_invoker (step3): response=<Response [204]>\n", + "2025-03-14 06:31:39,968 - __main__ - DEBUG - >>> delete_user\n", + "2025-03-14 06:31:39,969 - __main__ - DEBUG - delete_user: url=https://lab-oai.etsi.org:31120/deleteUser/411b9c40-fe50-527a-9e99-d255eed8859b\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:40,020 - __main__ - DEBUG - delete_user: response=<Response [204]>\n", + "2025-03-14 06:31:40,021 - __main__ - DEBUG - >>> remove_publish_api \n", + "2025-03-14 06:31:40,021 - __main__ - DEBUG - >>> offboarding_provider: 5887716a-35ef-5f99-bd94-38d1fa3d0317\n", + "2025-03-14 06:31:40,022 - __main__ - DEBUG - >>> offboard_provider\n", + "2025-03-14 06:31:40,022 - __main__ - DEBUG - offboard_provider: url=https://lab-oai.etsi.org:443/api-provider-management/v1/registrations/7d1e7acfc6bb19a31614da0968a8f8\n", + "2025-03-14 06:31:40,022 - __main__ - DEBUG - offboard_provider (step1): headers: {'Content-Type': 'application/json'}\n", + "2025-03-14 06:31:40,023 - __main__ - DEBUG - >>> store_certificate_2_files\n", + "2025-03-14 06:31:40,024 - __main__ - DEBUG - offboard_provider (step2): bundle: ['p_crt.crt', 'p_key.key', 'ca_root.pem']\n", + "2025-03-14 06:31:40,050 - __main__ - DEBUG - offboard_provider (step3): response=<Response [204]>\n", + "2025-03-14 06:31:40,052 - __main__ - DEBUG - >>> delete_user\n", + "2025-03-14 06:31:40,053 - __main__ - DEBUG - delete_user: url=https://lab-oai.etsi.org:31120/deleteUser/5887716a-35ef-5f99-bd94-38d1fa3d0317\n", + "/opt/conda/lib/python3.11/site-packages/urllib3/connectionpool.py:1099: InsecureRequestWarning: Unverified HTTPS request is being made to host 'lab-oai.etsi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warnings\n", + " warnings.warn(\n", + "2025-03-14 06:31:40,089 - __main__ - DEBUG - delete_user: response=<Response [204]>\n" + ] + } + ], + "source": [ + "#%%script echo skipping\n", + "# Comment the line above to execute this cell\n", + "def process_main():\n", + " \"\"\"\n", + " This is the fiveth sprint of our CAPIF/MEC application:\n", + " - Publish the MEC profile for CAPIF API\n", + " - Create a new user for the invoker\n", + " - Get certificates\n", + " - Onboad the API invoker\n", + " - Do the discovery\n", + " - Offboard the API invoker\n", + " - Delete the\n", + " - Logout the invoker user\n", + " - Remove the MEC profile for CAPIF API\n", + " \"\"\"\n", + " global logger, ca_root, ccf_api_onboarding_url, ccf_discover_url, ccf_onboarding_url, ccf_publish_url, ccf_security_url\n", + "\n", + " logger.debug('Starting at ' + time.strftime('%Y%m%d-%H%M%S'))\n", + " logger.debug('\\t pwd= ' + os.getcwd())\n", + "\n", + " # Publish the MEC profile for CAPIF API\n", + " res = publish_api()\n", + " if len(res) == 0:\n", + " return\n", + " api_id, bundle, prov_user_uuid, prov_admin_token = res\n", + "\n", + " # Login for the new user for the invoker\n", + " refresh_token, admin_token = process_login()\n", + " if refresh_token is None:\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Create a new user for the invoker\n", + " res = create_user(admin_token)\n", + " if len(res) == 0:\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + " user_name, user_uuid = res\n", + "\n", + " # Get certificates\n", + " auth = get_auth(user_name, USER_PASSWORD)\n", + " if len(auth) == 0:\n", + " delete_user(user_name, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Sanity checks\n", + " if auth['ca_root'] != ca_root:\n", + " raise Exception('CA root mismatch')\n", + " if auth['ccf_api_onboarding_url'] != ccf_api_onboarding_url:\n", + " raise Exception('CCF API onboarding URL mismatch')\n", + " if auth['ccf_discover_url'] != ccf_discover_url:\n", + " raise Exception('CCF discover URL mismatch')\n", + " if auth['ccf_onboarding_url'] != ccf_onboarding_url:\n", + " raise Exception('CCF onboarding URL mismatch')\n", + " if auth['ccf_publish_url'] != ccf_publish_url:\n", + " raise Exception('CCF publish URL mismatch')\n", + " if auth['ccf_security_url'] != ccf_security_url:\n", + " raise Exception('CCF security URL mismatch')\n", + " access_token = auth['access_token']\n", + "\n", + " # Onboad the API invoker\n", + " res = onboard_invoker('API Invoker', access_token)\n", + " if len(res) == 0:\n", + " delete_user(user_uuid, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Do the discovery\n", + " invoker_id = res['apiInvokerId']\n", + " certs_bundle = (res['onboardingInformation']['apiInvokerCertificate'], res['csr'][1])\n", + " mec_api = discover(invoker_id, certs_bundle, access_token)\n", + " if len(mec_api) == 0:\n", + " files_bundle = offboard_invoker(invoker_id, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + " delete_user(user_uuid, admin_token)\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + " return\n", + "\n", + " # Extract the URL to access to the MEC Sandbox platform\n", + " addrs = extract_ipv4_and_uri(mec_api)\n", + " logger.debug('addrs: ' + str(addrs))\n", + "\n", + " # Discovering MEC services\n", + " url = ''\n", + " if 'ports' in addrs:\n", + " url = 'https://' + addrs['ipv4Addr'][0] + ':' + addrs['ports'][0]\n", + " else:\n", + " url = 'https://' + addrs['ipv4Addr'][0]\n", + " url += addrs['uri'][0]\n", + " mec_services = discovering_mec_services(url)\n", + " if len(mec_services) != 0:\n", + " logger.debug('===> The list of the MEC services exposed by ' + addrs['ipv4Addr'][0] + ' is: ' + str(mec_services))\n", + "\n", + " # Offboard the API invoker\n", + " files_bundle = offboard_invoker(invoker_id, certs_bundle)\n", + " if len(files_bundle) == 0:\n", + " for file in files_bundle:\n", + " os.remove(file)\n", + "\n", + " # Delete the invoker user\n", + " delete_user(user_uuid, admin_token)\n", + "\n", + " # Logout the invoker user\n", + " process_logout()\n", + "\n", + " # Remove the MEC profile for CAPIF API\n", + " remove_publish_api(prov_user_uuid, api_id, bundle, prov_admin_token)\n", + "\n", + "if __name__ == '__main__':\n", + " process_main()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cfy6D8wYt5GA" + }, + "source": [ + "### What to do next\n", + "\n", + "here is a list of several additional tasks yo can do to refine our CAPIF application:\n", + "1. Simply the code of the process_main() function above\n", + "2. Find the endpoint of the MEC Location API service (MEC 013) and send a request to get the list of zones available\n", + "3. Create your own CAPIF application" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "m_BbV7KdpX24" + }, + "source": [ + "## Conlusion: what do we learn?\n", + "\n", + "The main objective of this tutorial is to demonstrate how to use the MEC profile for CAPIF (as described in MEC 011 v3.x.x Clause 9) in a CAPIF application. Along this tutrial, we learned how to develop a basic CAPIF application, including both API provider and API invoker. We learned also how to use a published API to send REQUEST to a MEC Sandbox platform instance.\n", + "\n", + "\n", + "**That's all Folks**\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "private_outputs": true, + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} -- GitLab