From 2ad24419ef7b498cfd5c1627e880b445ed4c2e2d Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 12:43:15 +0100 Subject: [PATCH 01/28] ci/cd --- pyproject.toml | 51 ------------------------------------------------ setup.py | 53 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 56 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 4434717..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,51 +0,0 @@ -[build-system] -requires = ["setuptools>=61.0"] -build-backend = "setuptools.build_meta" - -[project] -name = "opencapif_sdk" -version = "0.1.15" -authors = [ - { name="JorgeEcheva", email="jorge.echevarriauribarri.practicas@telefonica.com" }, - { name="dgs-cgm", email="daniel.garciasanchez@telefonica.com" } -] -description = "This repository develops a Python Software Development Kit(SDK) which focuses on connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." -readme = "./doc/README_pipy.md" -license = { file="LICENSE" } -requires-python = ">=3.9" -keywords = ["pesp_capif_sdk","capif","sdk capif","opencapif_sdk"] -dependencies = [ - "requests==2.32.3", - "PyYAML==6.0.1", - "cryptography==38.0.4", - "pyOpenSSL==22.1.0", - "urllib3==2.2.2", - "certifi==2024.7.4", - "idna==3.7", - "Flask==3.0.3", - "Flask-JWT-Extended==4.6.0", - "Jinja2==3.1.4", - "MarkupSafe==2.1.5", - "six==1.16.0", - "typing-extensions>=4.8.0", - "Werkzeug==3.0.4", - "pytest==8.3.2", - "flake8==3.9.2", - "coverage==4.5.4", - "mccabe==0.6.1", - "pycodestyle==2.7.0", - "pyflakes==2.3.1", - "python-dateutil==2.9.0.post0", - "jinja2-time==0.2.0", - "text-unidecode==1.3", - "binaryornot==0.4.4" -] - - -classifiers = [ - "Programming Language :: Python :: 3", - "Operating System :: OS Independent", -] - -[project.urls] -"Homepage" = "https://github.com/Telefonica/pesp_capif_sdk" diff --git a/setup.py b/setup.py index ace150b..92e13c6 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,52 @@ -"""The setup script.""" - from setuptools import setup, find_packages setup( - name='opencapif_sdk', - packages=find_packages(include=["opencapif_sdk"]), + name="opencapif_sdk", version="0.1.15", -) \ No newline at end of file + author="JorgeEcheva, dgs-cgm", + author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", + description=( + "This repository develops a Python Software Development Kit(SDK) which focuses on " + "connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, " + "lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." + ), + long_description=open("./doc/README_pipy.md").read(), + long_description_content_type="text/markdown", + license="LICENSE", + python_requires=">=3.9", + keywords=[ + "pesp_capif_sdk", "capif", "sdk capif", "opencapif_sdk" + ], + classifiers=[ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", + ], + packages=find_packages(), + install_requires=[ + "requests==2.32.3", + "PyYAML==6.0.1", + "cryptography==38.0.4", + "pyOpenSSL==22.1.0", + "urllib3==2.2.2", + "certifi==2024.7.4", + "idna==3.7", + "Flask==3.0.3", + "Flask-JWT-Extended==4.6.0", + "Jinja2==3.1.4", + "MarkupSafe==2.1.5", + "six==1.16.0", + "typing-extensions>=4.8.0", + "Werkzeug==3.0.4", + "pytest==8.3.2", + "flake8==3.9.2", + "coverage==4.5.4", + "mccabe==0.6.1", + "pycodestyle==2.7.0", + "pyflakes==2.3.1", + "python-dateutil==2.9.0.post0", + "jinja2-time==0.2.0", + "text-unidecode==1.3", + "binaryornot==0.4.4", + ], + url="https://github.com/Telefonica/pesp_capif_sdk", +) -- GitLab From 73d59cb3a434e6cedf5d791a379e450e14b0a656 Mon Sep 17 00:00:00 2001 From: Jorge Echevarria Uribarri <jorge.echevarriauribarri.practicas@telefonica.com> Date: Fri, 29 Nov 2024 12:59:10 +0100 Subject: [PATCH 02/28] Create python-publish.yml --- .github/workflows/python-publish.yml | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/python-publish.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..85ce499 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,70 @@ +# This workflow will upload a Python Package to PyPI when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + release-build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Build release distributions + run: | + # NOTE: put your own distribution build steps here. + python -m pip install build + python -m build + + - name: Upload distributions + uses: actions/upload-artifact@v4 + with: + name: release-dists + path: dist/ + + pypi-publish: + runs-on: ubuntu-latest + needs: + - release-build + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + + # Dedicated environments with protections for publishing are strongly recommended. + # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules + environment: + name: pypi + # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: + # url: https://pypi.org/p/YOURPROJECT + # + # ALTERNATIVE: if your GitHub Release name is the PyPI project version string + # ALTERNATIVE: exactly, uncomment the following line instead: + url: https://pypi.org/project/opencapif-sdk/${{ github.event.release.name }} + + steps: + - name: Retrieve release distributions + uses: actions/download-artifact@v4 + with: + name: release-dists + path: dist/ + + - name: Publish release distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ -- GitLab From 67df8bd5dbb37b27b3a54a9542db5039627f21d6 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:00:22 +0100 Subject: [PATCH 03/28] CI/CD test --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 92e13c6..d66f113 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="opencapif_sdk", - version="0.1.15", + version="0.1.16", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( -- GitLab From 9def63df96a6c02749d8a023f2c55b7386ed6535 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:03:47 +0100 Subject: [PATCH 04/28] modified: .github/workflows/python-publish.yml --- .github/workflows/python-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 85ce499..c96f81f 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -51,7 +51,7 @@ jobs: environment: name: pypi # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: - # url: https://pypi.org/p/YOURPROJECT + # # ALTERNATIVE: if your GitHub Release name is the PyPI project version string # ALTERNATIVE: exactly, uncomment the following line instead: -- GitLab From 649c333d0b5b425420aa5daec64d73639bd4ddab Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:15:08 +0100 Subject: [PATCH 05/28] CI/CD test --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d66f113..4f8fe95 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( "connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, " "lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." ), - long_description=open("./doc/README_pipy.md").read(), + long_description=open("doc/README_pipy.md").read(), long_description_content_type="text/markdown", license="LICENSE", python_requires=">=3.9", -- GitLab From 1198b535e477edbb4b792af07fb893845fa159a1 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:19:59 +0100 Subject: [PATCH 06/28] Move readme_pip --- doc/README_pipy.md => README_pipy.md | 0 setup.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename doc/README_pipy.md => README_pipy.md (100%) diff --git a/doc/README_pipy.md b/README_pipy.md similarity index 100% rename from doc/README_pipy.md rename to README_pipy.md diff --git a/setup.py b/setup.py index 4f8fe95..8dc1db4 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( "connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, " "lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." ), - long_description=open("doc/README_pipy.md").read(), + long_description=open("README_pipy.md").read(), long_description_content_type="text/markdown", license="LICENSE", python_requires=">=3.9", -- GitLab From f8e6e15a26ef84c35c44e7ade52ec3b2aa2fd25f Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:35:35 +0100 Subject: [PATCH 07/28] manifest --- MANIFEST.in | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..245e6aa --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README_pipy.md +include LICENSE \ No newline at end of file -- GitLab From 0cc3b7c1130f3730746ecc4cc15ea82a1ef451eb Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Fri, 29 Nov 2024 13:42:26 +0100 Subject: [PATCH 08/28] setup --- setup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8dc1db4..6877edc 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,9 @@ from setuptools import setup, find_packages +import os + +this_directory = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f: + long_description = f.read() setup( name="opencapif_sdk", @@ -10,7 +15,7 @@ setup( "connecting to OpenCAPIF (Common API Framework for 3GPP Northbound APIs) in a simple way, " "lowering integration complexity and allowing developers to focus on Network Applications (Network Apps) or services development." ), - long_description=open("README_pipy.md").read(), + long_description=long_description, long_description_content_type="text/markdown", license="LICENSE", python_requires=">=3.9", @@ -21,7 +26,7 @@ setup( "Programming Language :: Python :: 3", "Operating System :: OS Independent", ], - packages=find_packages(), + packages=find_packages(include=["opencapif_sdk", "opencapif_sdk.*"]), # Ajusta según tus necesidades install_requires=[ "requests==2.32.3", "PyYAML==6.0.1", -- GitLab From e25b521cff4ae9073d2d1d0959fc489e48063c57 Mon Sep 17 00:00:00 2001 From: Jorge Echevarria Uribarri <jorge.echevarriauribarri.practicas@telefonica.com> Date: Mon, 2 Dec 2024 10:12:16 +0100 Subject: [PATCH 09/28] Create gitlab.yml --- .github/workflows/gitlab.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/gitlab.yml diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml new file mode 100644 index 0000000..8b8fa51 --- /dev/null +++ b/.github/workflows/gitlab.yml @@ -0,0 +1,30 @@ +name: Sync GitHub to GitLab + +on: + push: + branches: + - develop # Se activa cuando hay cambios en la rama develop + +jobs: + sync: + runs-on: ubuntu-latest + + steps: + # 1. Checkout del código desde GitHub + - name: Checkout GitHub repository + uses: actions/checkout@v4 + + # 2. Configurar Git para empujar a GitLab + - name: Push to GitLab main + env: + GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} + run: | + # Configurar Git + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + # Agregar el repositorio remoto de GitLab + git remote add gitlab https://oauth2:${GITLAB_TOKEN}@labs.etsi.org/rep/ocf/sdk.git + + # Forzar el push de la rama develop a main en GitLab + git push -u gitlab develop:main --force -- GitLab From ba9a07c8faf17f7990f0a54ae7488f301af448bf Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Mon, 2 Dec 2024 10:16:18 +0100 Subject: [PATCH 10/28] empty configuration --- test/capif_sdk_config_sample_test.json | 54 +++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/capif_sdk_config_sample_test.json b/test/capif_sdk_config_sample_test.json index 49502a9..f91920e 100644 --- a/test/capif_sdk_config_sample_test.json +++ b/test/capif_sdk_config_sample_test.json @@ -1,27 +1,27 @@ { - "capif_host": "capif-prev.mobilesandbox.cloud", - "register_host": "registercapif-prev.mobilesandbox.cloud", - "capif_https_port": "36212", - "capif_register_port": "36211", - "capif_username": "echeva_0", - "capif_password": "echevapass", - "debug_mode": "True", + "capif_host": "", + "register_host": "", + "capif_https_port": "", + "capif_register_port": "", + "capif_username": "", + "capif_password": "", + "debug_mode": "", "invoker":{ - "invoker_folder": "/Users/IDB0128/Documents/OpenCapif/test_invoker_certificate_folder", - "capif_callback_url": "http://localhost:5000", - "supported_features":"fffffff", + "invoker_folder": "", + "capif_callback_url": "", + "supported_features":"", "check_authorization":{ "ip":"", "port":"" }, "cert_generation":{ - "csr_common_name": "Echeva", - "csr_organizational_unit": "discovery", - "csr_organization": "telefonica", - "csr_locality": "madrid", - "csr_state_or_province_name": "madrid", - "csr_country_name": "ES", - "csr_email_address": "adios@gmail.com" + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" }, "discover_filter": { "api-name": "", @@ -40,18 +40,18 @@ } }, "provider":{ - "provider_folder": "/Users/IDB0128/Documents/OpenCapif/test_provider_certificate_folder", + "provider_folder": "", "cert_generation":{ - "csr_common_name": "provider", - "csr_organizational_unit": "discovery", - "csr_organization": "telefonica", - "csr_locality": "madrid", - "csr_state_or_province_name": "madrid", - "csr_country_name": "ES", - "csr_email_address": "hola@gmail.com" + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" }, - "apfs": "2", - "aefs": "3", + "apfs": "", + "aefs": "", "publish_req": { "service_api_id": "", "publisher_apf_id": "", -- GitLab From ce660b078544e579c6a26b62c79644971f2dc5b7 Mon Sep 17 00:00:00 2001 From: Jorge Echevarria Uribarri <jorge.echevarriauribarri.practicas@telefonica.com> Date: Mon, 2 Dec 2024 10:29:32 +0100 Subject: [PATCH 11/28] Update gitlab.yml --- .github/workflows/gitlab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml index 8b8fa51..faa718a 100644 --- a/.github/workflows/gitlab.yml +++ b/.github/workflows/gitlab.yml @@ -27,4 +27,4 @@ jobs: git remote add gitlab https://oauth2:${GITLAB_TOKEN}@labs.etsi.org/rep/ocf/sdk.git # Forzar el push de la rama develop a main en GitLab - git push -u gitlab develop:main --force + git push -u gitlab develop:main -- GitLab From 6b9094c2e34cba95c8f63625ed57db7ef2ac3dbd Mon Sep 17 00:00:00 2001 From: Jorge Echevarria Uribarri <jorge.echevarriauribarri.practicas@telefonica.com> Date: Mon, 2 Dec 2024 10:36:28 +0100 Subject: [PATCH 12/28] Update gitlab.yml --- .github/workflows/gitlab.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml index faa718a..9ffac42 100644 --- a/.github/workflows/gitlab.yml +++ b/.github/workflows/gitlab.yml @@ -26,5 +26,11 @@ jobs: # Agregar el repositorio remoto de GitLab git remote add gitlab https://oauth2:${GITLAB_TOKEN}@labs.etsi.org/rep/ocf/sdk.git - # Forzar el push de la rama develop a main en GitLab + # Traer la última versión de main desde GitLab + git fetch gitlab main + + # Fusionar los cambios de main en develop (si es necesario) + git merge gitlab/main + + # Empujar los cambios de develop a main en GitLab git push -u gitlab develop:main -- GitLab From 4d56660e556a026c4f53871afb492cbad823f616 Mon Sep 17 00:00:00 2001 From: Jorge Echevarria Uribarri <jorge.echevarriauribarri.practicas@telefonica.com> Date: Mon, 2 Dec 2024 10:44:52 +0100 Subject: [PATCH 13/28] Update gitlab.yml --- .github/workflows/gitlab.yml | 39 +++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/.github/workflows/gitlab.yml b/.github/workflows/gitlab.yml index 9ffac42..68ca39a 100644 --- a/.github/workflows/gitlab.yml +++ b/.github/workflows/gitlab.yml @@ -6,7 +6,7 @@ on: - develop # Se activa cuando hay cambios en la rama develop jobs: - sync: + create-merge-request: runs-on: ubuntu-latest steps: @@ -14,23 +14,26 @@ jobs: - name: Checkout GitHub repository uses: actions/checkout@v4 - # 2. Configurar Git para empujar a GitLab - - name: Push to GitLab main + # 2. Crear un Merge Request en GitLab + - name: Create Merge Request in GitLab env: GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} run: | - # Configurar Git - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - # Agregar el repositorio remoto de GitLab - git remote add gitlab https://oauth2:${GITLAB_TOKEN}@labs.etsi.org/rep/ocf/sdk.git - - # Traer la última versión de main desde GitLab - git fetch gitlab main - - # Fusionar los cambios de main en develop (si es necesario) - git merge gitlab/main - - # Empujar los cambios de develop a main en GitLab - git push -u gitlab develop:main + # Información del MR + PROJECT_ID="335" # Reemplaza con el ID del proyecto de GitLab + SOURCE_BRANCH="develop" + TARGET_BRANCH="main" + + # Crear el Merge Request usando la API de GitLab + curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $GITLAB_TOKEN" \ + -d '{ + "id": "'"${PROJECT_ID}"'", + "source_branch": "'"${SOURCE_BRANCH}"'", + "target_branch": "'"${TARGET_BRANCH}"'", + "title": "Sync develop to main", + "remove_source_branch": false, + "squash": false + }' \ + https://labs.etsi.org/api/v4/projects/${PROJECT_ID}/merge_requests -- GitLab From 2216a4e98b38e7c40ae4ec33c18db4d3bcdbbe67 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Mon, 2 Dec 2024 12:32:02 +0100 Subject: [PATCH 14/28] Supported features modification --- README.md | 1 + config/capif_sdk_config.json | 7 +++-- doc/sdk_configuration.md | 2 ++ .../capif_sdk_config_sample.json | 11 +++---- .../capif_sdk_config_sample.json | 28 +++++++++--------- opencapif_sdk/capif_invoker_connector.py | 2 +- opencapif_sdk/capif_provider_connector.py | 10 +++++-- samples/config_sample.json | 6 ++-- test/capif_sdk_config_sample_test.json | 29 ++++++++++--------- 9 files changed, 55 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 8406887..c1020b0 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ Now, it is described in 4 simple steps how a Provider can be developed in just s provider.publish_req['publisher_apf_id'] = APF provider.publish_req['publisher_aefs_ids'] = [AEF1, AEF2] + provider.supported_features ="4" provider.publish_services() ``` diff --git a/config/capif_sdk_config.json b/config/capif_sdk_config.json index 34844f5..7096619 100644 --- a/config/capif_sdk_config.json +++ b/config/capif_sdk_config.json @@ -10,7 +10,7 @@ "invoker_folder": "", "capif_callback_url": "", "supported_features":"", - "check_authentication":{ + "check_authentication_data":{ "ip":"", "port":"" }, @@ -18,7 +18,7 @@ "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", - "crs_locality": "", + "csr_locality": "", "csr_state_or_province_name": "", "csr_country_name": "", "csr_email_address": "" @@ -41,6 +41,7 @@ }, "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -55,7 +56,7 @@ "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", - "crs_locality": "", + "csr_locality": "", "csr_state_or_province_name": "", "csr_country_name": "", "csr_email_address": "" diff --git a/doc/sdk_configuration.md b/doc/sdk_configuration.md index d9193cb..97a3daf 100644 --- a/doc/sdk_configuration.md +++ b/doc/sdk_configuration.md @@ -43,6 +43,7 @@ When configuring the SDK as a **Network App Invoker**, the following fields must For SDK configuration as a **Network App Provider**, the following fields are required: - `provider_folder` +- `supported_features` - `cert_generation` (fields such as `csr_common_name`, `csr_country_name`, etc.) - `APFs` - `AEFs` @@ -80,6 +81,7 @@ This file can also be populated using [environment variables](../samples/envirom - `invoker_folder`: The path (relative or absolute) where invoker information (certificates, keys, etc.) is stored. - `provider_folder`: The path (relative or absolute) where provider information is stored. +- `supported_features`: A string used to indicate the features supported by an API. The string shall contain a bitmask indicating supported features in hexadecimal representation Each character in the string shall take a value of "0" to "9", "a" to "f" or "A" to "F". [More information](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29571_CommonData.yaml) - `capif_host`: The domain name of the CAPIF host. - `register_host`: The domain name of the register host. - `capif_https_port`: The CAPIF host port number. diff --git a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json index c68a7ac..7096619 100644 --- a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json @@ -6,7 +6,7 @@ "capif_username": "", "capif_password": "", "debug_mode": "", - "invoker":{ + "invoker": { "invoker_folder": "", "capif_callback_url": "", "supported_features":"", @@ -14,7 +14,7 @@ "ip":"", "port":"" }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -39,8 +39,9 @@ "service-kpis": "" } }, - "provider":{ + "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -51,7 +52,7 @@ "" ] }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -61,5 +62,5 @@ "csr_email_address": "" }, "api_description_path": "" - } + } } diff --git a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json index f2c2c79..e6127a9 100644 --- a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json @@ -6,14 +6,15 @@ "capif_username": "", "capif_password": "", "debug_mode": "", - "invoker":{ + "invoker": { "invoker_folder": "", "capif_callback_url": "", + "supported_features":"", "check_authentication_data":{ "ip":"", "port":"" }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -38,17 +39,9 @@ "service-kpis": "" } }, - "provider":{ + "provider": { "provider_folder": "", - "cert_generation":{ - "csr_common_name": "", - "csr_organizational_unit": "", - "csr_organization": "", - "csr_locality": "", - "csr_state_or_province_name": "", - "csr_country_name": "", - "csr_email_address": "" - }, + "supported_features": "", "apfs": "2", "aefs": "3", "publish_req": { @@ -59,6 +52,15 @@ "" ] }, + "cert_generation": { + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" + }, "api_description_path": "" - } + } } diff --git a/opencapif_sdk/capif_invoker_connector.py b/opencapif_sdk/capif_invoker_connector.py index 528fb75..3e4e78f 100644 --- a/opencapif_sdk/capif_invoker_connector.py +++ b/opencapif_sdk/capif_invoker_connector.py @@ -82,7 +82,7 @@ class capif_invoker_connector: capif_invoker_password = os.getenv('CAPIF_PASSWORD', config.get('capif_password', '')).strip() capif_callback_url = os.getenv('INVOKER_CAPIF_CALLBACK_URL', invoker_config.get('capif_callback_url', '')).strip() - supported_features = os.getenv('INVOKER_FOLDER', invoker_config.get('supported_features', '')).strip() + supported_features = os.getenv('INVOKER_SUPPORTED_FEATURES', invoker_config.get('supported_features', '')).strip() check_authentication_data = invoker_config.get('check_authentication_data', {}) self.check_authentication = { "ip": os.getenv('INVOKER_CHECK_AUTHENTICATION_DATA_IP', check_authentication_data.get('ip', '')).strip(), diff --git a/opencapif_sdk/capif_provider_connector.py b/opencapif_sdk/capif_provider_connector.py index c96578e..9ea6a5b 100644 --- a/opencapif_sdk/capif_provider_connector.py +++ b/opencapif_sdk/capif_provider_connector.py @@ -99,6 +99,10 @@ class capif_provider_connector: csr_email_address = os.getenv('PROVIDER_CSR_EMAIL_ADDRESS', cert_generation.get('csr_email_address', '')).strip() # Retrieve provider specific values (APFs, AEFs) + supported_features = os.getenv('PROVIDER_SUPPORTED_FEATURES', provider_config.get('supported_features', '')).strip() + if not supported_features: + supported_features = "0" + apfs = os.getenv('PROVIDER_APFS', provider_config.get('apfs', '')).strip() aefs = os.getenv('PROVIDER_AEFS', provider_config.get('aefs', '')).strip() api_description_path = os.path.abspath(os.getenv('PROVIDER_API_DESCRIPTION_PATH', provider_config.get('api_description_path', '')).strip()) @@ -127,6 +131,7 @@ class capif_provider_connector: self.csr_state_or_province_name = csr_state_or_province_name self.csr_country_name = csr_country_name self.csr_email_address = csr_email_address + self.supported_features = supported_features self.aefs = int(aefs) self.apfs = int(apfs) @@ -276,7 +281,7 @@ class capif_provider_connector: for role in roles ], "apiProvDomInfo": "This is provider", - "suppFeat": "fff", + "suppFeat": self.supported_features, "failReason": "string", "regSec": access_token, } @@ -452,6 +457,7 @@ class capif_provider_connector: with open(service_api_description_json_full_path, "r") as service_file: data = json.load(service_file) + data["supportedFeatures"] = self.supported_features # Verifying that the number of AEFs is equal to the aefProfiles if len(AEFs_list) != len(data.get("aefProfiles", [])): self.logger.error( @@ -1262,7 +1268,7 @@ class capif_provider_connector: for role in roles ], "apiProvDomInfo": "This is provider", - "suppFeat": "fff", + "suppFeat": self.supported_features, "failReason": "string", "regSec": access_token, } diff --git a/samples/config_sample.json b/samples/config_sample.json index 1a75d7d..7096619 100644 --- a/samples/config_sample.json +++ b/samples/config_sample.json @@ -39,9 +39,9 @@ "service-kpis": "" } }, - "provider": { "provider_folder": "", + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -52,7 +52,7 @@ "" ] }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -62,5 +62,5 @@ "csr_email_address": "" }, "api_description_path": "" - } + } } diff --git a/test/capif_sdk_config_sample_test.json b/test/capif_sdk_config_sample_test.json index f91920e..7096619 100644 --- a/test/capif_sdk_config_sample_test.json +++ b/test/capif_sdk_config_sample_test.json @@ -6,15 +6,15 @@ "capif_username": "", "capif_password": "", "debug_mode": "", - "invoker":{ + "invoker": { "invoker_folder": "", "capif_callback_url": "", "supported_features":"", - "check_authorization":{ + "check_authentication_data":{ "ip":"", "port":"" }, - "cert_generation":{ + "cert_generation": { "csr_common_name": "", "csr_organizational_unit": "", "csr_organization": "", @@ -39,17 +39,9 @@ "service-kpis": "" } }, - "provider":{ + "provider": { "provider_folder": "", - "cert_generation":{ - "csr_common_name": "", - "csr_organizational_unit": "", - "csr_organization": "", - "csr_locality": "", - "csr_state_or_province_name": "", - "csr_country_name": "", - "csr_email_address": "" - }, + "supported_features": "", "apfs": "", "aefs": "", "publish_req": { @@ -60,6 +52,15 @@ "" ] }, + "cert_generation": { + "csr_common_name": "", + "csr_organizational_unit": "", + "csr_organization": "", + "csr_locality": "", + "csr_state_or_province_name": "", + "csr_country_name": "", + "csr_email_address": "" + }, "api_description_path": "" - } + } } -- GitLab From bb8b23d591b4a923fa739e339ec66b216c168f52 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Mon, 2 Dec 2024 12:54:01 +0100 Subject: [PATCH 15/28] pip readme --- README_pipy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README_pipy.md b/README_pipy.md index 57eacbc..908a9e2 100644 --- a/README_pipy.md +++ b/README_pipy.md @@ -101,6 +101,7 @@ When configuring the SDK as a **Network App Invoker**, the following fields must For SDK configuration as a **Network App Provider**, the following fields are required: - `provider_folder` +- `suported_features` - `cert_generation` (fields such as `csr_common_name`, `csr_country_name`, etc.) - `APFs` - `AEFs` @@ -133,10 +134,9 @@ If the `publisher_aefs_ids` do not match the `aefProfiles` in the API descriptio ## Descriptions of `capif_sdk_config` Fields -This file can also be populated using [environment variables](../samples/enviroment_variables_sample.txt). - - `invoker_folder`: The path (relative or absolute) where invoker information (certificates, keys, etc.) is stored. - `provider_folder`: The path (relative or absolute) where provider information is stored. +- `supported_features`: A string used to indicate the features supported by an API. The string shall contain a bitmask indicating supported features in hexadecimal representation Each character in the string shall take a value of "0" to "9", "a" to "f" or "A" to "F". [More information](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29571_CommonData.yaml) - `capif_host`: The domain name of the CAPIF host. - `register_host`: The domain name of the register host. - `capif_https_port`: The CAPIF host port number. @@ -148,8 +148,8 @@ This file can also be populated using [environment variables](../samples/envirom - `apfs`: The number of APFs to be onboarded as a provider (e.g., `5`). - `aefs`: The number of AEFs to be onboarded as a provider (e.g., `2`). - `debug_mode`: A boolean value to enable or disable SDK logs (e.g., `True` or `False`). -- `discover_filter`: Fields for configuring invoker service discovery. -- `publish_req`: Fields required for API publishing. +- [`discover_filter`](#configuration-of-discover_filter): Fields for configuring invoker service discovery. +- [`publish_req`](#configuration-of-publish_req): Fields required for API publishing. - `api_description_path`: The path to the [ServiceAPIDescription](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Publish_Service_API.yaml) JSON file. - `check_authentication_data`: The `ip` and `port` of the target Provider's AEF to get their supported features from. -- GitLab From 073d85174e70808971fe0da26d5d7f8748391f13 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Mon, 2 Dec 2024 13:01:04 +0100 Subject: [PATCH 16/28] version 0.1.17 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6877edc..ece18da 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.16", + version="0.1.17", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( -- GitLab From 99e3b4fbeebd59aedd66846e7b1c82621157929a Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 09:22:33 +0100 Subject: [PATCH 17/28] Interface description and support features --- opencapif_sdk/capif_invoker_connector.py | 4 ++-- opencapif_sdk/capif_provider_connector.py | 2 +- opencapif_sdk/service_discoverer.py | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/opencapif_sdk/capif_invoker_connector.py b/opencapif_sdk/capif_invoker_connector.py index 3e4e78f..6a159f1 100644 --- a/opencapif_sdk/capif_invoker_connector.py +++ b/opencapif_sdk/capif_invoker_connector.py @@ -325,7 +325,7 @@ class capif_invoker_connector: url = self.capif_https_url + capif_onboarding_url payload_dict = { "notificationDestination": self.capif_callback_url, - "supportedFeatures": self.supported_features, + "supportedFeatures": f"{self.supported_features}", "apiInvokerInformation": self.csr_common_name, "websockNotifConfig": { "requestWebsocketUri": True, @@ -429,7 +429,7 @@ class capif_invoker_connector: url = self.capif_https_url + capif_onboarding_url + "/" + invokerid payload_dict = { "notificationDestination": self.capif_callback_url, - "supportedFeatures": self.supported_features, + "supportedFeatures": f"{self.supported_features}", "apiInvokerInformation": self.csr_common_name, "websockNotifConfig": { "requestWebsocketUri": True, diff --git a/opencapif_sdk/capif_provider_connector.py b/opencapif_sdk/capif_provider_connector.py index 9ea6a5b..e7d6576 100644 --- a/opencapif_sdk/capif_provider_connector.py +++ b/opencapif_sdk/capif_provider_connector.py @@ -457,7 +457,7 @@ class capif_provider_connector: with open(service_api_description_json_full_path, "r") as service_file: data = json.load(service_file) - data["supportedFeatures"] = self.supported_features + data["supportedFeatures"] = f"{self.supported_features}" # Verifying that the number of AEFs is equal to the aefProfiles if len(AEFs_list) != len(data.get("aefProfiles", [])): self.logger.error( diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index 9f079a1..6b1c8eb 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -213,7 +213,7 @@ class service_discoverer: "websocketUri": "string", "requestWebsocketUri": True }, - "supportedFeatures": "fff" + "supportedFeatures": f"{self.supported_features}" } number_of_apis = len( @@ -225,8 +225,18 @@ class service_discoverer: api_id = self.invoker_capif_details["registered_security_contexes"][i]['api_id'] for n in range(0, len(aef_profiles)): aef_id = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['aef_id'] - + ip = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['ip'] + port = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['port'] security_info = { + "interfaceDescriptions": [ + { + "ipv4Addr": ip, + "port": port, + "securityMethods": [ + "Oauth" + ] + } + ], "prefSecurityMethods": ["Oauth"], "authenticationInfo": "string", "authorizationInfo": "string", @@ -274,7 +284,7 @@ class service_discoverer: "websocketUri": "string", "requestWebsocketUri": True }, - "supportedFeatures": "fff" + "supportedFeatures": f"{self.supported_features}" } number_of_apis = len( -- GitLab From 4da4e12c22f0e57ff1ce1a83e282a7b33c2360ce Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 09:26:49 +0100 Subject: [PATCH 18/28] version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ece18da..b3a2a98 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.17", + version="0.1.17.1", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( -- GitLab From 950310d7fcb768d2e3955c3a016f95d6517b6f0c Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 09:37:24 +0100 Subject: [PATCH 19/28] interfaceDetails --- opencapif_sdk/service_discoverer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index 6b1c8eb..ed78986 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -228,7 +228,7 @@ class service_discoverer: ip = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['ip'] port = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['port'] security_info = { - "interfaceDescriptions": [ + "interfaceDetails": [ { "ipv4Addr": ip, "port": port, -- GitLab From 92f5102a23b6fd3b96fe3658d75746789571e5d3 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 09:38:34 +0100 Subject: [PATCH 20/28] version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b3a2a98..d80ec6b 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.17.1", + version="0.1.17.2", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( -- GitLab From a75462d49efaa3d4a8704714c99ffab5112ac662 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 09:57:13 +0100 Subject: [PATCH 21/28] changes --- opencapif_sdk/service_discoverer.py | 2 ++ setup.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index ed78986..d913189 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -231,6 +231,8 @@ class service_discoverer: "interfaceDetails": [ { "ipv4Addr": ip, + "ipv6Addr": "string", + "fqdn": "string", "port": port, "securityMethods": [ "Oauth" diff --git a/setup.py b/setup.py index d80ec6b..85a43dc 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.17.2", + version="0.1.17.3", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( -- GitLab From 199d1aa8c163a5eb26c7c2cbb1ae51be573900a7 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 3 Dec 2024 13:07:41 +0100 Subject: [PATCH 22/28] OAUTH --- .../nef_upf_vendor_1.json | 8 +++---- .../nef_upf_vendor_2.json | 12 +++++----- opencapif_sdk/api_schema_translator.py | 4 ++-- opencapif_sdk/service_discoverer.py | 22 ++++--------------- samples/provider_api_description_sample.json | 8 +++---- test/network_app_provider_api_spec_2.json | 12 +++++----- test/network_app_provider_api_spec_3.json | 8 +++---- 7 files changed, 30 insertions(+), 44 deletions(-) diff --git a/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json b/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json index 8cc2fa4..58ceb6f 100755 --- a/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json +++ b/network_app_samples/network_app_provider_sample/nef_upf_vendor_1.json @@ -143,14 +143,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "localhost", "port": 8088, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -297,7 +297,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -305,7 +305,7 @@ "ipv4Addr": "localhost", "port": 8088, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json b/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json index 5feec72..5930f5c 100755 --- a/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json +++ b/network_app_samples/network_app_provider_sample/nef_upf_vendor_2.json @@ -127,7 +127,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -135,7 +135,7 @@ "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -283,14 +283,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -421,7 +421,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -429,7 +429,7 @@ "ipv4Addr": "localhost", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/opencapif_sdk/api_schema_translator.py b/opencapif_sdk/api_schema_translator.py index 7e29a76..1251990 100644 --- a/opencapif_sdk/api_schema_translator.py +++ b/opencapif_sdk/api_schema_translator.py @@ -143,12 +143,12 @@ class api_schema_translator: ], "protocol": "HTTP_1_1", "dataFormat": "JSON", - "securityMethods": ["Oauth"], + "securityMethods": ["OAUTH"], "interfaceDescriptions": [ { "ipv4Addr": ip, "port": port, - "securityMethods": ["Oauth"] + "securityMethods": ["OAUTH"] } ] } diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index d913189..d3ccfd7 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -225,21 +225,9 @@ class service_discoverer: api_id = self.invoker_capif_details["registered_security_contexes"][i]['api_id'] for n in range(0, len(aef_profiles)): aef_id = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['aef_id'] - ip = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['ip'] - port = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['port'] + security_info = { - "interfaceDetails": [ - { - "ipv4Addr": ip, - "ipv6Addr": "string", - "fqdn": "string", - "port": port, - "securityMethods": [ - "Oauth" - ] - } - ], - "prefSecurityMethods": ["Oauth"], + "prefSecurityMethods": ["OAUTH"], "authenticationInfo": "string", "authorizationInfo": "string", "aefId": aef_id, @@ -298,9 +286,8 @@ class service_discoverer: api_id = self.invoker_capif_details["registered_security_contexes"][i]['api_id'] for n in range(0, len(aef_profiles)): aef_id = self.invoker_capif_details["registered_security_contexes"][i]['aef_profiles'][n]['aef_id'] - security_info = { - "prefSecurityMethods": ["Oauth"], + "prefSecurityMethods": ["OAUTH"], "authenticationInfo": "string", "authorizationInfo": "string", "aefId": aef_id, @@ -308,9 +295,8 @@ class service_discoverer: } payload["securityInfo"].append(security_info) - payload["securityInfo"].append(security_info) - try: + print(payload) response = requests.put(url, json=payload, cert=(self.signed_key_crt_path, diff --git a/samples/provider_api_description_sample.json b/samples/provider_api_description_sample.json index 02d872f..9544269 100755 --- a/samples/provider_api_description_sample.json +++ b/samples/provider_api_description_sample.json @@ -47,14 +47,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -122,14 +122,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/network_app_provider_api_spec_2.json b/test/network_app_provider_api_spec_2.json index 0d54904..94175bd 100755 --- a/test/network_app_provider_api_spec_2.json +++ b/test/network_app_provider_api_spec_2.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -181,7 +181,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -189,7 +189,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/network_app_provider_api_spec_3.json b/test/network_app_provider_api_spec_3.json index 548b740..7b9fbe4 100755 --- a/test/network_app_provider_api_spec_3.json +++ b/test/network_app_provider_api_spec_3.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] -- GitLab From f087990b44c750aa5432b8c073735f290d50bb8a Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Wed, 4 Dec 2024 11:10:57 +0100 Subject: [PATCH 23/28] Fix error related to check-authentication and revoke-authenticacion. Little modifications in OAUTH configuration --- opencapif_sdk/capif_provider_connector.py | 102 ++++++++++++---------- opencapif_sdk/service_discoverer.py | 4 - test/network_app_provider_api_spec.json | 8 +- test/test.py | 2 + 4 files changed, 62 insertions(+), 54 deletions(-) diff --git a/opencapif_sdk/capif_provider_connector.py b/opencapif_sdk/capif_provider_connector.py index e7d6576..a875bd8 100644 --- a/opencapif_sdk/capif_provider_connector.py +++ b/opencapif_sdk/capif_provider_connector.py @@ -466,41 +466,45 @@ class capif_provider_connector: "Mismatch between number of AEFs and profiles") # Assigning each AEF + for profile, aef_id in zip(data.get("aefProfiles", []), AEFs_list): - profile["aefId"] = aef_id - for versions in profile["versions"]: - check = True - revoke = True - for custom in versions["custOperations"]: - if custom["custOpName"] == "check-authentication": - check = False - if custom["custOpName"] == "revoke-authentication": - revoke = False - # Si ambas condiciones ya son falsas, salir del bucle - if not check and not revoke: - break - # If 'check-authentication' custom operation doesn't exist, add it - if check: - versions["custOperations"].append({ + if not isinstance(profile, dict): # Verificar que profile sea un diccionario + raise TypeError(f"Expected profile to be a dict, got {type(profile).__name__}") + + profile["aefId"] = aef_id # Asignar el ID de AEF + + versions = profile.get("versions") # Obtener versions + + i = 1 + for version in versions: # Iterar sobre cada versión + if not isinstance(version, dict): # Verificar que cada versión sea un diccionario + raise TypeError(f"Expected each version to be a dict, got {type(version).__name__}") + + # Obtener nombres existentes de operaciones personalizadas + existing_operations = { + op["custOpName"].strip() + for op in version.get("custOperations", []) if isinstance(op, dict) + } + + # Verificar y agregar `check-authentication` si no existe + if "check-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "check-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Check authentication request." }) - # If 'revoke-authentication' custom operation doesn't exist, add it - if revoke: - versions["custOperations"].append({ + # Verificar y agregar `revoke-authentication` si no existe + if "revoke-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "revoke-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Revoke authorization for service APIs." }) - + i -= 1 + self.logger.info( "Service API description modified successfully") @@ -907,36 +911,42 @@ class capif_provider_connector: # Asing the chosen AEFs for profile, aef_id in zip(data.get("aefProfiles", []), AEFs_list): - profile["aefId"] = aef_id - for versions in profile["versions"]: - for custom in versions["custOperations"]: - check = True - revoke = True - if custom["custOpName"] == "check-authentication": - check = False - if custom["custOpName"] == "revoke-authentication ": - revoke = False - # If 'check-authentication' custom operation doesn't exist, add it - if check: - versions["custOperations"].append({ + if not isinstance(profile, dict): # Verificar que profile sea un diccionario + raise TypeError(f"Expected profile to be a dict, got {type(profile).__name__}") + + profile["aefId"] = aef_id # Asignar el ID de AEF + + versions = profile.get("versions") # Obtener versions + i = 1 + for version in versions: # Iterar sobre cada versión + if not isinstance(version, dict): # Verificar que cada versión sea un diccionario + raise TypeError(f"Expected each version to be a dict, got {type(version).__name__}") + + # Obtener nombres existentes de operaciones personalizadas + existing_operations = { + op["custOpName"].strip() + for op in version.get("custOperations", []) if isinstance(op, dict) + } + + # Verificar y agregar `check-authentication` si no existe + if "check-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "check-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Check authentication request." }) - # If 'revoke-authentication' custom operation doesn't exist, add it - if revoke: - versions["custOperations"].append({ + # Verificar y agregar `revoke-authentication` si no existe + if "revoke-authentication" not in existing_operations and i == 1: + version.setdefault("custOperations", []).append({ "commType": "REQUEST_RESPONSE", "custOpName": "revoke-authentication", - "operations": [ - "POST" - ], + "operations": ["POST"], "description": "Revoke authorization for service APIs." }) + i -= 1 + self.logger.info( "Service API description modified successfully") diff --git a/opencapif_sdk/service_discoverer.py b/opencapif_sdk/service_discoverer.py index d3ccfd7..6272e94 100644 --- a/opencapif_sdk/service_discoverer.py +++ b/opencapif_sdk/service_discoverer.py @@ -296,7 +296,6 @@ class service_discoverer: payload["securityInfo"].append(security_info) try: - print(payload) response = requests.put(url, json=payload, cert=(self.signed_key_crt_path, @@ -507,7 +506,6 @@ class service_discoverer: raise def check_authentication(self): - print("hola") self.logger.info("Checking authentication") try: invoker_details = self.__load_provider_api_details() @@ -519,7 +517,6 @@ class service_discoverer: "apiInvokerId": f"{invoker_id}", "supportedFeatures": f"{self.supported_features}" } - print(self.supported_features) headers = { "Authorization": "Bearer {}".format(self.token), @@ -533,7 +530,6 @@ class service_discoverer: json=payload ) - print(response.text) response.raise_for_status() self.logger.info("Authentication of supported_features checked") diff --git a/test/network_app_provider_api_spec.json b/test/network_app_provider_api_spec.json index 9672934..5cf4065 100755 --- a/test/network_app_provider_api_spec.json +++ b/test/network_app_provider_api_spec.json @@ -47,7 +47,7 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth", + "OAUTH", "PSK" ], "interfaceDescriptions": [ @@ -55,7 +55,7 @@ "ipv4Addr": "127.0.0.1", "port": 8888, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] @@ -123,14 +123,14 @@ "protocol": "HTTP_1_1", "dataFormat": "JSON", "securityMethods": [ - "Oauth" + "OAUTH" ], "interfaceDescriptions": [ { "ipv4Addr": "127.0.0.1", "port": 8899, "securityMethods": [ - "Oauth" + "OAUTH" ] } ] diff --git a/test/test.py b/test/test.py index 143558a..7332dc6 100644 --- a/test/test.py +++ b/test/test.py @@ -119,6 +119,8 @@ if __name__ == "__main__": print("INVOKER ONBOARDING COMPLETED") discoverer = service_discoverer(config_file=capif_sdk_config_path) + + discoverer.discover_filter["api-name"]= "Testtrece" discoverer.discover() -- GitLab From 95ff5a040227268279d76fe52fc8ffb2887dd32c Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Thu, 12 Dec 2024 10:32:31 +0100 Subject: [PATCH 24/28] code changes --- .gitignore | 2 +- config/capif_sdk_config.json | 11 +- .../capif_sdk_config_sample.json | 11 +- .../capif_sdk_config_sample.json | 11 +- opencapif_sdk/__init__.py | 3 +- opencapif_sdk/capif_logging_feature.py | 287 ++++++++++++++++++ samples/config_sample.json | 11 +- test/test.py | 8 +- 8 files changed, 337 insertions(+), 7 deletions(-) create mode 100644 opencapif_sdk/capif_logging_feature.py diff --git a/.gitignore b/.gitignore index 0781cbd..0688138 100644 --- a/.gitignore +++ b/.gitignore @@ -176,6 +176,6 @@ config */__pycache__ -*.capif_sdk_config_sample_test.json + /test/capif_sdk_config_sample_test.json diff --git a/config/capif_sdk_config.json b/config/capif_sdk_config.json index 7096619..f766132 100644 --- a/config/capif_sdk_config.json +++ b/config/capif_sdk_config.json @@ -61,6 +61,15 @@ "csr_country_name": "", "csr_email_address": "" }, - "api_description_path": "" + "api_description_path": "", + "log":{ + "apiName": "", + "apiVersion": "", + "resourceName": "", + "uri": "", + "protocol": "", + "operation": "", + "result": "" + } } } diff --git a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json index 7096619..f766132 100644 --- a/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_invoker_sample/capif_sdk_config_sample.json @@ -61,6 +61,15 @@ "csr_country_name": "", "csr_email_address": "" }, - "api_description_path": "" + "api_description_path": "", + "log":{ + "apiName": "", + "apiVersion": "", + "resourceName": "", + "uri": "", + "protocol": "", + "operation": "", + "result": "" + } } } diff --git a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json index e6127a9..67e6b90 100644 --- a/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json +++ b/network_app_samples/network_app_provider_sample/capif_sdk_config_sample.json @@ -61,6 +61,15 @@ "csr_country_name": "", "csr_email_address": "" }, - "api_description_path": "" + "api_description_path": "", + "log":{ + "apiName": "", + "apiVersion": "", + "resourceName": "", + "uri": "", + "protocol": "", + "operation": "", + "result": "" + } } } diff --git a/opencapif_sdk/__init__.py b/opencapif_sdk/__init__.py index 71154d7..b977cb1 100644 --- a/opencapif_sdk/__init__.py +++ b/opencapif_sdk/__init__.py @@ -2,5 +2,6 @@ from opencapif_sdk.capif_invoker_connector import capif_invoker_connector from opencapif_sdk.capif_provider_connector import capif_provider_connector from opencapif_sdk.service_discoverer import service_discoverer from opencapif_sdk.api_schema_translator import api_schema_translator +from opencapif_sdk.capif_logging_feature import capif_logging_feature -__all__ = ["capif_invoker_connector", "service_discoverer", "capif_provider_connector", "api_schema_translator"] \ No newline at end of file +__all__ = ["capif_invoker_connector", "service_discoverer", "capif_provider_connector", "api_schema_translator", "capif_logging_feature"] \ No newline at end of file diff --git a/opencapif_sdk/capif_logging_feature.py b/opencapif_sdk/capif_logging_feature.py new file mode 100644 index 0000000..c2f3b42 --- /dev/null +++ b/opencapif_sdk/capif_logging_feature.py @@ -0,0 +1,287 @@ +import os +import logging +import urllib3 +import requests +import json +import warnings +from requests.exceptions import RequestsDependencyWarning +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) +warnings.filterwarnings("ignore", category=RequestsDependencyWarning) +# noqa: E501 +# Basic configuration of the logger functionality + +log_path = 'logs/sdk_logs.log' + +log_dir = os.path.dirname(log_path) + +if not os.path.exists(log_dir): + os.makedirs(log_dir) + +logging.basicConfig( + level=logging.NOTSET, # Minimum severity level to log + # Log message format + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(log_path), # Log to a file + logging.StreamHandler() # Also display in the console + ] +) + + +class capif_logging_feature: + + def __init__(self, config_file: str): + """ + Initializes the CAPIFProvider connector with the parameters specified in the configuration file. + """ + # Load configuration from file if necessary + config_file = os.path.abspath(config_file) + self.config_path = os.path.dirname(config_file)+"/" + config = self.__load_config_file(config_file) + debug_mode = os.getenv('DEBUG_MODE', config.get('debug_mode', 'False')).strip().lower() + if debug_mode == "false": + debug_mode = False + else: + debug_mode = True + + # Initialize logger for this class + self.logger = logging.getLogger(self.__class__.__name__) + if debug_mode: + self.logger.setLevel(logging.DEBUG) + else: + self.logger.setLevel(logging.WARNING) + + # Set logging level for urllib based on debug_mode + urllib_logger = logging.getLogger("urllib3") + if not debug_mode: + urllib_logger.setLevel(logging.WARNING) + else: + urllib_logger.setLevel(logging.DEBUG) + + try: + # Retrieve provider configuration from JSON or environment variables + provider_config = config.get('provider', {}) + provider_general_folder = os.path.abspath( + os.getenv('PROVIDER_FOLDER', provider_config.get('provider_folder', '')).strip()) + + capif_host = os.getenv('CAPIF_HOST', config.get('capif_host', '')).strip() + capif_register_host = os.getenv('REGISTER_HOST', config.get('register_host', '')).strip() + capif_https_port = str(os.getenv('CAPIF_HTTPS_PORT', config.get('capif_https_port', '')).strip()) + capif_register_port = str(os.getenv('CAPIF_REGISTER_PORT', config.get('capif_register_port', '')).strip()) + capif_provider_username = os.getenv('CAPIF_USERNAME', config.get('capif_username', '')).strip() + capif_provider_password = os.getenv('CAPIF_PASSWORD', config.get('capif_password', '')).strip() + + # Get CSR (Certificate Signing Request) details from config or environment variables + cert_generation = provider_config.get('cert_generation', {}) + csr_common_name = os.getenv('PROVIDER_CSR_COMMON_NAME', cert_generation.get('csr_common_name', '')).strip() + csr_organizational_unit = os.getenv('PROVIDER_CSR_ORGANIZATIONAL_UNIT', cert_generation.get('csr_organizational_unit', '')).strip() + csr_organization = os.getenv('PROVIDER_CSR_ORGANIZATION', cert_generation.get('csr_organization', '')).strip() + csr_locality = os.getenv('PROVIDER_CSR_LOCALITY', cert_generation.get('csr_locality', '')).strip() + csr_state_or_province_name = os.getenv('PROVIDER_CSR_STATE_OR_PROVINCE_NAME', cert_generation.get('csr_state_or_province_name', '')).strip() + csr_country_name = os.getenv('PROVIDER_CSR_COUNTRY_NAME', cert_generation.get('csr_country_name', '')).strip() + csr_email_address = os.getenv('PROVIDER_CSR_EMAIL_ADDRESS', cert_generation.get('csr_email_address', '')).strip() + + # Retrieve provider specific values (APFs, AEFs) + supported_features = os.getenv('PROVIDER_SUPPORTED_FEATURES', provider_config.get('supported_features', '')).strip() + if not supported_features: + supported_features = "0" + + apfs = os.getenv('PROVIDER_APFS', provider_config.get('apfs', '')).strip() + aefs = os.getenv('PROVIDER_AEFS', provider_config.get('aefs', '')).strip() + api_description_path = os.path.abspath(os.getenv('PROVIDER_API_DESCRIPTION_PATH', provider_config.get('api_description_path', '')).strip()) + log = os.getenv('PROVIDER_LOG', provider_config.get('log', '')) + + # Check required fields and log warnings/errors + if not capif_host: + self.logger.warning("CAPIF_HOST is not provided; defaulting to an empty string") + if not capif_provider_username: + self.logger.error("CAPIF_PROVIDER_USERNAME is required but not provided") + raise ValueError("CAPIF_PROVIDER_USERNAME is required") + + # Setup the folder to store provider files (e.g., certificates) + self.provider_folder = os.path.join(provider_general_folder, capif_provider_username) + os.makedirs(self.provider_folder, exist_ok=True) + + # Set attributes for provider credentials and configuration + self.capif_host = capif_host.strip() + self.capif_provider_username = capif_provider_username + self.capif_provider_password = capif_provider_password + self.capif_register_host = capif_register_host + self.capif_register_port = capif_register_port + self.csr_common_name = csr_common_name + self.csr_organizational_unit = csr_organizational_unit + self.csr_organization = csr_organization + self.csr_locality = csr_locality + self.csr_state_or_province_name = csr_state_or_province_name + self.csr_country_name = csr_country_name + self.csr_email_address = csr_email_address + self.supported_features = supported_features + self.aefs = int(aefs) + self.apfs = int(apfs) + + # Get publish request details from config or environment variables + publish_req_config = provider_config.get('publish_req', {}) + self.publish_req = { + "service_api_id": os.getenv('PUBLISH_REQ_SERVICE_API_ID', publish_req_config.get('service_api_id', '')).strip(), + "publisher_apf_id": os.getenv('PUBLISH_REQ_PUBLISHER_APF_ID', publish_req_config.get('publisher_apf_id', '')).strip(), + "publisher_aefs_ids": os.getenv('PUBLISH_REQ_PUBLISHER_AEFS_IDS', publish_req_config.get('publisher_aefs_ids', '')) + } + + # Set the path for the API description file + self.api_description_path = api_description_path + + # Set the CAPIF HTTPS port and construct CAPIF URLs + self.capif_https_port = str(capif_https_port) + + self.provider_capif_ids = {} + + path_prov_funcs = os.path.join(self.provider_folder, "provider_capif_ids.json") + if os.path.exists(path_prov_funcs): + self.provider_capif_ids = self.__load_provider_api_details() + + path_published = os.path.join(self.provider_folder, "provider_service_ids.json") + if os.path.exists(path_published): + self.provider_service_ids = self.__load_config_file(path_published) + + # Construct the CAPIF HTTPS URL + if len(self.capif_https_port) == 0 or int(self.capif_https_port) == 443: + self.capif_https_url = f"https://{capif_host.strip()}/" + else: + self.capif_https_url = f"https://{capif_host.strip()}:{self.capif_https_port.strip()}/" + + # Construct the CAPIF register URL + if len(capif_register_port) == 0: + self.capif_register_url = f"https://{capif_register_host.strip()}:8084/" + else: + self.capif_register_url = f"https://{capif_register_host.strip()}:{capif_register_port.strip()}/" + + self.__search_aef_and_api_by_name(log) + + self.log = log + + # Log initialization success message + self.logger.info("capif_logging_feature initialized with the capif_sdk_config.json parameters") + + except Exception as e: + # Catch and log any exceptions that occur during initialization + self.logger.error(f"Error during initialization: {e}") + raise + + def __search_aef_and_api_by_name(self, log): + """ + Searches for an AEF and API by name and updates self.api_id with the corresponding ID. + + Args: + log (dict): A record containing API information, including "apiName". + + Raises: + KeyError: If "apiName" is not present in the log. + ValueError: If no ID is associated with the given name. + """ + # Validate that the log contains the "apiName" field + if "apiName" not in log: + raise KeyError("The provided log does not contain 'apiName'.") + + # Retrieve the API name + name = log["apiName"] + + # Search for the corresponding API ID + self.api_id = self.provider_service_ids.get(name) + + # Validate that a valid ID was found + if not self.api_id: + raise ValueError(f"No ID was found for the API '{name}'.") + + def create_logs(self, aefId, api_invoker_id): + path = self.capif_https_url + f"/api-invocation-logs/v1/{aefId}/logs" + + log_entry = { + "apiId": self.api_id, + "apiName": self.log["apiName"], + "apiVersion": self.log["apiVersion"], + "resourceName": self.log["resourceName"], + "uri": self.log["uri"], + "protocol": self.log["protocol"], + "operation": self.log["operation"], + "result": self.log["result"] + } + + payload = { + "aefId": f"{aefId}", + "apiInvokerId": f"{api_invoker_id}", + "logs": [log_entry], + "supportedFeatures": f"{self.supported_features}" + } + provider_details = self.__load_provider_api_details() + AEF_api_prov_func_id = aefId + aef_number = None + for key, value in provider_details.items(): + if value == AEF_api_prov_func_id and key.startswith("AEF-"): + aef_inter = key.split("-")[1] + # Obtain the aef number + aef_number = aef_inter.split("_")[0] + break + + if aef_number is None: + self.logger.error( + f"No matching AEF found for publisher_aef_id: {AEF_api_prov_func_id}") + raise ValueError("Invalid publisher_aef_id") + + cert = ( + os.path.join(self.provider_folder, f"aef-{aef_number}.crt"), + os.path.join(self.provider_folder, + f"AEF-{aef_number}_private_key.key"), + ) + + try: + response = requests.post( + url=path, + json=payload, + headers={"Content-Type": "application/json"}, + cert=cert, + verify=os.path.join(self.provider_folder, "ca.crt") + ) + + response.raise_for_status() + + return response.status_code, response.json() + + except Exception as e: + self.logger.error("Unexpected error: %s", e) + return None, {"error": f"Unexpected error: {e}"} + + def __load_provider_api_details(self) -> dict: + """ + Loads NEF API details from the CAPIF provider details JSON file. + + :return: A dictionary containing NEF API details. + :raises FileNotFoundError: If the CAPIF provider details file is not found. + :raises json.JSONDecodeError: If there is an error decoding the JSON file. + """ + file_path = os.path.join(self.provider_folder, + "provider_capif_ids.json") + + try: + with open(file_path, "r") as file: + return json.load(file) + except FileNotFoundError: + self.logger.error(f"File not found: {file_path}") + raise + except json.JSONDecodeError as e: + self.logger.error( + f"Error decoding JSON from file {file_path}: {e}") + raise + except Exception as e: + self.logger.error( + f"Unexpected error while loading NEF API details: {e}") + raise + + def __load_config_file(self, config_file: str): + """Carga el archivo de configuración.""" + try: + with open(config_file, 'r') as file: + return json.load(file) + except FileNotFoundError: + self.logger.warning( + f"Configuration file {config_file} not found. Using defaults or environment variables.") + return {} diff --git a/samples/config_sample.json b/samples/config_sample.json index 7096619..f766132 100644 --- a/samples/config_sample.json +++ b/samples/config_sample.json @@ -61,6 +61,15 @@ "csr_country_name": "", "csr_email_address": "" }, - "api_description_path": "" + "api_description_path": "", + "log":{ + "apiName": "", + "apiVersion": "", + "resourceName": "", + "uri": "", + "protocol": "", + "operation": "", + "result": "" + } } } diff --git a/test/test.py b/test/test.py index 7332dc6..6d026d5 100644 --- a/test/test.py +++ b/test/test.py @@ -2,7 +2,7 @@ import json # flake8: noqa -from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer +from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer,capif_logging_feature capif_sdk_config_path = "./capif_sdk_config_sample_test.json" @@ -130,6 +130,12 @@ if __name__ == "__main__": print("SERVICE GET TOKENS COMPLETED") + logger=capif_logging_feature(config_file=capif_sdk_config_path) + + invoker_id=discoverer.invoker_capif_details["api_invoker_id"] + + logger.create_logs(aefId=AEF1,api_invoker_id=invoker_id) + capif_invoker_connector.update_invoker() print("INVOKER UPDATE SERVICE COMPLETED") -- GitLab From 737bdac312ee2acd3736a7bb5649deb67e945ce8 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 17 Dec 2024 09:31:30 +0100 Subject: [PATCH 25/28] log tested --- README.md | 3 ++- doc/sdk_configuration.md | 1 + doc/sdk_full_documentation.md | 14 ++++++++++++++ setup.py | 2 +- test/test.py | 10 +++++----- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c1020b0..cda2d46 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,7 @@ OpenCAPIF SDK brings a set of functions to integrate with the 5G Core's function | /{apfId}/service-apis/{serviceApiId} (GET) | [get_service()](./doc/sdk_full_documentation.md#get-services) | Retrieves the details of a specific service API for a specific `apfId` and `serviceApiId` | | /{apfId}/service-apis (GET) | [get_all_services()](./doc/sdk_full_documentation.md#get-all-services) | Retrieves a list of all available service APIs for a specific `apfId` | | /aef-security/v1/check-authentication (POST) | [check_authentication()](./doc/sdk_full_documentation.md#check_authentication) | This custom operation allows the API invoker to confirm the `supported_features` from the API exposing function(AEF) | +| /api-invocation-logs/v1/{aefId}/logs (POST) | [create_logs( aefId, api_invoker_id)](./doc/sdk_full_documentation.md#create_logs) | This operation allows to the Provider to notice to the CCF about the query of an invoker for an especific `aefId` NOTE: Above mentioned CAPIF APIs are defined in these 3GPP references: - [CAPIF Invoker API specification](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_API_Invoker_Management_API.yaml) @@ -104,6 +105,7 @@ NOTE: Above mentioned CAPIF APIs are defined in these 3GPP references: - [CAPIF Publish API specification](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Publish_Service_API.yaml) - [CAPIF Security API specification](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Security_API.yaml) - [AEF Security API specification](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_AEF_Security_API.yaml) +- [CAPIF Logging API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Logging_API_Invocation_API.yaml) NOTE: In the [3GPP Technical Specification (TS) 29.222 V18.5.0 Common API Framework for 3GPP Northbound APIs](https://www.etsi.org/deliver/etsi_ts/129200_129299/129222/18.05.00_60/ts_129222v180500p.pdf) the `service` concept is understood as equal as the `API` concept. @@ -316,7 +318,6 @@ There are some features which **are not currently available at latest OpenCAPIF - [CAPIF Access control policy management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Access_Control_Policy_API.yaml) - [CAPIF Auditing API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Auditing_API.yaml) - [CAPIF Events API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Events_API.yaml) - - [CAPIF Logging API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Logging_API_Invocation_API.yaml) - [CAPIF Routing info API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Routing_Info_API.yaml) - [CAPIF Security API management](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Security_API.yaml) - /trustedInvokers/{apiInvokerId}/delete (POST) diff --git a/doc/sdk_configuration.md b/doc/sdk_configuration.md index 97a3daf..f5ee0cc 100644 --- a/doc/sdk_configuration.md +++ b/doc/sdk_configuration.md @@ -97,6 +97,7 @@ This file can also be populated using [environment variables](../samples/envirom - [`publish_req`](#configuration-of-publish_req): Fields required for API publishing. - `api_description_path`: The path to the [ServiceAPIDescription](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Publish_Service_API.yaml) JSON file. - `check_authentication_data`: The `ip` and `port` of the target Provider's AEF to get their supported features from. +- `log`: The structure defined in the [Log schema](https://github.com/jdegre/5GC_APIs/blob/Rel-18/TS29222_CAPIF_Logging_API_Invocation_API.yaml), it is not needed to fulfill the `apiId` field. ## Configuration via `capif_sdk_register.json` diff --git a/doc/sdk_full_documentation.md b/doc/sdk_full_documentation.md index d7f2b16..7cb2fd9 100644 --- a/doc/sdk_full_documentation.md +++ b/doc/sdk_full_documentation.md @@ -162,6 +162,20 @@ The provider must be onboarded before using these features.  +### Create logs + +OpenCAPIF SDK references: +- **Function**: `create_logs(aefId, api_invoker_id)` + +The provider notifies to the CCF that the published API has been used by certain invoker. + +For leveraging this feature the Provider must have onboarded and published an API previously. + +**Required SDK input**: +- aefId (Within the function) +- api_invoker_id (Within the function) +- log (Within [SDK configuration](./sdk_configuration.md) or object) + ## Invoker Network App The OpenCAPIF SDK enables efficient implementation of invoker functionality for Network App. This section details the SDK features related to CAPIF invokers. diff --git a/setup.py b/setup.py index 85a43dc..6a8ad4d 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.17.3", + version="0.1.17.5", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( diff --git a/test/test.py b/test/test.py index 6d026d5..85a30a8 100644 --- a/test/test.py +++ b/test/test.py @@ -2,7 +2,7 @@ import json # flake8: noqa -from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer,capif_logging_feature +from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer capif_sdk_config_path = "./capif_sdk_config_sample_test.json" @@ -120,7 +120,7 @@ if __name__ == "__main__": discoverer = service_discoverer(config_file=capif_sdk_config_path) - discoverer.discover_filter["api-name"]= "Testtrece" + discoverer.discover_filter["api-name"]= "safe-6g-resilience-function" discoverer.discover() @@ -130,11 +130,11 @@ if __name__ == "__main__": print("SERVICE GET TOKENS COMPLETED") - logger=capif_logging_feature(config_file=capif_sdk_config_path) + # logger=capif_logging_feature(config_file=capif_sdk_config_path) - invoker_id=discoverer.invoker_capif_details["api_invoker_id"] + # invoker_id=discoverer.invoker_capif_details["api_invoker_id"] - logger.create_logs(aefId=AEF1,api_invoker_id=invoker_id) + # logger.create_logs(aefId=AEF1,api_invoker_id=invoker_id) capif_invoker_connector.update_invoker() -- GitLab From 238977a29e172d4e1e3ae14d1dff8dbc4e09a670 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Thu, 19 Dec 2024 13:42:00 +0100 Subject: [PATCH 26/28] detail --- doc/sdk_full_documentation.md | 1 + opencapif_sdk/capif_provider_connector.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/sdk_full_documentation.md b/doc/sdk_full_documentation.md index 7cb2fd9..32d9f43 100644 --- a/doc/sdk_full_documentation.md +++ b/doc/sdk_full_documentation.md @@ -110,6 +110,7 @@ The SDK simplifies API deletion. Service deletion requires prior onboarding and **Required SDK inputs**: - publisher_apf_id - publisher_aefs_ids +- service_api_id ### Service Update diff --git a/opencapif_sdk/capif_provider_connector.py b/opencapif_sdk/capif_provider_connector.py index a875bd8..1ea9bc2 100644 --- a/opencapif_sdk/capif_provider_connector.py +++ b/opencapif_sdk/capif_provider_connector.py @@ -633,7 +633,7 @@ class capif_provider_connector: cert = ( os.path.join(self.provider_folder, f"apf-{apf_number}.crt"), os.path.join(self.provider_folder, - f"apf-{apf_number}_private_key.key"), + f"APF-{apf_number}_private_key.key"), ) self.logger.info(f"Unpublishing service to URL: {url}") @@ -749,7 +749,7 @@ class capif_provider_connector: cert = ( os.path.join(self.provider_folder, f"apf-{apf_number}.crt"), os.path.join(self.provider_folder, - f"apf-{apf_number}_private_key.key"), + f"APF-{apf_number}_private_key.key"), ) self.logger.info(f"Getting service to URL: {url}") @@ -823,7 +823,7 @@ class capif_provider_connector: cert = ( os.path.join(self.provider_folder, f"apf-{apf_number}.crt"), os.path.join(self.provider_folder, - f"apf-{apf_number}_private_key.key"), + f"APF-{apf_number}_private_key.key"), ) self.logger.info(f"Getting services to URL: {url}") @@ -971,7 +971,7 @@ class capif_provider_connector: cert = ( os.path.join(self.provider_folder, f"apf-{apf_number}.crt"), os.path.join(self.provider_folder, - f"apf-{apf_number}_private_key.key"), + f"APF-{apf_number}_private_key.key"), ) self.logger.info(f"Publishing services to URL: {url}") -- GitLab From 96acdc7a1556170b88d6ca728e523dc21c5e9c17 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Tue, 7 Jan 2025 09:51:49 +0100 Subject: [PATCH 27/28] final version of pip and test working correctly --- setup.py | 2 +- test/test.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 6a8ad4d..9b80f73 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open(os.path.join(this_directory, "README_pipy.md"), encoding="utf-8") as f setup( name="opencapif_sdk", - version="0.1.17.5", + version="0.1.17.6", author="JorgeEcheva, dgs-cgm", author_email="jorge.echevarriauribarri.practicas@telefonica.com, daniel.garciasanchez@telefonica.com", description=( diff --git a/test/test.py b/test/test.py index 85a30a8..9ca0b1f 100644 --- a/test/test.py +++ b/test/test.py @@ -2,7 +2,7 @@ import json # flake8: noqa -from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer +from opencapif_sdk import capif_invoker_connector, capif_provider_connector, service_discoverer,capif_logging_feature capif_sdk_config_path = "./capif_sdk_config_sample_test.json" @@ -130,11 +130,11 @@ if __name__ == "__main__": print("SERVICE GET TOKENS COMPLETED") - # logger=capif_logging_feature(config_file=capif_sdk_config_path) + logger=capif_logging_feature(config_file=capif_sdk_config_path) - # invoker_id=discoverer.invoker_capif_details["api_invoker_id"] + invoker_id=discoverer.invoker_capif_details["api_invoker_id"] - # logger.create_logs(aefId=AEF1,api_invoker_id=invoker_id) + logger.create_logs(aefId=AEF1,api_invoker_id=invoker_id) capif_invoker_connector.update_invoker() -- GitLab From 956c8672f729df982828c98989ba2f53276c27a3 Mon Sep 17 00:00:00 2001 From: JorgeEcheva26 <jorge.echevarriauribarri.practicas@telefonica.es> Date: Thu, 16 Jan 2025 14:00:55 +0100 Subject: [PATCH 28/28] REadme fix --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index cda2d46..5b54e21 100644 --- a/README.md +++ b/README.md @@ -17,18 +17,17 @@ This document serves as the [main bootstrap reference](#networkapp-developer-pat 1. [Repository structure](#repository-structure) 2. [Network App developers](#network-app-developers) - 3. [OpenCAPIF SDK summary](#opencapif-sdk-summary) - 4. [OpenCAPIF SDK requirements](#opencapif-sdk-requirements) - 5. [OpenCAPIF sdk installation](#opencapif-sdk-installation) - 6. [OpenCAPIF SDK data schema](#opencapif-sdk-data-schema) - 7. [OpenCAPIF SDK Configuration](./doc/sdk_configuration.md) - 8. [Network App developer path](#network-app-developer-path) + 3. [OpenCAPIF SDK requirements](#opencapif-sdk-requirements) + 4. [OpenCAPIF sdk installation](#opencapif-sdk-installation) + 5. [OpenCAPIF SDK data schema](#opencapif-sdk-data-schema) + 6. [OpenCAPIF SDK Configuration](./doc/sdk_configuration.md) + 7. [Network App developer path](#network-app-developer-path) 1. [Provider Network App](#provider-network-app) * [Provider Network App sample](#provider-network-app-sample) 2. [Invoker Network App](#invoker-network-app) * [Provider Network App sample](#provider-network-app-sample) - 9. [**OpenCAPIF SDK full documentation**](./doc/sdk_full_documentation.md) - 10. [OpenCAPIF SDK known issues](#opencapif-sdk-known-issues) + 8. [**OpenCAPIF SDK full documentation**](./doc/sdk_full_documentation.md) + 9. [OpenCAPIF SDK known issues](#opencapif-sdk-known-issues) # Repository structure -- GitLab