diff --git a/.gitignore b/.gitignore index 40d2726caa6c8b449d1c6de34025d9be0ac66f9a..ddc84e3dff4947d38b2c83bc330fb72c21e4cb53 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ results helm/capif/*.lock helm/capif/charts/tempo* +*.bak \ No newline at end of file diff --git a/.gitlab/issue_templates/default.md b/.gitlab/issue_templates/default.md new file mode 100644 index 0000000000000000000000000000000000000000..2bc23639be4946f1a6c65dca8d71365bc1cfbf68 --- /dev/null +++ b/.gitlab/issue_templates/default.md @@ -0,0 +1,24 @@ +# Proposers + +- name-of-proposer-1 (institution-of-proposer-1) +- name-of-proposer-2 (institution-of-proposer-2) +... + +# Description + +Describe your proposal in ~1000 characters. +You can reference external content listed in section "References" as [Ref-1]. + +# Demo or definition of done + +Describe which high level conditions needs to be fulfilled to demonstrate this feature implementation is completed. +You can reference external content (example, demo paper) listed in section "References" as [Ref-2]. + +# References + +1. [Reference name](https://reference-url) +2. Author1, Author2, Author3, et. al., “My demo using feature,” in Conference-Name Demo Track, 20XX. + +# Acknowledgements +This work is funded by the European Commission through the project with Grant Agreement number . +```example HORIZON-JU-SNS-2022 FLEX-SCALE project with Grant Agreement number 101096909.``` diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md new file mode 100644 index 0000000000000000000000000000000000000000..2bc23639be4946f1a6c65dca8d71365bc1cfbf68 --- /dev/null +++ b/.gitlab/merge_request_templates/Default.md @@ -0,0 +1,24 @@ +# Proposers + +- name-of-proposer-1 (institution-of-proposer-1) +- name-of-proposer-2 (institution-of-proposer-2) +... + +# Description + +Describe your proposal in ~1000 characters. +You can reference external content listed in section "References" as [Ref-1]. + +# Demo or definition of done + +Describe which high level conditions needs to be fulfilled to demonstrate this feature implementation is completed. +You can reference external content (example, demo paper) listed in section "References" as [Ref-2]. + +# References + +1. [Reference name](https://reference-url) +2. Author1, Author2, Author3, et. al., “My demo using feature,” in Conference-Name Demo Track, 20XX. + +# Acknowledgements +This work is funded by the European Commission through the project with Grant Agreement number . +```example HORIZON-JU-SNS-2022 FLEX-SCALE project with Grant Agreement number 101096909.``` diff --git a/README.md b/README.md index 74a32c286ad8d09fb78dc9b78aafa29c60fb826f..8043acab5fe6bdb1e1cdb526b19169964909ac25 100644 --- a/README.md +++ b/README.md @@ -1,153 +1,23 @@ # Common API Framework (CAPIF) - [Common API Framework (CAPIF)](#common-api-framework-capif) -- [CAPIF\_API\_Services](#capif_api_services) +- [3GPP Common API Framework OpenCAPIF implementation](#3gpp-common-api-framework-opencapif-implementation) - [Documentation](#documentation) - [Install and Run](#install-and-run) - - [How to run CAPIF services in this Repository](#how-to-run-capif-services-in-this-repository) - - [Run All CAPIF Services locally with Docker images](#run-all-capif-services-locally-with-docker-images) - - [Run All CAPIF Services locally with Docker images and deploy monitoring stack](#run-all-capif-services-locally-with-docker-images-and-deploy-monitoring-stack) - - [Run each service using Docker](#run-each-service-using-docker) - - [Run each service using Python](#run-each-service-using-python) -- [Important urls:](#important-urls) - - [Mongo CAPIF's DB Dashboard](#mongo-capifs-db-dashboard) - - [Mongo Register's DB Dashboard](#mongo-registers-db-dashboard) - [FAQ Documentation](#faq-documentation) -# CAPIF_API_Services -This repository has the python-flask Mockup servers created with openapi-generator related with CAPIF APIS defined here: -[Open API Descriptions of 3GPP 5G APIs] +# 3GPP Common API Framework OpenCAPIF implementation +This repository includes all services developed using Python Flask servers, created with openapi-generator with swagger definitions on [Open API Descriptions of 3GPP 5G APIs] for release 18 of Technical Specifications. # Documentation Please refer to [OCF Documentation] for more detailed information. +# Install and Run -# Install and Run - -## How to run CAPIF services in this Repository -Capif services are developed under /service/ folder. - -### Run All CAPIF Services locally with Docker images -To run using docker and docker compose, version 2.10 or higher, you must ensure you have that tools installed at your machine. Also to simplify the process, we have 3 script to control docker images to deploy, check and cleanup. - -To run all CAPIF APIs locally using docker and docker-compose you can execute: -``` -cd services/ - -./run.sh -``` -This will build and run all services using docker images, including mongodb and nginx locally and in background, and import ca.crt to nginx. - -Nginx deployed by default use **capifcore** hostname, but can add a parameter when run.sh is executed setting a different hostname, for example, -``` -./run.sh -c openshift.evolved-5g.eu -``` - -Also you can run monitoring just using option -m true, for example: -``` -./run.sh -m true -./run.sh -m true -c openshift.evolved-5g.eu -``` - -If you want to check if all CAPIF services are running properly in local machine after execute run.sh, we can use: -``` -./check_services_are_running.sh -``` -This shell script will return 0 if all services are running properly. - -When we need to stop all CAPIF services, we can use next bash script: -``` -./clean_capif_docker_services.sh -a -``` - -NOTE: You can use different flags if you only want to stop some of them, please check help using -``` -./clean_capif_docker_services.sh -h - -Usage: clean_capif_docker_services.sh - -c : clean capif services - -v : clean vault service - -r : clean register service - -m : clean monitoring service - -a : clean all services - -h : show this help -`````` - -This shell script will remove and clean all CAPIF services started previously with run.sh - -On the other hand you can check logs using show_logs.sh script, please check options: -``` -./show_logs.sh -You must specify an option before run script. -Usage: ./show_logs.sh - -c : Show capif services - -v : Show vault service - -r : Show register service - -m : Show monitoring service - -a : Show all services - -f : Follow log output - -h : Show this help -``` -You can also use option -f in order to live follow log output - -### Run All CAPIF Services locally with Docker images and deploy monitoring stack -It is now possible to deploy a monitoring stack for CAPIF with Grafana, Prometheus, FluentBit, Loki, Cadvisor, Tempo and Opentelemetry. - -To deploy CAPIF together with the monitoring stack, it is only necessary to execute the following. - -``` -./run.sh -m true -``` - -After they have been built, the different panels can be consulted in Grafana at the url - -``` -http://localhost:3000 -``` - -By default, the monitoring option is set to false. Once up, all data sources and dashboards are automatically provisioned - -### Run each service using Docker - -Also you can run service by service using docker: -``` -cd -docker build -t capif_security . -docker run -p 8080:8080 capif_security -``` - -### Run each service using Python - -Run using python -``` -cd -pip3 install -r requirements.txt -python3 -m -``` - -# Important urls: - -## Mongo CAPIF's DB Dashboard -``` -http://localhost:8082/ (if accessed from localhost) - -or - -http://:8082/ (if accessed from another host) -``` - -## Mongo Register's DB Dashboard -``` -http://localhost:8083/ (if accessed from localhost) - -or - -http://:8083/ (if accessed from another host) -``` - +Please refer to [OCF How to run] for more detailed information. # FAQ Documentation @@ -159,4 +29,5 @@ Frequently asked questions can be found here: [FAQ Directory] [Testing with Robot Framework]: ./docs/testing_with_robot/README.md "Testing with Robot Framework" [FAQ Directory]: https://ocf.etsi.org/documentation/latest/FAQ/ "FAQ Url" [OCF Documentation]: https://ocf.etsi.org/documentation/latest/ "OCF Documentation" +[OCF How to run]: https://ocf.etsi.org/documentation/latest/gettingstarted/howtorun/ "How to run" diff --git a/helm/capif/Chart.yaml b/helm/capif/Chart.yaml index 1c49c2c37c782bfe4095533ddedc57750f2db18b..89785865369522b11e226ced4ae87db254e898a8 100644 --- a/helm/capif/Chart.yaml +++ b/helm/capif/Chart.yaml @@ -68,6 +68,10 @@ dependencies: version: "*" - name: renderer version: "*" + - name: celery-beat + version: "*" + - name: celery-worker + version: "*" - name: "tempo" condition: tempo.enabled repository: "https://grafana.github.io/helm-charts" diff --git a/helm/capif/charts/celery-beat/.helmignore b/helm/capif/charts/celery-beat/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778 --- /dev/null +++ b/helm/capif/charts/celery-beat/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/capif/charts/celery-beat/Chart.yaml b/helm/capif/charts/celery-beat/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..140a2ff9d4422f7ee4736a971fe5cb7596cdb5a9 --- /dev/null +++ b/helm/capif/charts/celery-beat/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: celery-beat +description: A Helm chart for Kubernetes of celery-beat + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" \ No newline at end of file diff --git a/helm/capif/charts/celery-beat/README.md b/helm/capif/charts/celery-beat/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35b1639a6c6ce3260a9d0a335d1df7cacffc4fd8 --- /dev/null +++ b/helm/capif/charts/celery-beat/README.md @@ -0,0 +1,67 @@ +# celery-beat + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +A Helm chart for Kubernetes of celery-beat + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| autoscaling.enabled | bool | `false` | | +| autoscaling.maxReplicas | int | `100` | | +| autoscaling.minReplicas | int | `1` | | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | | +| env.capifHostname | string | `"capif"` | | +| env.logLevel | string | `"INFO"` | | +| env.mongoInitdbRootPassword | string | `"example"` | | +| env.mongoInitdbRootUsername | string | `"root"` | | +| env.monitoring | string | `"true"` | | +| env.vaultAccessToken | string | `"dev-only-token"` | | +| env.vaultHostname | string | `"vault"` | | +| env.vaultPort | int | `8200` | | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"Always"` | | +| image.repository | string | `"celery-beat"` | | +| image.tag | string | `""` | | +| imagePullSecrets | list | `[]` | | +| ingress.annotations | object | `{}` | | +| ingress.className | string | `""` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts[0].host | string | `"chart-example.local"` | | +| ingress.hosts[0].paths[0].path | string | `"/"` | | +| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | | +| ingress.tls | list | `[]` | | +| livenessProbe | string | `nil` | | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| readinessProbe.initialDelaySeconds | int | `10` | | +| readinessProbe.periodSeconds | int | `5` | | +| readinessProbe.tcpSocket.port | int | `8080` | | +| replicaCount | int | `1` | | +| resources.limits.cpu | string | `"100m"` | | +| resources.limits.memory | string | `"128Mi"` | | +| resources.requests.cpu | string | `"100m"` | | +| resources.requests.memory | string | `"128Mi"` | | +| securityContext | object | `{}` | | +| service.port | int | `8080` | | +| service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.automount | bool | `true` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.name | string | `""` | | +| tolerations | list | `[]` | | +| volumeMounts[0].mountPath | string | `"/usr/src/app/config.yaml"` | | +| volumeMounts[0].name | string | `"celery-beat"` | | +| volumeMounts[0].subPath | string | `"config.yaml"` | | +| volumes[0].configMap.items[0].key | string | `"config.yaml"` | | +| volumes[0].configMap.items[0].path | string | `"config.yaml"` | | +| volumes[0].configMap.name | string | `"celery-beat-configmap"` | | +| volumes[0].name | string | `"celery-beat"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/helm/capif/charts/celery-beat/templates/NOTES.txt b/helm/capif/charts/celery-beat/templates/NOTES.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dc54d5b6ac8f86cd7064a043ee1377bb0995c79 --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/NOTES.txt @@ -0,0 +1,8 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-beat/templates/_helpers.tpl b/helm/capif/charts/celery-beat/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..ece434bb1a5657dfff166875abea06aec6dbfae6 --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "celery-beat.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "celery-beat.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "celery-beat.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "celery-beat.labels" -}} +helm.sh/chart: {{ include "celery-beat.chart" . }} +{{ include "celery-beat.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "celery-beat.selectorLabels" -}} +app.kubernetes.io/name: {{ include "celery-beat.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "celery-beat.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "celery-beat.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-beat/templates/configmap.yaml b/helm/capif/charts/celery-beat/templates/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3ae5cde3b37aeac71a8f6a7222d437ca9a028466 --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: celery-beat-configmap +data: + config.yaml: | + mongo: { + 'user': '{{ .Values.env.mongoInitdbRootUsername }}', + 'password': '{{ .Values.env.mongoInitdbRootPassword }}', + 'db': 'capif', + 'notifications_col': 'notifications', + 'host': 'mongo', + 'port': "27017" + } diff --git a/helm/capif/charts/celery-beat/templates/deployment.yaml b/helm/capif/charts/celery-beat/templates/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4a231223a9d3d5a5f9a7f13f45e27c1d7b3f1f6a --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "celery-beat.fullname" . }} + labels: + {{- include "celery-beat.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "celery-beat.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + date: "{{ now | unixEpoch }}" + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + labels: + {{- include "celery-beat.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "celery-beat.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: CELERY_MODE + value: {{ quote .Values.env.celeryMode }} + - name: REDIS_HOST + value: {{ quote .Values.env.redisHost }} + - name: REDIS_PORT + value: {{ quote .Values.env.redisPort }} + - name: LOG_LEVEL + value: {{ quote .Values.env.logLevel }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/capif/charts/celery-beat/templates/hpa.yaml b/helm/capif/charts/celery-beat/templates/hpa.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4884b453e2bc2d7b6dc52ef129d4637fd8c5d112 --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "celery-beat.fullname" . }} + labels: + {{- include "celery-beat.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "celery-beat.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-beat/templates/ingress.yaml b/helm/capif/charts/celery-beat/templates/ingress.yaml new file mode 100644 index 0000000000000000000000000000000000000000..aa98da9211e789392b713ec3461eec9f9281b4eb --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "celery-beat.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "celery-beat.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-beat/templates/serviceaccount.yaml b/helm/capif/charts/celery-beat/templates/serviceaccount.yaml new file mode 100644 index 0000000000000000000000000000000000000000..368cfc15f7d48a7a46a1ade17fa726566b5edac1 --- /dev/null +++ b/helm/capif/charts/celery-beat/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "celery-beat.serviceAccountName" . }} + labels: + {{- include "celery-beat.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/helm/capif/charts/celery-beat/values.yaml b/helm/capif/charts/celery-beat/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bd7fc689c392daaa1760752d1403259a7b62fb03 --- /dev/null +++ b/helm/capif/charts/celery-beat/values.yaml @@ -0,0 +1,114 @@ +# Default values for celery-beat. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: celery + pullPolicy: Always + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +env: + celeryMode: beat + redisHost: redis + redisPort: 6379 + mongoInitdbRootUsername: root + mongoInitdbRootPassword: example + logLevel: DEBUG + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 1m + memory: 1Mi + +livenessProbe: +# httpGet: +# path: / +# port: http +readinessProbe: +# tcpSocket: +# port: 8080 +# initialDelaySeconds: 10 +# periodSeconds: 5 + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: + - name: celery-beat + configMap: + name: celery-beat-configmap + items: + - key: "config.yaml" + path: "config.yaml" + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - name: celery-beat + mountPath: /celery/config.yaml + subPath: config.yaml + +nodeSelector: {} + +tolerations: [] + +affinity: {} \ No newline at end of file diff --git a/helm/capif/charts/celery-worker/.helmignore b/helm/capif/charts/celery-worker/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778 --- /dev/null +++ b/helm/capif/charts/celery-worker/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/capif/charts/celery-worker/Chart.yaml b/helm/capif/charts/celery-worker/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cd71295e37635bc46afb88ca9f6bd1b07cd74caa --- /dev/null +++ b/helm/capif/charts/celery-worker/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: celery-worker +description: A Helm chart for Kubernetes of celery-worker + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/capif/charts/celery-worker/README.md b/helm/capif/charts/celery-worker/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1563d79c35c9de33fed9f524f81a2288bb21b371 --- /dev/null +++ b/helm/capif/charts/celery-worker/README.md @@ -0,0 +1,67 @@ +# celery-worker + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +A Helm chart for Kubernetes of celery-worker + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| autoscaling.enabled | bool | `false` | | +| autoscaling.maxReplicas | int | `100` | | +| autoscaling.minReplicas | int | `1` | | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | | +| env.capifHostname | string | `"capif"` | | +| env.logLevel | string | `"INFO"` | | +| env.mongoInitdbRootPassword | string | `"example"` | | +| env.mongoInitdbRootUsername | string | `"root"` | | +| env.monitoring | string | `"true"` | | +| env.vaultAccessToken | string | `"dev-only-token"` | | +| env.vaultHostname | string | `"vault"` | | +| env.vaultPort | int | `8200` | | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"Always"` | | +| image.repository | string | `"celery-worker"` | | +| image.tag | string | `""` | | +| imagePullSecrets | list | `[]` | | +| ingress.annotations | object | `{}` | | +| ingress.className | string | `""` | | +| ingress.enabled | bool | `false` | | +| ingress.hosts[0].host | string | `"chart-example.local"` | | +| ingress.hosts[0].paths[0].path | string | `"/"` | | +| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | | +| ingress.tls | list | `[]` | | +| livenessProbe | string | `nil` | | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podAnnotations | object | `{}` | | +| podLabels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| readinessProbe.initialDelaySeconds | int | `10` | | +| readinessProbe.periodSeconds | int | `5` | | +| readinessProbe.tcpSocket.port | int | `8080` | | +| replicaCount | int | `1` | | +| resources.limits.cpu | string | `"100m"` | | +| resources.limits.memory | string | `"128Mi"` | | +| resources.requests.cpu | string | `"100m"` | | +| resources.requests.memory | string | `"128Mi"` | | +| securityContext | object | `{}` | | +| service.port | int | `8080` | | +| service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.automount | bool | `true` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.name | string | `""` | | +| tolerations | list | `[]` | | +| volumeMounts[0].mountPath | string | `"/usr/src/app/config.yaml"` | | +| volumeMounts[0].name | string | `"celery-worker"` | | +| volumeMounts[0].subPath | string | `"config.yaml"` | | +| volumes[0].configMap.items[0].key | string | `"config.yaml"` | | +| volumes[0].configMap.items[0].path | string | `"config.yaml"` | | +| volumes[0].configMap.name | string | `"celery-worker-configmap"` | | +| volumes[0].name | string | `"celery-worker"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/helm/capif/charts/celery-worker/templates/NOTES.txt b/helm/capif/charts/celery-worker/templates/NOTES.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dc54d5b6ac8f86cd7064a043ee1377bb0995c79 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/NOTES.txt @@ -0,0 +1,8 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-worker/templates/_helpers.tpl b/helm/capif/charts/celery-worker/templates/_helpers.tpl new file mode 100644 index 0000000000000000000000000000000000000000..c545f56ef7ca096dbc70a404b60d5a6af3b67ae9 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "celery-worker.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "celery-worker.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "celery-worker.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "celery-worker.labels" -}} +helm.sh/chart: {{ include "celery-worker.chart" . }} +{{ include "celery-worker.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "celery-worker.selectorLabels" -}} +app.kubernetes.io/name: {{ include "celery-worker.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "celery-worker.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "celery-worker.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-worker/templates/configmap.yaml b/helm/capif/charts/celery-worker/templates/configmap.yaml new file mode 100644 index 0000000000000000000000000000000000000000..20d74ecf4b3305b421f3837b6487299731679642 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: celery-worker-configmap +data: + config.yaml: | + mongo: { + 'user': '{{ .Values.env.mongoInitdbRootUsername }}', + 'password': '{{ .Values.env.mongoInitdbRootPassword }}', + 'db': 'capif', + 'notifications_col': 'notifications', + 'host': 'mongo', + 'port': "27017" + } diff --git a/helm/capif/charts/celery-worker/templates/deployment.yaml b/helm/capif/charts/celery-worker/templates/deployment.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4431174060691e16e47bfd8749b986543324be31 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "celery-worker.fullname" . }} + labels: + {{- include "celery-worker.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "celery-worker.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + date: "{{ now | unixEpoch }}" + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + labels: + {{- include "celery-worker.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "celery-worker.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: CELERY_MODE + value: {{ quote .Values.env.celeryMode }} + - name: REDIS_HOST + value: {{ quote .Values.env.redisHost }} + - name: REDIS_PORT + value: {{ quote .Values.env.redisPort }} + - name: LOG_LEVEL + value: {{ quote .Values.env.logLevel }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/capif/charts/celery-worker/templates/hpa.yaml b/helm/capif/charts/celery-worker/templates/hpa.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c89649e82b8662bfa8fd650137cd3c6c5ea6951b --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "celery-worker.fullname" . }} + labels: + {{- include "celery-worker.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "celery-worker.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-worker/templates/ingress.yaml b/helm/capif/charts/celery-worker/templates/ingress.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5d07a917024aafad76f499f17dd91efeb6592d34 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "celery-worker.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "celery-worker.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/capif/charts/celery-worker/templates/serviceaccount.yaml b/helm/capif/charts/celery-worker/templates/serviceaccount.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2876baf0b85371ce4bdd7ee99b373edcf316a999 --- /dev/null +++ b/helm/capif/charts/celery-worker/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "celery-worker.serviceAccountName" . }} + labels: + {{- include "celery-worker.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/helm/capif/charts/celery-worker/values.yaml b/helm/capif/charts/celery-worker/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c410ac9456f3946ce2a16ea652cb3fc7a29aec40 --- /dev/null +++ b/helm/capif/charts/celery-worker/values.yaml @@ -0,0 +1,114 @@ +# Default values for celery-worker. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: celery + pullPolicy: Always + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +env: + celeryMode: worker + redisHost: redis + redisPort: 6379 + mongoInitdbRootUsername: root + mongoInitdbRootPassword: example + logLevel: DEBUG + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 1m + memory: 1Mi + +livenessProbe: +# httpGet: +# path: / +# port: http +readinessProbe: +# tcpSocket: +# port: 8080 +# initialDelaySeconds: 10 +# periodSeconds: 5 + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: + - name: celery-worker + configMap: + name: celery-worker-configmap + items: + - key: "config.yaml" + path: "config.yaml" + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - name: celery-worker + mountPath: /celery/config.yaml + subPath: config.yaml + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/helm/capif/charts/ocf-api-invocation-logs/templates/configmap.yaml b/helm/capif/charts/ocf-api-invocation-logs/templates/configmap.yaml index bd13f9f18e9d11ad35ccc041c1cc02f6224107da..8d814ea3d51f680c11289b54f08cd0b5b2629948 100644 --- a/helm/capif/charts/ocf-api-invocation-logs/templates/configmap.yaml +++ b/helm/capif/charts/ocf-api-invocation-logs/templates/configmap.yaml @@ -12,7 +12,8 @@ data: 'invoker_col': 'invokerdetails', 'prov_col': 'providerenrolmentdetails', 'serv_col': 'serviceapidescriptions', - 'capif_users_col': "user", + 'capif_users_col': 'user', + 'certs_col': 'certs', 'host': 'mongo', 'port': "27017" } diff --git a/helm/capif/charts/ocf-api-invoker-management/templates/configmap.yaml b/helm/capif/charts/ocf-api-invoker-management/templates/configmap.yaml index 4d83c986d75cee2cc228f2b34bae07ee8b95cfb7..f06888931bded3d1d59114a05b1877f9283db25d 100644 --- a/helm/capif/charts/ocf-api-invoker-management/templates/configmap.yaml +++ b/helm/capif/charts/ocf-api-invoker-management/templates/configmap.yaml @@ -9,8 +9,8 @@ data: 'password': '{{ .Values.env.mongoInitdbRootPassword }}', 'db': 'capif', 'col': 'invokerdetails', - 'capif_users_col': "user", - 'certs_col': "certs", + 'capif_users_col': 'user', + 'certs_col': 'certs', 'service_col': 'serviceapidescriptions', 'host': 'mongo', 'port': "27017" diff --git a/helm/capif/charts/ocf-api-provider-management/templates/configmap.yaml b/helm/capif/charts/ocf-api-provider-management/templates/configmap.yaml index e59cfe179aa1e2cd88444e2785371a5b398a40de..6da59dd82a3b4cded19ec9fe77cd88d85db7556a 100644 --- a/helm/capif/charts/ocf-api-provider-management/templates/configmap.yaml +++ b/helm/capif/charts/ocf-api-provider-management/templates/configmap.yaml @@ -9,7 +9,7 @@ data: 'password': '{{ .Values.env.mongoInitdbRootPassword }}', 'db': 'capif', 'col': 'providerenrolmentdetails', - 'certs_col': "certs", + 'certs_col': 'certs', 'capif_users': 'user', 'host': 'mongo', 'port': "27017" diff --git a/helm/capif/charts/ocf-auditing-api-logs/templates/configmap.yaml b/helm/capif/charts/ocf-auditing-api-logs/templates/configmap.yaml index 729d751f3656155cb05d6b3b4ea28b80c350cb97..b06b6d15d8332aa52d548cd6314ee37730ae5685 100644 --- a/helm/capif/charts/ocf-auditing-api-logs/templates/configmap.yaml +++ b/helm/capif/charts/ocf-auditing-api-logs/templates/configmap.yaml @@ -9,7 +9,8 @@ data: 'password': '{{ .Values.env.mongoInitdbRootPassword }}', 'db': 'capif', 'logs_col': 'invocationlogs', - 'capif_users_col': "user", + 'capif_users_col': 'user', + 'certs_col': 'certs', 'host': 'mongo', 'port': "27017" } diff --git a/helm/capif/charts/ocf-discover-service-api/templates/configmap.yaml b/helm/capif/charts/ocf-discover-service-api/templates/configmap.yaml index 96d0c367f3380331806c9c040a985cf22f9b4b27..1e217915e80fe4992e8249e00574d372d12a6237 100644 --- a/helm/capif/charts/ocf-discover-service-api/templates/configmap.yaml +++ b/helm/capif/charts/ocf-discover-service-api/templates/configmap.yaml @@ -10,7 +10,8 @@ data: 'db': 'capif', 'col': 'serviceapidescriptions', 'invokers_col': 'invokerdetails', - 'capif_users_col': "user", + 'capif_users_col': 'user', + 'certs_col': 'certs', 'host': 'mongo', 'port': "27017" } diff --git a/helm/capif/charts/ocf-events/templates/configmap.yaml b/helm/capif/charts/ocf-events/templates/configmap.yaml index a928cac58ffce782abccb40375ae00cfeae41a24..92697a2c40b1f3aa81a23d6fd745f0d15ea21110 100644 --- a/helm/capif/charts/ocf-events/templates/configmap.yaml +++ b/helm/capif/charts/ocf-events/templates/configmap.yaml @@ -9,9 +9,11 @@ data: 'password': '{{ .Values.env.mongoInitdbRootPassword }}', 'db': 'capif', 'col': 'eventsdetails', - 'certs_col': "certs", + 'certs_col': 'certs', 'capif_invokers_col': 'invokerdetails', 'capif_providers_col': 'providerenrolmentdetails', + 'capif_acls_col': 'acls', + 'notifications_col': 'notifications', 'host': 'mongo', 'port': "27017" } diff --git a/helm/capif/charts/ocf-helper/templates/ocf-helper-configmap.yaml b/helm/capif/charts/ocf-helper/templates/ocf-helper-configmap.yaml index 796a55cf7e451343b05c793a4bb1eb40486029f2..fe3e1c170fce991454b0442d0613ad3247c067a4 100644 --- a/helm/capif/charts/ocf-helper/templates/ocf-helper-configmap.yaml +++ b/helm/capif/charts/ocf-helper/templates/ocf-helper-configmap.yaml @@ -13,6 +13,7 @@ data: 'col_services': "serviceapidescriptions", 'col_security': "security", 'col_event': "eventsdetails", + 'col_capif_configuration': "capif_configuration", 'host': '{{ .Values.env.mongoHost }}', 'port': "{{ .Values.env.mongoPort }}" } @@ -21,4 +22,8 @@ data: "url": {{ quote .Values.env.vaultHostname }}, "port": {{ quote .Values.env.vaultPort }}, "token": {{ quote .Values.env.vaultAccessToken }} - } \ No newline at end of file + } + + {{- if .Values.capifConfiguration }} + capif_configuration: {{ .Values.capifConfiguration | toYaml | nindent 6 }} + {{- end }} \ No newline at end of file diff --git a/helm/capif/charts/ocf-helper/values.yaml b/helm/capif/charts/ocf-helper/values.yaml index 8a30745c82ac8b1e9a5e74eeccf98acaca4d758d..a255d463062dd9ebac9b11c8bbcf08a2bf4c9731 100644 --- a/helm/capif/charts/ocf-helper/values.yaml +++ b/helm/capif/charts/ocf-helper/values.yaml @@ -25,6 +25,24 @@ env: mongoInitdbRootPassword: example logLevel: "INFO" +capifConfiguration: + config_name: "default" + config_version: "1.0" + config_description: "Default CAPIF Configuration" + settings: + certificates_expiry: + ttl_superadmin_cert: "4300h" + ttl_invoker_cert: "4300h" + ttl_provider_cert: "4300h" + security_method_priority: + oauth: 1 + pki: 2 + psk: 3 + acl_policy_settings: + allowed_total_invocations: 5 + allowed_invocations_per_second: 10 + allowed_invocation_time_range_days: 365 + serviceAccount: # Specifies whether a service account should be created create: true diff --git a/helm/capif/charts/ocf-publish-service-api/templates/configmap.yaml b/helm/capif/charts/ocf-publish-service-api/templates/configmap.yaml index a76b2f2bbe1772205d1707635efb3df3209eeb8e..651ad05b2791bebd2a0a3f4f31c2725b80f24e28 100644 --- a/helm/capif/charts/ocf-publish-service-api/templates/configmap.yaml +++ b/helm/capif/charts/ocf-publish-service-api/templates/configmap.yaml @@ -9,8 +9,8 @@ data: 'password': '{{ .Values.env.mongoInitdbRootPassword }}', 'db': 'capif', 'col': 'serviceapidescriptions', - 'certs_col': "certs", - 'capif_provider_col': "providerenrolmentdetails", + 'certs_col': 'certs', + 'capif_provider_col': 'providerenrolmentdetails', 'host': 'mongo', 'port': "27017" } diff --git a/helm/capif/charts/ocf-register/templates/configmap.yaml b/helm/capif/charts/ocf-register/templates/configmap.yaml index 0c01aedcddf6b4159a86ea52db051e809155e0b3..2b89f18006c68505d7a1c5d0a4e84dd551fab99e 100644 --- a/helm/capif/charts/ocf-register/templates/configmap.yaml +++ b/helm/capif/charts/ocf-register/templates/configmap.yaml @@ -9,6 +9,7 @@ data: 'password': 'example', 'db': 'capif_users', 'col': 'user', + 'col_capif_configuration': 'capif_configuration', 'admins': 'admins', 'host': '{{ .Values.env.mongoHost }}', 'port': '{{ .Values.env.mongoPort }}' @@ -29,3 +30,7 @@ data: admin_users: {admin_user: "admin", admin_pass: "password123"} } + + {{- if .Values.capifConfiguration }} + capif_configuration: {{ .Values.capifConfiguration | toYaml | nindent 6 }} + {{- end }} diff --git a/helm/capif/charts/ocf-register/values.yaml b/helm/capif/charts/ocf-register/values.yaml index 1773a6b875f55e783e1bba6520abccc5c52e72ad..bf12e498a876405261c5214c3ebc7354e00cd399 100644 --- a/helm/capif/charts/ocf-register/values.yaml +++ b/helm/capif/charts/ocf-register/values.yaml @@ -23,6 +23,14 @@ env: capifHostname: capif-test.example.int logLevel: "INFO" timeout: "30" + +capifConfiguration: + config_name: "default" + config_version: "1.0" + config_description: "Default Register Configuration" + settings: + certificates_expiry: + ttl_superadmin_cert: "4300h" serviceAccount: # Specifies whether a service account should be created diff --git a/helm/capif/charts/ocf-security/templates/configmap.yaml b/helm/capif/charts/ocf-security/templates/configmap.yaml index 5d099d194854f2bc3a63fa1c83e075c4b3edff36..19e0c99b14145ef518ea1a307789a55a8f93dffd 100644 --- a/helm/capif/charts/ocf-security/templates/configmap.yaml +++ b/helm/capif/charts/ocf-security/templates/configmap.yaml @@ -10,7 +10,7 @@ data: 'db': 'capif', 'col': 'security', 'capif_service_col': 'serviceapidescriptions', - 'certs_col': "certs", + 'certs_col': 'certs', 'capif_invokers' : 'invokerdetails', 'host': 'mongo', 'port': "27017" diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/FILES b/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/FILES index dd0e2a9e7892c7379f62964a2f181f7327bd1220..716733b50c4a3eb61f5bd5dfa747bccff799aec9 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/FILES @@ -37,6 +37,7 @@ api_invoker_management/models/ipv6_address_range.py api_invoker_management/models/local2d_point_uncertainty_ellipse.py api_invoker_management/models/local3d_point_uncertainty_ellipsoid.py api_invoker_management/models/local_origin.py +api_invoker_management/models/o_auth_grant_type.py api_invoker_management/models/onboarding_information.py api_invoker_management/models/onboarding_notification.py api_invoker_management/models/operation.py diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/app.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/app.py index e44c08e4776684adbfc29617e7cb261c7a2434fb..abe585969bd76909574b9e9ee5596314f7eadd10 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/app.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/app.py @@ -6,6 +6,9 @@ from datetime import datetime from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config +from core.consumer_messager import Subscriber from flask_apscheduler import APScheduler from flask_executor import Executor from flask_jwt_extended import JWTManager @@ -19,10 +22,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config -from core.consumer_messager import Subscriber - NAME = "Invoker-Service" # Setting log level @@ -36,7 +35,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Invoker-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py index c080cd19675cf0f0ee67e7bbdeec4ca7c57d8a70..09ffb62420d0330c04292f3d2617c47cde0712e3 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py @@ -2,8 +2,8 @@ from functools import wraps from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app -from flask_jwt_extended import jwt_required, get_jwt_identity +from flask import current_app, request +from flask_jwt_extended import get_jwt_identity, jwt_required from ..core.apiinvokerenrolmentdetails import InvokerManagementOperations from ..core.validate_user import ControlAccess @@ -12,7 +12,6 @@ from ..models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails # invoker_operations = InvokerManagementOperations() valid_user = ControlAccess() - def cert_validation(): def _cert_validation(f): @wraps(f) @@ -47,9 +46,8 @@ def onboarded_invokers_onboarding_id_delete(onboarding_id): # noqa: E501 :param onboarding_id: String identifying an individual on-boarded API invoker resource :type onboarding_id: str - :rtype: None + :rtype: Union[None, Tuple[None, int], Tuple[None, int, Dict[str, str]] """ - current_app.logger.info("Removing invoker") res = invoker_operations.remove_apiinvokerenrolmentdetail(onboarding_id) @@ -66,7 +64,7 @@ def onboarded_invokers_onboarding_id_put(onboarding_id, body): # noqa: E501 :param api_invoker_enrolment_details: representation of the API invoker details to be updated in CAPIF core function :type api_invoker_enrolment_details: dict | bytes - :rtype: APIInvokerEnrolmentDetails + :rtype: Union[APIInvokerEnrolmentDetails, Tuple[APIInvokerEnrolmentDetails, int], Tuple[APIInvokerEnrolmentDetails, int, Dict[str, str]] """ current_app.logger.info("Updating invoker") if request.is_json: @@ -76,19 +74,17 @@ def onboarded_invokers_onboarding_id_put(onboarding_id, body): # noqa: E501 return res - @jwt_required() def onboarded_invokers_post(body): # noqa: E501 """onboarded_invokers_post Creates a new individual API Invoker profile. # noqa: E501 - :param api_invoker_enrolment_details: + :param api_invoker_enrolment_details: :type api_invoker_enrolment_details: dict | bytes - :rtype: APIInvokerEnrolmentDetails + :rtype: Union[APIInvokerEnrolmentDetails, Tuple[APIInvokerEnrolmentDetails, int], Tuple[APIInvokerEnrolmentDetails, int, Dict[str, str]] """ - identity = get_jwt_identity() username, uuid = identity.split() diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/individual_api_invoker_enrolment_details_controller.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/individual_api_invoker_enrolment_details_controller.py index 9cce3a04fe77786a839cab01f8389533d38c37e8..a033932ba7166e38aa0dc963afa45963d37d954f 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/individual_api_invoker_enrolment_details_controller.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/individual_api_invoker_enrolment_details_controller.py @@ -1,7 +1,45 @@ -from api_invoker_management.models.api_invoker_enrolment_details_patch import APIInvokerEnrolmentDetailsPatch # noqa: E501 +from flask import current_app, request +from functools import wraps +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from ..core.apiinvokerenrolmentdetails import InvokerManagementOperations +from ..core.validate_user import ControlAccess +from api_invoker_management.models.api_invoker_enrolment_details_patch import \ + APIInvokerEnrolmentDetailsPatch # noqa: E501 -def modify_ind_api_invoke_enrolment(onboarding_id, api_invoker_enrolment_details_patch): # noqa: E501 +invoker_operations = InvokerManagementOperations() +valid_user = ControlAccess() + + +def cert_validation(): + def _cert_validation(f): + @wraps(f) + def __cert_validation(*args, **kwargs): + + args = request.view_args + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + if cn != "superadmin": + cert_signature = cert.signature.hex() + result = valid_user.validate_user_cert(args["onboardingId"], cert_signature) + + if result is not None: + return result + + result = f(**kwargs) + return result + return __cert_validation + return _cert_validation + + +@cert_validation() +def modify_ind_api_invoke_enrolment(onboarding_id, body): # noqa: E501 """modify_ind_api_invoke_enrolment Modify an individual API invoker details. # noqa: E501 @@ -13,6 +51,11 @@ def modify_ind_api_invoke_enrolment(onboarding_id, api_invoker_enrolment_details :rtype: Union[APIInvokerEnrolmentDetails, Tuple[APIInvokerEnrolmentDetails, int], Tuple[APIInvokerEnrolmentDetails, int, Dict[str, str]] """ + current_app.logger.info("Updating invoker") if request.is_json: - api_invoker_enrolment_details_patch = APIInvokerEnrolmentDetailsPatch.from_dict(request.get_json()) # noqa: E501 - return 'do some magic!' + body = APIInvokerEnrolmentDetailsPatch.from_dict(request.get_json()) # noqa: E501 + + res = invoker_operations.patch_apiinvokerenrolmentdetail(onboarding_id, body) + + return res + diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py index fcc1a1883a7ea843d2a85166a900724a9b6c6310..381df7b75e1203b2ba2345a4fb94c279f16b4292 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/apiinvokerenrolmentdetails.py @@ -5,18 +5,37 @@ from datetime import datetime import requests import rfc3987 +from api_invoker_management.db.db import MongoDatabse from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails -from flask import current_app, Response +from flask import Response, current_app from pymongo import ReturnDocument +from ..config import Config +from ..util import dict_to_camel_case, serialize_clean_camel_case, clean_empty from .auth_manager import AuthManager from .publisher import Publisher from .redis_event import RedisEvent from .redis_internal_event import RedisInternalEvent from .resources import Resource -from .responses import bad_request_error, not_found_error, forbidden_error, internal_server_error, make_response -from ..config import Config -from ..util import dict_to_camel_case, serialize_clean_camel_case +from .responses import bad_request_error, forbidden_error, internal_server_error, make_response, not_found_error + + +TOTAL_FEATURES = 4 +SUPPORTED_FEATURES_HEX = "0" + + +def return_negotiated_supp_feat_dict(supp_feat): + + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "Notification_test_event": True if final_supp_feat[0] == "1" else False, + "Notification_websocket": True if final_supp_feat[1] == "1" else False, + "PatchUpdate": True if final_supp_feat[2] == "1" else False, + "ExpirationTime": True if final_supp_feat[3] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } + publisher_ops = Publisher() @@ -38,11 +57,14 @@ class InvokerManagementOperations(Resource): def __sign_cert(self, publick_key, invoker_id): + capif_config = self.db.get_col_by_name("capif_configuration").find_one({"config_name": "default"}) + ttl_invoker_cert = capif_config.get("settings", {}).get("certificates_expiry", {}).get("ttl_invoker_cert", "4300h") + url = f"http://{self.config['ca_factory']['url']}:{self.config['ca_factory']['port']}/v1/pki_int/sign/my-ca" headers = {'X-Vault-Token': self.config['ca_factory']['token']} data = { 'format': 'pem_bundle', - 'ttl': '43000h', + 'ttl': ttl_invoker_cert, 'csr': publick_key, 'common_name': invoker_id } @@ -58,6 +80,7 @@ class InvokerManagementOperations(Resource): Resource.__init__(self) self.auth_manager = AuthManager() self.config = Config().get_config() + self.db = MongoDatabse() def add_apiinvokerenrolmentdetail(self, apiinvokerenrolmentdetail, username, uuid): @@ -88,6 +111,8 @@ class InvokerManagementOperations(Resource): apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[ 'data']['certificate'] + apiinvokerenrolmentdetail.supported_features = return_negotiated_supp_feat_dict(apiinvokerenrolmentdetail.supported_features)["Final"] + # Onboarding Date Record invoker_dict = apiinvokerenrolmentdetail.to_dict() invoker_dict["onboarding_date"] = datetime.now() @@ -131,6 +156,60 @@ class InvokerManagementOperations(Resource): self.auth_manager.update_auth_invoker( cert['data']["certificate"], onboard_id) + apiinvokerenrolmentdetail.supported_features = return_negotiated_supp_feat_dict( + apiinvokerenrolmentdetail.supported_features)["Final"] + + apiinvokerenrolmentdetail.api_invoker_id = onboard_id + apiinvokerenrolmentdetail_update = apiinvokerenrolmentdetail.to_dict() + apiinvokerenrolmentdetail_update = clean_empty(apiinvokerenrolmentdetail_update) + + result = mycol.find_one_and_replace(result, + apiinvokerenrolmentdetail_update, + projection={'_id': 0}, + return_document=ReturnDocument.AFTER, + upsert=False) + + + current_app.logger.debug("Invoker Resource inserted in database") + + invoker_updated = APIInvokerEnrolmentDetails().from_dict(dict_to_camel_case(result)) + current_app.logger.debug(f"Invoker Updated: {invoker_updated}") + + res = make_response(object=serialize_clean_camel_case( + invoker_updated), status=200) + if res.status_code == 200: + current_app.logger.info("Invoker Updated") + RedisEvent("API_INVOKER_UPDATED", + api_invoker_ids=[onboard_id]).send_event() + return res + + except Exception as e: + exception = "An exception occurred in update invoker" + current_app.logger.error(exception + "::" + str(e)) + return internal_server_error(detail=exception, cause=str(e)) + + def patch_apiinvokerenrolmentdetail(self, onboard_id, apiinvokerenrolmentdetail): + + mycol = self.db.get_col_by_name(self.db.invoker_enrolment_details) + + try: + current_app.logger.debug("Patching invoker resource") + result = self.__check_api_invoker_id(onboard_id) + + if isinstance(result, Response): + return result + + if apiinvokerenrolmentdetail.onboarding_information: + if apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key != result["onboarding_information"]["api_invoker_public_key"]: + cert = self.__sign_cert( + apiinvokerenrolmentdetail.onboarding_information.api_invoker_public_key, result["api_invoker_id"]) + apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = cert[ + 'data']['certificate'] + self.auth_manager.update_auth_invoker( + cert['data']["certificate"], onboard_id) + else: + apiinvokerenrolmentdetail.onboarding_information.api_invoker_certificate = result["onboarding_information"]["api_invoker_certificate"] + apiinvokerenrolmentdetail_update = apiinvokerenrolmentdetail.to_dict() apiinvokerenrolmentdetail_update = { key: value for key, value in apiinvokerenrolmentdetail_update.items() if value is not None @@ -153,7 +232,7 @@ class InvokerManagementOperations(Resource): res = make_response(object=serialize_clean_camel_case( invoker_updated), status=200) if res.status_code == 200: - current_app.logger.info("Invoker Updated") + current_app.logger.info("Invoker Patched") RedisEvent("API_INVOKER_UPDATED", api_invoker_ids=[onboard_id]).send_event() return res diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py index 34fcdf453873b4b59a894d9f6b96b7ce1a217c2e..8292de4d4330b14c17be74e7448403b56fc5b9e3 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py @@ -1,5 +1,6 @@ import redis + class Publisher(): def __init__(self): diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_event.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_event.py index f80e6b2e666574188740a99a0da0837ea899e01d..3037ae76a7bff9e74674d6e3b686cfbb24cf0f58 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_event.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import JSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_internal_event.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_internal_event.py index 50e343424b8498d32078648978c719c923304353..c1ad0973675b69adf3a81bc9592feac33f0c2064 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_internal_event.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/redis_internal_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import JSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/validate_user.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/validate_user.py index 1b25fd6a4cd6f01a50401fcd62dd42965631d267..917c4ccbb7458c8683f135b4463558037c222f5f 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/validate_user.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/validate_user.py @@ -1,12 +1,12 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error class ControlAccess(Resource): diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_location.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_location.py index c5b5a7d07ea7e2ef876d97837749a627c29d2890..512c9804f4bb480bedbdab8d7c9ac0301cd49e15 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_location.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_profile.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_profile.py index 2556c6ecfde9e6f6f5e45790967acc3541a2abc7..6286622622af842e5b4b9d955c2cdb781d77186d 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_profile.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/aef_profile.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.aef_location import AefLocation # noqa: E501 @@ -7,6 +7,7 @@ from api_invoker_management.models.base_model import Model from api_invoker_management.models.data_format import DataFormat # noqa: E501 from api_invoker_management.models.interface_description import InterfaceDescription # noqa: E501 from api_invoker_management.models.ip_addr_range import IpAddrRange # noqa: E501 +from api_invoker_management.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from api_invoker_management.models.protocol import Protocol # noqa: E501 from api_invoker_management.models.security_method import SecurityMethod # noqa: E501 from api_invoker_management.models.service_kpis import ServiceKpis # noqa: E501 @@ -19,7 +20,7 @@ class AefProfile(Model): Do not edit the class manually. """ - def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 """AefProfile - a model defined in OpenAPI :param aef_id: The aef_id of this AefProfile. # noqa: E501 @@ -32,6 +33,8 @@ class AefProfile(Model): :type data_format: DataFormat :param security_methods: The security_methods of this AefProfile. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] :param domain_name: The domain_name of this AefProfile. # noqa: E501 :type domain_name: str :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 @@ -49,6 +52,7 @@ class AefProfile(Model): 'protocol': Protocol, 'data_format': DataFormat, 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], 'domain_name': str, 'interface_descriptions': List[InterfaceDescription], 'aef_location': AefLocation, @@ -62,6 +66,7 @@ class AefProfile(Model): 'protocol': 'protocol', 'data_format': 'dataFormat', 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', 'domain_name': 'domainName', 'interface_descriptions': 'interfaceDescriptions', 'aef_location': 'aefLocation', @@ -74,6 +79,7 @@ class AefProfile(Model): self._protocol = protocol self._data_format = data_format self._security_methods = security_methods + self._grant_types = grant_types self._domain_name = domain_name self._interface_descriptions = interface_descriptions self._aef_location = aef_location @@ -210,6 +216,29 @@ class AefProfile(Model): self._security_methods = security_methods + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types + @property def domain_name(self) -> str: """Gets the domain_name of this AefProfile. diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details.py index c29d55155cb3360795ac59ca0328b52736856503..bec061ae6b0ca7c7bd0cec0c1d5cc282f288ac27 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.api_list import APIList # noqa: E501 @@ -285,6 +285,6 @@ class APIInvokerEnrolmentDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details_patch.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details_patch.py index 55e0255e489a7abe38c0392741b756539bff2a22..c827f22bdf4440dce000cc719f1c7c55c076ccbf 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details_patch.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_invoker_enrolment_details_patch.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.api_list import APIList # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_list.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_list.py index 43fccbbe4abaf6c3b009c8fe7e77210cc2311728..25ddd0033bb259c8360700b463c9041f8d1cc929 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_list.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_list.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_status.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_status.py index 6d199deae834f32dfd79f3c2d583e4c5bef2894f..7bf0540b228019b16750a4d073aac24364f9c21b 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_status.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/api_status.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/civic_address.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/civic_address.py index 5c09caf97608cb4883172629219f13b733ddeab4..640aff79326cd2ef7d3183ca00bb689c31c05859 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/civic_address.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/civic_address.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/communication_type.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/communication_type.py index 84d3489a5d98d34496e85ceab5cf74a60171d9df..0f1993616b375171d286999895e9e2141e4d4f52 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/communication_type.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/communication_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/custom_operation.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/custom_operation.py index f9e7771f93c563889462c31fc20a6bb4f504c8e0..0fc567820dda825bea7921332167367750f3c030 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/custom_operation.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/custom_operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/data_format.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/data_format.py index ecd02ac5a2ad3dc2fe15cc2059a1c81c22096341..f6ba60af2a3c1240ae35b335f005491e3b57df48 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/data_format.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/data_format.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ellipsoid_arc.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ellipsoid_arc.py index 7be7c612bec90fae64c9a6a97246c9ce193a8d1c..de005059d93e860ad99b7fe9f81ee5abadbc63d0 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ellipsoid_arc.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ellipsoid_arc.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/gad_shape.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/gad_shape.py index 74c27870f702fb1a0e51b2a9b3d0fe3655d22268..496c79b9a1ddf99091928870ecb8a51866679ccb 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/gad_shape.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/gad_shape.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographic_area.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographic_area.py index 02477e5db52c7a12d1c13d9701935a091b498028..2ec1f5538d915fc30c7245261e118c618f833031 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographic_area.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographic_area.py @@ -1,9 +1,16 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.ellipsoid_arc import EllipsoidArc # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 +from api_invoker_management.models.point import Point # noqa: E501 +from api_invoker_management.models.point_altitude import PointAltitude # noqa: E501 +from api_invoker_management.models.point_altitude_uncertainty import PointAltitudeUncertainty # noqa: E501 +from api_invoker_management.models.point_uncertainty_circle import PointUncertaintyCircle # noqa: E501 +from api_invoker_management.models.point_uncertainty_ellipse import PointUncertaintyEllipse # noqa: E501 +from api_invoker_management.models.polygon import Polygon # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from api_invoker_management.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographical_coordinates.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographical_coordinates.py index c10a7c6441b338ceabb4e7bbae541a38bf4fd587..8c6609358611bf760771ac9b4cff772c0e8eaed5 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographical_coordinates.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/geographical_coordinates.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/interface_description.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/interface_description.py index 1c4e7192e23728ce86aef94b5fbfcf89c88505e6..3a9d6f55387eedef0650f1531b8dc960cb5a1909 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/interface_description.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from api_invoker_management.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/invalid_param.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/invalid_param.py index 60f94e86af1594b63381e3205a1b8623dc449b85..202708425223bd9b5d9ad5a339824268b0dadcff 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/invalid_param.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ip_addr_range.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ip_addr_range.py index 7a8a4bf50b91905f24e04aad2b8d46fa50ce269d..70ad8a6fcd67532ccc77e3addf5804915411eb32 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ip_addr_range.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ip_addr_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv4_address_range.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv4_address_range.py index eb6090840f480f531cb97542dad92fcca15f3488..822aaa85edbed60174254a7c438a1014e00b392c 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv4_address_range.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv4_address_range.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model @@ -67,7 +67,7 @@ class Ipv4AddressRange(Model): if start is None: raise ValueError("Invalid value for `start`, must not be `None`") # noqa: E501 if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -94,6 +94,6 @@ class Ipv4AddressRange(Model): if end is None: raise ValueError("Invalid value for `end`, must not be `None`") # noqa: E501 if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_addr1.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_addr1.py index d12cb20c0c5844fd54b9f0e1df3fd51c57ec149f..0d7d43f4834b4b7fa0f48677e87564739f895e8e 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_addr1.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_addr1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_address_range.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_address_range.py index 46203297e05f67419e259db76f29019c780fbe04..9dc04924d566bb6a2e6e6afe98adee7d378c4de2 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_address_range.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/ipv6_address_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local2d_point_uncertainty_ellipse.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local2d_point_uncertainty_ellipse.py index 50a6d460c250ad266981299f5cbccff14319f8ba..5e05b82071b2293309be5dc06d7989653cb54c98 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local2d_point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local2d_point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.local_origin import LocalOrigin # noqa: E501 from api_invoker_management.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local3d_point_uncertainty_ellipsoid.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local3d_point_uncertainty_ellipsoid.py index 7c8633fc79e91caa77d5a221362461c6e9ad8b5a..22c894f2bd1bc1e5f95487ca234737fb1fff8822 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local3d_point_uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local3d_point_uncertainty_ellipsoid.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.local_origin import LocalOrigin # noqa: E501 from api_invoker_management.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 @@ -15,7 +16,7 @@ class Local3dPointUncertaintyEllipsoid(Model): Do not edit the class manually. """ - def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None): # noqa: E501 + def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None, v_confidence=None): # noqa: E501 """Local3dPointUncertaintyEllipsoid - a model defined in OpenAPI :param shape: The shape of this Local3dPointUncertaintyEllipsoid. # noqa: E501 @@ -28,13 +29,16 @@ class Local3dPointUncertaintyEllipsoid(Model): :type uncertainty_ellipsoid: UncertaintyEllipsoid :param confidence: The confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 :type confidence: int + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 + :type v_confidence: int """ self.openapi_types = { 'shape': SupportedGADShapes, 'local_origin': LocalOrigin, 'point': RelativeCartesianLocation, 'uncertainty_ellipsoid': UncertaintyEllipsoid, - 'confidence': int + 'confidence': int, + 'v_confidence': int } self.attribute_map = { @@ -42,7 +46,8 @@ class Local3dPointUncertaintyEllipsoid(Model): 'local_origin': 'localOrigin', 'point': 'point', 'uncertainty_ellipsoid': 'uncertaintyEllipsoid', - 'confidence': 'confidence' + 'confidence': 'confidence', + 'v_confidence': 'vConfidence' } self._shape = shape @@ -50,6 +55,7 @@ class Local3dPointUncertaintyEllipsoid(Model): self._point = point self._uncertainty_ellipsoid = uncertainty_ellipsoid self._confidence = confidence + self._v_confidence = v_confidence @classmethod def from_dict(cls, dikt) -> 'Local3dPointUncertaintyEllipsoid': @@ -182,3 +188,30 @@ class Local3dPointUncertaintyEllipsoid(Model): raise ValueError("Invalid value for `confidence`, must be a value greater than or equal to `0`") # noqa: E501 self._confidence = confidence + + @property + def v_confidence(self) -> int: + """Gets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :return: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :rtype: int + """ + return self._v_confidence + + @v_confidence.setter + def v_confidence(self, v_confidence: int): + """Sets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :type v_confidence: int + """ + if v_confidence is not None and v_confidence > 100: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value less than or equal to `100`") # noqa: E501 + if v_confidence is not None and v_confidence < 0: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value greater than or equal to `0`") # noqa: E501 + + self._v_confidence = v_confidence diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local_origin.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local_origin.py index 1313b6837d54bed61f5bc9f81d45277c514b1ad8..489ceef80012f12b98a12ee57aa21ccffa0d4fdd 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local_origin.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/local_origin.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.geographic_area import GeographicArea # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 @@ -12,26 +13,36 @@ class LocalOrigin(Model): Do not edit the class manually. """ - def __init__(self, coordinate_id=None, point=None): # noqa: E501 + def __init__(self, coordinate_id=None, point=None, area=None, horiz_axes_orientation=None): # noqa: E501 """LocalOrigin - a model defined in OpenAPI :param coordinate_id: The coordinate_id of this LocalOrigin. # noqa: E501 :type coordinate_id: str :param point: The point of this LocalOrigin. # noqa: E501 :type point: GeographicalCoordinates + :param area: The area of this LocalOrigin. # noqa: E501 + :type area: GeographicArea + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. # noqa: E501 + :type horiz_axes_orientation: int """ self.openapi_types = { 'coordinate_id': str, - 'point': GeographicalCoordinates + 'point': GeographicalCoordinates, + 'area': GeographicArea, + 'horiz_axes_orientation': int } self.attribute_map = { 'coordinate_id': 'coordinateId', - 'point': 'point' + 'point': 'point', + 'area': 'area', + 'horiz_axes_orientation': 'horizAxesOrientation' } self._coordinate_id = coordinate_id self._point = point + self._area = area + self._horiz_axes_orientation = horiz_axes_orientation @classmethod def from_dict(cls, dikt) -> 'LocalOrigin': @@ -62,6 +73,8 @@ class LocalOrigin(Model): :param coordinate_id: The coordinate_id of this LocalOrigin. :type coordinate_id: str """ + if coordinate_id is None: + raise ValueError("Invalid value for `coordinate_id`, must not be `None`") # noqa: E501 self._coordinate_id = coordinate_id @@ -85,3 +98,51 @@ class LocalOrigin(Model): """ self._point = point + + @property + def area(self) -> GeographicArea: + """Gets the area of this LocalOrigin. + + + :return: The area of this LocalOrigin. + :rtype: GeographicArea + """ + return self._area + + @area.setter + def area(self, area: GeographicArea): + """Sets the area of this LocalOrigin. + + + :param area: The area of this LocalOrigin. + :type area: GeographicArea + """ + + self._area = area + + @property + def horiz_axes_orientation(self) -> int: + """Gets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :return: The horiz_axes_orientation of this LocalOrigin. + :rtype: int + """ + return self._horiz_axes_orientation + + @horiz_axes_orientation.setter + def horiz_axes_orientation(self, horiz_axes_orientation: int): + """Sets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. + :type horiz_axes_orientation: int + """ + if horiz_axes_orientation is not None and horiz_axes_orientation > 3600: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value less than or equal to `3600`") # noqa: E501 + if horiz_axes_orientation is not None and horiz_axes_orientation < 0: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value greater than or equal to `0`") # noqa: E501 + + self._horiz_axes_orientation = horiz_axes_orientation diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/o_auth_grant_type.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..a688eb0c7ca1e39b8c5cb022a5e7f3b5f5588d8d --- /dev/null +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from api_invoker_management import util +from api_invoker_management.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_information.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_information.py index b4a93bb7028e29bb66594925316ae1418f67d4c0..2ab7410e2e8d925876b3ff11572f5c263d5ec77d 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_information.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_notification.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_notification.py index d7ec7e249a53432034ec4f59ec35cafd40087179..c60d37ee81c37e3ee3946bd84b558c00f4a6faba 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_notification.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/onboarding_notification.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/operation.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/operation.py index 8ebd5c61f54d93fa13688eb5aa2c4d4f5410495b..330be5f04720821969ea48b731b0b159780475ae 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/operation.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point.py index 95ce36c24705d0f956290227e95082da28627c63..b9f091aee8af49583cf4837a19441ba804e64afc 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude.py index 4533b0cc7ad9d90f7d184f68017ad50f87064449..f4e1481d77c15cdaf052bef8e1f4d7fa6a94de6f 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude_uncertainty.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude_uncertainty.py index 4708b9b0e5dbed7f2245cdb14f8c970a698e6c31..5f5449dd19fbae8ed34f0520f49f3cae6db0f24e 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude_uncertainty.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_altitude_uncertainty.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from api_invoker_management.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_circle.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_circle.py index 89dd1c6808325060442d7c4bc8d8fa386f86e646..deb1f0a0e0907b426382f3be5e6f896c24f8ffab 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_circle.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_circle.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_ellipse.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_ellipse.py index 252f7be1d76468c57169bedcd823d96c1d450e98..ad7cc40dcab7914541b66ed460595c44223c784f 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from api_invoker_management.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/polygon.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/polygon.py index 9b1ea42a2389495bfd5ba441604f4d80fda77626..0999dd1bffe06365cdf45e64ef6ab6e161796f5f 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/polygon.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/polygon.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model +from api_invoker_management.models.gad_shape import GADShape # noqa: E501 from api_invoker_management.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from api_invoker_management.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/problem_details.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/problem_details.py index bf1b667727aaf047c00eecea1e76cdb5f1c5bbe5..f4405ce28408a513a5fd3922e27c0c054f0ab14b 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/problem_details.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/protocol.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/protocol.py index 8322eb2c2cfdaa5149fe4119d3b021ea955585a5..9fefc9c77d4092d7b0641ab6eac74ada4ca102a4 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/protocol.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/published_api_path.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/published_api_path.py index 76b6b93fdff8a9a5f079d864eb83baa4fc8b5eda..158dca12ad943685e448005c3dda529b6416e269 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/published_api_path.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/published_api_path.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/relative_cartesian_location.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/relative_cartesian_location.py index e5092005c9e00a51a4e25baf2b3339209213bd5a..82963b5f872c87c395a9140bc9adc1a9533194ff 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/relative_cartesian_location.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/relative_cartesian_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/resource.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/resource.py index 1fd97b395a38214ce47893267c9d95f7d63a2b85..e30732ae3f2a840bf11c090562b0eba5604828b9 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/resource.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/resource.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/security_method.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/security_method.py index 99a51a851b3c81c6878255555884d5558c10ae83..a5937300e078e41ed82f22632bae49eb764f297a 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/security_method.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_api_description.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_api_description.py index 29659b82fd7295af4d10907eb815ab4e8756ff01..1b38bd50460880ac4ce1372ab8de2448e706ee5a 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_api_description.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_api_description.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.aef_profile import AefProfile # noqa: E501 @@ -236,7 +236,7 @@ class ServiceAPIDescription(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features @@ -305,7 +305,7 @@ class ServiceAPIDescription(Model): :type api_supp_feats: str """ if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 - raise ValueError("Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._api_supp_feats = api_supp_feats diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_kpis.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_kpis.py index 9131233e2cbf9f32555cae6181c89b296c930648..9314fcd6f517de2cef5c7dd8501c775ec0062065 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_kpis.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/service_kpis.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model @@ -170,7 +170,7 @@ class ServiceKpis(Model): :type aval_comp: str """ if aval_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_comp = aval_comp @@ -195,7 +195,7 @@ class ServiceKpis(Model): :type aval_gra_comp: str """ if aval_gra_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_gra_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_gra_comp = aval_gra_comp @@ -220,7 +220,7 @@ class ServiceKpis(Model): :type aval_mem: str """ if aval_mem is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_mem): # noqa: E501 - raise ValueError("Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_mem = aval_mem @@ -245,7 +245,7 @@ class ServiceKpis(Model): :type aval_stor: str """ if aval_stor is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_stor): # noqa: E501 - raise ValueError("Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_stor = aval_stor diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/shareable_information.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/shareable_information.py index a6f198078eae31233b76dd7483be5d02c5ed1eb3..7e73226d4fdbdacdf47fb3747013640bb8c0f136 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/shareable_information.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/shareable_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/supported_gad_shapes.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/supported_gad_shapes.py index 4d459b98a55d4ba6e8c44bc5488d5b4fb10caa10..1242387f5a5b473d19ba07ec45a7472a4de6bbcf 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/supported_gad_shapes.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/supported_gad_shapes.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipse.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipse.py index b7e749492efb22ad5bfa7adb5b2ac8a6abf8274e..b5a594ebfe94924aac159ee18a51ec86efd1b3f9 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipse.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipsoid.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipsoid.py index 5d41877bf77a33bf223e5f4fdc62f86df2ae1162..496846f8d397c0a4409453c22be3d4bad404ded9 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/uncertainty_ellipsoid.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/version.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/version.py index dfdc783c1a3c166608ae7d9c897ab5f7241fbed7..9570e89f6676d5dcf3e68bd5f51bf1b7883b11fb 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/version.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/version.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/websock_notif_config.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/websock_notif_config.py index 2c38535d62622fc1444efbe602c7b97be0264f73..1a300a31b23c8bb3cbc8d098f9dffe8dc249e78e 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/websock_notif_config.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/models/websock_notif_config.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invoker_management import util from api_invoker_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/openapi/openapi.yaml b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/openapi/openapi.yaml index 12715c6e2c68e290d5182c0d8a2e3123ef40013c..799074641c3dc13e81c534dbf1d30b604ac119fa 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/openapi/openapi.yaml @@ -3,9 +3,9 @@ info: description: "API for API invoker management. \n© 2024, 3GPP Organizational Partners\ \ (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_API_Invoker_Management_API - version: 1.3.0-alpha.2 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.5.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/api-invoker-management/v1" @@ -18,10 +18,10 @@ paths: post: callbacks: notificationDestination: - '{request.body#/notificationDestination}': + '{$request.body#/notificationDestination}': post: description: Notify the API Invoker about the onboarding completion - operationId: notificationDestination_request_bodyNotificationDestinationPost + operationId: notification_destination_post requestBody: content: application/json: @@ -390,10 +390,10 @@ paths: put: callbacks: notificationDestination: - '{request.body#/notificationDestination}': + '{$request.body#/notificationDestination}': post: description: Notify the API Invoker about the API invoker update completion - operationId: notificationDestination_request_bodyNotificationDestinationPost + operationId: notification_destination_post requestBody: content: application/json: @@ -722,6 +722,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -900,6 +903,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -908,6 +914,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -925,6 +934,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1103,6 +1115,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1111,6 +1126,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1150,6 +1168,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1328,6 +1349,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1336,6 +1360,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1353,6 +1380,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1531,6 +1561,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1539,6 +1572,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1608,6 +1644,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1786,6 +1825,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1794,6 +1836,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1811,6 +1856,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1989,6 +2037,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1997,6 +2048,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2036,6 +2090,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2214,6 +2271,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2222,6 +2282,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2239,6 +2302,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2417,6 +2483,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2425,6 +2494,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2527,6 +2599,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2705,6 +2780,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2713,6 +2791,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2730,6 +2811,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2908,6 +2992,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2916,6 +3003,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2955,6 +3045,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3133,6 +3226,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3141,6 +3237,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3158,6 +3257,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3336,6 +3438,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3344,6 +3449,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3386,6 +3494,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3564,6 +3675,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3572,6 +3686,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3589,6 +3706,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3767,6 +3887,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3775,6 +3898,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3814,6 +3940,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3992,6 +4121,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4000,6 +4132,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4017,6 +4152,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4195,6 +4333,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4203,6 +4344,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4356,6 +4500,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4534,6 +4681,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4542,6 +4692,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4559,6 +4712,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4737,6 +4893,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4745,6 +4904,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4845,6 +5007,9 @@ components: description: Represents the AEF profile data. example: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -5023,6 +5188,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5031,6 +5199,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5048,7 +5219,10 @@ components: maxReqRate: 0 avalGraComp: avalGraComp nullable: true - oneOf: [] + oneOf: + - required: ["domainName"] + - required: ["interfaceDescriptions"] + - {} properties: aefId: description: Identifier of the API exposing function @@ -5072,6 +5246,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array domainName: description: Domain to which API belongs to title: domainName @@ -5251,14 +5431,10 @@ components: title: Resource type: object CommunicationType: - anyOf: - - enum: + enum: - REQUEST_RESPONSE - SUBSCRIBE_NOTIFY - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a communication type of the resource or the custom operation.\ \ \nPossible values are:\n- REQUEST_RESPONSE: The communication is of the\ \ type request-response.\n- SUBSCRIBE_NOTIFY: The communication is of the\ @@ -5299,32 +5475,24 @@ components: title: CustomOperation type: object Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" title: Operation Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -5332,30 +5500,22 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol DataFormat: - anyOf: - - enum: + enum: - JSON - XML - PROTOBUF3 - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a data format. \nPossible values are:\n- JSON: Indicates\ \ that the data format is JSON.\n- XML: Indicates that the data format is\ \ Extensible Markup Language.\n- PROTOBUF3: Indicates that the data format\ \ is Protocol buffers version 3.\n" title: DataFormat SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -5365,6 +5525,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5373,7 +5536,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: [] + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -5412,6 +5578,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object AefLocation: @@ -5534,7 +5706,9 @@ components: title: ServiceKpis type: object IpAddrRange: - anyOf: [] + anyOf: + - required: ["ueIpv4AddrRanges"] + - required: ["ueIpv6AddrRanges"] description: Represents the list of public IP ranges example: ueIpv4AddrRanges: @@ -5651,6 +5825,19 @@ components: nullable: true title: expTime type: string + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType Ipv4Addr: description: | string identifying a Ipv4 address formatted in the "dotted decimal" notation as defined in IETF RFC 1166. @@ -5866,8 +6053,7 @@ components: title: GADShape type: object SupportedGADShapes: - anyOf: - - enum: + enum: - POINT - POINT_UNCERTAINTY_CIRCLE - POINT_UNCERTAINTY_ELLIPSE @@ -5880,8 +6066,7 @@ components: - DISTANCE_DIRECTION - RELATIVE_2D_LOCATION_UNCERTAINTY_ELLIPSE - RELATIVE_3D_LOCATION_UNCERTAINTY_ELLIPSOID - type: string - - type: string + type: string description: Indicates supported GAD shapes. title: SupportedGADShapes PointUncertaintyCircle: @@ -6109,8 +6294,26 @@ components: type: string point: $ref: '#/components/schemas/GeographicalCoordinates' + area: + $ref: '#/components/schemas/GeographicArea' + horizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in + 0.1 degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer + required: + - coordinateId title: LocalOrigin type: object + HorizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in 0.1 + degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer RelativeCartesianLocation: description: Relative Cartesian Location properties: @@ -6146,6 +6349,8 @@ components: $ref: '#/components/schemas/UncertaintyEllipsoid' confidence: $ref: '#/components/schemas/Confidence' + vConfidence: + $ref: '#/components/schemas/Confidence' required: - confidence - localOrigin @@ -6245,9 +6450,6 @@ components: title: Ipv6AddressRange type: object Ipv6Addr_1: - allOf: - - pattern: "^((:|(0?|([1-9a-f][0-9a-f]{0,3}))):)((0?|([1-9a-f][0-9a-f]{0,3})):){0,6}(:|(0?|([1-9a-f][0-9a-f]{0,3})))$" - - pattern: "^((([^:]+:){7}([^:]+))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))$" description: | String identifying an IPv6 address formatted according to clause 4 of RFC5952. The mixed IPv4 IPv6 notation according to clause 5 of RFC5952 shall not be used. example: 2001:db8:85a3::8a2e:370:7334 diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_default_controller.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_default_controller.py index 5724e7dfa47e2fc97c2652b8851236fe0293f5be..0c5bab82ac203067c4f011c9b5d38672ef9d7329 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_default_controller.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_default_controller.py @@ -1,5 +1,7 @@ import unittest +from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails # noqa: E501 +from api_invoker_management.models.problem_details import ProblemDetails # noqa: E501 from api_invoker_management.test import BaseTestCase from flask import json @@ -27,7 +29,7 @@ class TestDefaultController(BaseTestCase): """ - api_invoker_enrolment_details = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","expTime":"2000-01-23T04:56:07.000+00:00","apiInvokerInformation":"apiInvokerInformation","websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"onboardingInformation":{"apiInvokerPublicKey":"apiInvokerPublicKey","onboardingSecret":"onboardingSecret","apiInvokerCertificate":"apiInvokerCertificate"},"requestTestNotification":True,"apiList":{"serviceAPIDescriptions":[{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}},{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}}]}} + api_invoker_enrolment_details = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","expTime":"2000-01-23T04:56:07.000+00:00","apiInvokerInformation":"apiInvokerInformation","websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"onboardingInformation":{"apiInvokerPublicKey":"apiInvokerPublicKey","onboardingSecret":"onboardingSecret","apiInvokerCertificate":"apiInvokerCertificate"},"requestTestNotification":True,"apiList":{"serviceAPIDescriptions":[{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}},{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}}]}} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', @@ -46,7 +48,7 @@ class TestDefaultController(BaseTestCase): """ - api_invoker_enrolment_details = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","expTime":"2000-01-23T04:56:07.000+00:00","apiInvokerInformation":"apiInvokerInformation","websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"onboardingInformation":{"apiInvokerPublicKey":"apiInvokerPublicKey","onboardingSecret":"onboardingSecret","apiInvokerCertificate":"apiInvokerCertificate"},"requestTestNotification":True,"apiList":{"serviceAPIDescriptions":[{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}},{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}}]}} + api_invoker_enrolment_details = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","expTime":"2000-01-23T04:56:07.000+00:00","apiInvokerInformation":"apiInvokerInformation","websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"onboardingInformation":{"apiInvokerPublicKey":"apiInvokerPublicKey","onboardingSecret":"onboardingSecret","apiInvokerCertificate":"apiInvokerCertificate"},"requestTestNotification":True,"apiList":{"serviceAPIDescriptions":[{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}},{"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}}]}} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_individual_api_invoker_enrolment_details_controller.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_individual_api_invoker_enrolment_details_controller.py index d0cece92aa3fc6093c66dcfe0cceb498beb8fb0b..1506dfbb65b41f903bc12b418c5a006d7f9edd0c 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_individual_api_invoker_enrolment_details_controller.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/test/test_individual_api_invoker_enrolment_details_controller.py @@ -1,5 +1,9 @@ import unittest +from api_invoker_management.models.api_invoker_enrolment_details import APIInvokerEnrolmentDetails # noqa: E501 +from api_invoker_management.models.api_invoker_enrolment_details_patch import \ + APIInvokerEnrolmentDetailsPatch # noqa: E501 +from api_invoker_management.models.problem_details import ProblemDetails # noqa: E501 from api_invoker_management.test import BaseTestCase from flask import json diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/typing_utils.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/typing_utils.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/prepare_invoker.sh b/services/TS29222_CAPIF_API_Invoker_Management_API/prepare_invoker.sh index 971ce33796ff7b7ab830118c4e4534a436119a5a..0e2accbb5cae55f617d052f22b0de73a752f66a4 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/prepare_invoker.sh +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/prepare_invoker.sh @@ -1,18 +1,39 @@ #!/bin/bash - VAULT_ADDR="http://$VAULT_HOSTNAME:$VAULT_PORT" VAULT_TOKEN=$VAULT_ACCESS_TOKEN -curl -vv -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/server_cert/pub" 2>/dev/null | jq -r '.data.data.pub_key' -j > /usr/src/app/api_invoker_management/pubkey.pem +# Maximum number of retry attempts +MAX_RETRIES=30 +# Delay between retries (in seconds) +RETRY_DELAY=10 +# Attempt counter +ATTEMPT=0 + +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/server_cert/pub" | jq -r '.data.data.pub_key') -gunicorn -k uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8080 \ + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > /usr/src/app/api_invoker_management/pubkey.pem + echo "Public key successfully saved." + gunicorn -k uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8080 \ --chdir /usr/src/app/api_invoker_management wsgi:app + exit 0 # Exit successfully + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +echo "Error: Failed to retrieve a valid response after $MAX_RETRIES attempts." +exit 1 # Exit with failure diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt index c28e5fb691113e5d9910216f9dd62b0aae387314..9e154c601a02dae73ec9f9b5513bcc83ccdb1e35 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt @@ -21,5 +21,5 @@ opentelemetry-sdk == 1.20.0 flask_executor == 1.0.0 Flask-APScheduler == 1.13.1 werkzeug == 3.0.6 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 \ No newline at end of file diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/setup.py b/services/TS29222_CAPIF_API_Invoker_Management_API/setup.py index 7187d5c15404799138cf880113816241f65be434..c41926d430d403800fb5c805d86533cffd97670a 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/setup.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup, find_packages +from setuptools import find_packages, setup NAME = "api_invoker_management" VERSION = "1.0.0" diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_API_Provider_Management_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_API_Provider_Management_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/README.md b/services/TS29222_CAPIF_API_Provider_Management_API/README.md index 3aa91ec68ea850ad7ece64da4412eb0da0423592..c9acf914cff1769f2c2527ba1c6398f97c607d1c 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/README.md +++ b/services/TS29222_CAPIF_API_Provider_Management_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m api_provider_management ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/app.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/app.py index 0838c6b75281847b0f735c3b40af2928ba19ccd2..c4b33c5713a99390eef66a04c78a42e38adb4b7a 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/app.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/app.py @@ -32,7 +32,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Provider-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py index 6232ea297304762760f2a8b01ed66ab6272b8bcb..0a67ace6383475fee45a17c18c509a2c55f559d4 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/default_controller.py @@ -3,8 +3,8 @@ from functools import wraps from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app -from flask_jwt_extended import jwt_required, get_jwt_identity +from flask import current_app, request +from flask_jwt_extended import get_jwt_identity, jwt_required from ..core.provider_enrolment_details_api import ProviderManagementOperations from ..core.validate_user import ControlAccess diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py index abc759378121d282e40d5bb0bfe2523be5e673e4..cefef1efcb8312e11b0aab822979e7c622c863fe 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/controllers/individual_api_provider_enrolment_details_controller.py @@ -1,4 +1,4 @@ -from flask import request, current_app +from flask import current_app, request from ..core.provider_enrolment_details_api import ProviderManagementOperations from ..models.api_provider_enrolment_details_patch import APIProviderEnrolmentDetailsPatch # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py index 9c96434553e438f1ad04f9044421913d3b5c3c7a..60b89b14c2e8ce2b7270525165916983f6440c1b 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py @@ -4,16 +4,26 @@ import secrets from datetime import datetime from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 -from flask import current_app, Response +from flask import Response, current_app from pymongo import ReturnDocument +from ..core.sign_certificate import sign_certificate +from ..util import clean_empty, dict_to_camel_case, serialize_clean_camel_case from .auth_manager import AuthManager from .redis_internal_event import RedisInternalEvent from .resources import Resource -from .responses import internal_server_error, not_found_error, forbidden_error, make_response, bad_request_error -from ..core.sign_certificate import sign_certificate -from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case +from .responses import bad_request_error, forbidden_error, internal_server_error, make_response, not_found_error + +TOTAL_FEATURES = 2 +SUPPORTED_FEATURES_HEX = "0" +def return_negotiated_supp_feat_dict(supp_feat): + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + return { + "PatchUpdate": True if final_supp_feat[0] == "1" else False, + "RNAA": True if final_supp_feat[1] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } class ProviderManagementOperations(Resource): @@ -49,6 +59,9 @@ class ProviderManagementOperations(Resource): api_provider_enrolment_details.api_prov_dom_id = secrets.token_hex( 15) + + negotiated_supported_features = return_negotiated_supp_feat_dict(api_provider_enrolment_details.supp_feat) + api_provider_enrolment_details.supp_feat = negotiated_supported_features["Final"] current_app.logger.debug("Generating certs to api prov funcs") @@ -135,6 +148,9 @@ class ProviderManagementOperations(Resource): if isinstance(result, Response): return result + + negotiated_supported_features = return_negotiated_supp_feat_dict(api_provider_enrolment_details.supp_feat) + api_provider_enrolment_details.supp_feat = negotiated_supported_features["Final"] for func in api_provider_enrolment_details.api_prov_funcs: if func.api_prov_func_id is None: diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py index acedb7e3e337fda548faf59c1a1b240a4ca6f905..9f50351696660e611ac36ff86527ba7f420b0054 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py @@ -1,5 +1,6 @@ import redis + class Publisher(): def __init__(self): diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/redis_internal_event.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/redis_internal_event.py index 50e343424b8498d32078648978c719c923304353..c1ad0973675b69adf3a81bc9592feac33f0c2064 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/redis_internal_event.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/redis_internal_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import JSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/sign_certificate.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/sign_certificate.py index f535a6c8d57fd234228f28a118ab9e87487c6cf5..f94895b2c009fac510a6b15240180d898e2b5071 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/sign_certificate.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/sign_certificate.py @@ -3,17 +3,23 @@ import json import requests from ..config import Config +from ..db.db import MongoDatabse def sign_certificate(publick_key, provider_id): config = Config().get_config() + + db = MongoDatabse() + capif_config = db.get_col_by_name("capif_configuration").find_one({"config_name": "default"}) + ttl_provider_cert = capif_config.get("settings", {}).get("certificates_expiry", {}).get("ttl_provider_cert", "4300h") + url = f"http://{config['ca_factory']['url']}:{config['ca_factory']['port']}/v1/pki_int/sign/my-ca" headers = {'X-Vault-Token': config['ca_factory']['token']} data = { 'format':'pem_bundle', - 'ttl': '43000h', + 'ttl': ttl_provider_cert, 'csr': publick_key, 'common_name': provider_id } diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/validate_user.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/validate_user.py index 153a90c7128e642b02fdf3ea43c568d59821ce1c..fea52c1186814f7da2de3b2a848f6d311c4eb154 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/validate_user.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/validate_user.py @@ -1,12 +1,12 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error class ControlAccess(Resource): diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details.py index 92a631209a444fdd1ea091f061f14574732719a2..18f2a1e6887504279197ef7936b3b57f76c048a8 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.api_provider_function_details import APIProviderFunctionDetails # noqa: E501 @@ -187,7 +187,7 @@ class APIProviderEnrolmentDetails(Model): :type supp_feat: str """ if supp_feat is not None and not re.search(r'^[A-Fa-f0-9]*$', supp_feat): # noqa: E501 - raise ValueError("Invalid value for `supp_feat`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supp_feat`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supp_feat = supp_feat diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details_patch.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details_patch.py index a9eeeceb6706559457d964725cec2042e32eb3c8..5f4ab09ba995ff1d65da1256ba17f4513894882d 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details_patch.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_enrolment_details_patch.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.api_provider_function_details import APIProviderFunctionDetails # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_func_role.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_func_role.py index 20cc6f7ef2fa0f0731d909c3fdc43124cf40892e..78d9546144b0af8f0157a5487e57a39d7d814256 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_func_role.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_func_role.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_function_details.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_function_details.py index 2646b41854e1b1b47300bf11e1400edf12f22934..1c5655bb2d1e3e93d1ea58832e7a6fa1b7d71b21 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_function_details.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/api_provider_function_details.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.api_provider_func_role import ApiProviderFuncRole # noqa: E501 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/invalid_param.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/invalid_param.py index 6d1bfc1552b2e79905697a70bc0d2cb4da885cc0..cb682f8171588fc54278338dfe4bdd4500792add 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/invalid_param.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/problem_details.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/problem_details.py index 89e0807ffc704af18bef569df3585aa7fc21e36a..9d7f12324fe44c31d9b3215b63ccc806e25accda 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/problem_details.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/registration_information.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/registration_information.py index 5255ef8ca3e8a88be1d60af0b8b3fa4c1fb06e1b..737b09941678c217795f91b430d23f66b8bcb660 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/registration_information.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/models/registration_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_provider_management import util from api_provider_management.models.base_model import Model diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/openapi/openapi.yaml b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/openapi/openapi.yaml index 60fd3db1a7bedc3d233410272113cd3e81095ef3..85be97d06d3e974d46c902c20bb893cee3fe8e2f 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/openapi/openapi.yaml @@ -4,9 +4,9 @@ info: \ Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights\ \ reserved.\n" title: CAPIF_API_Provider_Management_API - version: 1.2.0-alpha.3 + version: 1.2.0 externalDocs: - description: 3GPP TS 29.222 V18.5.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/api-provider-management/v1" @@ -617,15 +617,11 @@ components: title: APIProviderEnrolmentDetailsPatch type: object ApiProviderFuncRole: - anyOf: - - enum: + enum: - AEF - APF - AMF - type: string - - description: | - This string provides forward-compatiblity with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the role (e.g. AEF, APF, etc.) of an API provider domain\ \ function. \nPossible values are:\n- AEF: API provider function is API Exposing\ \ Function.\n- APF: API provider function is API Publishing Function.\n- AMF:\ diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_default_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_default_controller.py index 87052d9518b34b8ef3fd5a947244085382c5c396..120b96f850e45e1c1e516904263881433699ef53 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_default_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_default_controller.py @@ -1,5 +1,7 @@ import unittest +from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 +from api_provider_management.models.problem_details import ProblemDetails # noqa: E501 from api_provider_management.test import BaseTestCase from flask import json diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_individual_api_provider_enrolment_details_controller.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_individual_api_provider_enrolment_details_controller.py index 6d8533afd9dca27b58ee3aeea4b1d21cf2febd71..9c1819ac17460fe2618982f56653808e44e2e998 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_individual_api_provider_enrolment_details_controller.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/test/test_individual_api_provider_enrolment_details_controller.py @@ -1,5 +1,9 @@ import unittest +from api_provider_management.models.api_provider_enrolment_details import APIProviderEnrolmentDetails # noqa: E501 +from api_provider_management.models.api_provider_enrolment_details_patch import \ + APIProviderEnrolmentDetailsPatch # noqa: E501 +from api_provider_management.models.problem_details import ProblemDetails # noqa: E501 from api_provider_management.test import BaseTestCase from flask import json diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/typing_utils.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/typing_utils.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/wsgi copy.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/wsgi copy.py deleted file mode 100644 index 6026b0fa96078634d3455ab93d71dcdc78774276..0000000000000000000000000000000000000000 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/wsgi copy.py +++ /dev/null @@ -1,4 +0,0 @@ -from app import app - -if __name__ == "__main__": - app.run() diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/prepare_provider.sh b/services/TS29222_CAPIF_API_Provider_Management_API/prepare_provider.sh index 27cd6183ab9b3cc7c28f67350c0662a8586971b9..edefb5829ae4eeeea723113ef63f4c49c78c3c20 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/prepare_provider.sh +++ b/services/TS29222_CAPIF_API_Provider_Management_API/prepare_provider.sh @@ -3,15 +3,37 @@ VAULT_ADDR="http://$VAULT_HOSTNAME:$VAULT_PORT" VAULT_TOKEN=$VAULT_ACCESS_TOKEN -curl -vv -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/server_cert/pub" 2>/dev/null | jq -r '.data.data.pub_key' -j > /usr/src/app/api_provider_management/pubkey.pem +# Maximum number of retry attempts +MAX_RETRIES=30 +# Delay between retries (in seconds) +RETRY_DELAY=10 +# Attempt counter +ATTEMPT=0 -gunicorn -k uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8080 \ +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/server_cert/pub" | jq -r '.data.data.pub_key') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > /usr/src/app/api_provider_management/pubkey.pem + echo "Public key successfully saved." + gunicorn -k uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8080 \ --chdir /usr/src/app/api_provider_management wsgi:app + exit 0 # Exit successfully + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done +echo "Error: Failed to retrieve a valid response after $MAX_RETRIES attempts." +exit 1 # Exit with failure diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt index 0b5ec10e2e2b3f5deb197743248e0fbd8d8bd042..9d79f0840b3cc87c0a317f968557882708be9294 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt @@ -19,5 +19,5 @@ opentelemetry-api == 1.19.0 opentelemetry-sdk == 1.19.0 flask_executor == 1.0.0 werkzeug == 3.0.4 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/setup.py b/services/TS29222_CAPIF_API_Provider_Management_API/setup.py index 0f5d4a6207ca5caac051c10b37e4276ac23c1256..406d0daec290b7a293ca899a5ccd1ac23b108e59 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/setup.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup, find_packages +from setuptools import find_packages, setup NAME = "api_provider_management" VERSION = "1.0.0" diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Access_Control_Policy_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/README.md b/services/TS29222_CAPIF_Access_Control_Policy_API/README.md index 1222b0aaa2f6cd49ca656fe3a9c8ba7505ee9ccc..112662bc92618f81095cb09734e126ea2250d002 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/README.md +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m capif_acl ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/app.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/app.py index 0b39d964d744e37f7813f293083ed7a5013f136b..0841c2d21eb13453a6401e5669d55363302473dd 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/app.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/app.py @@ -6,6 +6,9 @@ from datetime import datetime from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config +from core.consumer_messager import Subscriber from flask_apscheduler import APScheduler from flask_executor import Executor from flask_jwt_extended import JWTManager @@ -19,10 +22,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config -from core.consumer_messager import Subscriber - NAME = "Acl-Service" # Setting log level @@ -36,7 +35,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Acl-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/default_controller.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/default_controller.py index bf9857c670738671f33772d16a47a1a3e26152d7..6c201ea4dff83012f9cfd67558f2b11cbab3e510 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/default_controller.py @@ -2,7 +2,7 @@ from functools import wraps from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app +from flask import current_app, request from ..core.accesscontrolpolicyapi import accessControlPolicyApi @@ -12,11 +12,11 @@ def cert_validation(): @wraps(f) def __cert_validation(*args, **kwargs): - args = request.view_args + request.view_args cert_tmp = request.headers['X-Ssl-Client-Cert'] cert_raw = cert_tmp.replace('\t', '') - cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) result = f(**kwargs) diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/security_controller.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/security_controller.py index 139597f9cb07c5d48bed18984ec4747f4b4f3438..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/security_controller.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/controllers/security_controller.py @@ -1,2 +1 @@ - diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/accesscontrolpolicyapi.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/accesscontrolpolicyapi.py index 27e7f248c2c19747c049625de6cd202a2e31da4b..5c00ac43a372d1662a58f2ef246e41ef9b34c69a 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/accesscontrolpolicyapi.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/accesscontrolpolicyapi.py @@ -1,9 +1,9 @@ from flask import current_app -from .responses import make_response, not_found_error, internal_server_error from ..core.resources import Resource from ..models.access_control_policy_list import AccessControlPolicyList from ..util import serialize_clean_camel_case +from .responses import internal_server_error, make_response, not_found_error class accessControlPolicyApi(Resource): diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py index 520f35c1b51515d076805f69ff04be934e7ebb87..700805b09ae2bbcb2d870b0d2d7dc4c026fe4d5c 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/core/internal_service_ops.py @@ -1,4 +1,3 @@ - from datetime import datetime, timedelta from flask import current_app @@ -21,6 +20,21 @@ class InternalServiceOps(Resource): mycol = self.db.get_col_by_name(self.db.acls) + # Retrieve parameters from capif_configuration in MongoDB + config_col = self.db.get_col_by_name("capif_configuration") + capif_config = config_col.find_one({"config_name": "default"}) + + if capif_config: + settings = capif_config.get("settings", {}).get("acl_policy_settings", {}) + allowed_total_invocations = settings.get("allowed_total_invocations", 100) + allowed_invocations_per_second = settings.get("allowed_invocations_per_second", 10) + time_range_days = settings.get("allowed_invocation_time_range_days", 365) + else: + current_app.logger.error("CAPIF Configuration not found, applying all values to 0.") + allowed_total_invocations = 0 + allowed_invocations_per_second = 0 + time_range_days = 0 + res = mycol.find_one( {"service_id": service_id, "aef_id": aef_id}, {"_id": 0}) @@ -28,21 +42,37 @@ class InternalServiceOps(Resource): current_app.logger.info( f"Adding invoker ACL for invoker {invoker_id}") range_list = [TimeRangeList( - datetime.utcnow(), datetime.utcnow()+timedelta(days=365))] + datetime.utcnow(), datetime.utcnow()+timedelta(days=time_range_days))] invoker_acl = ApiInvokerPolicy( - invoker_id, current_app.config["invocations"]["total"], current_app.config["invocations"]["perSecond"], range_list) + invoker_id, allowed_total_invocations, allowed_invocations_per_second, range_list) r = mycol.find_one({"service_id": service_id, "aef_id": aef_id, "api_invoker_policies.api_invoker_id": invoker_id}, {"_id": 0}) if r is None: mycol.update_one({"service_id": service_id, "aef_id": aef_id}, { "$push": {"api_invoker_policies": invoker_acl.to_dict()}}) + + inserted_invoker_acl = mycol.find_one({"service_id": service_id, "aef_id": aef_id, + "api_invoker_policies.api_invoker_id": invoker_id}, {"_id": 0}) + current_app.logger.info(inserted_invoker_acl) + inserted_invoker_acl_camel = dict_to_camel_case(inserted_invoker_acl) + current_app.logger.info(inserted_invoker_acl_camel) + + created_invoker_policy = next((policy for policy in inserted_invoker_acl_camel['apiInvokerPolicies'] if policy['apiInvokerId'] == invoker_id), None) + + accCtrlPolListExt = { + "apiId": service_id, + "apiInvokerPolicies": [created_invoker_policy] + } + RedisEvent("ACCESS_CONTROL_POLICY_UPDATE", + acc_ctrl_pol_list=accCtrlPolListExt).send_event() + else: current_app.logger.info( f"Creating service ACLs for service: {service_id}") range_list = [TimeRangeList( - datetime.utcnow(), datetime.utcnow()+timedelta(days=365))] + datetime.utcnow(), datetime.utcnow()+timedelta(days=time_range_days))] invoker_acl = ApiInvokerPolicy( - invoker_id, current_app.config["invocations"]["total"], current_app.config["invocations"]["perSecond"], range_list) + invoker_id, allowed_total_invocations, allowed_invocations_per_second, range_list) service_acls = { "service_id": service_id, @@ -51,13 +81,16 @@ class InternalServiceOps(Resource): } result = mycol.insert_one(service_acls) - inserted_service_acls=mycol.find_one({"_id": result.inserted_id}, {"_id": 0}) + inserted_service_acls = mycol.find_one({"_id": result.inserted_id}, {"_id": 0}) current_app.logger.info(inserted_service_acls) - inserted_service_acls_camel=dict_to_camel_case(inserted_service_acls) + inserted_service_acls_camel = dict_to_camel_case(inserted_service_acls) current_app.logger.info(inserted_service_acls_camel) + + created_invoker_policy = next((policy for policy in inserted_service_acls_camel['apiInvokerPolicies'] if policy['apiInvokerId'] == invoker_id), None) + accCtrlPolListExt = { "apiId": service_id, - "apiInvokerPolicies": inserted_service_acls_camel['apiInvokerPolicies'] + "apiInvokerPolicies": [created_invoker_policy] } RedisEvent("ACCESS_CONTROL_POLICY_UPDATE", acc_ctrl_pol_list=accCtrlPolListExt).send_event() diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/encoder.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/encoder.py index 9afbbe1de7d3bb358283f2bed1f0ab090aff349b..627a7bd72b3c9c9072df158b7418c530d89b0a3f 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/encoder.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/encoder.py @@ -15,4 +15,4 @@ class CustomJSONEncoder(JSONEncoder): attr = o.attribute_map[attr] dikt[attr] = value return dikt - return JSONEncoder.default(self, o) + return JSONEncoder.default(self, o) \ No newline at end of file diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/access_control_policy_list.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/access_control_policy_list.py index 03850940694ffde9a838d5fda1750ea61fb0cc1f..19dea5dc87cdfd9af4318c1fdc4cd6acc740c71b 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/access_control_policy_list.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/access_control_policy_list.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_acl import util from capif_acl.models.api_invoker_policy import ApiInvokerPolicy # noqa: E501 diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/api_invoker_policy.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/api_invoker_policy.py index 1798a003e165a12a7413a4168f12248dcad006c6..cdd35e29e0f34322e5f46591ae9cf591551d3fcb 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/api_invoker_policy.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/api_invoker_policy.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_acl import util from capif_acl.models.base_model import Model diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/invalid_param.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/invalid_param.py index cd2c0864d02a070050a6dfce39aaa4ed5a01b9ed..b94db8da5cc81fc88362de3106cc4140a9804d7b 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/invalid_param.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_acl import util from capif_acl.models.base_model import Model diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/problem_details.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/problem_details.py index 99610c5a6d01f3dbd4b293f77af99531daf57ff9..bf02e50e41fe23fd657c6c09b58937f20ac99ebf 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/problem_details.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_acl import util from capif_acl.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/time_range_list.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/time_range_list.py index 5585278a806491f8bb017f1b8f5619face836d58..71f38cfcba3f55db756cc3cad8a67bda84f70062 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/time_range_list.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/models/time_range_list.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_acl import util from capif_acl.models.base_model import Model diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/openapi/openapi.yaml b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/openapi/openapi.yaml index 164693101b1be8d3fdaab38d81075cea20decf7c..eebcdfe38e6189bf1be5e764034840e2ec2883cf 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for access control policy. \n© 2022, 3GPP Organizational Partners\ + description: "API for access control policy. \n© 2024, 3GPP Organizational Partners\ \ (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Access_Control_Policy_API - version: 1.3.0-alpha.1 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.0.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/access-control-policy/v1" diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/util.py b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/util.py index 599f221af0ad9351a0f94ef2d20e9dc16aa43a99..9fc4382f721d82b731c0588ad2a30bee4bf55c8f 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/util.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/capif_acl/util.py @@ -51,8 +51,6 @@ def dict_to_camel_case(my_dict): return result - - def _deserialize(data, klass): """Deserializes dict, list, str into an object. diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/requirements.txt b/services/TS29222_CAPIF_Access_Control_Policy_API/requirements.txt index e38f272cebb4b75f3862a7b01ee49d2f3cc3be76..9524b428474a65994a73415e09f64870c3aa64fe 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/requirements.txt +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/requirements.txt @@ -20,5 +20,5 @@ opentelemetry-sdk == 1.19.0 flask_executor == 1.0.0 Flask-APScheduler == 1.13.1 Flask-Script == 2.0.6 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 \ No newline at end of file diff --git a/services/TS29222_CAPIF_Access_Control_Policy_API/setup.py b/services/TS29222_CAPIF_Access_Control_Policy_API/setup.py index d4234b02c1d5a817c691413564f16afebaac9a7a..276b24f96e8f7cf5b0dcb2e2704f438437242702 100644 --- a/services/TS29222_CAPIF_Access_Control_Policy_API/setup.py +++ b/services/TS29222_CAPIF_Access_Control_Policy_API/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup, find_packages +from setuptools import find_packages, setup NAME = "capif_acl" VERSION = "1.0.0" @@ -30,7 +30,7 @@ setup( entry_points={ 'console_scripts': ['capif_acl=capif_acl.__main__:main']}, long_description="""\ - API for access control policy. © 2022, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for access control policy. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Auditing_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Auditing_API/.openapi-generator/FILES index 684a73b60645ff821764ab71687ecab433146cbe..bd1da3346cdaf61b7947732cc2288758d4950728 100644 --- a/services/TS29222_CAPIF_Auditing_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Auditing_API/.openapi-generator/FILES @@ -19,6 +19,7 @@ logs/models/invocation_log.py logs/models/invocation_logs.py logs/models/invocation_logs_retrieve_res.py logs/models/log.py +logs/models/o_auth_grant_type.py logs/models/operation.py logs/models/problem_details.py logs/models/protocol.py diff --git a/services/TS29222_CAPIF_Auditing_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Auditing_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Auditing_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Auditing_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Auditing_API/README.md b/services/TS29222_CAPIF_Auditing_API/README.md index 7f120ad3805905f9098f0244cde751badfa9be84..17eb857e7f965899d1e251d68f3bf66c55d18bcd 100644 --- a/services/TS29222_CAPIF_Auditing_API/README.md +++ b/services/TS29222_CAPIF_Auditing_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m logs ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Auditing_API/config.yaml b/services/TS29222_CAPIF_Auditing_API/config.yaml index 6943b30350583619fc33cb6c7fc4da415d281da0..116076c1c55bf7dc29a7ffd687ff0684ac8a7ae0 100644 --- a/services/TS29222_CAPIF_Auditing_API/config.yaml +++ b/services/TS29222_CAPIF_Auditing_API/config.yaml @@ -4,6 +4,7 @@ mongo: { 'db': 'capif', 'logs_col': 'invocationlogs', 'capif_users_col': "user", + 'certs_col': "certs", 'host': 'mongo', 'port': "27017" } diff --git a/services/TS29222_CAPIF_Auditing_API/logs/app.py b/services/TS29222_CAPIF_Auditing_API/logs/app.py index 4e8068e73885ded3f8eacd3d3707791c8c3b9c97..83fd706eb66ad2736ecd727d06964ae6acd5bc5e 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/app.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/app.py @@ -5,6 +5,8 @@ import os from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config from fluent import sender from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter @@ -14,9 +16,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config - NAME = "Logs-Service" # Setting log level @@ -30,7 +29,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Logs-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Auditing_API/logs/controllers/default_controller.py b/services/TS29222_CAPIF_Auditing_API/logs/controllers/default_controller.py index 87ecabbfc4c4d7d8b20f23d21ce425a0de053849..0f2866e5066a67cf500c31fb5310897acbb5ef73 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/controllers/default_controller.py @@ -1,15 +1,47 @@ -from flask import request, current_app +from flask import current_app, request from logs import util from logs.models.interface_description import InterfaceDescription # noqa: E501 from logs.models.operation import Operation # noqa: E501 from logs.models.protocol import Protocol # noqa: E501 +from functools import wraps +from cryptography import x509 +from cryptography.hazmat.backends import default_backend from ..core.auditoperations import AuditOperations from ..core.responses import bad_request_error +from ..core.validate_user import ControlAccess audit_operations = AuditOperations() +valid_user = ControlAccess() +def cert_validation(): + def _cert_validation(f): + @wraps(f) + def __cert_validation(*args, **kwargs): + + args = request.view_args + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() + + if cn != "superadmin": + cert_signature = cert.signature.hex() + result = valid_user.validate_user_cert(cert_signature) + + if result is not None: + return result + + result = f(**kwargs) + return result + return __cert_validation + return _cert_validation + + +@cert_validation() def api_invocation_logs_get(aef_id=None, api_invoker_id=None, time_range_start=None, time_range_end=None, api_id=None, api_name=None, api_version=None, protocol=None, operation=None, result=None, resource_name=None, src_interface=None, dest_interface=None, supported_features=None): # noqa: E501 """api_invocation_logs_get @@ -46,7 +78,6 @@ def api_invocation_logs_get(aef_id=None, api_invoker_id=None, time_range_start=N :rtype: Union[InvocationLogsRetrieveRes, Tuple[InvocationLogsRetrieveRes, int], Tuple[InvocationLogsRetrieveRes, int, Dict[str, str]] """ - current_app.logger.info("Audit logs") if aef_id is None or api_invoker_id is None: diff --git a/services/TS29222_CAPIF_Auditing_API/logs/core/auditoperations.py b/services/TS29222_CAPIF_Auditing_API/logs/core/auditoperations.py index 86586ed2c16698bde72d647d0d174663e15b079d..6d41cf70cca99b0ff97bebb7b223b1007292dc84 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/core/auditoperations.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/core/auditoperations.py @@ -3,11 +3,22 @@ import json from flask import current_app -from .resources import Resource -from .responses import bad_request_error, not_found_error, internal_server_error, make_response from ..models.invocation_log import InvocationLog from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import bad_request_error, internal_server_error, make_response, not_found_error + +TOTAL_FEATURES = 2 +SUPPORTED_FEATURES_HEX = "1" + +def return_negotiated_supp_feat_dict(supp_feat): + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + return { + "EnQueryInvokeLog": True if final_supp_feat[0] == "1" else False, + "SliceBasedAPIExposure": True if final_supp_feat[1] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } class AuditOperations (Resource): @@ -55,6 +66,13 @@ class AuditOperations (Resource): if not result['logs']: return not_found_error(detail="Parameters do not match any log entry", cause="No logs found") + client_features = query_parameters.get('supported_features') + if client_features: + negotiated = return_negotiated_supp_feat_dict(client_features) + result['supported_features'] = negotiated["Final"] + else: + result['supported_features'] = client_features + invocation_log = InvocationLog(result['aef_id'], result['api_invoker_id'], result['logs'], result['supported_features']) res = make_response(object=serialize_clean_camel_case(invocation_log), status=200) diff --git a/services/TS29222_CAPIF_Auditing_API/logs/core/validate_user.py b/services/TS29222_CAPIF_Auditing_API/logs/core/validate_user.py new file mode 100644 index 0000000000000000000000000000000000000000..545642e15ef13ac9db99679c02e6a2346de65db4 --- /dev/null +++ b/services/TS29222_CAPIF_Auditing_API/logs/core/validate_user.py @@ -0,0 +1,31 @@ +import json + +from flask import Response, current_app + +from ..encoder import CustomJSONEncoder +from ..models.problem_details import ProblemDetails +from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error + + +class ControlAccess(Resource): + + def validate_user_cert(self, cert_signature): + + cert_col = self.db.get_col_by_name(self.db.certs_col) + + try: + my_query = {'cert_signature': cert_signature} + cert_entry = cert_col.find_one(my_query) + + if cert_entry is not None: + if cert_entry["role"] != "AMF": + prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource") + prob = serialize_clean_camel_case(prob) + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json") + + except Exception as e: + exception = "An exception occurred in validate invoker" + current_app.logger.error(exception + "::" + str(e)) + return internal_server_error(detail=exception, cause=str(e)) \ No newline at end of file diff --git a/services/TS29222_CAPIF_Auditing_API/logs/db/db.py b/services/TS29222_CAPIF_Auditing_API/logs/db/db.py index 4520c84691184c8ab699bce82cfc967abb02b948..108793c1ff715d120dd3547ca2bfb46a7aafe0b2 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/db/db.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/db/db.py @@ -19,6 +19,7 @@ class MongoDatabse(): self.db = self.__connect() self.invocation_logs = self.config['mongo']['logs_col'] self.capif_users = self.config['mongo']['capif_users_col'] + self.certs_col = self.config['mongo']['certs_col'] def get_col_by_name(self, name): return self.db[name] diff --git a/services/TS29222_CAPIF_Auditing_API/logs/encoder.py b/services/TS29222_CAPIF_Auditing_API/logs/encoder.py index a6803052e0c0ff15c8bb0ef2e96c97f27d7ca830..f9d89aae1a1b66b91d9a0d0f20a2dc183c6797c4 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/encoder.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/encoder.py @@ -1,5 +1,4 @@ from connexion.jsonifier import JSONEncoder - from logs.models.base_model import Model @@ -16,4 +15,4 @@ class CustomJSONEncoder(JSONEncoder): attr = o.attribute_map[attr] dikt[attr] = value return dikt - return JSONEncoder.default(self, o) + return JSONEncoder.default(self, o) \ No newline at end of file diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/interface_description.py b/services/TS29222_CAPIF_Auditing_API/logs/models/interface_description.py index f470096294458c04b0e448c35d3ba9c313ce41da..2a92e75c44c4f8575aba4556c7873f33eb9f9683 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/interface_description.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model +from logs.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from logs.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/invalid_param.py b/services/TS29222_CAPIF_Auditing_API/logs/models/invalid_param.py index a7c83e71d656489bea9120c06c796f10bccaf7df..bafe0905192f73c8628043daafbbb5ae6f0f8b05 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/invalid_param.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_log.py b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_log.py index f5d5e0ecd4acb9f7380c2a57c58a8124e06afa91..bf5c2ee26e1340d5131d2dae2f345231089ae0ce 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_log.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_log.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model @@ -153,6 +153,6 @@ class InvocationLog(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs.py b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs.py index a4fe7ca4eab585e8fb3fdd59bf1afc65e782308d..55c37648da50eefd894aa1cf47e7fe7b4e78fe39 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model @@ -91,6 +91,6 @@ class InvocationLogs(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs_retrieve_res.py b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs_retrieve_res.py index b26a62f2bb044e9c0aa62ffa909c5e3e57d29f2f..07455f47d395ea827cc86198b971414f3d3a5800 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs_retrieve_res.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/invocation_logs_retrieve_res.py @@ -1,10 +1,11 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model from logs.models.invocation_log import InvocationLog # noqa: E501 +from logs.models.invocation_logs import InvocationLogs # noqa: E501 from logs.models.log import Log # noqa: E501 @@ -159,7 +160,7 @@ class InvocationLogsRetrieveRes(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/log.py b/services/TS29222_CAPIF_Auditing_API/logs/models/log.py index 2fb185c6d2241187865dca49d3019552a3c34b86..a3c965eed702014df5b6331483c309157fa5aa38 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/log.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/log.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Auditing_API/logs/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..57b4bf4ed4b7773036fe6d1421b07c6cd738893a --- /dev/null +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from logs import util +from logs.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/operation.py b/services/TS29222_CAPIF_Auditing_API/logs/models/operation.py index d36a4e88a17c250bc2221f724e225be6ede33053..cf35e30ed8419af92035355e487c81d8f853e7c8 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/operation.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/problem_details.py b/services/TS29222_CAPIF_Auditing_API/logs/models/problem_details.py index beca8ffd297744c5f663e7c1df6e2047142f5148..c074f0e54eca5bf240dc7ad201fd9c4871a08d41 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/problem_details.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/protocol.py b/services/TS29222_CAPIF_Auditing_API/logs/models/protocol.py index db5cdc90d6a0c59d66764f5350228abaa7a9cafa..e2b23e6b432f5fd4605c18dad2f12b3deb5e280a 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/protocol.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Auditing_API/logs/models/security_method.py b/services/TS29222_CAPIF_Auditing_API/logs/models/security_method.py index db5311a176764c80fa793689d6db8576f6c4f3c0..9091c514f5f8e3a58cb55d2af77bbc0016df5b07 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/models/security_method.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from logs import util from logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Auditing_API/logs/openapi/openapi.yaml b/services/TS29222_CAPIF_Auditing_API/logs/openapi/openapi.yaml index 7a2cfcd004c5974c420a600f8427b48468a436c8..8fb314aee31fdc301fd0b1e7e69c094ca78d7196 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Auditing_API/logs/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for auditing. \n© 2023, 3GPP Organizational Partners (ARIB, ATIS,\ + description: "API for auditing. \n© 2024, 3GPP Organizational Partners (ARIB, ATIS,\ \ CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Auditing_API - version: 1.3.0-alpha.2 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.1.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/logs/v1" @@ -323,16 +323,12 @@ components: title: DateTime type: string Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -340,17 +336,13 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" @@ -359,6 +351,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -367,7 +362,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: [] + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -406,18 +404,20 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -508,6 +508,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -525,6 +528,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -539,6 +545,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -556,6 +565,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -602,6 +614,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -619,6 +634,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -724,3 +742,16 @@ components: minimum: 0 title: Port type: integer + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType diff --git a/services/TS29222_CAPIF_Auditing_API/logs/test/test_default_controller.py b/services/TS29222_CAPIF_Auditing_API/logs/test/test_default_controller.py index 3223c999100c4c4bb5f0afb1aa8a3f5c1201e7d3..3e2153c698928b38b480f5515ee684aa2df07279 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/test/test_default_controller.py @@ -1,5 +1,10 @@ import unittest +from logs.models.interface_description import InterfaceDescription # noqa: E501 +from logs.models.invocation_logs_retrieve_res import InvocationLogsRetrieveRes # noqa: E501 +from logs.models.operation import Operation # noqa: E501 +from logs.models.problem_details import ProblemDetails # noqa: E501 +from logs.models.protocol import Protocol # noqa: E501 from logs.test import BaseTestCase diff --git a/services/TS29222_CAPIF_Auditing_API/logs/typing_utils.py b/services/TS29222_CAPIF_Auditing_API/logs/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Auditing_API/logs/typing_utils.py +++ b/services/TS29222_CAPIF_Auditing_API/logs/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Auditing_API/requirements.txt b/services/TS29222_CAPIF_Auditing_API/requirements.txt index da3a4c516c3d71cc4160bc0170a572a7818ef814..40ed48bc91701df99195001fb4fa7b034ce3485b 100644 --- a/services/TS29222_CAPIF_Auditing_API/requirements.txt +++ b/services/TS29222_CAPIF_Auditing_API/requirements.txt @@ -20,5 +20,5 @@ opentelemetry-sdk == 1.19.0 flask_executor == 1.0.0 werkzeug == 3.0.4 pyopenssl == 24.1.0 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_Auditing_API/setup.py b/services/TS29222_CAPIF_Auditing_API/setup.py index c593a4122eaa6a814731cb88a1c09e001e2c802b..cbd1ece814a8385bc3e5a8736a78ef3059004677 100644 --- a/services/TS29222_CAPIF_Auditing_API/setup.py +++ b/services/TS29222_CAPIF_Auditing_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "logs" VERSION = "1.0.0" @@ -30,7 +31,7 @@ setup( entry_points={ 'console_scripts': ['logs=logs.__main__:main']}, long_description="""\ - API for auditing. © 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for auditing. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/FILES index a2f706ddcae717fe58062908b3ab43a83c38e0e1..58bf048706ca533004614150810a464658968860 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/FILES @@ -1,5 +1,6 @@ .dockerignore .gitignore +.openapi-generator-ignore .travis.yml Dockerfile README.md @@ -34,6 +35,7 @@ service_apis/models/ipv6_address_range.py service_apis/models/local2d_point_uncertainty_ellipse.py service_apis/models/local3d_point_uncertainty_ellipsoid.py service_apis/models/local_origin.py +service_apis/models/o_auth_grant_type.py service_apis/models/operation.py service_apis/models/point.py service_apis/models/point_altitude.py @@ -56,6 +58,7 @@ service_apis/models/uncertainty_ellipsoid.py service_apis/models/version.py service_apis/openapi/openapi.yaml service_apis/test/__init__.py +service_apis/test/test_default_controller.py service_apis/typing_utils.py service_apis/util.py requirements.txt diff --git a/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Discover_Service_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Discover_Service_API/README.md b/services/TS29222_CAPIF_Discover_Service_API/README.md index d27fa9b368278b43c5782f7e38988d4c78927499..f522a7de8792c85b4b772ac934da91bc1be45fb1 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/README.md +++ b/services/TS29222_CAPIF_Discover_Service_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m service_apis ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Discover_Service_API/config.yaml b/services/TS29222_CAPIF_Discover_Service_API/config.yaml index 6257115b4f972041d4b01b50419283f8ce1657a3..47851c027ad2a0d7ea39123055e48214b5c172e7 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/config.yaml +++ b/services/TS29222_CAPIF_Discover_Service_API/config.yaml @@ -5,6 +5,7 @@ mongo: { 'col': 'serviceapidescriptions', 'invokers_col': 'invokerdetails', 'capif_users_col': "user", + 'certs_col': "certs", 'host': 'mongo', 'port': "27017" } diff --git a/services/TS29222_CAPIF_Discover_Service_API/requirements.txt b/services/TS29222_CAPIF_Discover_Service_API/requirements.txt index 32a15be25ab0afc062f029940f58f84ccb466548..04ff0c7747c9fdcea4fefc1f2f5d0b37eea3cd9e 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/requirements.txt +++ b/services/TS29222_CAPIF_Discover_Service_API/requirements.txt @@ -20,5 +20,5 @@ opentelemetry-api == 1.19.0 opentelemetry-sdk == 1.19.0 flask_executor == 1.0.0 werkzeug == 3.0.4 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/app.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/app.py index 4084bfdb45306b7bd78a1130930a76d8eaefa7a1..f84d18445767ff17e6407552dc42462383106854 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/app.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/app.py @@ -5,6 +5,8 @@ import os from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config from flask_jwt_extended import JWTManager from fluent import sender from opentelemetry import trace @@ -16,9 +18,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config - NAME = "Discover-Service" # Setting log level @@ -32,7 +31,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Discover-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py index 2ce066eeba789cd59771cdb8c8e9823d151d0bc6..f742f499500f488c5a78f871d9b98eb66e3edc77 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/controllers/default_controller.py @@ -1,16 +1,45 @@ -from service_apis.models.discovered_apis import DiscoveredAPIs # noqa: E501 - import json - -from flask import request, current_app +from functools import wraps +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from flask import current_app, request from service_apis.models.discovered_apis import DiscoveredAPIs # noqa: E501 -from ..core.discoveredapis import DiscoverApisOperations +from ..core.discoveredapis import DiscoverApisOperations, return_negotiated_supp_feat_dict +from ..core.validate_user import ControlAccess discover_apis = DiscoverApisOperations() +valid_user = ControlAccess() + +def cert_validation(): + def _cert_validation(f): + @wraps(f) + def __cert_validation(*args, **kwargs): + + args = request.view_args + cert_tmp = request.headers['X-Ssl-Client-Cert'] + cert_raw = cert_tmp.replace('\t', '') + + cert = x509.load_pem_x509_certificate(str.encode(cert_raw), default_backend()) + cn = cert.subject.get_attributes_for_oid(x509.OID_COMMON_NAME)[0].value.strip() -def all_service_apis_get(api_invoker_id, api_name=None, api_version=None, comm_type=None, protocol=None, aef_id=None, data_format=None, api_cat=None, preferred_aef_loc=None, req_api_prov_name=None, supported_features=None, api_supported_features=None, ue_ip_addr=None, service_kpis=None): # noqa: E501 + if cn != "superadmin": + cert_signature = cert.signature.hex() + current_app.logger.debug(request.args) + result = valid_user.validate_user_cert(request.args["api-invoker-id"], cert_signature) + + if result is not None: + return result + + result = f(**kwargs) + return result + return __cert_validation + return _cert_validation + + +@cert_validation() +def all_service_apis_get(api_invoker_id, api_name=None, api_version=None, comm_type=None, protocol=None, aef_id=None, data_format=None, api_cat=None, preferred_aef_loc=None, req_api_prov_name=None, supported_features=None, api_supported_features=None, ue_ip_addr=None, service_kpis=None, grant_types=None): # noqa: E501 """all_service_apis_get Discover published service APIs and retrieve a collection of APIs according to certain filter criteria. # noqa: E501 @@ -43,10 +72,11 @@ def all_service_apis_get(api_invoker_id, api_name=None, api_version=None, comm_t :type ue_ip_addr: dict | bytes :param service_kpis: Contains iInformation about service characteristics provided by the targeted service API(s). :type service_kpis: dict | bytes + :param grant_types: Contains the OAuth grant types that need to be supported. + :type grant_types: list | bytes :rtype: Union[DiscoveredAPIs, Tuple[DiscoveredAPIs, int], Tuple[DiscoveredAPIs, int, Dict[str, str]] """ - current_app.logger.info("Discovering service apis") query_params = {"api_name": api_name, "api_version": api_version, "comm_type": comm_type, @@ -55,8 +85,7 @@ def all_service_apis_get(api_invoker_id, api_name=None, api_version=None, comm_t "supported_features": supported_features} if supported_features is not None: - supp_feat_dict = DiscoveredAPIs.return_supp_feat_dict(supported_features) - current_app.logger.info(supp_feat_dict) + supp_feat_dict = return_negotiated_supp_feat_dict(supported_features) if supp_feat_dict['VendSpecQueryParams']: for q_params in request.args: if "vend-spec" in q_params: diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/discoveredapis.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/discoveredapis.py index f4b0d8fdf5800ec6c0c995e1432a3f542547fcd0..394bad686021f3d075a36c6ab34fd3ed5baf0b84 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/discoveredapis.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/discoveredapis.py @@ -7,8 +7,14 @@ from ..core.resources import Resource from ..core.responses import internal_server_error, make_response, not_found_error from ..models.discovered_apis import DiscoveredAPIs from ..util import serialize_clean_camel_case -from ..vendor_specific import find_attribute_in_body, filter_apis_with_vendor_specific_params, \ +from ..vendor_specific import ( + filter_apis_with_vendor_specific_params, + find_attribute_in_body, remove_vendor_specific_fields +) + +TOTAL_FEATURES = 4 +SUPPORTED_FEATURES_HEX = "2" def filter_fields(filtered_apis): @@ -24,6 +30,18 @@ def filter_fields(filtered_apis): return field_filtered_api +def return_negotiated_supp_feat_dict(supp_feat): + + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "ApiSupportedFeatureQuery": True if final_supp_feat[0] == "1" else False, + "VendSpecQueryParams": True if final_supp_feat[1] == "1" else False, + "RNAA": True if final_supp_feat[2] == "1" else False, + "SliceBasedAPIExposure": True if final_supp_feat[3] == "1" else False + } + + class DiscoverApisOperations(Resource): def get_discoveredapis(self, api_invoker_id, query_params): @@ -79,7 +97,7 @@ class DiscoverApisOperations(Resource): vendor_specific_fields_path = find_attribute_in_body(discoved_api, '') json_docs.append(filter_fields(remove_vendor_specific_fields(discoved_api, vendor_specific_fields_path))) else: - supported_features = DiscoveredAPIs.return_supp_feat_dict(supp_feat) + supported_features = return_negotiated_supp_feat_dict(supp_feat) if supported_features['VendSpecQueryParams']: for discoved_api in discoved_apis: vendor_specific_fields_path = find_attribute_in_body(discoved_api, '') diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/validate_user.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/validate_user.py new file mode 100644 index 0000000000000000000000000000000000000000..6d2ea40f361cccaf4182100cef3b59f7c5929a1c --- /dev/null +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/core/validate_user.py @@ -0,0 +1,32 @@ +import json + +from flask import Response, current_app + +from ..encoder import CustomJSONEncoder +from ..models.problem_details import ProblemDetails +from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error + + +class ControlAccess(Resource): + + def validate_user_cert(self, api_invoker_id, cert_signature): + + cert_col = self.db.get_col_by_name(self.db.certs_col) + + try: + + my_query = {'id': api_invoker_id} + cert_entry = cert_col.find_one(my_query) + + if cert_entry is not None: + if cert_entry["cert_signature"] != cert_signature: + prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource") + prob = serialize_clean_camel_case(prob) + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json") + + except Exception as e: + exception = "An exception occurred in validate invoker" + current_app.logger.error(exception + "::" + str(e)) + return internal_server_error(detail=exception, cause=str(e)) \ No newline at end of file diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/db/db.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/db/db.py index 39b1889d6b77c982f18986385e4fc04a7178d583..15e7e13816b03e53c5ceee36f67e6ccadc00ba4b 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/db/db.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/db/db.py @@ -20,6 +20,7 @@ class MongoDatabse(): self.invoker_col = self.config['mongo']['invokers_col'] self.service_api_descriptions = self.config['mongo']['col'] self.capif_users = self.config['mongo']['capif_users_col'] + self.certs_col = self.config['mongo']['certs_col'] def get_col_by_name(self, name): diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/encoder.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/encoder.py index c741e68b91b490a5548c213daf3bd032c74831d0..26d334081b611666b8942e4c9068c34db8870a0b 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/encoder.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/encoder.py @@ -1,5 +1,4 @@ from connexion.jsonifier import JSONEncoder - from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_location.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_location.py index 1174800e0fe1f17bfa0276948c4d9890a3c88084..bbceaa45cd9a719def2eb43f34b93e2a5bd434de 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_location.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_profile.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_profile.py index 4c1ce31df166ccdf798ad532997afa0400ce00fd..1196944181c6d50d1435945100f2f01bb369090f 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_profile.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/aef_profile.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.aef_location import AefLocation # noqa: E501 @@ -7,6 +7,7 @@ from service_apis.models.base_model import Model from service_apis.models.data_format import DataFormat # noqa: E501 from service_apis.models.interface_description import InterfaceDescription # noqa: E501 from service_apis.models.ip_addr_range import IpAddrRange # noqa: E501 +from service_apis.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from service_apis.models.protocol import Protocol # noqa: E501 from service_apis.models.security_method import SecurityMethod # noqa: E501 from service_apis.models.service_kpis import ServiceKpis # noqa: E501 @@ -19,7 +20,7 @@ class AefProfile(Model): Do not edit the class manually. """ - def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 """AefProfile - a model defined in OpenAPI :param aef_id: The aef_id of this AefProfile. # noqa: E501 @@ -32,6 +33,8 @@ class AefProfile(Model): :type data_format: DataFormat :param security_methods: The security_methods of this AefProfile. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] :param domain_name: The domain_name of this AefProfile. # noqa: E501 :type domain_name: str :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 @@ -49,6 +52,7 @@ class AefProfile(Model): 'protocol': Protocol, 'data_format': DataFormat, 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], 'domain_name': str, 'interface_descriptions': List[InterfaceDescription], 'aef_location': AefLocation, @@ -62,6 +66,7 @@ class AefProfile(Model): 'protocol': 'protocol', 'data_format': 'dataFormat', 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', 'domain_name': 'domainName', 'interface_descriptions': 'interfaceDescriptions', 'aef_location': 'aefLocation', @@ -74,6 +79,7 @@ class AefProfile(Model): self._protocol = protocol self._data_format = data_format self._security_methods = security_methods + self._grant_types = grant_types self._domain_name = domain_name self._interface_descriptions = interface_descriptions self._aef_location = aef_location @@ -210,6 +216,29 @@ class AefProfile(Model): self._security_methods = security_methods + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types + @property def domain_name(self) -> str: """Gets the domain_name of this AefProfile. diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/api_status.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/api_status.py index 2cb1a216ee786c7f0eaa6a45f042337cb357f963..eef94f955d0404ee74a77a80bc3539a975c8446d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/api_status.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/api_status.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/civic_address.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/civic_address.py index 5e8fb961815bd0a4250a42f78d5514f17caef189..7314bca7ebf31b3c1da912dde25e3135b5567f57 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/civic_address.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/civic_address.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/communication_type.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/communication_type.py index e6b697a16299e357bfd4f9796fc95c392dfa855d..ea17cb872c46f179939bf8d9ca792ab75072f046 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/communication_type.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/communication_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/custom_operation.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/custom_operation.py index 7c93f551fd7dc53cd6eaf4c077a27504ec3feea9..fed2a347858ea46bd47e385379120e8f60e8e0fa 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/custom_operation.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/custom_operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/data_format.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/data_format.py index 9cbf6ff5b314fd81f7ffb6670eebaf043d0f867d..7575f306cc771b2167585db5a8ac4a9f3d270a76 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/data_format.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/data_format.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/discovered_apis.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/discovered_apis.py index cce42aefced990612b5ad36cafb7408099880942..a237756324106618552ca47476c59739c89626df 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/discovered_apis.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/discovered_apis.py @@ -1,5 +1,6 @@ +import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model @@ -12,33 +13,26 @@ class DiscoveredAPIs(Model): Do not edit the class manually. """ - def __init__(self, service_api_descriptions=None): # noqa: E501 + def __init__(self, service_api_descriptions=None, supp_feat=None): # noqa: E501 """DiscoveredAPIs - a model defined in OpenAPI :param service_api_descriptions: The service_api_descriptions of this DiscoveredAPIs. # noqa: E501 :type service_api_descriptions: List[ServiceAPIDescription] + :param supp_feat: The supp_feat of this DiscoveredAPIs. # noqa: E501 + :type supp_feat: str """ self.openapi_types = { - 'service_api_descriptions': List[ServiceAPIDescription] + 'service_api_descriptions': List[ServiceAPIDescription], + 'supp_feat': str } self.attribute_map = { - 'service_api_descriptions': 'serviceAPIDescriptions' + 'service_api_descriptions': 'serviceAPIDescriptions', + 'supp_feat': 'suppFeat' } self._service_api_descriptions = service_api_descriptions - - @classmethod - def return_supp_feat_dict(cls, supp_feat): - TOTAL_FEATURES = 3 - supp_feat_in_hex = int(supp_feat, 16) - supp_feat_in_bin = bin(supp_feat_in_hex)[2:].zfill(TOTAL_FEATURES)[::-1] - - return { - "ApiSupportedFeatureQuery": True if supp_feat_in_bin[0] == "1" else False, - "VendSpecQueryParams": True if supp_feat_in_bin[1] == "1" else False, - "RNAA": True if supp_feat_in_bin[2] == "1" else False - } + self._supp_feat = supp_feat @classmethod def from_dict(cls, dikt) -> 'DiscoveredAPIs': @@ -55,7 +49,7 @@ class DiscoveredAPIs(Model): def service_api_descriptions(self) -> List[ServiceAPIDescription]: """Gets the service_api_descriptions of this DiscoveredAPIs. - Description of the service API as published by the service. Each service API description shall include AEF profiles matching the filter criteria. # noqa: E501 + Description of the service API as published by the service. Each service API information shall include AEF profiles matching the filter criteria. # noqa: E501 :return: The service_api_descriptions of this DiscoveredAPIs. :rtype: List[ServiceAPIDescription] @@ -66,7 +60,7 @@ class DiscoveredAPIs(Model): def service_api_descriptions(self, service_api_descriptions: List[ServiceAPIDescription]): """Sets the service_api_descriptions of this DiscoveredAPIs. - Description of the service API as published by the service. Each service API description shall include AEF profiles matching the filter criteria. # noqa: E501 + Description of the service API as published by the service. Each service API information shall include AEF profiles matching the filter criteria. # noqa: E501 :param service_api_descriptions: The service_api_descriptions of this DiscoveredAPIs. :type service_api_descriptions: List[ServiceAPIDescription] @@ -75,3 +69,28 @@ class DiscoveredAPIs(Model): raise ValueError("Invalid value for `service_api_descriptions`, number of items must be greater than or equal to `1`") # noqa: E501 self._service_api_descriptions = service_api_descriptions + + @property + def supp_feat(self) -> str: + """Gets the supp_feat of this DiscoveredAPIs. + + A string used to indicate the features supported by an API that is used as defined in clause 6.6 in 3GPP TS 29.500. 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\" and shall represent the support of 4 features as described in table 5.2.2-3. The most significant character representing the highest-numbered features shall appear first in the string, and the character representing features 1 to 4 shall appear last in the string. The list of features and their numbering (starting with 1) are defined separately for each API. If the string contains a lower number of characters than there are defined features for an API, all features that would be represented by characters that are not present in the string are not supported. # noqa: E501 + + :return: The supp_feat of this DiscoveredAPIs. + :rtype: str + """ + return self._supp_feat + + @supp_feat.setter + def supp_feat(self, supp_feat: str): + """Sets the supp_feat of this DiscoveredAPIs. + + A string used to indicate the features supported by an API that is used as defined in clause 6.6 in 3GPP TS 29.500. 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\" and shall represent the support of 4 features as described in table 5.2.2-3. The most significant character representing the highest-numbered features shall appear first in the string, and the character representing features 1 to 4 shall appear last in the string. The list of features and their numbering (starting with 1) are defined separately for each API. If the string contains a lower number of characters than there are defined features for an API, all features that would be represented by characters that are not present in the string are not supported. # noqa: E501 + + :param supp_feat: The supp_feat of this DiscoveredAPIs. + :type supp_feat: str + """ + if supp_feat is not None and not re.search(r'^[A-Fa-f0-9]*$', supp_feat): # noqa: E501 + raise ValueError(r"Invalid value for `supp_feat`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + + self._supp_feat = supp_feat diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ellipsoid_arc.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ellipsoid_arc.py index 98745d95e1024eebc8021380b4951503333facbf..a5747b5e3fc9ea83ab85ad2b38f510a85eda761e 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ellipsoid_arc.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ellipsoid_arc.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/gad_shape.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/gad_shape.py index 7e4f7c4a4859991c1104d7b7234cd9803c8198f1..dfc5dedb02331b769bb85e5a8a56423640c4bafb 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/gad_shape.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/gad_shape.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographic_area.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographic_area.py index bc7034d3b3334c6c673daf8879e6746e6f8e6f1c..3c2d44c20cab166dbb1d40d1a999965c82e059bd 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographic_area.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographic_area.py @@ -1,9 +1,16 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.ellipsoid_arc import EllipsoidArc # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 +from service_apis.models.point import Point # noqa: E501 +from service_apis.models.point_altitude import PointAltitude # noqa: E501 +from service_apis.models.point_altitude_uncertainty import PointAltitudeUncertainty # noqa: E501 +from service_apis.models.point_uncertainty_circle import PointUncertaintyCircle # noqa: E501 +from service_apis.models.point_uncertainty_ellipse import PointUncertaintyEllipse # noqa: E501 +from service_apis.models.polygon import Polygon # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from service_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographical_coordinates.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographical_coordinates.py index c07d138fb41e81a3fa7d8040f1d63472877da0c9..755e077a2178dcd94e5820379f92a665fe3f79ed 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographical_coordinates.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/geographical_coordinates.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/interface_description.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/interface_description.py index 74bf6544fd466c37e56e3928a20690fc4a120a16..7c44ba11a876f74aaf847c6d7a8be32e05bce3a3 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/interface_description.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from service_apis.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/invalid_param.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/invalid_param.py index 75965c054a9c0c8d1105ec8b2c4f24bc97171a98..74464bd14869e33bcc3a651edf6907665c314700 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/invalid_param.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_info.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_info.py index 3f40627b5357d5d830be9aba4fe902833b467d47..1791b5a349d12d536d8025b6424fb0c8174b60b6 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_info.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_info.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_range.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_range.py index 7d19e3393ff119578dfabda9e913a8cd631051cb..b95a30bd03a0659993ce303cd1b1e02d7538fd2d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_range.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ip_addr_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv4_address_range.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv4_address_range.py index a7e40ff61897e85c65dc94952d2cc8b102be222f..e2e91ad71ede31f0f471ec5dfa8f2a33bec0f34c 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv4_address_range.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv4_address_range.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model @@ -67,7 +67,7 @@ class Ipv4AddressRange(Model): if start is None: raise ValueError("Invalid value for `start`, must not be `None`") # noqa: E501 if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -94,6 +94,6 @@ class Ipv4AddressRange(Model): if end is None: raise ValueError("Invalid value for `end`, must not be `None`") # noqa: E501 if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_addr1.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_addr1.py index b7af560a0407e1f381e2d515d1fc72db35ac10bc..7c01304e88115615aca7a9f5df55e8409cfc452b 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_addr1.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_addr1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_address_range.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_address_range.py index 841f7dad5d14bbaa2c82e3d8b40b83d396350333..b8e1c5e029a9ea3ee1ae9035bab70f3ac2c010bc 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_address_range.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/ipv6_address_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local2d_point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local2d_point_uncertainty_ellipse.py index 1d99c36b21761bea841c92cd4a3101e281d38758..105c1408d0de95e89d5ff2861659a93ddc7338a4 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local2d_point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local2d_point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.local_origin import LocalOrigin # noqa: E501 from service_apis.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local3d_point_uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local3d_point_uncertainty_ellipsoid.py index 4ab20c6b308caf952b54eda94ef862c141c3288a..68e561097af82903837c90da4a808ace9ec196f2 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local3d_point_uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local3d_point_uncertainty_ellipsoid.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.local_origin import LocalOrigin # noqa: E501 from service_apis.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 @@ -15,7 +16,7 @@ class Local3dPointUncertaintyEllipsoid(Model): Do not edit the class manually. """ - def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None): # noqa: E501 + def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None, v_confidence=None): # noqa: E501 """Local3dPointUncertaintyEllipsoid - a model defined in OpenAPI :param shape: The shape of this Local3dPointUncertaintyEllipsoid. # noqa: E501 @@ -28,13 +29,16 @@ class Local3dPointUncertaintyEllipsoid(Model): :type uncertainty_ellipsoid: UncertaintyEllipsoid :param confidence: The confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 :type confidence: int + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 + :type v_confidence: int """ self.openapi_types = { 'shape': SupportedGADShapes, 'local_origin': LocalOrigin, 'point': RelativeCartesianLocation, 'uncertainty_ellipsoid': UncertaintyEllipsoid, - 'confidence': int + 'confidence': int, + 'v_confidence': int } self.attribute_map = { @@ -42,7 +46,8 @@ class Local3dPointUncertaintyEllipsoid(Model): 'local_origin': 'localOrigin', 'point': 'point', 'uncertainty_ellipsoid': 'uncertaintyEllipsoid', - 'confidence': 'confidence' + 'confidence': 'confidence', + 'v_confidence': 'vConfidence' } self._shape = shape @@ -50,6 +55,7 @@ class Local3dPointUncertaintyEllipsoid(Model): self._point = point self._uncertainty_ellipsoid = uncertainty_ellipsoid self._confidence = confidence + self._v_confidence = v_confidence @classmethod def from_dict(cls, dikt) -> 'Local3dPointUncertaintyEllipsoid': @@ -182,3 +188,30 @@ class Local3dPointUncertaintyEllipsoid(Model): raise ValueError("Invalid value for `confidence`, must be a value greater than or equal to `0`") # noqa: E501 self._confidence = confidence + + @property + def v_confidence(self) -> int: + """Gets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :return: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :rtype: int + """ + return self._v_confidence + + @v_confidence.setter + def v_confidence(self, v_confidence: int): + """Sets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :type v_confidence: int + """ + if v_confidence is not None and v_confidence > 100: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value less than or equal to `100`") # noqa: E501 + if v_confidence is not None and v_confidence < 0: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value greater than or equal to `0`") # noqa: E501 + + self._v_confidence = v_confidence diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local_origin.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local_origin.py index f7e3fc5808ae288022ff8858a834bd7ab6f6637a..880120dceef973d11f0e9dc0643b976f0faa01a4 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local_origin.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/local_origin.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.geographic_area import GeographicArea # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 @@ -12,26 +13,36 @@ class LocalOrigin(Model): Do not edit the class manually. """ - def __init__(self, coordinate_id=None, point=None): # noqa: E501 + def __init__(self, coordinate_id=None, point=None, area=None, horiz_axes_orientation=None): # noqa: E501 """LocalOrigin - a model defined in OpenAPI :param coordinate_id: The coordinate_id of this LocalOrigin. # noqa: E501 :type coordinate_id: str :param point: The point of this LocalOrigin. # noqa: E501 :type point: GeographicalCoordinates + :param area: The area of this LocalOrigin. # noqa: E501 + :type area: GeographicArea + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. # noqa: E501 + :type horiz_axes_orientation: int """ self.openapi_types = { 'coordinate_id': str, - 'point': GeographicalCoordinates + 'point': GeographicalCoordinates, + 'area': GeographicArea, + 'horiz_axes_orientation': int } self.attribute_map = { 'coordinate_id': 'coordinateId', - 'point': 'point' + 'point': 'point', + 'area': 'area', + 'horiz_axes_orientation': 'horizAxesOrientation' } self._coordinate_id = coordinate_id self._point = point + self._area = area + self._horiz_axes_orientation = horiz_axes_orientation @classmethod def from_dict(cls, dikt) -> 'LocalOrigin': @@ -62,6 +73,8 @@ class LocalOrigin(Model): :param coordinate_id: The coordinate_id of this LocalOrigin. :type coordinate_id: str """ + if coordinate_id is None: + raise ValueError("Invalid value for `coordinate_id`, must not be `None`") # noqa: E501 self._coordinate_id = coordinate_id @@ -85,3 +98,51 @@ class LocalOrigin(Model): """ self._point = point + + @property + def area(self) -> GeographicArea: + """Gets the area of this LocalOrigin. + + + :return: The area of this LocalOrigin. + :rtype: GeographicArea + """ + return self._area + + @area.setter + def area(self, area: GeographicArea): + """Sets the area of this LocalOrigin. + + + :param area: The area of this LocalOrigin. + :type area: GeographicArea + """ + + self._area = area + + @property + def horiz_axes_orientation(self) -> int: + """Gets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :return: The horiz_axes_orientation of this LocalOrigin. + :rtype: int + """ + return self._horiz_axes_orientation + + @horiz_axes_orientation.setter + def horiz_axes_orientation(self, horiz_axes_orientation: int): + """Sets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. + :type horiz_axes_orientation: int + """ + if horiz_axes_orientation is not None and horiz_axes_orientation > 3600: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value less than or equal to `3600`") # noqa: E501 + if horiz_axes_orientation is not None and horiz_axes_orientation < 0: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value greater than or equal to `0`") # noqa: E501 + + self._horiz_axes_orientation = horiz_axes_orientation diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..b5020552167238121f791d785d223e69169af5ca --- /dev/null +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from service_apis import util +from service_apis.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/operation.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/operation.py index db7461ed893b86a2de0ce0434f803574605ea7b3..a43fd60d2dc567f5673a3c202a0b5190cfc0b2fa 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/operation.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point.py index 4dd203f43833394159db68ddcafa2de8869f0f27..802b8a3dc245b963ed89c56d928309aa3477e130 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude.py index c692296e84767fff568c5f15b29cb359e9e82301..32b8233fb715db426d96b1b2ebd6c2a5bbfe0adf 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude_uncertainty.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude_uncertainty.py index 8cb287ae555465cc844bb26bd00156ec1007a150..9a70de0b37cb3d01e5eeb779006a0d81d7f7fa3a 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude_uncertainty.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_altitude_uncertainty.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from service_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_circle.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_circle.py index aa0d9101133ac4effd0b3d13ad5a0d1a23917c4a..2870ddf91c0357305b00faeb06b83d62e8284768 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_circle.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_circle.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_ellipse.py index 498296e30cce3b71236705e359aab270cad0f456..32f2ab66d1063741479dcc700504d132fd798e2d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from service_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/polygon.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/polygon.py index e8c152b2e9f89117b1479b8159075e50e520ba7e..b3374e3f335aef9f85323621271875c7a0cb50d2 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/polygon.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/polygon.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model +from service_apis.models.gad_shape import GADShape # noqa: E501 from service_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from service_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/problem_details.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/problem_details.py index 371d6452270de67424a20bc33418b92f10889455..ac177318b8300aefb2e4b626bcf329f16406b51d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/problem_details.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/protocol.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/protocol.py index bd8783f2b51286cbe93199465b0c05f38c3da89e..d88a4100a628d2190a377b9607aa4179c11aac15 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/protocol.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/published_api_path.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/published_api_path.py index 5135c5a7e4aff1e2fb979606665fd6a56cf9ff8b..5736c4735d3bf18bde302a3ec5020ac7db2602fb 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/published_api_path.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/published_api_path.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/relative_cartesian_location.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/relative_cartesian_location.py index b40cde6be43a3cf40843f00500e5a1bfb162a374..f2f1a68978fdb6143ff188771692d439fab2db3c 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/relative_cartesian_location.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/relative_cartesian_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/resource.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/resource.py index 6e0a6c356c95406644737e12df8018f253f8e514..0f340dfe4edfe90d5106e4105836a9063e56ec99 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/resource.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/resource.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/security_method.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/security_method.py index 62ebc962cd9c1cb4162d2e83969626e9fb83d238..23372e621183cb96483444b3e2cc78851b5bac7d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/security_method.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_api_description.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_api_description.py index 339b35c67ce6e89fc2fc8519caccbfe529849527..b81515a9307a3f5a21cd184e5093e16bcfc05d91 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_api_description.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_api_description.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.aef_profile import AefProfile # noqa: E501 @@ -236,7 +236,7 @@ class ServiceAPIDescription(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features @@ -305,7 +305,7 @@ class ServiceAPIDescription(Model): :type api_supp_feats: str """ if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 - raise ValueError("Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._api_supp_feats = api_supp_feats diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_kpis.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_kpis.py index b8024ec96416d6e066744acc7828945bc46c65e7..66dd9e353baa7632e8128d05b755842c103957a8 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_kpis.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/service_kpis.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model @@ -170,7 +170,7 @@ class ServiceKpis(Model): :type aval_comp: str """ if aval_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_comp = aval_comp @@ -195,7 +195,7 @@ class ServiceKpis(Model): :type aval_gra_comp: str """ if aval_gra_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_gra_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_gra_comp = aval_gra_comp @@ -220,7 +220,7 @@ class ServiceKpis(Model): :type aval_mem: str """ if aval_mem is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_mem): # noqa: E501 - raise ValueError("Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_mem = aval_mem @@ -245,7 +245,7 @@ class ServiceKpis(Model): :type aval_stor: str """ if aval_stor is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_stor): # noqa: E501 - raise ValueError("Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_stor = aval_stor diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/shareable_information.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/shareable_information.py index 6970e3dae428e3d4a557117bea7b654cd1937ab1..0f0c7b02cf1b06f23a73821067a572b9bf58c234 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/shareable_information.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/shareable_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/supported_gad_shapes.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/supported_gad_shapes.py index 2f2a6aea3070500e6387121c48c2aac2d69aaed6..d5e17a12e20d513247967341bdb0e2f05956f3d9 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/supported_gad_shapes.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/supported_gad_shapes.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipse.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipse.py index 0250ace198fbcf2726f0ed3b660051f458d7d824..53e6a3ad7f5b8f9c8a46e8f5990d772deef92a9d 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipse.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipsoid.py index 0779259693afc8ce63822d337f008972f8ce787c..bac421f251b5ff37bb5d931a18582b328e3cbd78 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/uncertainty_ellipsoid.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/version.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/version.py index 3e4f6efa3593cc2a326a957b89af81437e458d5f..7efbc3f7bdde49f75410126141057ec883f35aa9 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/version.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/models/version.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from service_apis import util from service_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/openapi/openapi.yaml b/services/TS29222_CAPIF_Discover_Service_API/service_apis/openapi/openapi.yaml index c0c2608827529438b279e370570467dbc75aa6c3..bcdeb091ca021ece59f5e92382b419a7b12068e4 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for discovering service APIs. \n© 2023, 3GPP Organizational Partners\ + description: "API for discovering service APIs. \n© 2024, 3GPP Organizational Partners\ \ (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Discover_Service_API - version: 1.3.0-alpha.2 + version: 1.3.1 externalDocs: - description: 3GPP TS 29.222 V18.4.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.7.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/service-apis/v1" @@ -138,6 +138,17 @@ paths: schema: $ref: '#/components/schemas/ServiceKpis' style: form + - content: + application/json: + schema: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + type: array + description: Contains the OAuth grant types that need to be supported. + in: query + name: grant-types + required: false responses: "200": content: @@ -318,6 +329,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -496,6 +510,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -504,6 +521,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -521,6 +541,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -699,6 +722,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -707,6 +733,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -746,6 +775,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -924,6 +956,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -932,6 +967,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -949,6 +987,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1127,6 +1168,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1135,6 +1179,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1155,21 +1202,30 @@ components: ccfIds: - ccfIds - ccfIds + suppFeat: suppFeat properties: serviceAPIDescriptions: description: | - Description of the service API as published by the service. Each service API description shall include AEF profiles matching the filter criteria. + Description of the service API as published by the service. Each service API information shall include AEF profiles matching the filter criteria. items: $ref: '#/components/schemas/ServiceAPIDescription' minItems: 1 title: serviceAPIDescriptions type: array + suppFeat: + description: | + A string used to indicate the features supported by an API that is used as defined in clause 6.6 in 3GPP TS 29.500. 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" and shall represent the support of 4 features as described in table 5.2.2-3. The most significant character representing the highest-numbered features shall appear first in the string, and the character representing features 1 to 4 shall appear last in the string. The list of features and their numbering (starting with 1) are defined separately for each API. If the string contains a lower number of characters than there are defined features for an API, all features that would be represented by characters that are not present in the string are not supported. + pattern: "^[A-Fa-f0-9]*$" + title: SupportedFeatures + type: string title: DiscoveredAPIs type: object IpAddrInfo: description: Represents the UE IP address information. nullable: true - oneOf: [] + oneOf: + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -1184,14 +1240,9 @@ components: type: object CommunicationType: type: string - anyOf: - - enum: + enum: - REQUEST_RESPONSE - SUBSCRIBE_NOTIFY - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string description: "Indicates a communication type of the resource or the custom operation.\ \ \nPossible values are:\n- REQUEST_RESPONSE: The communication is of the\ \ type request-response.\n- SUBSCRIBE_NOTIFY: The communication is of the\ @@ -1199,16 +1250,11 @@ components: title: CommunicationType Protocol: type: string - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -1217,15 +1263,10 @@ components: title: Protocol DataFormat: type: string - anyOf: - - enum: + enum: - JSON - XML - PROTOBUF3 - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string description: "Indicates a data format. \nPossible values are:\n- JSON: Indicates\ \ that the data format is JSON.\n- XML: Indicates that the data format is\ \ Extensible Markup Language.\n- PROTOBUF3: Indicates that the data format\ @@ -1356,6 +1397,19 @@ components: type: integer title: ServiceKpis type: object + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType ProblemDetails: description: Represents additional information and details on an error response. properties: @@ -1446,6 +1500,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1624,6 +1681,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1632,6 +1692,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1649,6 +1712,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1827,6 +1893,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1835,6 +1904,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1935,6 +2007,9 @@ components: description: Represents the AEF profile data. example: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2113,6 +2188,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2121,6 +2199,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2138,7 +2219,10 @@ components: maxReqRate: 0 avalGraComp: avalGraComp nullable: true - oneOf: [] + oneOf: + - required: ["domainName"] + - required: ["interfaceDescriptions"] + - {} properties: aefId: description: Identifier of the API exposing function @@ -2162,6 +2246,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array domainName: description: Domain to which API belongs to title: domainName @@ -2375,31 +2465,23 @@ components: title: CustomOperation type: object Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" title: Operation SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -2409,6 +2491,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2417,7 +2502,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: [] + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -2456,10 +2544,18 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object IpAddrRange: - anyOf: [] + anyOf: + - required: ["ueIpv4AddrRanges"] + - required: ["ueIpv6AddrRanges"] description: Represents the list of public IP ranges example: ueIpv4AddrRanges: @@ -2735,8 +2831,7 @@ components: title: GADShape type: object SupportedGADShapes: - anyOf: - - enum: + enum: - POINT - POINT_UNCERTAINTY_CIRCLE - POINT_UNCERTAINTY_ELLIPSE @@ -2749,8 +2844,7 @@ components: - DISTANCE_DIRECTION - RELATIVE_2D_LOCATION_UNCERTAINTY_ELLIPSE - RELATIVE_3D_LOCATION_UNCERTAINTY_ELLIPSOID - type: string - - type: string + type: string description: Indicates supported GAD shapes. title: SupportedGADShapes PointUncertaintyCircle: @@ -2978,8 +3072,26 @@ components: type: string point: $ref: '#/components/schemas/GeographicalCoordinates' + area: + $ref: '#/components/schemas/GeographicArea' + horizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in + 0.1 degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer + required: + - coordinateId title: LocalOrigin type: object + HorizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in 0.1 + degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer RelativeCartesianLocation: description: Relative Cartesian Location properties: @@ -3015,6 +3127,8 @@ components: $ref: '#/components/schemas/UncertaintyEllipsoid' confidence: $ref: '#/components/schemas/Confidence' + vConfidence: + $ref: '#/components/schemas/Confidence' required: - confidence - localOrigin @@ -3133,9 +3247,6 @@ components: title: Ipv6AddressRange type: object Ipv6Addr_1: - allOf: - - pattern: "^((:|(0?|([1-9a-f][0-9a-f]{0,3}))):)((0?|([1-9a-f][0-9a-f]{0,3})):){0,6}(:|(0?|([1-9a-f][0-9a-f]{0,3})))$" - - pattern: "^((([^:]+:){7}([^:]+))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))$" description: | String identifying an IPv6 address formatted according to clause 4 of RFC5952. The mixed IPv4 IPv6 notation according to clause 5 of RFC5952 shall not be used. example: 2001:db8:85a3::8a2e:370:7334 diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/test/test_default_controller.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/test/test_default_controller.py index 3d4afdbc502e49678a51a31478d1c0c451d6c32c..6e626023ebcfcaee0f98fe9cd06891af45c6f272 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/test/test_default_controller.py @@ -1,5 +1,14 @@ import unittest +from service_apis.models.aef_location import AefLocation # noqa: E501 +from service_apis.models.communication_type import CommunicationType # noqa: E501 +from service_apis.models.data_format import DataFormat # noqa: E501 +from service_apis.models.discovered_apis import DiscoveredAPIs # noqa: E501 +from service_apis.models.ip_addr_info import IpAddrInfo # noqa: E501 +from service_apis.models.o_auth_grant_type import OAuthGrantType # noqa: E501 +from service_apis.models.problem_details import ProblemDetails # noqa: E501 +from service_apis.models.protocol import Protocol # noqa: E501 +from service_apis.models.service_kpis import ServiceKpis # noqa: E501 from service_apis.test import BaseTestCase @@ -24,7 +33,8 @@ class TestDefaultController(BaseTestCase): ('supported-features', 'supported_features_example'), ('api-supported-features', 'api_supported_features_example'), ('ue-ip-addr', openapi_server.IpAddrInfo()), - ('service-kpis', openapi_server.ServiceKpis())] + ('service-kpis', openapi_server.ServiceKpis()), + ('grant-types', [openapi_server.OAuthGrantType()])] headers = { 'Accept': 'application/json', } diff --git a/services/TS29222_CAPIF_Discover_Service_API/service_apis/typing_utils.py b/services/TS29222_CAPIF_Discover_Service_API/service_apis/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/service_apis/typing_utils.py +++ b/services/TS29222_CAPIF_Discover_Service_API/service_apis/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Discover_Service_API/setup.py b/services/TS29222_CAPIF_Discover_Service_API/setup.py index 3594e776f541076eb5210fecb462a24592e927a8..da11c500f9628c9c553fd7ea54e06c77d5c35753 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/setup.py +++ b/services/TS29222_CAPIF_Discover_Service_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "service_apis" VERSION = "1.0.0" @@ -30,7 +31,7 @@ setup( entry_points={ 'console_scripts': ['service_apis=service_apis.__main__:main']}, long_description="""\ - API for discovering service APIs. © 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for discovering service APIs. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Discover_Service_API/test-requirements.txt b/services/TS29222_CAPIF_Discover_Service_API/test-requirements.txt index 6952c4e268f8f76a7769106b9101387565e144ba..58f51d6a00272d7515a20e3618f345b73c68afa0 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/test-requirements.txt +++ b/services/TS29222_CAPIF_Discover_Service_API/test-requirements.txt @@ -1,4 +1,4 @@ pytest~=7.1.0 pytest-cov>=2.8.1 -pytest-randomly==1.2.3 +pytest-randomly>=1.2.3 Flask-Testing==0.8.1 diff --git a/services/TS29222_CAPIF_Events_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Events_API/.openapi-generator/FILES index 54c709f66c81094be746c23eac6df18d20638d18..2bcc916b8c380d71db69b02312855cd91383d4f2 100644 --- a/services/TS29222_CAPIF_Events_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Events_API/.openapi-generator/FILES @@ -1,5 +1,6 @@ .dockerignore .gitignore +.openapi-generator-ignore .travis.yml Dockerfile README.md @@ -50,6 +51,7 @@ capif_events/models/muting_exception_instructions.py capif_events/models/muting_notifications_settings.py capif_events/models/notification_flag.py capif_events/models/notification_method.py +capif_events/models/o_auth_grant_type.py capif_events/models/operation.py capif_events/models/partitioning_criteria.py capif_events/models/point.py @@ -79,6 +81,7 @@ capif_events/models/version.py capif_events/models/websock_notif_config.py capif_events/openapi/openapi.yaml capif_events/test/__init__.py +capif_events/test/test_default_controller.py capif_events/typing_utils.py capif_events/util.py requirements.txt diff --git a/services/TS29222_CAPIF_Events_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Events_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Events_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Events_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Events_API/README.md b/services/TS29222_CAPIF_Events_API/README.md index e6189d5346f7d95bbab11277ddcd18acbc6dfbbe..9f89fecda371a76b63bfccae48159dc22eb216da 100644 --- a/services/TS29222_CAPIF_Events_API/README.md +++ b/services/TS29222_CAPIF_Events_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m capif_events ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Events_API/capif_events/app.py b/services/TS29222_CAPIF_Events_API/capif_events/app.py index ef1d8c3a535c0c5658b4babb1458fcd3dcf0bf0f..b9f0bd9bc7436db9bb1895c07ec024984a7994a5 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/app.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/app.py @@ -6,6 +6,10 @@ from datetime import datetime from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config +from core.consumer_messager import Subscriber +from core.notifications import Notifications from flask_apscheduler import APScheduler from flask_executor import Executor from flask_jwt_extended import JWTManager @@ -19,11 +23,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config -from core.consumer_messager import Subscriber -from core.notifications import Notifications - NAME = "Events-Service" # Setting log level @@ -37,7 +36,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Events-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py b/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py index 2e071c8bd0b60f7be06ff5118f3c8cf175a99244..5e6cba2d4dbfe35e3d36889516257fe31105ca98 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/controllers/default_controller.py @@ -4,7 +4,7 @@ from capif_events.models.event_subscription import EventSubscription # noqa: E5 from capif_events.models.event_subscription_patch import EventSubscriptionPatch # noqa: E501 from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app +from flask import current_app, request from ..core.events_apis import EventSubscriptionsOperations from ..core.validate_user import ControlAccess @@ -27,7 +27,10 @@ def cert_validation(): if cn != "superadmin": cert_signature = cert.signature.hex() - result = valid_user.validate_user_cert(args["subscriptionId"], args["subscriberId"], cert_signature) + if request.method != 'POST': + result = valid_user.validate_user_cert(args["subscriptionId"], args["subscriberId"], cert_signature) + else: + result = valid_user.validate_user_cert(None, args["subscriberId"], cert_signature) if result is not None: return result @@ -37,6 +40,8 @@ def cert_validation(): return __cert_validation return _cert_validation + +@cert_validation() def subscriber_id_subscriptions_post(subscriber_id, body): # noqa: E501 """subscriber_id_subscriptions_post @@ -76,7 +81,7 @@ def subscriber_id_subscriptions_subscription_id_delete(subscriber_id, subscripti return res - +@cert_validation() def subscriber_id_subscriptions_subscription_id_patch(subscriber_id, subscription_id, body): # noqa: E501 """subscriber_id_subscriptions_subscription_id_patch @@ -97,7 +102,7 @@ def subscriber_id_subscriptions_subscription_id_patch(subscriber_id, subscriptio res = events_ops.patch_event(body, subscriber_id, subscription_id) return res - +@cert_validation() def subscriber_id_subscriptions_subscription_id_put(subscriber_id, subscription_id, body): # noqa: E501 """subscriber_id_subscriptions_subscription_id_put diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/events_apis.py b/services/TS29222_CAPIF_Events_API/capif_events/core/events_apis.py index 57fe0c70c0b3bbd1b9745b8423a8e21d44c42afb..1f9acaf3e4ff5c26e5aea1c729b1c02968960b2c 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/events_apis.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/events_apis.py @@ -4,15 +4,37 @@ import secrets import rfc3987 from capif_events.models.event_subscription import EventSubscription # noqa: E501 from flask import current_app, Response +from datetime import datetime, timezone +import asyncio +from ..util import clean_empty, dict_to_camel_case, serialize_clean_camel_case from .auth_manager import AuthManager from .resources import Resource from .responses import internal_server_error, not_found_error, make_response, bad_request_error from ..util import serialize_clean_camel_case, clean_empty, dict_to_camel_case +from .notifications import Notifications +TOTAL_FEATURES = 4 +SUPPORTED_FEATURES_HEX = "c" + +def return_negotiated_supp_feat_dict(supp_feat): + + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "NotificationTestEvent": True if final_supp_feat[0] == "1" else False, + "NotificationWebsocket": True if final_supp_feat[1] == "1" else False, + "EnhancedEventReport": True if final_supp_feat[2] == "1" else False, + "ApiStatusMonitoring": True if final_supp_feat[3] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } class EventSubscriptionsOperations(Resource): + def __init__(self): + super().__init__() + self.notifications = Notifications() + def __check_subscriber_id(self, subscriber_id): mycol_invoker= self.db.get_col_by_name(self.db.invoker_collection) mycol_provider= self.db.get_col_by_name(self.db.provider_collection) @@ -33,6 +55,61 @@ class EventSubscriptionsOperations(Resource): return None + def __check_event_filters(self, events, filters): + current_app.logger.debug("Checking event filters.") + valid_filters = { + "SERVICE_API_UPDATE": ["api_ids"], + "SERVICE_API_AVAILABLE" : ["api_ids"], + "SERVICE_API_UNAVAILABLE" : ["api_ids"], + "API_INVOKER_ONBOARDED": ["api_invoker_ids"], + "API_INVOKER_OFFBOARDED": ["api_invoker_ids"], + "API_INVOKER_UPDATED": ["api_invoker_ids"], + "ACCESS_CONTROL_POLICY_UPDATE":["api_invoker_ids", "api_ids"], + "SERVICE_API_INVOCATION_SUCCESS": ["api_invoker_ids", "api_ids", "aef_ids"], + "SERVICE_API_INVOCATION_FAILURE": ["api_invoker_ids", "api_ids", "aef_ids"], + "API_TOPOLOGY_HIDING_CREATED": [], + "API_TOPOLOGY_HIDING_REVOKED": [] + } + + for event, filter in zip(events, filters): + invalid_filters = set(filter.keys()) - set(valid_filters.get(event, [])) + + if invalid_filters: + current_app.logger.debug(f"The eventFilter {invalid_filters} for event {event} are not applicable.") + return bad_request_error(detail="Bad Param", cause = f"Invalid eventFilter for event {event}", invalid_params=[{"param": "eventFilter", "reason": f"The eventFilter {invalid_filters} for event {event} are not applicable."}]) + return None + + def __check_event_req(self, event_subscription, subscription_id=None): + current_app.logger.debug("Checking event requirement.") + expired_at = None + if event_subscription.event_req.mon_dur: + if event_subscription.event_req.mon_dur > datetime.now(timezone.utc): + expired_at = event_subscription.event_req.mon_dur + else: + current_app.logger.error("monDur is in the past") + return bad_request_error( + detail="Bad Param", + cause="monDur is in the past", + invalid_params=[{"param": "monDur", "reason": "monDur is in the past"}] + ) + + if event_subscription.event_req.notif_method == "PERIODIC" and event_subscription.event_req.rep_period is None: + current_app.logger.error("Periodic notification method selected but repPeriod not provided") + return bad_request_error( + detail="Bad Param", + cause="Periodic notification method selected but repPeriod not provided", + invalid_params=[{"param": "repPeriod", "reason": "Periodic notification method selected but repPeriod not provided"}] + ) + + if event_subscription.event_req.imm_rep and subscription_id is not None: + current_app.logger.debug("Sending immediate notification") + notifications_col = self.db.get_col_by_name(self.db.notifications_col) + result = notifications_col.find({"subscription_id": subscription_id}) + for notification in result: + asyncio.run(self.notifications.send(notification["url"], notification["notification"])) + + return expired_at + def __init__(self): Resource.__init__(self) self.auth_manager = AuthManager() @@ -59,16 +136,52 @@ class EventSubscriptionsOperations(Resource): result = self.__check_subscriber_id(subscriber_id) - if isinstance(result, Response): return result + negotiated_supported_features = return_negotiated_supp_feat_dict(event_subscription.supported_features) + + expired_at = None + # Check if EnhancedEventReport is enabled and validate event filters + if negotiated_supported_features["EnhancedEventReport"]: + if event_subscription.event_filters: + current_app.logger.debug(event_subscription.event_filters) + result = self.__check_event_filters(event_subscription.events, clean_empty(event_subscription.to_dict()["event_filters"])) + if isinstance(result, Response): + return result + if event_subscription.event_req: + current_app.logger.debug(event_subscription.event_req) + expired_at = self.__check_event_req(event_subscription) + if isinstance(expired_at, Response): + return result + else: + if event_subscription.event_filters: + current_app.logger.error("Event filters provided but EnhancedEventReport is not enabled") + return bad_request_error( + detail="Bad Param", + cause="Event filters provided but EnhancedEventReport is not enabled", + invalid_params=[{"param": "eventFilters", "reason": "EnhancedEventReport is not enabled"}] + ) + if event_subscription.event_req: + current_app.logger.error("Event requirement provided but EnhancedEventReport is not enabled") + return bad_request_error( + detail="Bad Param", + cause="Event requirement provided but EnhancedEventReport is not enabled", + invalid_params=[{"param": "eventReq", "reason": "EnhancedEventReport is not enabled"}] + ) + # Generate subscriptionID subscription_id = secrets.token_hex(15) evnt = dict() evnt["subscriber_id"] = subscriber_id evnt["subscription_id"] = subscription_id + + evnt["report_nbr"] = 0 + evnt["created_at"] = datetime.now(timezone.utc) + evnt["expire_at"] = expired_at + event_subscription.supported_features = negotiated_supported_features["Final"] + evnt.update(event_subscription.to_dict()) mycol.insert_one(evnt) @@ -90,6 +203,7 @@ class EventSubscriptionsOperations(Resource): try: mycol = self.db.get_col_by_name(self.db.event_collection) + notifications_col = self.db.get_col_by_name(self.db.notifications_col) current_app.logger.debug("Removing event subscription") @@ -108,6 +222,7 @@ class EventSubscriptionsOperations(Resource): return not_found_error(detail="Event subscription not exist", cause="Event API subscription id not found") mycol.delete_one(my_query) + notifications_col.delete_many({"subscription_id": subscription_id}) current_app.logger.debug("Event subscription removed from database") self.auth_manager.remove_auth_event(subscription_id, subscriber_id) @@ -119,13 +234,14 @@ class EventSubscriptionsOperations(Resource): exception= "An exception occurred in delete event" current_app.logger.error(exception + "::" + str(e)) return internal_server_error(detail=exception, cause=str(e)) - + def put_event(self, event_subscription, subscriber_id, subscription_id): try: mycol = self.db.get_col_by_name(self.db.event_collection) + notifications_col = self.db.get_col_by_name(self.db.notifications_col) current_app.logger.debug("Updating event subscription") - + if event_subscription.supported_features is None: return bad_request_error( detail="supportedFeatures not present in request", @@ -137,19 +253,53 @@ class EventSubscriptionsOperations(Resource): if isinstance(result, Response): return result - + + current_app.logger.debug(event_subscription) + expired_at = None + + negotiated_supported_features = return_negotiated_supp_feat_dict(event_subscription.supported_features) + if negotiated_supported_features["EnhancedEventReport"]: + if event_subscription.event_filters: + current_app.logger.debug(event_subscription.event_filters) + result = self.__check_event_filters(event_subscription.events, clean_empty(event_subscription.to_dict()["event_filters"])) + if isinstance(result, Response): + return result + if event_subscription.event_req: + current_app.logger.debug(event_subscription.event_req) + expired_at = self.__check_event_req(event_subscription) + if isinstance(expired_at, Response): + return result + else: + if event_subscription.event_filters: + current_app.logger.error("Event filters provided but EnhancedEventReport is not enabled") + return bad_request_error( + detail="Bad Param", + cause="Event filters provided but EnhancedEventReport is not enabled", + invalid_params=[{"param": "eventFilters", "reason": "EnhancedEventReport is not enabled"}] + ) + if event_subscription.event_req: + current_app.logger.error("Event requirement provided but EnhancedEventReport is not enabled") + return bad_request_error( + detail="Bad Param", + cause="Event requirement provided but EnhancedEventReport is not enabled", + invalid_params=[{"param": "eventReq", "reason": "EnhancedEventReport is not enabled"}] + ) my_query = {'subscriber_id': subscriber_id, - 'subscription_id': subscription_id} + 'subscription_id': subscription_id} eventdescription = mycol.find_one(my_query) - if eventdescription is None: - current_app.logger.error("Event subscription not found") - return not_found_error(detail="Event subscription not exist", cause="Event API subscription id not found") + event_subscription.supported_features = negotiated_supported_features["Final"] + body = event_subscription.to_dict() body["subscriber_id"] = subscriber_id body["subscription_id"] = subscription_id + body["report_nbr"] = eventdescription.get("report_nbr", 0) + body["created_at"] = eventdescription.get("created_at", datetime.now(timezone.utc)) + body["expire_at"] = expired_at if expired_at else eventdescription.get("expire_at", None) + + notifications_col.delete_many({"subscription_id": subscription_id}) mycol.replace_one(my_query, body) current_app.logger.debug("Event subscription updated from database") @@ -157,16 +307,17 @@ class EventSubscriptionsOperations(Resource): res = make_response(object=serialize_clean_camel_case(event_subscription), status=200) return res - + except Exception as e: exception= "An exception occurred in updating event" current_app.logger.error(exception + "::" + str(e)) - return internal_server_error(detail=exception, cause=str(e)) + return internal_server_error(detail=exception, cause=str(e)) def patch_event(self, event_subscription, subscriber_id, subscription_id): try: mycol = self.db.get_col_by_name(self.db.event_collection) + notifications_col = self.db.get_col_by_name(self.db.notifications_col) current_app.logger.debug("Patching event subscription") @@ -183,7 +334,37 @@ class EventSubscriptionsOperations(Resource): current_app.logger.error("Event subscription not found") return not_found_error(detail="Event subscription not exist", cause="Event API subscription id not found") + current_app.logger.debug(event_subscription) + expired_at = None + + negotiated_supported_features = return_negotiated_supp_feat_dict(eventdescription.get("supported_features")) + + if negotiated_supported_features["EnhancedEventReport"]: + if event_subscription.events and event_subscription.event_filters: + result = self.__check_event_filters(event_subscription.events, clean_empty(event_subscription.to_dict()["event_filters"])) + elif event_subscription.events and event_subscription.event_filters is None and eventdescription.get("event_filters", None): + result = self.__check_event_filters(event_subscription.events, eventdescription.get("event_filters")) + elif event_subscription.events is None and event_subscription.event_filters: + result = self.__check_event_filters(eventdescription.get("events"), clean_empty(event_subscription.to_dict()["event_filters"])) + if isinstance(result, Response): + return result + + if event_subscription.event_req: + updated_data = EventSubscription.from_dict(dict_to_camel_case({**eventdescription, **clean_empty(event_subscription.to_dict())})) + expired_at = self.__check_event_req(updated_data, subscription_id) + if isinstance(expired_at, Response): + return result + else: + expired_at = expired_at if expired_at else eventdescription.get("expire_at", None) + + if isinstance(result, Response): + return result + + event_subscription.supported_features = negotiated_supported_features["Final"] + body = clean_empty(event_subscription.to_dict()) + body["expire_at"] = expired_at + notifications_col.delete_many({"subscription_id": subscription_id}) document = mycol.update_one(my_query, {"$set":body}) document = mycol.find_one(my_query) current_app.logger.debug("Event subscription patched from database") @@ -191,8 +372,8 @@ class EventSubscriptionsOperations(Resource): res = make_response(object=EventSubscription.from_dict(dict_to_camel_case(document)), status=200) return res - + except Exception as e: exception= "An exception occurred in patching event" current_app.logger.error(exception + "::" + str(e)) - return internal_server_error(detail=exception, cause=str(e)) + return internal_server_error(detail=exception, cause=str(e)) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/internal_event_ops.py b/services/TS29222_CAPIF_Events_API/capif_events/core/internal_event_ops.py index f9daf00889930f64567a573ba7bbb219ecf585ec..73ea353f6a31c482a25716be2336e80b9d8c6b81 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/internal_event_ops.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/internal_event_ops.py @@ -21,6 +21,14 @@ class InternalEventOperations(Resource): #We dont need remove all auth events, becase when invoker is removed, remove auth entry #self.auth_manager.remove_auth_all_event(subscriber_id) + + def delete_subscription(self, subscription_id): + + mycol = self.db.get_col_by_name(self.db.event_collection) + my_query = {'subscription_id': subscription_id} + mycol.delete_one(my_query) + + current_app.logger.info(f"Removed subscription: {subscription_id}") def get_event_subscriptions(self, event): current_app.logger.info("get subscription from db") @@ -42,3 +50,26 @@ class InternalEventOperations(Resource): except Exception as e: current_app.logger.error("An exception occurred ::" + str(e)) return False + + def add_notification(self, notification): + current_app.logger.info("Adding Notification to notifications list") + try: + mycol = self.db.get_col_by_name(self.db.notifications_col) + mycol.insert_one(notification) + current_app.logger.info("Notification added to notifications list") + except Exception as e: + current_app.logger.error("An exception occurred ::" + str(e)) + return False + + def update_report_nbr(self, subscription_id): + current_app.logger.info("Incrementing report number") + try: + mycol = self.db.get_col_by_name(self.db.event_collection) + my_query = {'subscription_id': subscription_id} + result = mycol.update_one(my_query, {'$inc': {'report_nbr': 1}}) + current_app.logger.info(result) + current_app.logger.info("Report number incremented") + except Exception as e: + current_app.logger.error("An exception occurred ::" + str(e)) + return False + diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py index 6288c3386414bdc967a09cae787bb89bb79874c6..0bd895575b416ae813f0828099c0895f54d433f8 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/notifications.py @@ -8,11 +8,25 @@ import requests from encoder import CustomJSONEncoder from flask import current_app from models.event_notification import EventNotification -from models.event_subscription import EventSubscription from util import serialize_clean_camel_case +from datetime import datetime, timedelta, timezone from .internal_event_ops import InternalEventOperations +TOTAL_FEATURES = 4 +SUPPORTED_FEATURES_HEX = "c" + +def return_negotiated_supp_feat_dict(supp_feat): + + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "NotificationTestEvent": True if final_supp_feat[0] == "1" else False, + "NotificationWebsocket": True if final_supp_feat[1] == "1" else False, + "EnhancedEventReport": True if final_supp_feat[2] == "1" else False, + "ApiStatusMonitoring": True if final_supp_feat[3] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } class Notifications(): @@ -36,21 +50,97 @@ class Notifications(): data = EventNotification(sub["subscription_id"], events=event) event_detail_redis=redis_event.get('event_detail', None) if event_detail_redis is not None: - if EventSubscription.return_supp_feat_dict(sub["supported_features"])["EnhancedEventReport"]: + if return_negotiated_supp_feat_dict(sub["supported_features"])["EnhancedEventReport"]: event_detail={} current_app.logger.debug(f"event: {event_detail_redis}") + + event_filters = sub.get("event_filters", None) + event_filter=None + if event_filters: + try: + event_filter = None if all(value is None for value in event_filters[sub.get("events", []).index(event)].values()) else event_filters[sub.get("events", []).index(event)] + current_app.logger.debug(f"Event filters: {event_filter}") + except IndexError: + event_filter=None + if event in ["SERVICE_API_AVAILABLE", "SERVICE_API_UNAVAILABLE"]: - event_detail["apiIds"]=event_detail_redis.get('apiIds', None) - if EventSubscription.return_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]: - event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) + if event_filter: + api_ids_list = event_filter.get("api_ids", None) + if api_ids_list and event_detail_redis.get('apiIds', None)[0] in api_ids_list: + event_detail["apiIds"]=event_detail_redis.get('apiIds', None) + if return_negotiated_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]: + event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) + else: + continue + else: + event_detail["apiIds"]=event_detail_redis.get('apiIds', None) + if return_negotiated_supp_feat_dict(sub["supported_features"])["ApiStatusMonitoring"]: + event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) elif event in ["SERVICE_API_UPDATE"]: - event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) + if event_filter: + api_ids_list = event_filter.get("api_ids", None) + if api_ids_list and event_detail_redis.get('serviceAPIDescriptions', {})[0].get('apiId') in api_ids_list: + event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) + else: + continue + else: + event_detail["serviceAPIDescriptions"]=event_detail_redis.get('serviceAPIDescriptions', None) elif event in ["API_INVOKER_ONBOARDED", "API_INVOKER_OFFBOARDED", "API_INVOKER_UPDATED"]: - event_detail["apiInvokerIds"]=event_detail_redis.get('apiInvokerIds', None) + if event_filter: + invoker_ids_list = event_filter.get("api_invoker_ids", None) + if invoker_ids_list and event_detail_redis.get('apiInvokerIds', None)[0] in invoker_ids_list: + event_detail["apiInvokerIds"]=event_detail_redis.get('apiInvokerIds', None) + else: + continue + else: + event_detail["apiInvokerIds"]=event_detail_redis.get('apiInvokerIds', None) elif event in ["ACCESS_CONTROL_POLICY_UPDATE"]: - event_detail["accCtrlPolList"]=event_detail_redis.get('accCtrlPolList', None) + if event_filter: + filter_invoker_ids = event_filter.get("api_invoker_ids", []) + filter_api_ids = event_filter.get("api_ids", []) + + invoker_ids_list = [invoker.get("apiInvokerId") for invoker in event_detail_redis.get("accCtrlPolList", None).get("apiInvokerPolicies")] + api_id = event_detail_redis.get("accCtrlPolList").get("apiId", None) + + if (filter_api_ids and not filter_invoker_ids) and (api_id in filter_api_ids): + event_detail["accCtrlPolList"]=event_detail_redis.get('accCtrlPolList', None) + elif (not filter_api_ids and filter_invoker_ids) and bool(set(filter_invoker_ids) & set(invoker_ids_list)): + event_detail["accCtrlPolList"]=event_detail_redis.get('accCtrlPolList', None) + elif (filter_api_ids and filter_invoker_ids) and bool(set(filter_invoker_ids) & set(invoker_ids_list)) and api_id in filter_api_ids: + event_detail["accCtrlPolList"]=event_detail_redis.get('accCtrlPolList', None) + else: + continue + else: + event_detail["accCtrlPolList"]=event_detail_redis.get('accCtrlPolList', None) elif event in ["SERVICE_API_INVOCATION_SUCCESS", "SERVICE_API_INVOCATION_FAILURE"]: - event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + if event_filter: + filter_invoker_ids = event_filter.get("api_invoker_ids", None) + filter_api_ids = event_filter.get("api_ids", None) + filter_aef_ids = event_filter.get("aef_ids", None) + + invoker_id = event_detail_redis.get("invocationLogs", None)[0].get("api_invoker_id", None) + aef_id = event_detail_redis.get("invocationLogs", None)[0].get("aef_id", None) + api_id = event_detail_redis.get("invocationLogs", None)[0].get("logs", None)[0].get("api_id", None) + + if (filter_api_ids and not filter_invoker_ids and not filter_aef_ids) and (api_id in filter_api_ids): + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (not filter_api_ids and filter_invoker_ids and not filter_aef_ids) and invoker_id in filter_invoker_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (not filter_api_ids and not filter_invoker_ids and filter_aef_ids) and aef_id in filter_aef_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (filter_api_ids and filter_invoker_ids and not filter_aef_ids) and (api_id in filter_api_ids) and invoker_id in filter_invoker_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (filter_api_ids and not filter_invoker_ids and filter_aef_ids) and (api_id in filter_api_ids) and aef_id in filter_aef_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (not filter_api_ids and filter_invoker_ids and filter_aef_ids) and invoker_id in filter_invoker_ids and aef_id in filter_aef_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + elif (filter_api_ids and filter_invoker_ids and filter_aef_ids) and (api_id in filter_api_ids) and invoker_id in filter_invoker_ids and aef_id in filter_aef_ids: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) + else: + continue + + else: + event_detail["invocationLogs"]=event_detail_redis.get('invocationLogs', None) elif event in ["API_TOPOLOGY_HIDING_CREATED", "API_TOPOLOGY_HIDING_REVOKED"]: event_detail["apiTopoHide"]=event_detail_redis.get('apiTopoHide', None) @@ -59,7 +149,35 @@ class Notifications(): current_app.logger.debug(json.dumps(data.to_dict(),cls=CustomJSONEncoder)) - asyncio.run(self.send(url, serialize_clean_camel_case(data))) + if return_negotiated_supp_feat_dict(sub["supported_features"])["EnhancedEventReport"] and sub.get("event_req", None): + current_app.logger.debug(f"Creating notification for {sub['subscription_id']}") + + if sub["event_req"]["notif_method"] == "PERIODIC": + transcurred_time = (datetime.now(timezone.utc)-sub["created_at"]).total_seconds() + if transcurred_time > sub["event_req"]["rep_period"]: + transcurred_blocks = int(transcurred_time // sub["event_req"]["rep_period"]) + next_report_time = sub["created_at"] + timedelta(seconds=((transcurred_blocks+1) * sub["event_req"]["rep_period"])) + else: + next_report_time = sub["created_at"] + timedelta(seconds=sub["event_req"]["rep_period"]) + + notification = {"notification": data.to_dict(), "next_report_time" : next_report_time, "url": url, "subscription_id": sub["subscription_id"]} + + self.events_ops.add_notification(notification) + self.events_ops.update_report_nbr(sub["subscription_id"]) + + if sub["event_req"]["notif_method"] == "ONE_TIME": + asyncio.run(self.send(url, serialize_clean_camel_case(data))) + self.events_ops.delete_subscription(sub["subscription_id"]) + + if sub["event_req"].get("max_report_nbr", None) and sub["report_nbr"] + 1 == sub["event_req"].get("max_report_nbr", None): + current_app.logger.debug(f"Limit reached, deleting subscription {sub['subscription_id']}") + self.events_ops.delete_subscription(sub["subscription_id"]) + + else: + asyncio.run(self.send(url, serialize_clean_camel_case(data))) + self.events_ops.update_report_nbr(sub["subscription_id"]) + + except Exception as e: current_app.logger.error("An exception occurred ::" + str(e)) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/validate_user.py b/services/TS29222_CAPIF_Events_API/capif_events/core/validate_user.py index 168e903f1f9f272b6f8bdf5e289aa97ec0c2c23c..8d1f8b05fad5eda954a723ae355e22214dc27574 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/validate_user.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/validate_user.py @@ -1,12 +1,12 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error class ControlAccess(Resource): @@ -20,13 +20,17 @@ class ControlAccess(Resource): cert_entry = cert_col.find_one(my_query) if cert_entry is not None: - if cert_entry["cert_signature"] != cert_signature or "event_subscriptions" not in cert_entry["resources"] or event_id not in cert_entry["resources"]["event_subscriptions"]: - prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource") - prob = serialize_clean_camel_case(prob) + if (event_id is None and cert_entry["cert_signature"] != cert_signature): + prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource") + prob = serialize_clean_camel_case(prob) - return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json") + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json") + elif event_id is not None and (cert_entry["cert_signature"] != cert_signature or "event_subscriptions" not in cert_entry["resources"] or event_id not in cert_entry["resources"]["event_subscriptions"]): + prob = ProblemDetails(title="Unauthorized", detail="User not authorized", cause="You are not the owner of this resource") + prob = serialize_clean_camel_case(prob) + return Response(json.dumps(prob, cls=CustomJSONEncoder), status=401, mimetype="application/json") except Exception as e: exception = "An exception occurred in validate subscriber" current_app.logger.error(exception + "::" + str(e)) - return internal_server_error(detail=exception, cause=str(e)) \ No newline at end of file + return internal_server_error(detail=exception, cause=str(e)) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/db/db.py b/services/TS29222_CAPIF_Events_API/capif_events/db/db.py index adfc472a567be9deb866e90eab1d8986281be0e8..c48884660da34a72900833d38ecb357928011f80 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/db/db.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/db/db.py @@ -21,7 +21,9 @@ class MongoDatabse(): self.invoker_collection = self.config['mongo']['capif_invokers_col'] self.provider_collection = self.config['mongo']['capif_providers_col'] self.certs_col = self.config['mongo']['certs_col'] - # self.acls_col = self.config['mongo']['capif_acls_col'] + self.notifications_col = self.config['mongo']['notifications_col'] + + self.get_col_by_name(self.event_collection).create_index([("expire_at", 1)],expireAfterSeconds=0) def get_col_by_name(self, name): return self.db[name].with_options(codec_options=CodecOptions(tz_aware=True)) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list.py b/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list.py index 95e986c1f31988d0b6ce011546d89d7180cb4ffe..42b98fed0c60768af1cdd6067eb5c0e655126814 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.api_invoker_policy import ApiInvokerPolicy # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list_ext.py b/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list_ext.py index 2492b928ec63192f90df8c7f56943bcc69846c23..5cdc5543c7499fed73c7be30b3b49d10d0c47d86 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list_ext.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/access_control_policy_list_ext.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.api_invoker_policy import ApiInvokerPolicy # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/aef_location.py b/services/TS29222_CAPIF_Events_API/capif_events/models/aef_location.py index 3487b6f38820c2c3312f02c86538bc0a30a868f3..5c51a242ed2567912de4d362a1a04fa1c2e9c627 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/aef_location.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/aef_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/aef_profile.py b/services/TS29222_CAPIF_Events_API/capif_events/models/aef_profile.py index c59fc51faeed458a548864e126eebede10fd7e57..c29502c6a0e1c02996fc9dd2bc7be56d223c7662 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/aef_profile.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/aef_profile.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.aef_location import AefLocation # noqa: E501 @@ -7,6 +7,7 @@ from capif_events.models.base_model import Model from capif_events.models.data_format import DataFormat # noqa: E501 from capif_events.models.interface_description import InterfaceDescription # noqa: E501 from capif_events.models.ip_addr_range import IpAddrRange # noqa: E501 +from capif_events.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from capif_events.models.protocol import Protocol # noqa: E501 from capif_events.models.security_method import SecurityMethod # noqa: E501 from capif_events.models.service_kpis import ServiceKpis # noqa: E501 @@ -19,7 +20,7 @@ class AefProfile(Model): Do not edit the class manually. """ - def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 """AefProfile - a model defined in OpenAPI :param aef_id: The aef_id of this AefProfile. # noqa: E501 @@ -32,6 +33,8 @@ class AefProfile(Model): :type data_format: DataFormat :param security_methods: The security_methods of this AefProfile. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] :param domain_name: The domain_name of this AefProfile. # noqa: E501 :type domain_name: str :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 @@ -49,6 +52,7 @@ class AefProfile(Model): 'protocol': Protocol, 'data_format': DataFormat, 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], 'domain_name': str, 'interface_descriptions': List[InterfaceDescription], 'aef_location': AefLocation, @@ -62,6 +66,7 @@ class AefProfile(Model): 'protocol': 'protocol', 'data_format': 'dataFormat', 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', 'domain_name': 'domainName', 'interface_descriptions': 'interfaceDescriptions', 'aef_location': 'aefLocation', @@ -74,6 +79,7 @@ class AefProfile(Model): self._protocol = protocol self._data_format = data_format self._security_methods = security_methods + self._grant_types = grant_types self._domain_name = domain_name self._interface_descriptions = interface_descriptions self._aef_location = aef_location @@ -210,6 +216,29 @@ class AefProfile(Model): self._security_methods = security_methods + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types + @property def domain_name(self) -> str: """Gets the domain_name of this AefProfile. diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/api_invoker_policy.py b/services/TS29222_CAPIF_Events_API/capif_events/models/api_invoker_policy.py index 30c021c2c6c067dc6e9f8ccbf3d1428b36816c19..a627518b753ec9912f07a0b888c361aa20dc4b37 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/api_invoker_policy.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/api_invoker_policy.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/api_status.py b/services/TS29222_CAPIF_Events_API/capif_events/models/api_status.py index c088f5bd2f98e04e0f69e2073adbb6f163b4bc11..25b8d95c8679095bd13d713386cc5b4ac4cedbb3 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/api_status.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/api_status.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/buffered_notifications_action.py b/services/TS29222_CAPIF_Events_API/capif_events/models/buffered_notifications_action.py index 4275f2907b2720077cbf443e4cbe385ec679dbcf..b53e72cf3ecfdf01310b87f6f8e1f853a521617e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/buffered_notifications_action.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/buffered_notifications_action.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event.py b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event.py index 381df838bb3d53c3eef4a68bc14ed3c23b2aee76..2d55c4ef27293a56e2aa46ed4afe0fe31928123e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_detail.py b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_detail.py index ebc44655810f491d8b54322167fa858b8a657107..6dcc6c7fdbd607c07b7c47e9f21761e9f547c997 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_detail.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_detail.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.access_control_policy_list_ext import AccessControlPolicyListExt # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_filter.py b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_filter.py index 6db6dce0dff50e6415c2e8a12ee4a05781648827..dd7c2d7c9bd803cba5c89cd426e72198ac303e41 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_filter.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/capif_event_filter.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/civic_address.py b/services/TS29222_CAPIF_Events_API/capif_events/models/civic_address.py index 34b6e912a343a93ee359914305261e68d8e3158f..379ebe0a0e24a23c4818a6d2ff0297f5ea818db4 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/civic_address.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/civic_address.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/communication_type.py b/services/TS29222_CAPIF_Events_API/capif_events/models/communication_type.py index 93fb327500a8881a97fe944506217bd744ce836f..3beb1ab15158899c53c271fc5dadd21b142d92b2 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/communication_type.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/communication_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/custom_operation.py b/services/TS29222_CAPIF_Events_API/capif_events/models/custom_operation.py index 57deea3beed891b9805a84b82d303cfeec05ee90..4b20ff1e3a13e1f0e365787d542913d634afe3ac 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/custom_operation.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/custom_operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/data_format.py b/services/TS29222_CAPIF_Events_API/capif_events/models/data_format.py index 751627ee5b61091654f48a6e4a65113f6b7a03b4..c668244c4b522293bcd56415be4e3f3713bb40e1 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/data_format.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/data_format.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ellipsoid_arc.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ellipsoid_arc.py index 05a4ea3eb8267b5f83d8bdeb71476385e58de204..928435e920ac7a14957e517255761d332108254e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ellipsoid_arc.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ellipsoid_arc.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/event_notification.py b/services/TS29222_CAPIF_Events_API/capif_events/models/event_notification.py index e59efbbc35e41ed537930e1ae20b9a133dd83dba..a77a357e1abf68cf57f15d8ab3b5031c7cf87b6a 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/event_notification.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/event_notification.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py index fef528652c2bfef2c4b7ee1bc00af5129a1eadf1..0470f4e68343a62cff358f070463eb8afe871109 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -62,18 +62,6 @@ class EventSubscription(Model): self._websock_notif_config = websock_notif_config self._supported_features = supported_features - @classmethod - def return_supp_feat_dict(cls, supp_feat): - TOTAL_FEATURES=4 - supp_feat_in_hex = int(supp_feat, 16) - supp_feat_in_bin = bin(supp_feat_in_hex)[2:].zfill(TOTAL_FEATURES)[::-1] - - return { - "NotificationTestEvent": True if supp_feat_in_bin[0] == "1" else False, - "NotificationWebsocket": True if supp_feat_in_bin[1] == "1" else False, - "EnhancedEventReport": True if supp_feat_in_bin[2] == "1" else False, - "ApiStatusMonitoring": True if supp_feat_in_bin[3] == "1" else False - } @classmethod def from_dict(cls, dikt) -> 'EventSubscription': @@ -249,6 +237,6 @@ class EventSubscription(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription_patch.py b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription_patch.py index 401b92e577156034ea63bca357c5f536485da7b3..437e372d7337e9115faeea54e3ce633317b94bbe 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription_patch.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/event_subscription_patch.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/gad_shape.py b/services/TS29222_CAPIF_Events_API/capif_events/models/gad_shape.py index 568a10bf718e11d663b2ab6792734cdde7612f4f..4ff103ebce6ff1a8bdacba50c6a97089b144d3dc 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/gad_shape.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/gad_shape.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/geographic_area.py b/services/TS29222_CAPIF_Events_API/capif_events/models/geographic_area.py index 69ee22dac20e1a6fdb3d9d79477097f2df6eec2b..f09f9422ef661d84c6c0fd1dc14e7cbc53e8c996 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/geographic_area.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/geographic_area.py @@ -1,9 +1,16 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.ellipsoid_arc import EllipsoidArc # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 +from capif_events.models.point import Point # noqa: E501 +from capif_events.models.point_altitude import PointAltitude # noqa: E501 +from capif_events.models.point_altitude_uncertainty import PointAltitudeUncertainty # noqa: E501 +from capif_events.models.point_uncertainty_circle import PointUncertaintyCircle # noqa: E501 +from capif_events.models.point_uncertainty_ellipse import PointUncertaintyEllipse # noqa: E501 +from capif_events.models.polygon import Polygon # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_events.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/geographical_coordinates.py b/services/TS29222_CAPIF_Events_API/capif_events/models/geographical_coordinates.py index 8337fc1bba7149a56bbaf39aed2c969142065ec3..c0cc15c60a80b6ff17367fa80417bdfc68120dda 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/geographical_coordinates.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/geographical_coordinates.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/interface_description.py b/services/TS29222_CAPIF_Events_API/capif_events/models/interface_description.py index 42ddd5f046ded87bbda36eabbd63c046e342c58b..69bf2441b39692756e06e13daf0c589a2bd4d00f 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/interface_description.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from capif_events.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/invalid_param.py b/services/TS29222_CAPIF_Events_API/capif_events/models/invalid_param.py index 795b8890bcbf7a77e9f4105bdf965e959a0eb672..ce023bf2ba2b4c6236debbf769c92a530613bd3e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/invalid_param.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/invocation_log.py b/services/TS29222_CAPIF_Events_API/capif_events/models/invocation_log.py index 1762fbc704b1604c3219ba6759004e1eeb00df50..450c08bb2a307696a8f9a7ee85e12c6b54a87525 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/invocation_log.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/invocation_log.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -153,6 +153,6 @@ class InvocationLog(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ip_addr_range.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ip_addr_range.py index f2b3d3b0712234587ab1ea6b576156b3cd03c776..0c43c0a4fa792bb1367566d624977ed9074f9f7e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ip_addr_range.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ip_addr_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range.py index a76dee2138581594b9b50b2e1213f97c4e5caf94..2f1dc1f9129534b02cfc229d00715d2a434fa771 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -67,7 +67,7 @@ class Ipv4AddressRange(Model): if start is None: raise ValueError("Invalid value for `start`, must not be `None`") # noqa: E501 if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -94,6 +94,6 @@ class Ipv4AddressRange(Model): if end is None: raise ValueError("Invalid value for `end`, must not be `None`") # noqa: E501 if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range1.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range1.py index 6773c80c93f75858879e198bfaaaf732d700b1b0..8c0d666428aff5b236d8815c0f3d27af1fd318ae 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range1.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv4_address_range1.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -65,7 +65,7 @@ class Ipv4AddressRange1(Model): :type start: str """ if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -90,6 +90,6 @@ class Ipv4AddressRange1(Model): :type end: str """ if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_addr1.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_addr1.py index 01cf6762ff9df505614f9fa8478a669f46760918..0dd4716a6568b8d2b64048a30f7598879651e5ea 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_addr1.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_addr1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range.py index 3d7e5c83f6413e3fd7dd181682785e8744b7d069..b7a59aff0fa5cf0034de377034f26520de5dbad4 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range1.py b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range1.py index 4eff20b6fc392738fe7383b0de538eb7b80a5307..1f9927194d543b8c597769cd79064aa066df7b2c 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range1.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/ipv6_address_range1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/local2d_point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Events_API/capif_events/models/local2d_point_uncertainty_ellipse.py index 588ecb63c229e45a6f39a0970598a8160699df9d..3432c47665c645f6c81432f55ebc05de10809cf4 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/local2d_point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/local2d_point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.local_origin import LocalOrigin # noqa: E501 from capif_events.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/local3d_point_uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Events_API/capif_events/models/local3d_point_uncertainty_ellipsoid.py index a70f1a00f53bbeb181d38273e49d029427a51e23..702a38e1c1c8dd565993b21be3f586362a19713f 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/local3d_point_uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/local3d_point_uncertainty_ellipsoid.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.local_origin import LocalOrigin # noqa: E501 from capif_events.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 @@ -15,7 +16,7 @@ class Local3dPointUncertaintyEllipsoid(Model): Do not edit the class manually. """ - def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None): # noqa: E501 + def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None, v_confidence=None): # noqa: E501 """Local3dPointUncertaintyEllipsoid - a model defined in OpenAPI :param shape: The shape of this Local3dPointUncertaintyEllipsoid. # noqa: E501 @@ -28,13 +29,16 @@ class Local3dPointUncertaintyEllipsoid(Model): :type uncertainty_ellipsoid: UncertaintyEllipsoid :param confidence: The confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 :type confidence: int + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 + :type v_confidence: int """ self.openapi_types = { 'shape': SupportedGADShapes, 'local_origin': LocalOrigin, 'point': RelativeCartesianLocation, 'uncertainty_ellipsoid': UncertaintyEllipsoid, - 'confidence': int + 'confidence': int, + 'v_confidence': int } self.attribute_map = { @@ -42,7 +46,8 @@ class Local3dPointUncertaintyEllipsoid(Model): 'local_origin': 'localOrigin', 'point': 'point', 'uncertainty_ellipsoid': 'uncertaintyEllipsoid', - 'confidence': 'confidence' + 'confidence': 'confidence', + 'v_confidence': 'vConfidence' } self._shape = shape @@ -50,6 +55,7 @@ class Local3dPointUncertaintyEllipsoid(Model): self._point = point self._uncertainty_ellipsoid = uncertainty_ellipsoid self._confidence = confidence + self._v_confidence = v_confidence @classmethod def from_dict(cls, dikt) -> 'Local3dPointUncertaintyEllipsoid': @@ -182,3 +188,30 @@ class Local3dPointUncertaintyEllipsoid(Model): raise ValueError("Invalid value for `confidence`, must be a value greater than or equal to `0`") # noqa: E501 self._confidence = confidence + + @property + def v_confidence(self) -> int: + """Gets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :return: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :rtype: int + """ + return self._v_confidence + + @v_confidence.setter + def v_confidence(self, v_confidence: int): + """Sets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :type v_confidence: int + """ + if v_confidence is not None and v_confidence > 100: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value less than or equal to `100`") # noqa: E501 + if v_confidence is not None and v_confidence < 0: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value greater than or equal to `0`") # noqa: E501 + + self._v_confidence = v_confidence diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/local_origin.py b/services/TS29222_CAPIF_Events_API/capif_events/models/local_origin.py index 4cb83ca670e926e5391a3583e5a52b539ff7f029..f11e9ffe08e9d3f873962e5f849d33d991dda4ca 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/local_origin.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/local_origin.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.geographic_area import GeographicArea # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 @@ -12,26 +13,36 @@ class LocalOrigin(Model): Do not edit the class manually. """ - def __init__(self, coordinate_id=None, point=None): # noqa: E501 + def __init__(self, coordinate_id=None, point=None, area=None, horiz_axes_orientation=None): # noqa: E501 """LocalOrigin - a model defined in OpenAPI :param coordinate_id: The coordinate_id of this LocalOrigin. # noqa: E501 :type coordinate_id: str :param point: The point of this LocalOrigin. # noqa: E501 :type point: GeographicalCoordinates + :param area: The area of this LocalOrigin. # noqa: E501 + :type area: GeographicArea + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. # noqa: E501 + :type horiz_axes_orientation: int """ self.openapi_types = { 'coordinate_id': str, - 'point': GeographicalCoordinates + 'point': GeographicalCoordinates, + 'area': GeographicArea, + 'horiz_axes_orientation': int } self.attribute_map = { 'coordinate_id': 'coordinateId', - 'point': 'point' + 'point': 'point', + 'area': 'area', + 'horiz_axes_orientation': 'horizAxesOrientation' } self._coordinate_id = coordinate_id self._point = point + self._area = area + self._horiz_axes_orientation = horiz_axes_orientation @classmethod def from_dict(cls, dikt) -> 'LocalOrigin': @@ -62,6 +73,8 @@ class LocalOrigin(Model): :param coordinate_id: The coordinate_id of this LocalOrigin. :type coordinate_id: str """ + if coordinate_id is None: + raise ValueError("Invalid value for `coordinate_id`, must not be `None`") # noqa: E501 self._coordinate_id = coordinate_id @@ -85,3 +98,51 @@ class LocalOrigin(Model): """ self._point = point + + @property + def area(self) -> GeographicArea: + """Gets the area of this LocalOrigin. + + + :return: The area of this LocalOrigin. + :rtype: GeographicArea + """ + return self._area + + @area.setter + def area(self, area: GeographicArea): + """Sets the area of this LocalOrigin. + + + :param area: The area of this LocalOrigin. + :type area: GeographicArea + """ + + self._area = area + + @property + def horiz_axes_orientation(self) -> int: + """Gets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :return: The horiz_axes_orientation of this LocalOrigin. + :rtype: int + """ + return self._horiz_axes_orientation + + @horiz_axes_orientation.setter + def horiz_axes_orientation(self, horiz_axes_orientation: int): + """Sets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. + :type horiz_axes_orientation: int + """ + if horiz_axes_orientation is not None and horiz_axes_orientation > 3600: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value less than or equal to `3600`") # noqa: E501 + if horiz_axes_orientation is not None and horiz_axes_orientation < 0: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value greater than or equal to `0`") # noqa: E501 + + self._horiz_axes_orientation = horiz_axes_orientation diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/log.py b/services/TS29222_CAPIF_Events_API/capif_events/models/log.py index 5b9f5bb7b6df2d174ec3f7d3334c97fa9b901cd5..647a3c0807a971e1cd1c111417fae252741766e4 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/log.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/log.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/muting_exception_instructions.py b/services/TS29222_CAPIF_Events_API/capif_events/models/muting_exception_instructions.py index d8882bfbbbcda2a01fabe7b827cfb91dd2743def..a928f40f863e485b4ed3f6d0424379cf37be212f 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/muting_exception_instructions.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/muting_exception_instructions.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/muting_notifications_settings.py b/services/TS29222_CAPIF_Events_API/capif_events/models/muting_notifications_settings.py index 902cf1933feccfd4e1dfa2b293a6598afb903d38..a1de5ef7dd2d19c1df9d0a729e0b7257cf0f2c66 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/muting_notifications_settings.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/muting_notifications_settings.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/notification_flag.py b/services/TS29222_CAPIF_Events_API/capif_events/models/notification_flag.py index 17eff44ae2171e0ac5304e39a20abc2aa583d5c1..85bf9cdee0440a7c0cd8344e43ea8f56e7ea646f 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/notification_flag.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/notification_flag.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/notification_method.py b/services/TS29222_CAPIF_Events_API/capif_events/models/notification_method.py index f8676038ea967eb7e4720c1a5a4f26db9fd3bb35..b6832cd015631c635c10273f52f7fd823061c58e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/notification_method.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/notification_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Events_API/capif_events/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..42bce0038fbda8dea68659de75421f4cc2ab885b --- /dev/null +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from capif_events import util +from capif_events.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/operation.py b/services/TS29222_CAPIF_Events_API/capif_events/models/operation.py index 1a8a1f97a4ba1a0e927975d9c63f76db7b095c16..ae36b0295589d970a718a311259c96f91e1b92f9 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/operation.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/partitioning_criteria.py b/services/TS29222_CAPIF_Events_API/capif_events/models/partitioning_criteria.py index 40a8bf7bbec0b9b1ccc6a1e7e20d27698eab840d..e744de1aa4694e448a3b0f4dd3cf8407dc5d0c65 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/partitioning_criteria.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/partitioning_criteria.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/point.py b/services/TS29222_CAPIF_Events_API/capif_events/models/point.py index 3f9f2e2376f97455575e1663e1328cc01997dbb1..68b096fbea1392e7bcecf40415ceb6c99d6e6152 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/point.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/point.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude.py b/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude.py index 64134eca71ac18bedea9675a7dbc58592ab09c68..637b2e254c45c29b7552ceb8d9c23e6de0a69617 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude_uncertainty.py b/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude_uncertainty.py index f45227d1d0f258105f1071b21ccbd44a092c6f0b..81b375b6a6e845162fb6528967e1a4a354318c59 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude_uncertainty.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/point_altitude_uncertainty.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_events.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_circle.py b/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_circle.py index a62a475cec8f7161a6d6bd48ffcefe41c33846a8..55ac081d56aa5c25b6275d686037bdfbf6830cb1 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_circle.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_circle.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_ellipse.py index 618bb46d93e05119f0b4292c2dfeb6a2b4f586d9..515a1d183326a9f8882ada63bcb51fe5faf12489 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_events.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/polygon.py b/services/TS29222_CAPIF_Events_API/capif_events/models/polygon.py index 7d89244dfd0f6a0390c8878eefda89988cc17cb5..8d8fe40566c6cbdb9b74e429c777c04686df5c73 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/polygon.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/polygon.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model +from capif_events.models.gad_shape import GADShape # noqa: E501 from capif_events.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_events.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/problem_details.py b/services/TS29222_CAPIF_Events_API/capif_events/models/problem_details.py index bbf924527ac4e21018e437e264614f8e1175bd84..225739b576d0e3c73a9274045178bac8830b29e2 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/problem_details.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/protocol.py b/services/TS29222_CAPIF_Events_API/capif_events/models/protocol.py index a92a428aa51087ffc42b7bce764e117e877d2c4a..3fb57d952012c7f97bc056637e38a8014a9b1c52 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/protocol.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/published_api_path.py b/services/TS29222_CAPIF_Events_API/capif_events/models/published_api_path.py index 6f2ae66268e0b014b12f50e956c568313a500944..f66c1853a4366db00f80ec884e8267650463a140 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/published_api_path.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/published_api_path.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/relative_cartesian_location.py b/services/TS29222_CAPIF_Events_API/capif_events/models/relative_cartesian_location.py index e6c06126627a42f13a61c59cac93a5dca5e4c061..eeeb3d3184ebb504c0235f66f78bec9c8ea09892 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/relative_cartesian_location.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/relative_cartesian_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/reporting_information.py b/services/TS29222_CAPIF_Events_API/capif_events/models/reporting_information.py index cb2fcfe99585407811692e031c81b8d73f2ae570..ac8dde652e4b900e5e04654ab98f31b7b54a9e0b 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/reporting_information.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/reporting_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/resource.py b/services/TS29222_CAPIF_Events_API/capif_events/models/resource.py index 9ab8c7718399c694a099c25489f47cadc81fda95..a675ea250bc1423893c4cfc40c79778f98da5508 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/resource.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/resource.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/routing_rule.py b/services/TS29222_CAPIF_Events_API/capif_events/models/routing_rule.py index 0560f90fd1e414b9da2cde14f59d179c61d4df5d..abfb9e619824fe3b27de5285a501ef0db18fdeb5 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/routing_rule.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/routing_rule.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.aef_profile import AefProfile # noqa: E501 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/security_method.py b/services/TS29222_CAPIF_Events_API/capif_events/models/security_method.py index fa70435cf343f93ef8fb6d1243d908a3a93730de..cf8caff4780219014873777a5a4d6ec76a778f6b 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/security_method.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/service_api_description.py b/services/TS29222_CAPIF_Events_API/capif_events/models/service_api_description.py index ac3bb24275fe24527cd8377294fd3228c767f25e..88daceb2aed32d51798451878dd5f82b74c4be0e 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/service_api_description.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/service_api_description.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.aef_profile import AefProfile # noqa: E501 @@ -236,7 +236,7 @@ class ServiceAPIDescription(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features @@ -305,7 +305,7 @@ class ServiceAPIDescription(Model): :type api_supp_feats: str """ if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 - raise ValueError("Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._api_supp_feats = api_supp_feats diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/service_kpis.py b/services/TS29222_CAPIF_Events_API/capif_events/models/service_kpis.py index 1bbabf845871d651475e7da75d0763bde4c45490..5a536e99c735680425035420c9721784323a91cb 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/service_kpis.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/service_kpis.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model @@ -170,7 +170,7 @@ class ServiceKpis(Model): :type aval_comp: str """ if aval_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_comp = aval_comp @@ -195,7 +195,7 @@ class ServiceKpis(Model): :type aval_gra_comp: str """ if aval_gra_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_gra_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_gra_comp = aval_gra_comp @@ -220,7 +220,7 @@ class ServiceKpis(Model): :type aval_mem: str """ if aval_mem is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_mem): # noqa: E501 - raise ValueError("Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_mem = aval_mem @@ -245,7 +245,7 @@ class ServiceKpis(Model): :type aval_stor: str """ if aval_stor is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_stor): # noqa: E501 - raise ValueError("Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_stor = aval_stor diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/shareable_information.py b/services/TS29222_CAPIF_Events_API/capif_events/models/shareable_information.py index 0521026981694ad6bda7f3a7810f3fea1dd47c0b..c67425be677121c321cc247a168b860784bd40f4 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/shareable_information.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/shareable_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/subscription_action.py b/services/TS29222_CAPIF_Events_API/capif_events/models/subscription_action.py index 99f4aab2780db0706387659caa861045cb198cc1..c0ada57ad068092adfc9603a04817692d2142306 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/subscription_action.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/subscription_action.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/supported_gad_shapes.py b/services/TS29222_CAPIF_Events_API/capif_events/models/supported_gad_shapes.py index e78e057a3ca56201e0cdb0ae9ac5a4265dc8270d..919cd5ad3d2330fb87f56eec45f5eb1bf0d80815 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/supported_gad_shapes.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/supported_gad_shapes.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/time_range_list.py b/services/TS29222_CAPIF_Events_API/capif_events/models/time_range_list.py index ad689a1382d2d0b9f89fa89eec8343f9976385d3..0adae28ca1b48af57b880569ea73f018202ca136 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/time_range_list.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/time_range_list.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/topology_hiding.py b/services/TS29222_CAPIF_Events_API/capif_events/models/topology_hiding.py index 7f56cc9f9d114209df1dc5f7553362ad8a89d76f..5cb44ed03c1589e90f458406bf2b5b0ef5d9dbb9 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/topology_hiding.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/topology_hiding.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipse.py b/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipse.py index c10203df5d243e4d1113d46889a179cec6a2cbf5..88c3675d0bcd6dace5bed601e93ae9af75286b61 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipse.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipsoid.py index e1a4a1f24c6a5f648737d9c402914cd3af050049..5e7e36ad021a23cebb5073af6bd01341ff68297a 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/uncertainty_ellipsoid.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/version.py b/services/TS29222_CAPIF_Events_API/capif_events/models/version.py index 5777e684360941e7db1f5413d3abd0594c458009..8185274bc4440d5019df3223623cbf4b1efea1e0 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/version.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/version.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/models/websock_notif_config.py b/services/TS29222_CAPIF_Events_API/capif_events/models/websock_notif_config.py index f1ceeb001a04c47189d64f7f3cd379e533f1769f..de4a84b084654f9b1cb8f0f4f7c9b31369ba50a6 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/models/websock_notif_config.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/models/websock_notif_config.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_events import util from capif_events.models.base_model import Model diff --git a/services/TS29222_CAPIF_Events_API/capif_events/openapi/openapi.yaml b/services/TS29222_CAPIF_Events_API/capif_events/openapi/openapi.yaml index 892a7a2b13e51a0105dd6e7edb43a2a22a0481af..cdf36c3621008b2005c103e0214565e06b7ceb65 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Events_API/capif_events/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for event subscription management. \n© 2023, 3GPP Organizational\ + description: "API for event subscription management. \n© 2024, 3GPP Organizational\ \ Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Events_API - version: 1.3.0-alpha.4 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.4.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/capif-events/v1" @@ -18,9 +18,9 @@ paths: post: callbacks: notificationDestination: - '{request.body#/notificationDestination}': + '{$request.body#/notificationDestination}': post: - operationId: notificationDestination_request_bodyNotificationDestinationPost + operationId: notification_destination_post requestBody: content: application/json: @@ -673,6 +673,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -690,6 +693,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -704,6 +710,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -721,6 +730,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -739,6 +751,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -756,6 +771,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -770,6 +788,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -787,6 +808,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -807,6 +831,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -985,6 +1012,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -993,6 +1023,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1021,6 +1054,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1199,6 +1235,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1207,6 +1246,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1267,6 +1309,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1445,6 +1490,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1453,6 +1501,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1470,6 +1521,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1648,6 +1702,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1656,6 +1713,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1695,6 +1755,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1873,6 +1936,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1881,6 +1947,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1898,6 +1967,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2076,6 +2148,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2084,6 +2159,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2174,6 +2252,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2191,6 +2272,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2205,6 +2289,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2222,6 +2309,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2240,6 +2330,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2257,6 +2350,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2271,6 +2367,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2288,6 +2387,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2308,6 +2410,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2486,6 +2591,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2494,6 +2602,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2522,6 +2633,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2700,6 +2814,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2708,6 +2825,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2768,6 +2888,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -2946,6 +3069,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2954,6 +3080,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -2971,6 +3100,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3149,6 +3281,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3157,6 +3292,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3196,6 +3334,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3374,6 +3515,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3382,6 +3526,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3399,6 +3546,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3577,6 +3727,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3585,6 +3738,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3685,6 +3841,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -3863,6 +4022,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3871,6 +4033,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -3899,6 +4064,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4077,6 +4245,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4085,6 +4256,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4148,8 +4322,7 @@ components: title: EventSubscriptionPatch type: object CAPIFEvent: - anyOf: - - enum: + enum: - SERVICE_API_AVAILABLE - SERVICE_API_UNAVAILABLE - SERVICE_API_UPDATE @@ -4163,10 +4336,7 @@ components: - API_INVOKER_UPDATED - API_TOPOLOGY_HIDING_CREATED - API_TOPOLOGY_HIDING_REVOKED - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Describes the CAPIF event. \nPossible values are:\n- SERVICE_API_AVAILABLE:\n\ \ Events related to the availability of service APIs after the service APIs\ \ are\n published.\n- SERVICE_API_UNAVAILABLE:\n Events related to the unavailability\ @@ -4376,6 +4546,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4554,6 +4727,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4562,6 +4738,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4579,6 +4758,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -4757,6 +4939,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4765,6 +4950,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -4865,6 +5053,9 @@ components: description: Represents the AEF profile data. example: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -5043,6 +5234,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5051,6 +5245,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5068,13 +5265,10 @@ components: maxReqRate: 0 avalGraComp: avalGraComp nullable: true - oneOf: - - required: - - ipv4Addr - - required: - - ipv6Addr - - required: - - fqdn + oneOf: + - required: ["domainName"] + - required: ["interfaceDescriptions"] + - {} properties: aefId: description: Identifier of the API exposing function @@ -5098,6 +5292,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array domainName: description: Domain to which API belongs to title: domainName @@ -5277,14 +5477,10 @@ components: title: Resource type: object CommunicationType: - anyOf: - - enum: + enum: - REQUEST_RESPONSE - SUBSCRIBE_NOTIFY - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a communication type of the resource or the custom operation.\ \ \nPossible values are:\n- REQUEST_RESPONSE: The communication is of the\ \ type request-response.\n- SUBSCRIBE_NOTIFY: The communication is of the\ @@ -5325,32 +5521,24 @@ components: title: CustomOperation type: object Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" title: Operation Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -5358,30 +5546,22 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol DataFormat: - anyOf: - - enum: + enum: - JSON - XML - PROTOBUF3 - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a data format. \nPossible values are:\n- JSON: Indicates\ \ that the data format is JSON.\n- XML: Indicates that the data format is\ \ Extensible Markup Language.\n- PROTOBUF3: Indicates that the data format\ \ is Protocol buffers version 3.\n" title: DataFormat SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -5391,6 +5571,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5399,11 +5582,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: - - required: - - domainName - - required: - - interfaceDescriptions + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -5442,6 +5624,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object AefLocation: @@ -5564,7 +5752,9 @@ components: title: ServiceKpis type: object IpAddrRange: - anyOf: [] + anyOf: + - required: ["ueIpv4AddrRanges"] + - required: ["ueIpv6AddrRanges"] description: Represents the list of public IP ranges example: ueIpv4AddrRanges: @@ -5651,6 +5841,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5668,6 +5861,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5682,6 +5878,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5699,6 +5898,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5745,6 +5947,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5762,6 +5967,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -5923,6 +6131,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -6101,6 +6312,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -6109,6 +6323,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -6171,15 +6388,11 @@ components: title: Ipv6AddressRange type: object NotificationMethod: - anyOf: - - enum: + enum: - PERIODIC - ONE_TIME - ON_EVENT_DETECTION - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration and is not used to encode content defined in the present version of this API. - type: string + type: string description: "Represents the notification methods that can be subscribed. \n\ Possible values are:\n- PERIODIC\n- ONE_TIME\n- ON_EVENT_DETECTION\n" title: NotificationMethod @@ -6205,17 +6418,13 @@ components: title: SamplingRatio type: integer PartitioningCriteria: - anyOf: - - enum: + enum: - TAC - SUBPLMN - GEOAREA - SNSSAI - DNN - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: | Possible values are: - "TAC": Type Allocation Code @@ -6225,16 +6434,11 @@ components: - "DNN": DNN title: PartitioningCriteria NotificationFlag: - anyOf: - - enum: + enum: - ACTIVATE - DEACTIVATE - RETRIEVAL - type: string - - description: "This string provides forward-compatibility with future extensions\ - \ to the enumeration but is not used to encode content defined in the present\ - \ version of this API. \n" - type: string + type: string description: "Possible values are:\n- ACTIVATE: The event notification is activated.\n\ - DEACTIVATE: The event notification is deactivated and shall be muted. The\ \ available\n event(s) shall be stored.\n- RETRIEVAL: The event notification\ @@ -6255,24 +6459,20 @@ components: title: MutingExceptionInstructions type: object BufferedNotificationsAction: - anyOf: - - enum: + enum: - SEND_ALL - DISCARD_ALL - DROP_OLD - type: string - - type: string + type: string description: | Indicates the required action by the event producer NF on the buffered Notifications. title: BufferedNotificationsAction SubscriptionAction: - anyOf: - - enum: + enum: - CLOSE - CONTINUE_WITH_MUTING - CONTINUE_WITHOUT_MUTING - type: string - - type: string + type: string description: | Indicates the required action by the event producer NF on the event subscription if an exception occurs while the event is muted. title: SubscriptionAction @@ -6292,6 +6492,19 @@ components: type: integer title: MutingNotificationsSettings type: object + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType DateTime_1: description: string with format "date-time" as defined in OpenAPI. format: date-time @@ -6512,8 +6725,7 @@ components: title: GADShape type: object SupportedGADShapes: - anyOf: - - enum: + enum: - POINT - POINT_UNCERTAINTY_CIRCLE - POINT_UNCERTAINTY_ELLIPSE @@ -6526,8 +6738,7 @@ components: - DISTANCE_DIRECTION - RELATIVE_2D_LOCATION_UNCERTAINTY_ELLIPSE - RELATIVE_3D_LOCATION_UNCERTAINTY_ELLIPSOID - type: string - - type: string + type: string description: Indicates supported GAD shapes. title: SupportedGADShapes PointUncertaintyCircle: @@ -6755,8 +6966,26 @@ components: type: string point: $ref: '#/components/schemas/GeographicalCoordinates' + area: + $ref: '#/components/schemas/GeographicArea' + horizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in + 0.1 degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer + required: + - coordinateId title: LocalOrigin type: object + HorizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in 0.1 + degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer RelativeCartesianLocation: description: Relative Cartesian Location properties: @@ -6792,6 +7021,8 @@ components: $ref: '#/components/schemas/UncertaintyEllipsoid' confidence: $ref: '#/components/schemas/Confidence' + vConfidence: + $ref: '#/components/schemas/Confidence' required: - confidence - localOrigin @@ -6886,9 +7117,6 @@ components: title: Ipv6AddressRange_1 type: object Ipv6Addr_1: - allOf: - - pattern: "^((:|(0?|([1-9a-f][0-9a-f]{0,3}))):)((0?|([1-9a-f][0-9a-f]{0,3})):){0,6}(:|(0?|([1-9a-f][0-9a-f]{0,3})))$" - - pattern: "^((([^:]+:){7}([^:]+))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))$" description: | String identifying an IPv6 address formatted according to clause 4 of RFC5952. The mixed IPv4 IPv6 notation according to clause 5 of RFC5952 shall not be used. example: 2001:db8:85a3::8a2e:370:7334 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/test/test_default_controller.py b/services/TS29222_CAPIF_Events_API/capif_events/test/test_default_controller.py index b724d9aef5f5a791e47b4e381d347ee72d743b58..79cc892f18610d2b020b24c2076a7eaa84fe1b07 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/test/test_default_controller.py @@ -1,5 +1,8 @@ import unittest +from capif_events.models.event_subscription import EventSubscription # noqa: E501 +from capif_events.models.event_subscription_patch import EventSubscriptionPatch # noqa: E501 +from capif_events.models.problem_details import ProblemDetails # noqa: E501 from capif_events.test import BaseTestCase from flask import json diff --git a/services/TS29222_CAPIF_Events_API/capif_events/typing_utils.py b/services/TS29222_CAPIF_Events_API/capif_events/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/typing_utils.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Events_API/config.yaml b/services/TS29222_CAPIF_Events_API/config.yaml index 101d300e8b86d57d77a4d054e9100cc25bf42aa0..a64584dd0da0d0f2dc2735f69d8a4cdbe76a275b 100644 --- a/services/TS29222_CAPIF_Events_API/config.yaml +++ b/services/TS29222_CAPIF_Events_API/config.yaml @@ -7,6 +7,7 @@ mongo: { 'capif_invokers_col': 'invokerdetails', 'capif_providers_col': 'providerenrolmentdetails', 'capif_acls_col': 'acls', + 'notifications_col': 'notifications', 'host': 'mongo', 'port': "27017" } diff --git a/services/TS29222_CAPIF_Events_API/requirements.txt b/services/TS29222_CAPIF_Events_API/requirements.txt index bfe2e17c53647b77962f50b9885fef525393c33f..1edc40a9b8d68f47e5f55a18401e3657c766a2df 100644 --- a/services/TS29222_CAPIF_Events_API/requirements.txt +++ b/services/TS29222_CAPIF_Events_API/requirements.txt @@ -24,5 +24,5 @@ aiohttp == 3.10.5 async-timeout == 4.0.3 werkzeug == 3.0.4 pyopenssl == 24.2.1 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 \ No newline at end of file diff --git a/services/TS29222_CAPIF_Events_API/setup.py b/services/TS29222_CAPIF_Events_API/setup.py index defed2ccdf4811792f1c8e90ff70d50eec1d89f6..f126a701844e3fd9dd10fb8ee0db3159aaf2bbc3 100644 --- a/services/TS29222_CAPIF_Events_API/setup.py +++ b/services/TS29222_CAPIF_Events_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "capif_events" VERSION = "1.0.0" @@ -30,7 +31,7 @@ setup( entry_points={ 'console_scripts': ['capif_events=capif_events.__main__:main']}, long_description="""\ - API for event subscription management. © 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for event subscription management. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Events_API/test-requirements.txt b/services/TS29222_CAPIF_Events_API/test-requirements.txt index 202a684feef71ff540d6aa528d348febf0b37d1e..58f51d6a00272d7515a20e3618f345b73c68afa0 100644 --- a/services/TS29222_CAPIF_Events_API/test-requirements.txt +++ b/services/TS29222_CAPIF_Events_API/test-requirements.txt @@ -1,4 +1,4 @@ -pytest~=4.6.7 # needed for python 2.7+3.4 +pytest~=7.1.0 pytest-cov>=2.8.1 -pytest-randomly == 1.2.3 # needed for python 2.7+3.4 -Flask-Testing == 0.8.0 +pytest-randomly>=1.2.3 +Flask-Testing==0.8.1 diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/FILES index 691fa78ca682780032ad7499166c9dbc98db38ed..fd69e2e1d1357e821cdd25f0232c8795f078b32b 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/FILES @@ -17,6 +17,7 @@ api_invocation_logs/models/interface_description.py api_invocation_logs/models/invalid_param.py api_invocation_logs/models/invocation_log.py api_invocation_logs/models/log.py +api_invocation_logs/models/o_auth_grant_type.py api_invocation_logs/models/operation.py api_invocation_logs/models/problem_details.py api_invocation_logs/models/protocol.py diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/README.md b/services/TS29222_CAPIF_Logging_API_Invocation_API/README.md index 9d330236d45009a4712233fbfd4e9e3aa202de6c..4c9ab923afeaccca940210e6dab592af62487c1e 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/README.md +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m api_invocation_logs ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/app.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/app.py index eda5d2bcae556fc1c4515520812a8984813dc8ca..56c94af9489f5211e915ddb49601ac294ebe3c44 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/app.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/app.py @@ -5,6 +5,8 @@ import os from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config from fluent import sender from opentelemetry import trace from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter @@ -14,9 +16,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config - NAME = "Logging-Service" # Setting log level @@ -30,7 +29,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Logging-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/controllers/default_controller.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/controllers/default_controller.py index 6877196b2e5eda95aad456588eff4d9279c047f6..f23e60283788d794ceb6f33cb503bf09705d7291 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/controllers/default_controller.py @@ -1,9 +1,8 @@ -from api_invocation_logs.models.invocation_log import InvocationLog # noqa: E501 - from api_invocation_logs.models.invocation_log import InvocationLog # noqa: E501 from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app +from flask import current_app, request +from functools import wraps from ..core.invocationlogs import LoggingInvocationOperations from ..core.validate_user import ControlAccess @@ -12,6 +11,7 @@ logging_invocation_operations = LoggingInvocationOperations() valid_user = ControlAccess() + def cert_validation(): def _cert_validation(f): @wraps(f) @@ -38,6 +38,7 @@ def cert_validation(): return _cert_validation +@cert_validation() def aef_id_logs_post(aef_id, body): # noqa: E501 """aef_id_logs_post diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py index 43106643a5b2b328108e858b417ed68217ca18d6..614181d940f8fd192a02a21fbe13f485f6a931dd 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/invocationlogs.py @@ -6,12 +6,23 @@ import secrets from flask import current_app from pymongo import ReturnDocument -from .redis_event import RedisEvent -from .resources import Resource -from .responses import internal_server_error, not_found_error, unauthorized_error, make_response from ..encoder import CustomJSONEncoder from ..util import serialize_clean_camel_case +from .redis_event import RedisEvent +from .resources import Resource +from .responses import internal_server_error, make_response, not_found_error, unauthorized_error +TOTAL_FEATURES = 1 +SUPPORTED_FEATURES_HEX = "0" + +def return_negotiated_supp_feat_dict(supp_feat): + + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "SliceBasedAPIExposure": True if final_supp_feat[0] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } class LoggingInvocationOperations(Resource): @@ -78,6 +89,8 @@ class LoggingInvocationOperations(Resource): if result is not None: return result + invocationlog.supported_features = return_negotiated_supp_feat_dict(invocationlog.supported_features)["Final"] + current_app.logger.debug("Check service apis") event = None invocation_log_base = json.loads(json.dumps( diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/redis_event.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/redis_event.py index c65a6a20313002902b4660493d05be5c4cd20a24..8dccdf3d3ad9ad7f9c1460d420390c421ab4289d 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/redis_event.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/redis_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import CustomJSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/validate_user.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/validate_user.py index c2bdf50f8cafd9a4119b9bbb4ccb7922afed8a81..f3f5cb6fce91214007c1b065ad70f0cc7db2e2a6 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/validate_user.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/core/validate_user.py @@ -1,12 +1,12 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error class ControlAccess(Resource): diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/db/db.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/db/db.py index 1999a2daf6fe02fafa11228a93bfdd50bf1de243..5cf1f6c7c60b623c316bfa0385020fbb09484618 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/db/db.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/db/db.py @@ -22,6 +22,7 @@ class MongoDatabse(): self.provider_details = self.config['mongo']['prov_col'] self.service_apis = self.config['mongo']['serv_col'] self.capif_users = self.config['mongo']['capif_users_col'] + self.certs_col = self.config['mongo']['certs_col'] def get_col_by_name(self, name): return self.db[name] diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/interface_description.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/interface_description.py index cffe68d5dc05695e01201b37e088cb6e19d02936..03cb6d5a4e803a6f2ea3ec17f0d4b0aed1dff2e3 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/interface_description.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model +from api_invocation_logs.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from api_invocation_logs.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invalid_param.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invalid_param.py index cabf7c8aa0f77b157ff71e631a462be837e3b519..18d055db58e82bc0ba1f75dbaa2e4868643b3c66 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invalid_param.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invocation_log.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invocation_log.py index 2ecb4d636c4afed8406f8950a0337a44253ec779..e7464b7f8f6217eeec903634882faedd332ed2f1 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invocation_log.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/invocation_log.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model @@ -153,6 +153,6 @@ class InvocationLog(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/log.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/log.py index 657d6a724c0fa288c0c2be3b36d3d5dac8b08858..84715f3068385d053d9adacd3540245748eb0a9a 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/log.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/log.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..9c8fcf7d5d8fa71b8a4305bd801510bf6270706d --- /dev/null +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from api_invocation_logs import util +from api_invocation_logs.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/operation.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/operation.py index 87835c09f561eebb4b19a5b4b2d1ec1dcd31295b..a4bea82522b1f12123a8b63dd8dd919211da79c1 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/operation.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/problem_details.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/problem_details.py index 0a10c19db834cc70ee16f422c6b113a0e2d72ef2..0f87859cabce40bd1ac09cd7e8ad048bca333d04 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/problem_details.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/protocol.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/protocol.py index 708e8bc4f46ebbd8a31006f60bd7e02eaff4200e..fe449f012305fd73e493d85f5108415c323447f2 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/protocol.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/security_method.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/security_method.py index fe2fcfe31bcff642379cdbf6c5699b2c8baae61f..3f0ff15bf0d1e0c7e9327f94b2c496945cca1685 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/security_method.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from api_invocation_logs import util from api_invocation_logs.models.base_model import Model diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/openapi/openapi.yaml b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/openapi/openapi.yaml index f1a93904b8f72512de593c92b8dad3cad206a2c7..7e794c1a7d52c0a4366616d7fd075ac36e6c3131 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for invocation logs. \n© 2022, 3GPP Organizational Partners (ARIB,\ + description: "API for invocation logs. \n© 2024, 3GPP Organizational Partners (ARIB,\ \ ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Logging_API_Invocation_API - version: 1.3.0-alpha.1 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.0.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/api-invocation-logs/v1" @@ -192,6 +192,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -209,6 +212,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -223,6 +229,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -240,6 +249,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -286,6 +298,9 @@ components: invocationTime: 2000-01-23T04:56:07.000+00:00 srcInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -303,6 +318,9 @@ components: apiVersion: apiVersion destInterface: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -458,16 +476,12 @@ components: title: supportedFeatures type: string Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -475,17 +489,13 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" @@ -499,6 +509,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -508,12 +521,9 @@ components: ipv4Addr: ipv4Addr nullable: true oneOf: - - required: - - ipv4Addr - - required: - - ipv6Addr - - required: - - fqdn + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -552,18 +562,20 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -593,3 +605,16 @@ components: minimum: 0 title: Port type: integer + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/test/test_default_controller.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/test/test_default_controller.py index f5c22b452718589984da98915642c2b09c9c6eb2..1475dbad48a6bf2d627dece7cbc29f7551ec39ca 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/test/test_default_controller.py @@ -1,5 +1,7 @@ import unittest +from api_invocation_logs.models.invocation_log import InvocationLog # noqa: E501 +from api_invocation_logs.models.problem_details import ProblemDetails # noqa: E501 from api_invocation_logs.test import BaseTestCase from flask import json @@ -12,7 +14,7 @@ class TestDefaultController(BaseTestCase): """ - invocation_log = {"supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","aefId":"aefId","logs":[{"apiName":"apiName","invocationTime":"2000-01-23T04:56:07.000+00:00","srcInterface":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"fwdInterface":"fwdInterface","resourceName":"resourceName","uri":"uri","inputParameters":"","invocationLatency":0,"result":"result","protocol":"HTTP_1_1","apiVersion":"apiVersion","destInterface":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"operation":"GET","apiId":"apiId","outputParameters":""},{"apiName":"apiName","invocationTime":"2000-01-23T04:56:07.000+00:00","srcInterface":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"fwdInterface":"fwdInterface","resourceName":"resourceName","uri":"uri","inputParameters":"","invocationLatency":0,"result":"result","protocol":"HTTP_1_1","apiVersion":"apiVersion","destInterface":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"operation":"GET","apiId":"apiId","outputParameters":""}]} + invocation_log = {"supportedFeatures":"supportedFeatures","apiInvokerId":"apiInvokerId","aefId":"aefId","logs":[{"apiName":"apiName","invocationTime":"2000-01-23T04:56:07.000+00:00","srcInterface":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"fwdInterface":"fwdInterface","resourceName":"resourceName","uri":"uri","inputParameters":"","invocationLatency":0,"result":"result","protocol":"HTTP_1_1","apiVersion":"apiVersion","destInterface":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"operation":"GET","apiId":"apiId","outputParameters":""},{"apiName":"apiName","invocationTime":"2000-01-23T04:56:07.000+00:00","srcInterface":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"fwdInterface":"fwdInterface","resourceName":"resourceName","uri":"uri","inputParameters":"","invocationLatency":0,"result":"result","protocol":"HTTP_1_1","apiVersion":"apiVersion","destInterface":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":39500,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"operation":"GET","apiId":"apiId","outputParameters":""}]} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/typing_utils.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/typing_utils.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/api_invocation_logs/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/config.yaml b/services/TS29222_CAPIF_Logging_API_Invocation_API/config.yaml index 0625fc64a5792a5246f81ea9ab556c23b984a384..8b8825bdb06039ebabccc4307e280f2bb9460b29 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/config.yaml +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/config.yaml @@ -7,6 +7,7 @@ mongo: { 'prov_col': 'providerenrolmentdetails', 'serv_col': 'serviceapidescriptions', 'capif_users_col': "user", + 'certs_col': "certs", 'host': 'mongo', 'port': "27017" } diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt b/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt index e5640804e1111309cbc5e90caf086b44916ed8e2..7abd46099797a5916f493661532e243c34571089 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt @@ -21,5 +21,5 @@ opentelemetry-sdk == 1.19.0 flask_executor == 1.0.0 werkzeug == 3.0.4 pyopenssl == 24.1.0 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/setup.py b/services/TS29222_CAPIF_Logging_API_Invocation_API/setup.py index 2edd1f3578279a90d77e9e8836f41d275b2b2eaa..aed8492996aef557130e39dc81933efc0fa5d94c 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/setup.py +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "api_invocation_logs" VERSION = "1.0.0" @@ -30,7 +31,7 @@ setup( entry_points={ 'console_scripts': ['api_invocation_logs=api_invocation_logs.__main__:main']}, long_description="""\ - API for invocation logs. © 2022, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for invocation logs. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/FILES index a238cf9c4aa9ace65c39dfb652a057ca53ab8ec9..44333b51519691ba1428cad21ca5c707b9b66549 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/FILES @@ -34,6 +34,7 @@ published_apis/models/ipv6_address_range.py published_apis/models/local2d_point_uncertainty_ellipse.py published_apis/models/local3d_point_uncertainty_ellipsoid.py published_apis/models/local_origin.py +published_apis/models/o_auth_grant_type.py published_apis/models/operation.py published_apis/models/point.py published_apis/models/point_altitude.py diff --git a/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Publish_Service_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Publish_Service_API/README.md b/services/TS29222_CAPIF_Publish_Service_API/README.md index a8ee25750f7e1979fac432c942c9975c6e9b778b..60ff8b067416f4815ed1c0b7b954e45a1a0e0189 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/README.md +++ b/services/TS29222_CAPIF_Publish_Service_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m published_apis ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/app.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/app.py index 6cddfc9eca54d3914e8c0dfcc0102afce2331ff5..46e0941cd496c55614ddff1b3e82c1187d455535 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/app.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/app.py @@ -6,6 +6,10 @@ from datetime import datetime from logging.handlers import RotatingFileHandler import connexion +# from published_apis import encoder +import encoder +from config import Config +from core.consumer_messager import Subscriber from flask_apscheduler import APScheduler from flask_executor import Executor from flask_jwt_extended import JWTManager @@ -19,11 +23,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -# from published_apis import encoder -import encoder -from config import Config -from core.consumer_messager import Subscriber - NAME = "Publish-Service" # Setting log level @@ -37,7 +36,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Publish-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py index 695b3ae2d76701115deac7f2d80317cafaa8793f..29839084d1420d7243c9c1bd655a8f8cdf52a5cf 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py @@ -2,11 +2,12 @@ from functools import wraps from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app -from published_apis.vendor_specific import vendor_specific_key_n_value, find_attribute_in_body +from flask import current_app, request +from published_apis.vendor_specific import find_attribute_in_body, vendor_specific_key_n_value from ..core.responses import bad_request_error from ..core.serviceapidescriptions import PublishServiceOperations +from ..core.serviceapidescriptions import return_negotiated_supp_feat_dict from ..core.validate_user import ControlAccess from ..models.service_api_description import ServiceAPIDescription # noqa: E501 @@ -14,7 +15,6 @@ service_operations = PublishServiceOperations() valid_user = ControlAccess() - def cert_validation(): def _cert_validation(f): @wraps(f) @@ -51,7 +51,6 @@ def cert_validation(): return __cert_validation return _cert_validation - @cert_validation() def apf_id_service_apis_get(apf_id): # noqa: E501 """apf_id_service_apis_get @@ -68,7 +67,6 @@ def apf_id_service_apis_get(apf_id): # noqa: E501 return res - @cert_validation() def apf_id_service_apis_post(apf_id, body): # noqa: E501 """apf_id_service_apis_post @@ -91,7 +89,7 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501 invalid_params=[{"param": "supportedFeatures", "reason": "not defined"}] ) - supp_feat_dict = ServiceAPIDescription.return_supp_feat_dict( + supp_feat_dict = return_negotiated_supp_feat_dict( body['supportedFeatures']) vendor_specific = [] @@ -114,7 +112,6 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501 return res - @cert_validation() def apf_id_service_apis_service_api_id_delete(service_api_id, apf_id): # noqa: E501 """apf_id_service_apis_service_api_id_delete @@ -134,7 +131,6 @@ def apf_id_service_apis_service_api_id_delete(service_api_id, apf_id): # noqa: return res - @cert_validation() def apf_id_service_apis_service_api_id_get(service_api_id, apf_id): # noqa: E501 """apf_id_service_apis_service_api_id_get @@ -153,7 +149,6 @@ def apf_id_service_apis_service_api_id_get(service_api_id, apf_id): # noqa: E50 return res - @cert_validation() def apf_id_service_apis_service_api_id_put(service_api_id, apf_id, body): # noqa: E501 """apf_id_service_apis_service_api_id_put diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/individual_apf_published_api_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/individual_apf_published_api_controller.py index 0661991fe4961b9b4abc8f62cd31c07e7575c985..78336ca4aa2717bb23f1adc21a57fbb828c4d828 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/individual_apf_published_api_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/individual_apf_published_api_controller.py @@ -2,7 +2,7 @@ from functools import wraps from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app +from flask import current_app, request from published_apis.models.service_api_description_patch import ServiceAPIDescriptionPatch # noqa: E501 from ..core.serviceapidescriptions import PublishServiceOperations diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/security_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/security_controller.py index 139597f9cb07c5d48bed18984ec4747f4b4f3438..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/security_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/security_controller.py @@ -1,2 +1 @@ - diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/publisher.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/publisher.py index 34fcdf453873b4b59a894d9f6b96b7ce1a217c2e..8292de4d4330b14c17be74e7448403b56fc5b9e3 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/publisher.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/publisher.py @@ -1,5 +1,6 @@ import redis + class Publisher(): def __init__(self): diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/redis_event.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/redis_event.py index f80e6b2e666574188740a99a0da0837ea899e01d..3037ae76a7bff9e74674d6e3b686cfbb24cf0f58 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/redis_event.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/redis_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import JSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py index 9e7ef755449e52e84b36ada01dcb54b5ce7eab62..658957efe4602fe98d6151662c35d52ec95a24af 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/serviceapidescriptions.py @@ -5,15 +5,25 @@ from datetime import datetime from flask import current_app from pymongo import ReturnDocument +from ..models.service_api_description import ServiceAPIDescription +from ..util import clean_empty, clean_n_camel_case, dict_to_camel_case +from ..vendor_specific import add_vend_spec_fields from .auth_manager import AuthManager from .publisher import Publisher from .redis_event import RedisEvent from .resources import Resource -from .responses import internal_server_error, forbidden_error, not_found_error, unauthorized_error, make_response, \ - bad_request_error -from ..models.service_api_description import ServiceAPIDescription -from ..util import dict_to_camel_case, clean_empty, clean_n_camel_case -from ..vendor_specific import add_vend_spec_fields +from .responses import ( + bad_request_error, + forbidden_error, + internal_server_error, + make_response, + not_found_error, + unauthorized_error +) + + +TOTAL_FEATURES = 10 +SUPPORTED_FEATURES_HEX = "120" publisher_ops = Publisher() @@ -21,6 +31,23 @@ publisher_ops = Publisher() service_api_not_found_message = "Service API not found" +def return_negotiated_supp_feat_dict(supp_feat): + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + + return { + "ApiSupportedFeaturePublishing": True if final_supp_feat[0] == "1" else False, + "PatchUpdate": True if final_supp_feat[1] == "1" else False, + "ExtendedIntfDesc": True if final_supp_feat[2] == "1" else False, + "MultipleCustomOperations": True if final_supp_feat[3] == "1" else False, + "ProtocDataFormats_Ext1": True if final_supp_feat[4] == "1" else False, + "ApiStatusMonitoring": True if final_supp_feat[5] == "1" else False, + "EdgeApp_2": True if final_supp_feat[6] == "1" else False, + "RNAA": True if final_supp_feat[7] == "1" else False, + "VendorExt": True if final_supp_feat[8] == "1" else False, + "SliceBasedAPIExposure": True if final_supp_feat[9] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:].zfill(3) + } + class PublishServiceOperations(Resource): def check_apf(self, apf_id): @@ -120,7 +147,7 @@ class PublishServiceOperations(Resource): vendor_specific, serviceapidescription_dict) rec.update(serviceapidescription_dict) - if not ServiceAPIDescription.return_supp_feat_dict(rec.get("supported_features"))["ApiStatusMonitoring"] and rec.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(rec.get("supported_features"))["ApiStatusMonitoring"] and rec.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -290,8 +317,9 @@ class PublishServiceOperations(Resource): service_api_description["apf_id"] = serviceapidescription_old["apf_id"] service_api_description["onboarding_date"] = serviceapidescription_old["onboarding_date"] service_api_description["api_id"] = serviceapidescription_old["api_id"] + service_api_description["supported_features"] = return_negotiated_supp_feat_dict(service_api_description["supported_features"])["Final"] - if not ServiceAPIDescription.return_supp_feat_dict(service_api_description.get("supported_features"))["ApiStatusMonitoring"] and service_api_description.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(service_api_description.get("supported_features"))["ApiStatusMonitoring"] and service_api_description.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -316,7 +344,6 @@ class PublishServiceOperations(Resource): return_document=ReturnDocument.AFTER, upsert=False) result = clean_empty(result) - current_app.logger.debug("Updated service api") service_api_description_updated = dict_to_camel_case(result) @@ -328,7 +355,13 @@ class PublishServiceOperations(Resource): RedisEvent("SERVICE_API_UPDATE", service_api_descriptions=[service_api_description_updated]).send_event() - my_service_api = clean_n_camel_case(serviceapidescription_old) + my_service_api = clean_empty(serviceapidescription_old) + + if (api_status := serviceapidescription_old.get("api_status")): + my_service_api["api_status"] = api_status + + my_service_api = dict_to_camel_case(my_service_api) + self.send_events_on_update( service_api_id, my_service_api, @@ -371,11 +404,14 @@ class PublishServiceOperations(Resource): patch_service_api_description = patch_service_api_description.to_dict() api_status = patch_service_api_description.get("api_status", None) + supported_features = patch_service_api_description.get("supported_features", None) patch_service_api_description = clean_empty(patch_service_api_description) if api_status: patch_service_api_description["api_status"]=api_status + if supported_features: + patch_service_api_description["supported_features"] = return_negotiated_supp_feat_dict(patch_service_api_description["supported_features"])["Final"] - if not ServiceAPIDescription.return_supp_feat_dict(serviceapidescription_old.get("supported_features"))["ApiStatusMonitoring"] and patch_service_api_description.get("api_status", None) is not None: + if not return_negotiated_supp_feat_dict(serviceapidescription_old.get("supported_features"))["ApiStatusMonitoring"] and patch_service_api_description.get("api_status", None) is not None: return bad_request_error( detail="Set apiStatus with apiStatusMonitoring feature inactive at supportedFeatures if not allowed", cause="apiStatus can't be set if apiStatusMonitoring is inactive", @@ -405,7 +441,6 @@ class PublishServiceOperations(Resource): service_api_description_updated = dict_to_camel_case(result) - current_app.logger.debug(service_api_description_updated) response = make_response( object=service_api_description_updated, status=200) @@ -413,7 +448,13 @@ class PublishServiceOperations(Resource): RedisEvent("SERVICE_API_UPDATE", service_api_descriptions=[service_api_description_updated]).send_event() - my_service_api = clean_n_camel_case(serviceapidescription_old) + my_service_api = clean_empty(serviceapidescription_old) + + if (api_status := serviceapidescription_old.get("api_status")): + my_service_api["api_status"] = api_status + + my_service_api = dict_to_camel_case(my_service_api) + self.send_events_on_update( service_api_id, my_service_api, @@ -455,7 +496,7 @@ class PublishServiceOperations(Resource): def service_api_availability_event(self, service_api_description): service_api_status = "" - if ServiceAPIDescription.return_supp_feat_dict(service_api_description.get("supportedFeatures"))["ApiStatusMonitoring"]: + if return_negotiated_supp_feat_dict(service_api_description.get("supportedFeatures"))["ApiStatusMonitoring"]: current_app.logger.info( "ApiStatusMonitoring active") if service_api_description.get("apiStatus") is None or len(service_api_description.get("apiStatus").get("aefIds")) > 0: diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py index 94fe1d4bc014038a11cefbbd2cfe82dfa5c7e14d..1782fe0425311da838e31af7d96338c28e236bf6 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/validate_user.py @@ -1,12 +1,12 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails from ..util import serialize_clean_camel_case +from .resources import Resource +from .responses import internal_server_error class ControlAccess(Resource): diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/encoder.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/encoder.py index 4d957655c7a45b96d9a0193333a35f1de7a47acd..6f24878a3c5f09dfd0accb35785385b3cfd59159 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/encoder.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/encoder.py @@ -1,5 +1,4 @@ from connexion.jsonifier import JSONEncoder - from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_location.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_location.py index 40e90aa6254b2b16f5338c80305125cdd9fbf05b..ca2cc22eda46173d3151563f0d4b546717d23752 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_location.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_profile.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_profile.py index 8d8ae4708c42e76200ee598aacf4d643a4df8c07..b50b23b78c674d1b199b65a0ea0f151e9fe416dc 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_profile.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/aef_profile.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.aef_location import AefLocation # noqa: E501 @@ -7,6 +7,7 @@ from published_apis.models.base_model import Model from published_apis.models.data_format import DataFormat # noqa: E501 from published_apis.models.interface_description import InterfaceDescription # noqa: E501 from published_apis.models.ip_addr_range import IpAddrRange # noqa: E501 +from published_apis.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from published_apis.models.protocol import Protocol # noqa: E501 from published_apis.models.security_method import SecurityMethod # noqa: E501 from published_apis.models.service_kpis import ServiceKpis # noqa: E501 @@ -19,7 +20,7 @@ class AefProfile(Model): Do not edit the class manually. """ - def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 """AefProfile - a model defined in OpenAPI :param aef_id: The aef_id of this AefProfile. # noqa: E501 @@ -32,6 +33,8 @@ class AefProfile(Model): :type data_format: DataFormat :param security_methods: The security_methods of this AefProfile. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] :param domain_name: The domain_name of this AefProfile. # noqa: E501 :type domain_name: str :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 @@ -49,6 +52,7 @@ class AefProfile(Model): 'protocol': Protocol, 'data_format': DataFormat, 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], 'domain_name': str, 'interface_descriptions': List[InterfaceDescription], 'aef_location': AefLocation, @@ -62,6 +66,7 @@ class AefProfile(Model): 'protocol': 'protocol', 'data_format': 'dataFormat', 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', 'domain_name': 'domainName', 'interface_descriptions': 'interfaceDescriptions', 'aef_location': 'aefLocation', @@ -74,6 +79,7 @@ class AefProfile(Model): self._protocol = protocol self._data_format = data_format self._security_methods = security_methods + self._grant_types = grant_types self._domain_name = domain_name self._interface_descriptions = interface_descriptions self._aef_location = aef_location @@ -210,6 +216,29 @@ class AefProfile(Model): self._security_methods = security_methods + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types + @property def domain_name(self) -> str: """Gets the domain_name of this AefProfile. diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/api_status.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/api_status.py index 14b0d36b47f51f02a1eba14e8904e281668bdd19..4fcf081767b9ecb1b39cd5d20da889340ca3fbcc 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/api_status.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/api_status.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/civic_address.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/civic_address.py index 94b868bebcd2edca4e57d5b7a1c7e6d87446f0a1..2985c188eb06e9d11b0dc573a8ceb56381095e11 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/civic_address.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/civic_address.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/communication_type.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/communication_type.py index d69e24ba75985f9a34b7370fd6ebdeb8d8bc36c6..34963f38384b204a81b2ffa06a40c0e4ac27b891 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/communication_type.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/communication_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/custom_operation.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/custom_operation.py index f99e4aedae9b09337c670881277243a2966f467f..2900d43e17262cad2e54846c54435e290ce8b8e7 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/custom_operation.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/custom_operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/data_format.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/data_format.py index b8892d621d6c465009716813c0d4ce3010f849e6..0f79d52e5065ec93093869492ba323a67936bcd6 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/data_format.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/data_format.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ellipsoid_arc.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ellipsoid_arc.py index 550649e40a9e3c4371175299c3a22a2ef8d06372..9b065e534e33fc866ce64014a327986c52bf3708 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ellipsoid_arc.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ellipsoid_arc.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/gad_shape.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/gad_shape.py index 1bee0024fd3a619ecf1d16813f26af9a3725b324..370e1da43523b25efd6ff6b24aaf82bb884c62c5 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/gad_shape.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/gad_shape.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographic_area.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographic_area.py index 4c88245f94b88b140eeac6171d234019815855a2..226225be6b0c16d010f3b706afe4b3480c6c7b21 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographic_area.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographic_area.py @@ -1,9 +1,16 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.ellipsoid_arc import EllipsoidArc # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 +from published_apis.models.point import Point # noqa: E501 +from published_apis.models.point_altitude import PointAltitude # noqa: E501 +from published_apis.models.point_altitude_uncertainty import PointAltitudeUncertainty # noqa: E501 +from published_apis.models.point_uncertainty_circle import PointUncertaintyCircle # noqa: E501 +from published_apis.models.point_uncertainty_ellipse import PointUncertaintyEllipse # noqa: E501 +from published_apis.models.polygon import Polygon # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from published_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographical_coordinates.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographical_coordinates.py index 7ef6a2cd12e48b4c1ea27dbb6603a21b6c8a5b50..253a9089c9cb7e930ccfacafeacfe01ec8ec6171 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographical_coordinates.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/geographical_coordinates.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/interface_description.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/interface_description.py index dec959628c16f492cff126fdd8c2928b700cccda..7c8707c4f072fb8cde6149618d79f4268318439d 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/interface_description.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from published_apis.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/invalid_param.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/invalid_param.py index 4dd00c7af87dc50fe1ad6b9940c8b470f10dcae9..b7b4d5ce3dbb78a15125941d0e0fcf33d14ce649 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/invalid_param.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ip_addr_range.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ip_addr_range.py index e4bffa1c6834d9da8fadd80a9ef0a58a4e8fdbc4..48c4ede0261690c73fc09e414d7b7b9941c611ed 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ip_addr_range.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ip_addr_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv4_address_range.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv4_address_range.py index bfca85a70a36e4bc6fa708d32a8d74c889f82e04..2547d74c60efd7deabec57a76d6b54f8e78f5968 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv4_address_range.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv4_address_range.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model @@ -67,7 +67,7 @@ class Ipv4AddressRange(Model): if start is None: raise ValueError("Invalid value for `start`, must not be `None`") # noqa: E501 if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -94,6 +94,6 @@ class Ipv4AddressRange(Model): if end is None: raise ValueError("Invalid value for `end`, must not be `None`") # noqa: E501 if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_addr1.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_addr1.py index 082fbaf1aeb951e7199eb70647a2f8d39735f162..354ce4697a8d26ba5022df31632a963a3231bb6d 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_addr1.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_addr1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_address_range.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_address_range.py index 3270bfc550671772f04e9089e3c70e68cbeff70a..a28eff1fbd9d8b2f3d1f658c1eccb119ce17985a 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_address_range.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/ipv6_address_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local2d_point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local2d_point_uncertainty_ellipse.py index 777b98ed5fbc2c0337000ee68db6b003d80c1a08..2b13ab8c53823918d162de6ef89908954298d456 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local2d_point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local2d_point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.local_origin import LocalOrigin # noqa: E501 from published_apis.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local3d_point_uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local3d_point_uncertainty_ellipsoid.py index 728f69a97952fdd9d256ba460856f91bd8307d12..ca17643db139f7c8197dc2a855a196c848f6cacc 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local3d_point_uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local3d_point_uncertainty_ellipsoid.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.local_origin import LocalOrigin # noqa: E501 from published_apis.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 @@ -15,7 +16,7 @@ class Local3dPointUncertaintyEllipsoid(Model): Do not edit the class manually. """ - def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None): # noqa: E501 + def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None, v_confidence=None): # noqa: E501 """Local3dPointUncertaintyEllipsoid - a model defined in OpenAPI :param shape: The shape of this Local3dPointUncertaintyEllipsoid. # noqa: E501 @@ -28,13 +29,16 @@ class Local3dPointUncertaintyEllipsoid(Model): :type uncertainty_ellipsoid: UncertaintyEllipsoid :param confidence: The confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 :type confidence: int + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 + :type v_confidence: int """ self.openapi_types = { 'shape': SupportedGADShapes, 'local_origin': LocalOrigin, 'point': RelativeCartesianLocation, 'uncertainty_ellipsoid': UncertaintyEllipsoid, - 'confidence': int + 'confidence': int, + 'v_confidence': int } self.attribute_map = { @@ -42,7 +46,8 @@ class Local3dPointUncertaintyEllipsoid(Model): 'local_origin': 'localOrigin', 'point': 'point', 'uncertainty_ellipsoid': 'uncertaintyEllipsoid', - 'confidence': 'confidence' + 'confidence': 'confidence', + 'v_confidence': 'vConfidence' } self._shape = shape @@ -50,6 +55,7 @@ class Local3dPointUncertaintyEllipsoid(Model): self._point = point self._uncertainty_ellipsoid = uncertainty_ellipsoid self._confidence = confidence + self._v_confidence = v_confidence @classmethod def from_dict(cls, dikt) -> 'Local3dPointUncertaintyEllipsoid': @@ -182,3 +188,30 @@ class Local3dPointUncertaintyEllipsoid(Model): raise ValueError("Invalid value for `confidence`, must be a value greater than or equal to `0`") # noqa: E501 self._confidence = confidence + + @property + def v_confidence(self) -> int: + """Gets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :return: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :rtype: int + """ + return self._v_confidence + + @v_confidence.setter + def v_confidence(self, v_confidence: int): + """Sets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :type v_confidence: int + """ + if v_confidence is not None and v_confidence > 100: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value less than or equal to `100`") # noqa: E501 + if v_confidence is not None and v_confidence < 0: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value greater than or equal to `0`") # noqa: E501 + + self._v_confidence = v_confidence diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local_origin.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local_origin.py index 82df6391e1ac6b1253028f6edac90e0c7840b1ec..d86b7142076691f2bfdad4b5b5b44e1a4afc1017 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local_origin.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/local_origin.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.geographic_area import GeographicArea # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 @@ -12,26 +13,36 @@ class LocalOrigin(Model): Do not edit the class manually. """ - def __init__(self, coordinate_id=None, point=None): # noqa: E501 + def __init__(self, coordinate_id=None, point=None, area=None, horiz_axes_orientation=None): # noqa: E501 """LocalOrigin - a model defined in OpenAPI :param coordinate_id: The coordinate_id of this LocalOrigin. # noqa: E501 :type coordinate_id: str :param point: The point of this LocalOrigin. # noqa: E501 :type point: GeographicalCoordinates + :param area: The area of this LocalOrigin. # noqa: E501 + :type area: GeographicArea + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. # noqa: E501 + :type horiz_axes_orientation: int """ self.openapi_types = { 'coordinate_id': str, - 'point': GeographicalCoordinates + 'point': GeographicalCoordinates, + 'area': GeographicArea, + 'horiz_axes_orientation': int } self.attribute_map = { 'coordinate_id': 'coordinateId', - 'point': 'point' + 'point': 'point', + 'area': 'area', + 'horiz_axes_orientation': 'horizAxesOrientation' } self._coordinate_id = coordinate_id self._point = point + self._area = area + self._horiz_axes_orientation = horiz_axes_orientation @classmethod def from_dict(cls, dikt) -> 'LocalOrigin': @@ -62,6 +73,8 @@ class LocalOrigin(Model): :param coordinate_id: The coordinate_id of this LocalOrigin. :type coordinate_id: str """ + if coordinate_id is None: + raise ValueError("Invalid value for `coordinate_id`, must not be `None`") # noqa: E501 self._coordinate_id = coordinate_id @@ -85,3 +98,51 @@ class LocalOrigin(Model): """ self._point = point + + @property + def area(self) -> GeographicArea: + """Gets the area of this LocalOrigin. + + + :return: The area of this LocalOrigin. + :rtype: GeographicArea + """ + return self._area + + @area.setter + def area(self, area: GeographicArea): + """Sets the area of this LocalOrigin. + + + :param area: The area of this LocalOrigin. + :type area: GeographicArea + """ + + self._area = area + + @property + def horiz_axes_orientation(self) -> int: + """Gets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :return: The horiz_axes_orientation of this LocalOrigin. + :rtype: int + """ + return self._horiz_axes_orientation + + @horiz_axes_orientation.setter + def horiz_axes_orientation(self, horiz_axes_orientation: int): + """Sets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. + :type horiz_axes_orientation: int + """ + if horiz_axes_orientation is not None and horiz_axes_orientation > 3600: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value less than or equal to `3600`") # noqa: E501 + if horiz_axes_orientation is not None and horiz_axes_orientation < 0: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value greater than or equal to `0`") # noqa: E501 + + self._horiz_axes_orientation = horiz_axes_orientation diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..a61d636f96cf630eea524d82a1b66e01a92d2761 --- /dev/null +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from published_apis import util +from published_apis.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/operation.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/operation.py index c59a6702cbbb5458c6fb9df20adf3969f0f18006..abfa0c2274c1fccd47f7d9b6d9b33fb98bee3ca8 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/operation.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point.py index 433aa9e86eed54a6499d9592629ee17d96d8cf12..b0d7a764fe3f9ea0c8949c3694bd0c875378b912 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude.py index 7bfb24aea35a99d1598137df1cb78f603953e66b..7fd826c19e66f439059bbf63ce60c22732da0a1f 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude_uncertainty.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude_uncertainty.py index 9bc6dbd52c146d8a6b477ec6d520f9c62c9fe00d..98b36ca7499c574f0c07f8afbb79c3c5373be86d 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude_uncertainty.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_altitude_uncertainty.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from published_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_circle.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_circle.py index 7b15b671711acb96bf78cb2d285aa43c89613f9c..477dfae0a5dc41fc9de892511f8826cdbf56f0d9 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_circle.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_circle.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_ellipse.py index 13c8e1b728b0c0e5c1aa77b258e8b3eec1601aaa..1e328c073b5bf6e476e872d24a34fd95e26d0539 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/point_uncertainty_ellipse.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from published_apis.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/polygon.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/polygon.py index d4ce9418c9f81429e04d259f481296f6b0fb84d0..d021ee3b87fe4b369133ee5793bcef43e6c7aa22 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/polygon.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/polygon.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model +from published_apis.models.gad_shape import GADShape # noqa: E501 from published_apis.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from published_apis.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/problem_details.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/problem_details.py index ac7c9ee947d49dbbf350ba9b552285d5192504a0..39abad6a1db12b1b640c33deea95e56eaae3674a 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/problem_details.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/protocol.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/protocol.py index dc6ae7eb66a5790f3ad46a5469d3e3edaa5adc50..011e1942fce34f3b749ae9bf7d7bebc08be298ff 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/protocol.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/published_api_path.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/published_api_path.py index a76f56fae938dacb1734239ba6e81cdf70038454..8e02d4859804bce2851a8290edbeb45be9941870 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/published_api_path.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/published_api_path.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/relative_cartesian_location.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/relative_cartesian_location.py index 35c9dbf5b7190a018396cd9529d63e23829b752f..0d1e9116e2b1b158d4ffdec945b53d4401035a7a 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/relative_cartesian_location.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/relative_cartesian_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/resource.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/resource.py index 6c8d09d8689135cde8c056ccb40395e5a233eaf2..d00e3ee8a4b0ace5c27b9cec789beb91f0530b2c 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/resource.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/resource.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/security_method.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/security_method.py index 01847e2b25c67b269906c42ed1c1bcda2cb2823c..97c264ab4b5795168820700c331d712acceb3b59 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/security_method.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py index e50c9e0156d90e4b43dc914951ff08f787b8e186..3f97250d39f8451513b1ff6905f7dfff8a4258b1 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.aef_profile import AefProfile # noqa: E501 @@ -87,24 +87,6 @@ class ServiceAPIDescription(Model): self._ccf_id = ccf_id self._api_prov_name = api_prov_name - @classmethod - def return_supp_feat_dict(cls, supp_feat): - TOTAL_FEATURES = 9 - supp_feat_in_hex = int(supp_feat, 16) - supp_feat_in_bin = bin(supp_feat_in_hex)[2:].zfill(TOTAL_FEATURES)[::-1] - - - return { - "ApiSupportedFeaturePublishing": True if supp_feat_in_bin[0] == "1" else False, - "PatchUpdate": True if supp_feat_in_bin[1] == "1" else False, - "ExtendedIntfDesc": True if supp_feat_in_bin[2] == "1" else False, - "MultipleCustomOperations": True if supp_feat_in_bin[3] == "1" else False, - "ProtocDataFormats_Ext1": True if supp_feat_in_bin[4] == "1" else False, - "ApiStatusMonitoring": True if supp_feat_in_bin[5] == "1" else False, - "EdgeApp_2": True if supp_feat_in_bin[6] == "1" else False, - "RNAA": True if supp_feat_in_bin[7] == "1" else False, - "VendorExt": True if supp_feat_in_bin[8] == "1" else False - } @classmethod def from_dict(cls, dikt) -> 'ServiceAPIDescription': @@ -255,7 +237,7 @@ class ServiceAPIDescription(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features @@ -324,7 +306,7 @@ class ServiceAPIDescription(Model): :type api_supp_feats: str """ if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 - raise ValueError("Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._api_supp_feats = api_supp_feats diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description_patch.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description_patch.py index d812d30d0c2d01195a9b3a1d8e13533df9900d60..283a1a0791a6f6f1b6f591a081b7f87b9dfe6fb0 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description_patch.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_api_description_patch.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.aef_profile import AefProfile # noqa: E501 @@ -212,7 +212,7 @@ class ServiceAPIDescriptionPatch(Model): :type api_supp_feats: str """ if api_supp_feats is not None and not re.search(r'^[A-Fa-f0-9]*$', api_supp_feats): # noqa: E501 - raise ValueError("Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `api_supp_feats`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._api_supp_feats = api_supp_feats diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_kpis.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_kpis.py index 2d0b3c17db4afbc15b0b13d915399174cd6b9cc8..ac1a773e675c9607fbe6ecb9862f4c92cfe4abdd 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_kpis.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/service_kpis.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model @@ -170,7 +170,7 @@ class ServiceKpis(Model): :type aval_comp: str """ if aval_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_comp = aval_comp @@ -195,7 +195,7 @@ class ServiceKpis(Model): :type aval_gra_comp: str """ if aval_gra_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_gra_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_gra_comp = aval_gra_comp @@ -220,7 +220,7 @@ class ServiceKpis(Model): :type aval_mem: str """ if aval_mem is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_mem): # noqa: E501 - raise ValueError("Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_mem = aval_mem @@ -245,7 +245,7 @@ class ServiceKpis(Model): :type aval_stor: str """ if aval_stor is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_stor): # noqa: E501 - raise ValueError("Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_stor = aval_stor diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/shareable_information.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/shareable_information.py index 548e3753599f8f5140d3f4fc30815af64dd70e03..a2dfbeaf55bb62c23ae192b2811662d34aa15690 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/shareable_information.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/shareable_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/supported_gad_shapes.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/supported_gad_shapes.py index 7b5da39915dde3f281e64fed7538a37ec001d0b4..095abd0a7e66febeb50854297069f72e3f733ff3 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/supported_gad_shapes.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/supported_gad_shapes.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipse.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipse.py index 7fc3e1720fe863c3e4fcf1a5e108266b2377005f..44957aa6658285616b2c203fd727239b7b357a47 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipse.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipsoid.py index 7a89fe9675241a553b87ce3a27e81e53dbaa7547..0a34178324ae19541d8de1436ed837bf20dec49c 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/uncertainty_ellipsoid.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/version.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/version.py index a53e20f2d53c692458e5042c6f57659efd32be3d..4188ad7993ce37586e783b92532850928abad182 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/version.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/models/version.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from published_apis import util from published_apis.models.base_model import Model diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/openapi/openapi.yaml b/services/TS29222_CAPIF_Publish_Service_API/published_apis/openapi/openapi.yaml index 041eed50493715bf874d53f509ae22769e7a3d11..6fd9b48632d3bc98c7de20ed0a7ac3f16f1897f4 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/openapi/openapi.yaml @@ -3,9 +3,9 @@ info: description: "API for publishing service APIs. \n© 2024, 3GPP Organizational Partners\ \ (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Publish_Service_API - version: 1.3.0-alpha.5 + version: 1.3.1 externalDocs: - description: 3GPP TS 29.222 V18.5.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.7.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/published-apis/v1" @@ -715,6 +715,9 @@ components: - aefIds aefProfiles: - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -893,6 +896,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -901,6 +907,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -918,6 +927,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp - protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1096,6 +1108,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1104,6 +1119,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1185,6 +1203,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1193,13 +1214,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: - - required: - - ipv4Addr - - required: - - ipv6Addr - - required: - - fqdn + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -1238,12 +1256,21 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object AefProfile: description: Represents the AEF profile data. example: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1422,6 +1449,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1430,6 +1460,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1447,11 +1480,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp nullable: true - oneOf: - - required: - - domainName - - required: - - interfaceDescriptions + oneOf: + - required: ["domainName"] + - required: ["interfaceDescriptions"] properties: aefId: description: Identifier of the API exposing function @@ -1475,6 +1506,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array domainName: description: Domain to which API belongs to title: domainName @@ -1907,7 +1944,9 @@ components: title: ServiceKpis type: object IpAddrRange: - anyOf: [] + anyOf: + - required: ["ueIpv4AddrRanges"] + - required: ["ueIpv6AddrRanges"] description: Represents the list of public IP ranges example: ueIpv4AddrRanges: @@ -1939,16 +1978,12 @@ components: title: IpAddrRange type: object Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -1956,61 +1991,45 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol CommunicationType: - anyOf: - - enum: + enum: - REQUEST_RESPONSE - SUBSCRIBE_NOTIFY - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a communication type of the resource or the custom operation.\ \ \nPossible values are:\n- REQUEST_RESPONSE: The communication is of the\ \ type request-response.\n- SUBSCRIBE_NOTIFY: The communication is of the\ \ type subscribe-notify.\n" title: CommunicationType DataFormat: - anyOf: - - enum: + enum: - JSON - XML - PROTOBUF3 - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a data format. \nPossible values are:\n- JSON: Indicates\ \ that the data format is JSON.\n- XML: Indicates that the data format is\ \ Extensible Markup Language.\n- PROTOBUF3: Indicates that the data format\ \ is Protocol buffers version 3.\n" title: DataFormat SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ \ Security method 3 (TLS with OAuth token) as described in 3GPP TS 33.122.\n" title: SecurityMethod Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" @@ -2112,6 +2131,19 @@ components: minimum: 0 title: Port type: integer + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType DateTime: description: string with format "date-time" as defined in OpenAPI. format: date-time @@ -2308,8 +2340,7 @@ components: title: GADShape type: object SupportedGADShapes: - anyOf: - - enum: + enum: - POINT - POINT_UNCERTAINTY_CIRCLE - POINT_UNCERTAINTY_ELLIPSE @@ -2322,8 +2353,8 @@ components: - DISTANCE_DIRECTION - RELATIVE_2D_LOCATION_UNCERTAINTY_ELLIPSE - RELATIVE_3D_LOCATION_UNCERTAINTY_ELLIPSOID - type: string - - type: string + + type: string description: Indicates supported GAD shapes. title: SupportedGADShapes PointUncertaintyCircle: @@ -2551,8 +2582,26 @@ components: type: string point: $ref: '#/components/schemas/GeographicalCoordinates' + area: + $ref: '#/components/schemas/GeographicArea' + horizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in + 0.1 degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer + required: + - coordinateId title: LocalOrigin type: object + HorizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in 0.1 + degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer RelativeCartesianLocation: description: Relative Cartesian Location properties: @@ -2588,6 +2637,8 @@ components: $ref: '#/components/schemas/UncertaintyEllipsoid' confidence: $ref: '#/components/schemas/Confidence' + vConfidence: + $ref: '#/components/schemas/Confidence' required: - confidence - localOrigin @@ -2687,9 +2738,6 @@ components: title: Ipv6AddressRange type: object Ipv6Addr_1: - allOf: - - pattern: "^((:|(0?|([1-9a-f][0-9a-f]{0,3}))):)((0?|([1-9a-f][0-9a-f]{0,3})):){0,6}(:|(0?|([1-9a-f][0-9a-f]{0,3})))$" - - pattern: "^((([^:]+:){7}([^:]+))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))$" description: | String identifying an IPv6 address formatted according to clause 4 of RFC5952. The mixed IPv4 IPv6 notation according to clause 5 of RFC5952 shall not be used. example: 2001:db8:85a3::8a2e:370:7334 diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_default_controller.py index 7f824b920aa117a74730d8d5cb6a7236e729534a..aa3a20d40b74688c95ec3c6258472fa735487f0d 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_default_controller.py @@ -1,6 +1,8 @@ import unittest from flask import json +from published_apis.models.problem_details import ProblemDetails # noqa: E501 +from published_apis.models.service_api_description import ServiceAPIDescription # noqa: E501 from published_apis.test import BaseTestCase @@ -27,7 +29,7 @@ class TestDefaultController(BaseTestCase): """ - service_api_description = {"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}} + service_api_description = {"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', @@ -76,7 +78,7 @@ class TestDefaultController(BaseTestCase): """ - service_api_description = {"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}} + service_api_description = {"serviceAPICategory":"serviceAPICategory","ccfId":"ccfId","apiName":"apiName","shareableInfo":{"capifProvDoms":["capifProvDoms","capifProvDoms"],"isShareable":True},"apiProvName":"apiProvName","supportedFeatures":"supportedFeatures","description":"description","apiSuppFeats":"apiSuppFeats","apiId":"apiId","apiStatus":{"aefIds":["aefIds","aefIds"]},"aefProfiles":[{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}},{"protocol":"HTTP_1_1","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"ueIpRange":{"ueIpv4AddrRanges":[{"start":"198.51.100.1","end":"198.51.100.1"},{"start":"198.51.100.1","end":"198.51.100.1"}],"ueIpv6AddrRanges":[{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"},{"start":"2001:db8:85a3::8a2e:370:7334","end":"2001:db8:85a3::8a2e:370:7334"}]},"securityMethods":["PSK","PSK"],"versions":[{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"},{"apiVersion":"apiVersion","resources":[{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"},{"operations":[null,null],"commType":"REQUEST_RESPONSE","custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"description":"description","resourceName":"resourceName","custOpName":"custOpName","uri":"uri"}],"custOperations":[{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"},{"operations":["GET","GET"],"description":"description","custOpName":"custOpName"}],"expiry":"2000-01-23T04:56:07.000+00:00"}],"dataFormat":"JSON","domainName":"domainName","aefLocation":{"dcId":"dcId","geoArea":{"shape":"POINT","point":{"lon":36.988422590534526,"lat":-63.615366350946985}},"civicAddr":{"POBOX":"POBOX","usageRules":"usageRules","country":"country","PRD":"PRD","PLC":"PLC","HNO":"HNO","PRM":"PRM","HNS":"HNS","FLR":"FLR","A1":"A1","A2":"A2","A3":"A3","A4":"A4","STS":"STS","A5":"A5","A6":"A6","RDSEC":"RDSEC","providedBy":"providedBy","LOC":"LOC","UNIT":"UNIT","SEAT":"SEAT","POD":"POD","RDBR":"RDBR","method":"method","LMK":"LMK","POM":"POM","ADDCODE":"ADDCODE","RD":"RD","PC":"PC","PCN":"PCN","NAM":"NAM","BLD":"BLD","ROOM":"ROOM","RDSUBBR":"RDSUBBR"}},"aefId":"aefId","interfaceDescriptions":[{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},{"ipv6Addr":"ipv6Addr","grantTypes":[null,null],"securityMethods":[null,null],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"}],"serviceKpis":{"avalMem":"avalMem","avalStor":"avalStor","avalComp":"avalComp","conBand":0,"maxRestime":0,"availability":0,"maxReqRate":0,"avalGraComp":"avalGraComp"}}],"pubApiPath":{"ccfIds":["ccfIds","ccfIds"]}} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_individual_apf_published_api_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_individual_apf_published_api_controller.py index 76ef07950be6c5c7741944d89558faa4c457d238..c9664f15017ceed886888771eb336d2eba60dd60 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_individual_apf_published_api_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/test/test_individual_apf_published_api_controller.py @@ -1,6 +1,9 @@ import unittest from flask import json +from published_apis.models.problem_details import ProblemDetails # noqa: E501 +from published_apis.models.service_api_description import ServiceAPIDescription # noqa: E501 +from published_apis.models.service_api_description_patch import ServiceAPIDescriptionPatch # noqa: E501 from published_apis.test import BaseTestCase diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/typing_utils.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/typing_utils.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/vendor_specific.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/vendor_specific.py index 21fd6b6d0a6676e5a1b19efbaaf0adec32e694d4..97cfd8001ffa56350b21ebcedb9f5b9ba83a694e 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/vendor_specific.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/vendor_specific.py @@ -1,5 +1,6 @@ import re + def find_attribute_in_body(test, path): f_key = [] if type(test) == dict: diff --git a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt index 0496b8e4b3591b45b7f93c1b60ba8c10807f6e5e..73be6c5fc1a99d4511cb803ed2df4131fe2f5404 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt +++ b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt @@ -20,6 +20,6 @@ opentelemetry-sdk == 1.17.0 flask_executor == 1.0.0 Flask-APScheduler == 1.13.1 werkzeug == 3.0.4 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_Publish_Service_API/setup.py b/services/TS29222_CAPIF_Publish_Service_API/setup.py index 8b1c991255816f36ad3ecced8745484a6162e5a6..9cd039a1bc7640b1fd10d53f0531b12407a742f5 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/setup.py +++ b/services/TS29222_CAPIF_Publish_Service_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "published_apis" VERSION = "1.0.0" diff --git a/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/FILES index be8f43b72f15e9d43510b5fa60ebd25e0872a090..850cbed46d8e4ac07390cf5d14736db4d0d18d56 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/FILES @@ -34,6 +34,7 @@ capif_routing_info/models/ipv6_address_range1.py capif_routing_info/models/local2d_point_uncertainty_ellipse.py capif_routing_info/models/local3d_point_uncertainty_ellipsoid.py capif_routing_info/models/local_origin.py +capif_routing_info/models/o_auth_grant_type.py capif_routing_info/models/operation.py capif_routing_info/models/point.py capif_routing_info/models/point_altitude.py diff --git a/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Routing_Info_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Routing_Info_API/README.md b/services/TS29222_CAPIF_Routing_Info_API/README.md index edacb4a6f8839ed6e00ca6b7250bd7aca3d9df43..b239418e6ca48afcab32df49aeb265a57a253a3c 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/README.md +++ b/services/TS29222_CAPIF_Routing_Info_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m capif_routing_info ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/app.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/app.py index 48e8769b25cbe6c591bc4486b116d21def6a8fe0..4df40da69432a169b724788f808ba260a0d775f0 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/app.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/app.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import connexion - import encoder app = connexion.App(__name__, specification_dir='openapi/') diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/default_controller.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/default_controller.py index 9dafc055a9b0e9e95accef08aaf07610d76331ac..575fc24577116a078df5342b9a1462681ebc80e1 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/default_controller.py @@ -1,11 +1,6 @@ -import connexion -from typing import Dict -from typing import Tuple -from typing import Union from capif_routing_info.models.problem_details import ProblemDetails # noqa: E501 from capif_routing_info.models.routing_info import RoutingInfo # noqa: E501 -from capif_routing_info import util def service_apis_service_api_id_get(service_api_id, aef_id, supp_feat=None): # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/security_controller.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/security_controller.py index 6d294ffd6df1a26a469dbb4e72533b01503468dd..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/security_controller.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/controllers/security_controller.py @@ -1,2 +1 @@ -from typing import List diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/encoder.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/encoder.py index ba7c4d5e37a65102002ee1a785da9eb1e49da013..61d252c5e965bac05ac1b9bd589e72b70023b516 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/encoder.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/encoder.py @@ -1,7 +1,5 @@ -from connexion.jsonifier import JSONEncoder -import six - from capif_routing_info.models.base_model import Model +from connexion.jsonifier import JSONEncoder class CustomJSONEncoder(JSONEncoder): diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_location.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_location.py index f0e756be690433fcf944def5f64229fd20e75748..aede9133a325c6682962fc375903c6acadcd0ead 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_location.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_location.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_profile.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_profile.py index ccf24ad69e698692adb1f873fa673cd204a7b6fe..62efcf1933982f08fdec8ac9ba615ee15cf59186 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_profile.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/aef_profile.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.aef_location import AefLocation # noqa: E501 @@ -7,6 +7,7 @@ from capif_routing_info.models.base_model import Model from capif_routing_info.models.data_format import DataFormat # noqa: E501 from capif_routing_info.models.interface_description import InterfaceDescription # noqa: E501 from capif_routing_info.models.ip_addr_range import IpAddrRange # noqa: E501 +from capif_routing_info.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from capif_routing_info.models.protocol import Protocol # noqa: E501 from capif_routing_info.models.security_method import SecurityMethod # noqa: E501 from capif_routing_info.models.service_kpis import ServiceKpis # noqa: E501 @@ -19,7 +20,7 @@ class AefProfile(Model): Do not edit the class manually. """ - def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 + def __init__(self, aef_id=None, versions=None, protocol=None, data_format=None, security_methods=None, grant_types=None, domain_name=None, interface_descriptions=None, aef_location=None, service_kpis=None, ue_ip_range=None): # noqa: E501 """AefProfile - a model defined in OpenAPI :param aef_id: The aef_id of this AefProfile. # noqa: E501 @@ -32,6 +33,8 @@ class AefProfile(Model): :type data_format: DataFormat :param security_methods: The security_methods of this AefProfile. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this AefProfile. # noqa: E501 + :type grant_types: List[OAuthGrantType] :param domain_name: The domain_name of this AefProfile. # noqa: E501 :type domain_name: str :param interface_descriptions: The interface_descriptions of this AefProfile. # noqa: E501 @@ -49,6 +52,7 @@ class AefProfile(Model): 'protocol': Protocol, 'data_format': DataFormat, 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType], 'domain_name': str, 'interface_descriptions': List[InterfaceDescription], 'aef_location': AefLocation, @@ -62,6 +66,7 @@ class AefProfile(Model): 'protocol': 'protocol', 'data_format': 'dataFormat', 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes', 'domain_name': 'domainName', 'interface_descriptions': 'interfaceDescriptions', 'aef_location': 'aefLocation', @@ -74,6 +79,7 @@ class AefProfile(Model): self._protocol = protocol self._data_format = data_format self._security_methods = security_methods + self._grant_types = grant_types self._domain_name = domain_name self._interface_descriptions = interface_descriptions self._aef_location = aef_location @@ -210,6 +216,29 @@ class AefProfile(Model): self._security_methods = security_methods + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this AefProfile. + + + :return: The grant_types of this AefProfile. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this AefProfile. + + + :param grant_types: The grant_types of this AefProfile. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types + @property def domain_name(self) -> str: """Gets the domain_name of this AefProfile. diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/civic_address.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/civic_address.py index e12616c961824a301b1af41fe3dbf471ec6ba956..46b947c1d84995f8b1c124e2f7d3a9557e085804 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/civic_address.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/civic_address.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/communication_type.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/communication_type.py index 02f3063dda850439667db3d3ee6a07c28d7be1e9..84355f1b16295dc3d0eb46736fc35494b5b1fe12 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/communication_type.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/communication_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/custom_operation.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/custom_operation.py index 6ea6b7059ce6f8d02a9b784008d62a95731d4e2f..d6a2f42a3104b9149eafe68ef56b6fbaa00e9ce4 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/custom_operation.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/custom_operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/data_format.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/data_format.py index 3b453d17bc4f39e447f89c96913113c721558905..8c400e5eca82cd8eaa526c92d6c2ee2e2c503a5a 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/data_format.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/data_format.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ellipsoid_arc.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ellipsoid_arc.py index 790d70a094bdf1a4de495c033be74595d004de61..246c731e1ce7b941bed67947d7a8106555fb41f1 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ellipsoid_arc.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ellipsoid_arc.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/gad_shape.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/gad_shape.py index de28747699d8840f565a4408119912eee256510f..c4606e3addf004a87ad47faee99e0125aaae8a54 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/gad_shape.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/gad_shape.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographic_area.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographic_area.py index f0fd6607f0701b96db86c9be546b1f1cb823114b..83b2f60ac2c2c0dcb7aa3ec96295a4b3a8844536 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographic_area.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographic_area.py @@ -1,9 +1,16 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.ellipsoid_arc import EllipsoidArc # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 +from capif_routing_info.models.point import Point # noqa: E501 +from capif_routing_info.models.point_altitude import PointAltitude # noqa: E501 +from capif_routing_info.models.point_altitude_uncertainty import PointAltitudeUncertainty # noqa: E501 +from capif_routing_info.models.point_uncertainty_circle import PointUncertaintyCircle # noqa: E501 +from capif_routing_info.models.point_uncertainty_ellipse import PointUncertaintyEllipse # noqa: E501 +from capif_routing_info.models.polygon import Polygon # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographical_coordinates.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographical_coordinates.py index 8b0e51f2785d65a76975f5d71d8d1dfa80570f15..e33c892b620f5856605531a3bf763710ce4c034c 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographical_coordinates.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/geographical_coordinates.py @@ -1,9 +1,8 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model from capif_routing_info import util +from capif_routing_info.models.base_model import Model class GeographicalCoordinates(Model): diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/interface_description.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/interface_description.py index 6d0075be6c8732003d5184a3993e5df6e3183dd0..e895f9dbcdf8be5e5d76d0369930157e830518a9 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/interface_description.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from capif_routing_info.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/invalid_param.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/invalid_param.py index 3014346fa88dc43513de02189977734f0fc0fcd2..b42e24b5f26b70398fca28d2d275e01e7bdbda73 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/invalid_param.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ip_addr_range.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ip_addr_range.py index 6fa0acf3a648c993cc37968a0925723c3406d460..b9869baf6afd0fb77d256742e9a28f79fcfef4de 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ip_addr_range.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ip_addr_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range.py index a8025b6cb70da8555be363e1ac5ef1a59026ff85..cdde631bae1ca0c5aea3bd55598169fa48aefd18 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model @@ -65,7 +65,7 @@ class Ipv4AddressRange(Model): :type start: str """ if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -90,6 +90,6 @@ class Ipv4AddressRange(Model): :type end: str """ if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range1.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range1.py index ebb34a4abaf993a285dc769286c65b7f9db34367..beae3e04e7eb4885252671709d62cdf676990d4e 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range1.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv4_address_range1.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model @@ -67,7 +67,7 @@ class Ipv4AddressRange1(Model): if start is None: raise ValueError("Invalid value for `start`, must not be `None`") # noqa: E501 if start is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', start): # noqa: E501 - raise ValueError("Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `start`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._start = start @@ -94,6 +94,6 @@ class Ipv4AddressRange1(Model): if end is None: raise ValueError("Invalid value for `end`, must not be `None`") # noqa: E501 if end is not None and not re.search(r'^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$', end): # noqa: E501 - raise ValueError("Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 + raise ValueError(r"Invalid value for `end`, must be a follow pattern or equal to `/^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/`") # noqa: E501 self._end = end diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_addr1.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_addr1.py index a08058027ebdc12cff398ed5b394e83bc9791fb0..bfe953152e3f1792dfc4863ea4d054a8522eec8c 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_addr1.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_addr1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range.py index 2067eb2d4600f322d0bce17c8676ce28733ede39..c419f267679d7414833d8da2c2e001ee734f7080 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range1.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range1.py index 270b9ac93a0ccf3bc6f4586f262595b80880f9ff..2efedbc22e95a5112548ff7516d5ff22f263183f 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range1.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/ipv6_address_range1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local2d_point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local2d_point_uncertainty_ellipse.py index c9b258b16c56b4118051ac79c9ddeb7d99cc4074..e1f2f11d61ce3df625961983b7533b92257c9306 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local2d_point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local2d_point_uncertainty_ellipse.py @@ -1,21 +1,15 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model -from capif_routing_info.models.gad_shape import GADShape -from capif_routing_info.models.local_origin import LocalOrigin -from capif_routing_info.models.relative_cartesian_location import RelativeCartesianLocation -from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes -from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse from capif_routing_info import util - +from capif_routing_info.models.base_model import Model from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.local_origin import LocalOrigin # noqa: E501 from capif_routing_info.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 + class Local2dPointUncertaintyEllipse(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local3d_point_uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local3d_point_uncertainty_ellipsoid.py index 2539de2ce701974bc68b9d0873ef30d0eb853fa0..f494ead2a284323f4f0eafe2d8214cd73c23a096 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local3d_point_uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local3d_point_uncertainty_ellipsoid.py @@ -1,28 +1,22 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model -from capif_routing_info.models.gad_shape import GADShape -from capif_routing_info.models.local_origin import LocalOrigin -from capif_routing_info.models.relative_cartesian_location import RelativeCartesianLocation -from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes -from capif_routing_info.models.uncertainty_ellipsoid import UncertaintyEllipsoid from capif_routing_info import util - +from capif_routing_info.models.base_model import Model from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.local_origin import LocalOrigin # noqa: E501 from capif_routing_info.models.relative_cartesian_location import RelativeCartesianLocation # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_routing_info.models.uncertainty_ellipsoid import UncertaintyEllipsoid # noqa: E501 + class Local3dPointUncertaintyEllipsoid(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). Do not edit the class manually. """ - def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None): # noqa: E501 + def __init__(self, shape=None, local_origin=None, point=None, uncertainty_ellipsoid=None, confidence=None, v_confidence=None): # noqa: E501 """Local3dPointUncertaintyEllipsoid - a model defined in OpenAPI :param shape: The shape of this Local3dPointUncertaintyEllipsoid. # noqa: E501 @@ -35,13 +29,16 @@ class Local3dPointUncertaintyEllipsoid(Model): :type uncertainty_ellipsoid: UncertaintyEllipsoid :param confidence: The confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 :type confidence: int + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. # noqa: E501 + :type v_confidence: int """ self.openapi_types = { 'shape': SupportedGADShapes, 'local_origin': LocalOrigin, 'point': RelativeCartesianLocation, 'uncertainty_ellipsoid': UncertaintyEllipsoid, - 'confidence': int + 'confidence': int, + 'v_confidence': int } self.attribute_map = { @@ -49,7 +46,8 @@ class Local3dPointUncertaintyEllipsoid(Model): 'local_origin': 'localOrigin', 'point': 'point', 'uncertainty_ellipsoid': 'uncertaintyEllipsoid', - 'confidence': 'confidence' + 'confidence': 'confidence', + 'v_confidence': 'vConfidence' } self._shape = shape @@ -57,6 +55,7 @@ class Local3dPointUncertaintyEllipsoid(Model): self._point = point self._uncertainty_ellipsoid = uncertainty_ellipsoid self._confidence = confidence + self._v_confidence = v_confidence @classmethod def from_dict(cls, dikt) -> 'Local3dPointUncertaintyEllipsoid': @@ -189,3 +188,30 @@ class Local3dPointUncertaintyEllipsoid(Model): raise ValueError("Invalid value for `confidence`, must be a value greater than or equal to `0`") # noqa: E501 self._confidence = confidence + + @property + def v_confidence(self) -> int: + """Gets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :return: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :rtype: int + """ + return self._v_confidence + + @v_confidence.setter + def v_confidence(self, v_confidence: int): + """Sets the v_confidence of this Local3dPointUncertaintyEllipsoid. + + Indicates value of confidence. # noqa: E501 + + :param v_confidence: The v_confidence of this Local3dPointUncertaintyEllipsoid. + :type v_confidence: int + """ + if v_confidence is not None and v_confidence > 100: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value less than or equal to `100`") # noqa: E501 + if v_confidence is not None and v_confidence < 0: # noqa: E501 + raise ValueError("Invalid value for `v_confidence`, must be a value greater than or equal to `0`") # noqa: E501 + + self._v_confidence = v_confidence diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local_origin.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local_origin.py index 8eb4a75aa3736a6a1c1c3ed99035c8ace4ed5441..a301c3ac640d9b878e32f090d0f740cc491d4be8 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local_origin.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/local_origin.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.geographic_area import GeographicArea # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 @@ -12,26 +13,36 @@ class LocalOrigin(Model): Do not edit the class manually. """ - def __init__(self, coordinate_id=None, point=None): # noqa: E501 + def __init__(self, coordinate_id=None, point=None, area=None, horiz_axes_orientation=None): # noqa: E501 """LocalOrigin - a model defined in OpenAPI :param coordinate_id: The coordinate_id of this LocalOrigin. # noqa: E501 :type coordinate_id: str :param point: The point of this LocalOrigin. # noqa: E501 :type point: GeographicalCoordinates + :param area: The area of this LocalOrigin. # noqa: E501 + :type area: GeographicArea + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. # noqa: E501 + :type horiz_axes_orientation: int """ self.openapi_types = { 'coordinate_id': str, - 'point': GeographicalCoordinates + 'point': GeographicalCoordinates, + 'area': GeographicArea, + 'horiz_axes_orientation': int } self.attribute_map = { 'coordinate_id': 'coordinateId', - 'point': 'point' + 'point': 'point', + 'area': 'area', + 'horiz_axes_orientation': 'horizAxesOrientation' } self._coordinate_id = coordinate_id self._point = point + self._area = area + self._horiz_axes_orientation = horiz_axes_orientation @classmethod def from_dict(cls, dikt) -> 'LocalOrigin': @@ -62,6 +73,8 @@ class LocalOrigin(Model): :param coordinate_id: The coordinate_id of this LocalOrigin. :type coordinate_id: str """ + if coordinate_id is None: + raise ValueError("Invalid value for `coordinate_id`, must not be `None`") # noqa: E501 self._coordinate_id = coordinate_id @@ -85,3 +98,51 @@ class LocalOrigin(Model): """ self._point = point + + @property + def area(self) -> GeographicArea: + """Gets the area of this LocalOrigin. + + + :return: The area of this LocalOrigin. + :rtype: GeographicArea + """ + return self._area + + @area.setter + def area(self, area: GeographicArea): + """Sets the area of this LocalOrigin. + + + :param area: The area of this LocalOrigin. + :type area: GeographicArea + """ + + self._area = area + + @property + def horiz_axes_orientation(self) -> int: + """Gets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :return: The horiz_axes_orientation of this LocalOrigin. + :rtype: int + """ + return self._horiz_axes_orientation + + @horiz_axes_orientation.setter + def horiz_axes_orientation(self, horiz_axes_orientation: int): + """Sets the horiz_axes_orientation of this LocalOrigin. + + Horizontal axes orientation angle clockwise from northing in 0.1 degrees. # noqa: E501 + + :param horiz_axes_orientation: The horiz_axes_orientation of this LocalOrigin. + :type horiz_axes_orientation: int + """ + if horiz_axes_orientation is not None and horiz_axes_orientation > 3600: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value less than or equal to `3600`") # noqa: E501 + if horiz_axes_orientation is not None and horiz_axes_orientation < 0: # noqa: E501 + raise ValueError("Invalid value for `horiz_axes_orientation`, must be a value greater than or equal to `0`") # noqa: E501 + + self._horiz_axes_orientation = horiz_axes_orientation diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/o_auth_grant_type.py new file mode 100644 index 0000000000000000000000000000000000000000..eabc37f6c2f9293968dbff73bb44a820618092b6 --- /dev/null +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/o_auth_grant_type.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from capif_routing_info import util +from capif_routing_info.models.base_model import Model + + +class OAuthGrantType(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """OAuthGrantType - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'OAuthGrantType': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The OAuthGrantType of this OAuthGrantType. # noqa: E501 + :rtype: OAuthGrantType + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/operation.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/operation.py index 3e0511a1860ec3f6d451cf77f5e7655c10d6fd75..b72c36a01e02f240f217b4b8cfe23f89f556a976 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/operation.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/operation.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point.py index 471c405c488739b2ea9b8bed187d30e82391a532..a6f38782a4c13997bc91c54e2193460d06ce0b4a 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude.py index 8524f90298135d054c687cc304afb06753a32624..72156c95accd736576d9ae3f9af19da600a925fb 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude_uncertainty.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude_uncertainty.py index fdcea5e2713a88881a422e4fc1a2172b9aef963d..63f0459a392fb043ae96cb1cf1ce38ed92a5bc90 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude_uncertainty.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_altitude_uncertainty.py @@ -1,19 +1,14 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model -from capif_routing_info.models.gad_shape import GADShape -from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates -from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes -from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse from capif_routing_info import util - +from capif_routing_info.models.base_model import Model from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 + class PointAltitudeUncertainty(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_circle.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_circle.py index 80faac436162d573d9f9ace49bbeec0a11cc21ca..7a7e2cd8a9a79b045d83da05ca8fc94382fdfbdf 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_circle.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_circle.py @@ -1,17 +1,13 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model -from capif_routing_info.models.gad_shape import GADShape -from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates -from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes from capif_routing_info import util - +from capif_routing_info.models.base_model import Model from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 + class PointUncertaintyCircle(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_ellipse.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_ellipse.py index 03c55bf712de32ce6a2f6ac845c783e0d353b1ed..df2712164c10f378ffb3380df1db8add3ecb5c77 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/point_uncertainty_ellipse.py @@ -1,19 +1,14 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model -from capif_routing_info.models.gad_shape import GADShape -from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates -from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes -from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse from capif_routing_info import util - +from capif_routing_info.models.base_model import Model from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 from capif_routing_info.models.uncertainty_ellipse import UncertaintyEllipse # noqa: E501 + class PointUncertaintyEllipse(Model): """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/polygon.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/polygon.py index 977b02264d6e0f1988660ce5423fd4f96b9ffaf8..c4e0ed43a1c612faba708efb6da736053a3ac850 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/polygon.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/polygon.py @@ -1,8 +1,9 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model +from capif_routing_info.models.gad_shape import GADShape # noqa: E501 from capif_routing_info.models.geographical_coordinates import GeographicalCoordinates # noqa: E501 from capif_routing_info.models.supported_gad_shapes import SupportedGADShapes # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/problem_details.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/problem_details.py index e2a91365ae14fe297d8c12b6a2b54a31b07566c7..d095ab5a0f7869c35f0e371b003887d381589a82 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/problem_details.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/protocol.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/protocol.py index 48cda2a8fbf79ffff6fde64dc11a85029db46d18..59c0a37d65d9834f28d5b103cc96e5120898a377 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/protocol.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/protocol.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/relative_cartesian_location.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/relative_cartesian_location.py index 592f4bc6f6168af43830e8f6f7c19403e3d11d3b..b71e9ce1b4cc9c9080fde9c332331730c98984ae 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/relative_cartesian_location.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/relative_cartesian_location.py @@ -1,9 +1,8 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model from capif_routing_info import util +from capif_routing_info.models.base_model import Model class RelativeCartesianLocation(Model): diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/resource.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/resource.py index 11872f4956b1bf735f272764f90a9c4bf52b2f8b..ee34d66fab1f64cd542967a9f7455c0c46ffd5cb 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/resource.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/resource.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_info.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_info.py index e81e9048a76c696da9a358140882987a246a76eb..9615bb65153cfc2fd418645d0c8267dcceb91c0a 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_info.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_info.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_rule.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_rule.py index 14216c31d50518bcb63cd014e1406b0257c35527..f5072e733c0002c0c99c5f4cd1100696f5f1b91d 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_rule.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/routing_rule.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.aef_profile import AefProfile # noqa: E501 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/security_method.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/security_method.py index dc073f400e54197b4644303edcd593ddca912869..948a0e089daf765bf2fe503474e7ba21831964a0 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/security_method.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/service_kpis.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/service_kpis.py index 05926a00f7016ce60d930cfc065969673c500fda..b06404f71cefeb1f66c19b1950c6f4623c5b4004 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/service_kpis.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/service_kpis.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model @@ -170,7 +170,7 @@ class ServiceKpis(Model): :type aval_comp: str """ if aval_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_comp = aval_comp @@ -195,7 +195,7 @@ class ServiceKpis(Model): :type aval_gra_comp: str """ if aval_gra_comp is not None and not re.search(r'^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$', aval_gra_comp): # noqa: E501 - raise ValueError("Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_gra_comp`, must be a follow pattern or equal to `/^\d+(\.\d+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$/`") # noqa: E501 self._aval_gra_comp = aval_gra_comp @@ -220,7 +220,7 @@ class ServiceKpis(Model): :type aval_mem: str """ if aval_mem is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_mem): # noqa: E501 - raise ValueError("Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_mem`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_mem = aval_mem @@ -245,7 +245,7 @@ class ServiceKpis(Model): :type aval_stor: str """ if aval_stor is not None and not re.search(r'^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$', aval_stor): # noqa: E501 - raise ValueError("Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `aval_stor`, must be a follow pattern or equal to `/^\d+(\.\d+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$/`") # noqa: E501 self._aval_stor = aval_stor diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/supported_gad_shapes.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/supported_gad_shapes.py index 98407a0e203a26f5b3650c7f16429b97af3f4dfa..ef3f27bad0e980acbe614f2b169b20efc899a535 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/supported_gad_shapes.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/supported_gad_shapes.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipse.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipse.py index 9d802dd4c13e7dc4e6c47054f367119fe8edd1c1..00d8acb97933eedfb03d721c049bb160bed83c34 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipse.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipse.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipsoid.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipsoid.py index 45538ba797abdfca3825c1dc1f69f3458ab74f75..c1307ee35664c5dac0674fac7f4b40a8652052de 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipsoid.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/uncertainty_ellipsoid.py @@ -1,9 +1,8 @@ from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 -from typing import List, Dict # noqa: F401 - -from capif_routing_info.models.base_model import Model from capif_routing_info import util +from capif_routing_info.models.base_model import Model class UncertaintyEllipsoid(Model): diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/version.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/version.py index 6e7df34151ca1fa86ec73bc191ffab1332456376..990be9ce880456035f83ac1a90522c249e3e9c6a 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/version.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/models/version.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_routing_info import util from capif_routing_info.models.base_model import Model diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/openapi/openapi.yaml b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/openapi/openapi.yaml index 5e93c85aac7ab73a113427949cca3bac11566a58..218463684f74a4c6ed85323ac37533ce01962499 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/openapi/openapi.yaml @@ -1,11 +1,11 @@ openapi: 3.0.0 info: - description: "API for Routing information. \n© 2022, 3GPP Organizational Partners\ + description: "API for Routing information. \n© 2024, 3GPP Organizational Partners\ \ (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Routing_Info_API - version: 1.2.0-alpha.1 + version: 1.2.0 externalDocs: - description: 3GPP TS 29.222 V18.0.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/capif-routing-info/v1" @@ -209,6 +209,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -387,6 +390,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -395,6 +401,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -423,6 +432,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -601,6 +613,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -609,6 +624,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -651,6 +669,9 @@ components: end: end aefProfile: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -829,6 +850,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -837,6 +861,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -997,6 +1024,9 @@ components: description: Represents the AEF profile data. example: protocol: HTTP_1_1 + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS ueIpRange: ueIpv4AddrRanges: - start: 198.51.100.1 @@ -1175,6 +1205,9 @@ components: aefId: aefId interfaceDescriptions: - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1183,6 +1216,9 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr - ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1200,11 +1236,9 @@ components: maxReqRate: 0 avalGraComp: avalGraComp nullable: true - oneOf: - - required: - - domainName - - required: - - interfaceDescriptions + oneOf: + - required: ["domainName"] + - required: ["interfaceDescriptions"] properties: aefId: description: Identifier of the API exposing function @@ -1228,6 +1262,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array domainName: description: Domain to which API belongs to title: domainName @@ -1407,14 +1447,10 @@ components: title: Resource type: object CommunicationType: - anyOf: - - enum: + enum: - REQUEST_RESPONSE - SUBSCRIBE_NOTIFY - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a communication type of the resource or the custom operation.\ \ \nPossible values are:\n- REQUEST_RESPONSE: The communication is of the\ \ type request-response.\n- SUBSCRIBE_NOTIFY: The communication is of the\ @@ -1455,32 +1491,24 @@ components: title: CustomOperation type: object Operation: - anyOf: - - enum: + enum: - GET - POST - PUT - PATCH - DELETE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates an HTTP method. \nPossible values are:\n- GET: HTTP\ \ GET method.\n- POST: HTTP POST method.\n- PUT: HTTP PUT method.\n- PATCH:\ \ HTTP PATCH method.\n- DELETE: HTTP DELETE method.\n" title: Operation Protocol: - anyOf: - - enum: + enum: - HTTP_1_1 - HTTP_2 - MQTT - WEBSOCKET - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a protocol and protocol version used by the API. \n\ Possible values are:\n- HTTP_1_1: Indicates that the protocol is HTTP version\ \ 1.1.\n- HTTP_2: Indicates that the protocol is HTTP version 2.\n- MQTT:\ @@ -1488,30 +1516,22 @@ components: \ Indicates that the protocol is Websocket.\n" title: Protocol DataFormat: - anyOf: - - enum: + enum: - JSON - XML - PROTOBUF3 - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates a data format. \nPossible values are:\n- JSON: Indicates\ \ that the data format is JSON.\n- XML: Indicates that the data format is\ \ Extensible Markup Language.\n- PROTOBUF3: Indicates that the data format\ \ is Protocol buffers version 3.\n" title: DataFormat SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -1521,6 +1541,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - null + - null securityMethods: - null - null @@ -1529,13 +1552,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: - - required: - - ipv4Addr - - required: - - ipv6Addr - - required: - - fqdn + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -1574,6 +1594,12 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object AefLocation: @@ -1696,7 +1722,9 @@ components: title: ServiceKpis type: object IpAddrRange: - anyOf: [] + anyOf: + - required: ["ueIpv4AddrRanges"] + - required: ["ueIpv6AddrRanges"] description: Represents the list of public IP ranges example: ueIpv4AddrRanges: @@ -1739,6 +1767,19 @@ components: pattern: "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$" title: Ipv4Addr type: string + OAuthGrantType: + enum: + - CLIENT_CREDENTIALS + - AUTHORIZATION_CODE + - AUTHORIZATION_CODE_WITH_PKCE + type: string + description: "Indicates the supported authorization flow (e.g. client credentials\ + \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ + \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ + \ credentials flow.\n- AUTHORIZATION_CODE: Indicate that the grant type is\ + \ authorization code.\n- AUTHORIZATION_CODE_WITH_PKCE: Indicate that the grant\ + \ type is authorization code with PKCE.\n" + title: OAuthGrantType DateTime: description: string with format "date-time" as defined in OpenAPI. format: date-time @@ -1954,8 +1995,7 @@ components: title: GADShape type: object SupportedGADShapes: - anyOf: - - enum: + enum: - POINT - POINT_UNCERTAINTY_CIRCLE - POINT_UNCERTAINTY_ELLIPSE @@ -1968,8 +2008,7 @@ components: - DISTANCE_DIRECTION - RELATIVE_2D_LOCATION_UNCERTAINTY_ELLIPSE - RELATIVE_3D_LOCATION_UNCERTAINTY_ELLIPSOID - type: string - - type: string + type: string description: Indicates supported GAD shapes. title: SupportedGADShapes PointUncertaintyCircle: @@ -2197,8 +2236,26 @@ components: type: string point: $ref: '#/components/schemas/GeographicalCoordinates' + area: + $ref: '#/components/schemas/GeographicArea' + horizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in + 0.1 degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer + required: + - coordinateId title: LocalOrigin type: object + HorizAxesOrientation: + description: Horizontal axes orientation angle clockwise from northing in 0.1 + degrees. + maximum: 3600 + minimum: 0 + title: HorizAxesOrientation + type: integer RelativeCartesianLocation: description: Relative Cartesian Location properties: @@ -2234,6 +2291,8 @@ components: $ref: '#/components/schemas/UncertaintyEllipsoid' confidence: $ref: '#/components/schemas/Confidence' + vConfidence: + $ref: '#/components/schemas/Confidence' required: - confidence - localOrigin @@ -2326,9 +2385,6 @@ components: title: Ipv6AddressRange_1 type: object Ipv6Addr_1: - allOf: - - pattern: "^((:|(0?|([1-9a-f][0-9a-f]{0,3}))):)((0?|([1-9a-f][0-9a-f]{0,3})):){0,6}(:|(0?|([1-9a-f][0-9a-f]{0,3})))$" - - pattern: "^((([^:]+:){7}([^:]+))|((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?))$" description: | String identifying an IPv6 address formatted according to clause 4 of RFC5952. The mixed IPv4 IPv6 notation according to clause 5 of RFC5952 shall not be used. example: 2001:db8:85a3::8a2e:370:7334 diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/test/test_default_controller.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/test/test_default_controller.py index e90ce9235112e14d0517a5508215f5dae8c2c4c6..cf2e7c38182b332a62e9da67b6011e3d6657a2f5 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/test/test_default_controller.py @@ -1,5 +1,7 @@ import unittest +from capif_routing_info.models.problem_details import ProblemDetails # noqa: E501 +from capif_routing_info.models.routing_info import RoutingInfo # noqa: E501 from capif_routing_info.test import BaseTestCase diff --git a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/util.py b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/util.py index 6f369d510e55cbab6fb999fe743b26757c2e91c1..fc17a1caf0e6643d07026f90da90d1fcbed857bc 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/util.py +++ b/services/TS29222_CAPIF_Routing_Info_API/capif_routing_info/util.py @@ -1,6 +1,5 @@ import datetime -import typing from capif_routing_info import typing_utils diff --git a/services/TS29222_CAPIF_Routing_Info_API/requirements.txt b/services/TS29222_CAPIF_Routing_Info_API/requirements.txt index 0ecdd1f3b7931f42166a8e8cc214755a04462e6c..9c1909386d58da9be7f1452fd8d40789eeb58184 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/requirements.txt +++ b/services/TS29222_CAPIF_Routing_Info_API/requirements.txt @@ -4,5 +4,5 @@ python_dateutil >= 2.6.0 setuptools == 74.0.0 Flask == 3.0.3 werkzeug == 3.0.4 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/TS29222_CAPIF_Routing_Info_API/setup.py b/services/TS29222_CAPIF_Routing_Info_API/setup.py index 6d66c72675bb2bd84baebd370e98e511f3312eba..327037e0efdf06c6e4bcf9aa870bbe6ad277ca7f 100644 --- a/services/TS29222_CAPIF_Routing_Info_API/setup.py +++ b/services/TS29222_CAPIF_Routing_Info_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "capif_routing_info" VERSION = "1.0.0" @@ -30,7 +31,7 @@ setup( entry_points={ 'console_scripts': ['capif_routing_info=capif_routing_info.__main__:main']}, long_description="""\ - API for Routing information. © 2022, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. + API for Routing information. © 2024, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved. """ ) diff --git a/services/TS29222_CAPIF_Security_API/.openapi-generator/FILES b/services/TS29222_CAPIF_Security_API/.openapi-generator/FILES index 1fd34c24a0763985d9f135288f82a424d7f4c66d..a3947acd44363fa560ce0e5e3c34285ccf95a204 100644 --- a/services/TS29222_CAPIF_Security_API/.openapi-generator/FILES +++ b/services/TS29222_CAPIF_Security_API/.openapi-generator/FILES @@ -22,9 +22,11 @@ capif_security/models/cause.py capif_security/models/interface_description.py capif_security/models/invalid_param.py capif_security/models/invalid_param1.py +capif_security/models/ml_model_inter_ind.py capif_security/models/nf_type.py capif_security/models/no_profile_match_info.py capif_security/models/no_profile_match_reason.py +capif_security/models/nwdaf_event.py capif_security/models/o_auth_grant_type.py capif_security/models/plmn_id.py capif_security/models/plmn_id_nid.py diff --git a/services/TS29222_CAPIF_Security_API/.openapi-generator/VERSION b/services/TS29222_CAPIF_Security_API/.openapi-generator/VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..b23eb27529e2bacf6c8c06f725c323d9fb87f042 100644 --- a/services/TS29222_CAPIF_Security_API/.openapi-generator/VERSION +++ b/services/TS29222_CAPIF_Security_API/.openapi-generator/VERSION @@ -1 +1 @@ -7.5.0 +7.11.0 diff --git a/services/TS29222_CAPIF_Security_API/README.md b/services/TS29222_CAPIF_Security_API/README.md index 6534bceb3d41c0580fba545343824b1629f05bd8..66df10994ad85cbdf33b6eda4b8bfcf0d0ca940b 100644 --- a/services/TS29222_CAPIF_Security_API/README.md +++ b/services/TS29222_CAPIF_Security_API/README.md @@ -15,7 +15,7 @@ To run the server, please execute the following from the root directory: ``` pip3 install -r requirements.txt -python3 -m openapi_server +python3 -m capif_security ``` and open your browser to here: diff --git a/services/TS29222_CAPIF_Security_API/capif_security/app.py b/services/TS29222_CAPIF_Security_API/capif_security/app.py index c61896eea8d8488eb0d5dbc1053df55238292c2d..f4f39fde845188be2a9768e7d1a71093c05a4ddc 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/app.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/app.py @@ -6,6 +6,9 @@ from datetime import datetime from logging.handlers import RotatingFileHandler import connexion +import encoder +from config import Config +from core.consumer_messager import Subscriber from flask_apscheduler import APScheduler from flask_executor import Executor from flask_jwt_extended import JWTManager @@ -19,10 +22,6 @@ from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator -import encoder -from config import Config -from core.consumer_messager import Subscriber - NAME = "Security-Service" # Setting log level @@ -36,7 +35,7 @@ def configure_monitoring(app, config): fluent_bit_host = config['monitoring']['fluent_bit_host'] fluent_bit_port = config['monitoring']['fluent_bit_port'] fluent_bit_sender = sender.FluentSender('Security-Service', host=fluent_bit_host, port=fluent_bit_port) - propagator = TraceContextTextMapPropagator() + TraceContextTextMapPropagator() tracer_provider = TracerProvider(resource=resource) trace.set_tracer_provider(tracer_provider) diff --git a/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py b/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py index 3609bd8f17bb6f3267fa72750280e82c61ef5d04..385d3cfd4a8c6bb03a4f517c8863e1e0141dec3c 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py @@ -5,7 +5,7 @@ from capif_security.models.security_notification import SecurityNotification # from capif_security.models.service_security import ServiceSecurity # noqa: E501 from cryptography import x509 from cryptography.hazmat.backends import default_backend -from flask import request, current_app +from flask import current_app, request from ..core.publisher import Publisher from ..core.redis_internal_event import RedisInternalEvent @@ -17,7 +17,6 @@ publish_ops = Publisher() valid_user = ControlAccess() - def cert_validation(): def _cert_validation(f): @wraps(f) @@ -51,7 +50,6 @@ def cert_validation(): return __cert_validation return _cert_validation - @cert_validation() def securities_security_id_token_post(security_id, body): # noqa: E501 """securities_security_id_token_post @@ -111,7 +109,6 @@ def trusted_invokers_api_invoker_id_delete(api_invoker_id): # noqa: E501 current_app.logger.info("Removing security context") return service_security_ops.delete_servicesecurity(api_invoker_id) - @cert_validation() def trusted_invokers_api_invoker_id_delete_post(api_invoker_id, body): # noqa: E501 """trusted_invokers_api_invoker_id_delete_post @@ -125,7 +122,6 @@ def trusted_invokers_api_invoker_id_delete_post(api_invoker_id, body): # noqa: :rtype: Union[None, Tuple[None, int], Tuple[None, int, Dict[str, str]] """ - if request.is_json: body = SecurityNotification.from_dict(request.get_json()) # noqa: E501 @@ -134,7 +130,6 @@ def trusted_invokers_api_invoker_id_delete_post(api_invoker_id, body): # noqa: return res - @cert_validation() def trusted_invokers_api_invoker_id_get(api_invoker_id, authentication_info=None, authorization_info=None): # noqa: E501 """trusted_invokers_api_invoker_id_get @@ -156,7 +151,6 @@ def trusted_invokers_api_invoker_id_get(api_invoker_id, authentication_info=None return res - @cert_validation() def trusted_invokers_api_invoker_id_put(api_invoker_id, body): # noqa: E501 """trusted_invokers_api_invoker_id_put @@ -188,7 +182,6 @@ def trusted_invokers_api_invoker_id_put(api_invoker_id, body): # noqa: E501 return res - @cert_validation() def trusted_invokers_api_invoker_id_update_post(api_invoker_id, body): # noqa: E501 """trusted_invokers_api_invoker_id_update_post diff --git a/services/TS29222_CAPIF_Security_API/capif_security/controllers/security_controller.py b/services/TS29222_CAPIF_Security_API/capif_security/controllers/security_controller.py index 139597f9cb07c5d48bed18984ec4747f4b4f3438..8b137891791fe96927ad78e64b0aad7bded08bdc 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/controllers/security_controller.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/controllers/security_controller.py @@ -1,2 +1 @@ - diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/redis_event.py b/services/TS29222_CAPIF_Security_API/capif_security/core/redis_event.py index c65a6a20313002902b4660493d05be5c4cd20a24..8dccdf3d3ad9ad7f9c1460d420390c421ab4289d 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/redis_event.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/redis_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import CustomJSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/redis_internal_event.py b/services/TS29222_CAPIF_Security_API/capif_security/core/redis_internal_event.py index 50e343424b8498d32078648978c719c923304353..c1ad0973675b69adf3a81bc9592feac33f0c2064 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/redis_internal_event.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/redis_internal_event.py @@ -1,7 +1,7 @@ import json -from .publisher import Publisher from ..encoder import JSONEncoder +from .publisher import Publisher publisher_ops = Publisher() diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py b/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py index 916b2861a11a9f0e3fd55fa6f236e2cc9d448fb4..e6d367abe2a42c6f5a6543db21e1159d94167ded 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py @@ -5,18 +5,22 @@ from datetime import datetime, timedelta import rfc3987 from bson import json_util -from flask import current_app +from flask import current_app, request from flask_jwt_extended import create_access_token from pymongo import ReturnDocument +import hmac +import hashlib +import unicodedata + -from .redis_event import RedisEvent -from .resources import Resource -from .responses import not_found_error, make_response, bad_request_error, internal_server_error, forbidden_error from ..core.publisher import Publisher from ..models.access_token_claims import AccessTokenClaims from ..models.access_token_err import AccessTokenErr from ..models.access_token_rsp import AccessTokenRsp -from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case +from ..util import clean_empty, dict_to_camel_case, serialize_clean_camel_case +from .redis_event import RedisEvent +from .resources import Resource +from .responses import bad_request_error, forbidden_error, internal_server_error, make_response, not_found_error publish_ops = Publisher() @@ -24,6 +28,18 @@ security_context_not_found_detail = "Security context not found" api_invoker_no_context_cause = "API Invoker has no security context" +TOTAL_FEATURES = 3 +SUPPORTED_FEATURES_HEX = "4" + +def return_negotiated_supp_feat_dict(supp_feat): + final_supp_feat = bin(int(supp_feat, 16) & int(SUPPORTED_FEATURES_HEX, 16))[2:].zfill(TOTAL_FEATURES)[::-1] + return { + "Notification_test_event": True if final_supp_feat[0] == "1" else False, + "Notification_websocket": True if final_supp_feat[1] == "1" else False, + "SecurityInfoPerAPI": True if final_supp_feat[2] == "1" else False, + "Final": hex(int(final_supp_feat[::-1], 2))[2:] + } + class SecurityOperations(Resource): def __check_invoker(self, api_invoker_id): @@ -81,6 +97,47 @@ class SecurityOperations(Resource): current_app.logger.error("Bad format Scope: " + e) token_error = AccessTokenErr(error="invalid_scope", error_description="malformed scope") return make_response(object=clean_empty(token_error.to_dict()), status=400) + + + def __derive_psk(self, master_key:str, session_id:str, interface:dict): + ## Derive the PSK using the provided master key, session ID, and interface information + + # Interface information + host = None + if 'fqdn' in interface: + host = interface['fqdn'] + elif 'ipv4Addr' in interface: + host = interface['ipv4Addr'] + elif 'ipv6Addr' in interface: + host = interface['ipv6Addr'] + port = interface.get('port', None) + + api_prefix = interface.get('apiPrefix', '') + scheme = "https" if port in (None, 443) else "http" + + interface_info = f"{scheme}://{host}" + if port and port != 443: + interface_info += f":{port}" + interface_info += api_prefix + + # Normalize the strings to NFKC form + p0_string = unicodedata.normalize("NFKC", interface_info).encode("utf-8") + p1_string = unicodedata.normalize("NFKC", session_id).encode("utf-8") + + # Convert to octet format (0xFF) + p0_octet_string = ' '.join(f'0x{byte:02X}' for byte in p0_string) + p1_octet_string = ' '.join(f'0x{byte:02X}' for byte in p1_string) + + # Convert number of bytes to 16-bit big-endian + l0 = ' '.join(f'0x{byte:02X}' for byte in len(p0_octet_string).to_bytes(2, 'big')) + l1 = ' '.join(f'0x{byte:02X}' for byte in len(p1_octet_string).to_bytes(2, 'big')) + + # Create S string using FC (0x7A) and the octet strings with their lengths + S = "0x7A" + ' ' + p0_octet_string + ' ' + l0 + ' ' + p1_octet_string + ' ' + l1 + psk = hmac.new(master_key.encode("utf-8"), S.encode("utf-8"), hashlib.sha256).digest() + + return psk + def __init__(self): Resource.__init__(self) @@ -105,12 +162,66 @@ class SecurityOperations(Resource): current_app.logger.error("Not found security context") return not_found_error(detail=security_context_not_found_detail, cause=api_invoker_no_context_cause) - if not authentication_info: - for security_info_obj in services_security_object['security_info']: - del security_info_obj['authentication_info'] - if not authorization_info: - for security_info_obj in services_security_object['security_info']: - del security_info_obj['authorization_info'] + for security_info_obj in services_security_object['security_info']: + if security_info_obj.get('sel_security_method') == "PKI": + current_app.logger.debug("PKI security method selected") + if authentication_info: + # Read the CA certificate from the file + with open("/usr/src/app/capif_security/ca.crt", "rb") as key_file: + key_data = key_file.read() + # Decode the certificate to a string + key_data = key_data.decode('utf-8') + # Add the CA certificate to the authentication_info + security_info_obj['authentication_info'] = key_data + else: + # If authentication_info is not needed, remove the key_data + del security_info_obj['authentication_info'] + + if authorization_info: + security_info_obj['authorization_info'] = security_info_obj.get('authorization_info', "") + else: + # If authorization_info is not needed, remove the key_data + del security_info_obj['authorization_info'] + + elif security_info_obj.get('sel_security_method') == "PSK": + current_app.logger.debug("PSK security method selected") + if authentication_info: + # Read the PSK from the file -> TODO + with open("/usr/src/app/capif_security/ca.crt", "rb") as key_file: + key_data = key_file.read() + # Decode the PSK to a string + key_data = key_data.decode('utf-8') + # Add the PSK to the authentication_info + security_info_obj['authentication_info'] = key_data + else: + # If authentication_info is not needed, remove the key_data + del security_info_obj['authentication_info'] + + if authorization_info: + security_info_obj['authorization_info'] = security_info_obj.get('authorization_info', "UNDER DEVELOPMENT") + else: + # If authorization_info is not needed, remove the key_data + del security_info_obj['authorization_info'] + + elif security_info_obj.get('sel_security_method') == "OAUTH": + current_app.logger.debug("OAUTH security method selected, this request is not needed") + + if authentication_info: + security_info_obj['authentication_info'] = security_info_obj.get('authentication_info', "") + else: + # If authentication_info is not needed, remove the key_data + del security_info_obj['authentication_info'] + + if authorization_info: + security_info_obj['authorization_info'] = security_info_obj.get('authorization_info', "") + else: + # If authorization_info is not needed, remove the key_data + del security_info_obj['authorization_info'] + + else: + current_app.logger.error("Bad format security method") + return bad_request_error(detail="Bad format security method", cause="Bad format security method", invalid_params=[{"param": "securityMethod", "reason": "Bad format security method"}]) + properyly_json = json.dumps( services_security_object, default=json_util.default) @@ -130,7 +241,7 @@ class SecurityOperations(Resource): return internal_server_error(detail=exception, cause=str(e)) def create_servicesecurity(self, api_invoker_id, service_security): - + mycol = self.db.get_col_by_name(self.db.security_info) try: @@ -153,9 +264,52 @@ class SecurityOperations(Resource): "Already security context defined with same api invoker id") return forbidden_error(detail="Security method already defined", cause="Identical AEF Profile IDs") + negotiated = return_negotiated_supp_feat_dict(service_security.supported_features) + service_security.supported_features = negotiated["Final"] + for service_instance in service_security.security_info: if service_instance.interface_details is not None: - security_methods = service_instance.interface_details.security_methods + + # We look for if the passed interface exists for the given apiId + capif_service_col = self.db.get_col_by_name( + self.db.capif_service_col) + + aef_profile = capif_service_col.find_one( + {"api_id": service_instance.api_id, + "aef_profiles.interface_descriptions":{ + "$elemMatch": service_instance.interface_details.to_dict() + } + }, + {"aef_profiles.interface_descriptions.$": 1, "_id": 0}) + + current_app.logger.debug("Aef profile: " + str(aef_profile)) + + if aef_profile is None: + current_app.logger.error( + "Not found service with this interface description: " + json.dumps(clean_empty(service_instance.interface_details.to_dict()))) + return not_found_error(detail=f"Service with interfaceDescription {json.dumps(clean_empty(service_instance.interface_details.to_dict()))} not found", cause="Not found Service") + + # We obtain the interface security methods + # We need to go deeper here, because the interface description is an array + # and we need to find the correct one according to preferred security method by invoker, + # maybe Published API contains more than one interface description, and each one is related + # with a different security method, then we need to get a complete list (interface and related security methods) + # amd then we need to check if the preferred security method is compatible with the interface description + # also the security methods inside interface description is not mandatory, in that case we use aefProfile.securityMethods + # an also that aefProfile.securityMethods is not mandatory, only in cases described on TS 29222 - 8.2.4.2.4 Type: AefProfile - + # + # NOTE4: + # For AEFs defined by 3GPP interacting with API invokers via CAPIF-2e, at least one of the "securityMethods" attribute + # within this data type or the "securityMethods" attribute within the "interfaceDescriptions" attribute shall be present. + # For AEFs defined by 3GPP interacting with API invokers via CAPIF-2, the "securityMethods" attribute is optional. + # For AEFs not defined by 3GPP, the "securityMethods" attribute is optional. + # + # To achieve this, we need to setup at config which domains or IPs are CAPIF-2e or CAPIF-2, and then we need to check if the domain or IP of the service is in the list. + + security_methods = aef_profile["aef_profiles"][0]["interface_descriptions"][0]["security_methods"] + + current_app.logger.debug("Interface security methods: " + str(security_methods)) + pref_security_methods = service_instance.pref_security_methods valid_security_method = set( security_methods) & set(pref_security_methods) @@ -165,7 +319,7 @@ class SecurityOperations(Resource): self.db.capif_service_col) services_security_object = capif_service_col.find_one( {"api_id": service_instance.api_id, self.filter_aef_id: service_instance.aef_id}, {"aef_profiles.security_methods.$": 1}) - + current_app.logger.debug("Aef profile: " + str(services_security_object)) if services_security_object is None: current_app.logger.error( "Not found service with this aef id: " + service_instance.aef_id) @@ -182,8 +336,51 @@ class SecurityOperations(Resource): "Not found comptaible security method with pref security method") return bad_request_error(detail="Not found compatible security method with pref security method", cause="Error pref security method", invalid_params=[{"param": "prefSecurityMethods", "reason": "pref security method not compatible with security method available"}]) - service_instance.sel_security_method = list( - valid_security_method)[0] + # Retrieve security method priority configuration from the database + config_col = self.db.get_col_by_name("capif_configuration") + capif_config = config_col.find_one({"config_name": "default"}) + if not capif_config: + current_app.logger.error("CAPIF Configuration not found when trying to retrieve security method priority") + return internal_server_error(detail="CAPIF Configuration not found when trying to retrieve security method priority", cause="Database Error") + + priority_mapping = capif_config["settings"]["security_method_priority"] + + # Sort valid security methods based on priority from the configuration + sorted_methods = sorted(valid_security_method, key=lambda method: priority_mapping.get(method.lower(), float('inf'))) + + # Select the highest-priority security method + service_instance.sel_security_method = sorted_methods[0] + + if service_instance.sel_security_method == "PSK": + request.headers.get('X-TLS-Protocol', 'N/A') + sesionId = request.headers.get('X-TLS-Session-ID', 'N/A') + Mkey = request.headers.get('X-TLS-MKey', 'N/A') + current_app.logger.info(f"TLS Protocol: {request.headers.get('X-TLS-Protocol', 'N/A')}, Session id: {sesionId}, Master Key: {Mkey}") + + interface = None + if service_instance.interface_details: + current_app.logger.debug("Interface details found") + interface = service_instance.interface_details.to_dict() + + else: + current_app.logger.error("Interface details not found") + services_security_object = capif_service_col.find_one( + {"api_id": service_instance.api_id}, {"aef_profiles": {"$elemMatch": {"aef_id": service_instance.aef_id}}, "_id": 0}) + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0])) + if "interface_descriptions" in services_security_object["aef_profiles"][0]: + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0]["interface_descriptions"])) + interface = services_security_object["aef_profiles"][0]["interface_descriptions"][0] + elif "domain_name" in services_security_object["aef_profiles"][0]: + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0]["domain_name"])) + interface = services_security_object["aef_profiles"][0]["domain_name"] + + if interface: + current_app.logger.debug("Deriving PSK") + psk = self.__derive_psk(Mkey, sesionId, interface) + current_app.logger.debug("PSK derived : " + str(psk)) + + service_instance.authorization_info = str(psk) + # Send service instance to ACL current_app.logger.debug("Sending message to create ACL") publish_ops.publish_message("acls-messages", "create-acl:"+str( @@ -305,6 +502,9 @@ class SecurityOperations(Resource): mycol = self.db.get_col_by_name(self.db.security_info) try: + negotiated_supported_features = return_negotiated_supp_feat_dict(service_security.supported_features) + service_security.supported_features = negotiated_supported_features["Final"] + current_app.logger.debug("Updating security context") result = self.__check_invoker(api_invoker_id) if result != None: @@ -317,14 +517,38 @@ class SecurityOperations(Resource): "Service api not found with id: " + api_invoker_id) return not_found_error(detail="Service API not existing", cause="Not exist securiy information for this invoker") + update_acls=list() for service_instance in service_security.security_info: if service_instance.interface_details is not None: - security_methods = service_instance.interface_details.security_methods + + # We look for if the passed interface exists for the given apiId + capif_service_col = self.db.get_col_by_name( + self.db.capif_service_col) + + aef_profile = capif_service_col.find_one( + {"api_id": service_instance.api_id, + "aef_profiles.interface_descriptions":{ + "$elemMatch": service_instance.interface_details.to_dict() + } + }, + {"aef_profiles.interface_descriptions.$": 1, "_id": 0}) + + current_app.logger.debug("Aef profile: " + str(aef_profile)) + + if aef_profile is None: + current_app.logger.error( + "Not found service with this interface description: " + json.dumps(clean_empty(service_instance.interface_details.to_dict()))) + return not_found_error(detail=f"Service with interfaceDescription {json.dumps(clean_empty(service_instance.interface_details.to_dict()))} not found", cause="Not found Service") + + # We obtain the interface security methods + security_methods = aef_profile["aef_profiles"][0]["interface_descriptions"][0]["security_methods"] + + current_app.logger.debug("Interface security methods: " + str(security_methods)) + pref_security_methods = service_instance.pref_security_methods valid_security_method = set( security_methods) & set(pref_security_methods) - service_instance.sel_security_method = list( - valid_security_method)[0] + else: capif_service_col = self.db.get_col_by_name( self.db.capif_service_col) @@ -341,16 +565,60 @@ class SecurityOperations(Resource): for security_method in array_methods["security_methods"]] valid_security_method = set( valid_security_methods) & set(pref_security_methods) - service_instance.sel_security_method = list( + + + if len(list(valid_security_method)) == 0: + current_app.logger.error( + "Not found comptaible security method with pref security method") + return bad_request_error(detail="Not found compatible security method with pref security method", cause="Error pref security method", invalid_params=[{"param": "prefSecurityMethods", "reason": "pref security method not compatible with security method available"}]) + + service_instance.sel_security_method = list( valid_security_method)[0] - + update_acls.append({"api_id": service_instance.api_id, "aef_id": service_instance.aef_id}) + + if service_instance.sel_security_method == "PSK": + request.headers.get('X-TLS-Protocol', 'N/A') + sesionId = request.headers.get('X-TLS-Session-ID', 'N/A') + Mkey = request.headers.get('X-TLS-MKey', 'N/A') + current_app.logger.info(f"TLS Protocol: {request.headers.get('X-TLS-Protocol', 'N/A')}, Session id: {sesionId}, Master Key: {Mkey}") + + interface = None + if service_instance.interface_details: + current_app.logger.debug("Interface details found") + interface = service_instance.interface_details.to_dict() + + else: + current_app.logger.error("Interface details not found") + services_security_object = capif_service_col.find_one( + {"api_id": service_instance.api_id}, {"aef_profiles": {"$elemMatch": {"aef_id": service_instance.aef_id}}, "_id": 0}) + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0])) + if "interface_descriptions" in services_security_object["aef_profiles"][0]: + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0]["interface_descriptions"])) + interface = services_security_object["aef_profiles"][0]["interface_descriptions"][0] + elif "domain_name" in services_security_object["aef_profiles"][0]: + current_app.logger.debug("Aef profile: " + str(services_security_object["aef_profiles"][0]["domain_name"])) + interface = services_security_object["aef_profiles"][0]["domain_name"] + + if interface: + current_app.logger.debug("Deriving PSK") + psk = self.__derive_psk(Mkey, sesionId, interface) + current_app.logger.debug("PSK derived : " + str(psk)) + + service_instance.authorization_info = str(psk) service_security = service_security.to_dict() service_security = clean_empty(service_security) result = mycol.find_one_and_update(old_object, {"$set": service_security}, projection={ '_id': 0, "api_invoker_id": 0}, return_document=ReturnDocument.AFTER, upsert=False) + current_app.logger.debug( + "Inserted security context in database") # result = clean_empty(result) + for update_acl in update_acls: + # Send service instance to ACL + current_app.logger.debug("Sending message to create ACL") + publish_ops.publish_message("acls-messages", "create-acl:"+str( + api_invoker_id)+":"+str(update_acl['api_id'])+":"+str(update_acl['aef_id'])) current_app.logger.debug("Updated security context") diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/validate_user.py b/services/TS29222_CAPIF_Security_API/capif_security/core/validate_user.py index c3f70049a8f7cfc869839bed8563fe1e82304f7d..29180d1a1a697cae8a4548945c8e619c6791882f 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/validate_user.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/validate_user.py @@ -1,11 +1,11 @@ import json -from flask import current_app, Response +from flask import Response, current_app -from .resources import Resource -from .responses import internal_server_error, serialize_clean_camel_case from ..encoder import CustomJSONEncoder from ..models.problem_details import ProblemDetails +from .resources import Resource +from .responses import internal_server_error, serialize_clean_camel_case class ControlAccess(Resource): diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_claims.py b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_claims.py index 71d49c28b2f01a003dc9bdda6cd25a43f8bc2899..61a482b62939553c5673585c9c69e9f28a7a7f64 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_claims.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_claims.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err.py b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err.py index b5d7f6f8e415d419bd42e9a819f7c73952adc860..3e7629b59cc6656802ee046b3f7c49106e2520cd 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err1.py b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err1.py index 325b219770cb2e32fdaff49e727994030b09b5d8..efd3e8f4fa2e261ceaa3b285448722b2aff16e88 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err1.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_err1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_req1.py b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_req1.py index b9e4ff408db15c09cd03ecf79f6a76e8b03a67a2..0530651a6dd30da7ebcb1f3194c282416b4d7f47 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_req1.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_req1.py @@ -1,10 +1,12 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model +from capif_security.models.ml_model_inter_ind import MlModelInterInd # noqa: E501 from capif_security.models.nf_type import NFType # noqa: E501 +from capif_security.models.nwdaf_event import NwdafEvent # noqa: E501 from capif_security.models.plmn_id import PlmnId # noqa: E501 from capif_security.models.plmn_id_nid import PlmnIdNid # noqa: E501 from capif_security.models.snssai import Snssai # noqa: E501 @@ -16,7 +18,7 @@ class AccessTokenReq1(Model): Do not edit the class manually. """ - def __init__(self, grant_type=None, nf_instance_id=None, nf_type=None, target_nf_type=None, scope=None, target_nf_instance_id=None, requester_plmn=None, requester_plmn_list=None, requester_snssai_list=None, requester_fqdn=None, requester_snpn_list=None, target_plmn=None, target_snpn=None, target_snssai_list=None, target_nsi_list=None, target_nf_set_id=None, target_nf_service_set_id=None, hnrf_access_token_uri=None, source_nf_instance_id=None): # noqa: E501 + def __init__(self, grant_type=None, nf_instance_id=None, nf_type=None, target_nf_type=None, scope=None, target_nf_instance_id=None, requester_plmn=None, requester_plmn_list=None, requester_snssai_list=None, requester_fqdn=None, requester_snpn_list=None, target_plmn=None, target_snpn=None, target_snssai_list=None, target_nsi_list=None, target_nf_set_id=None, target_nf_service_set_id=None, hnrf_access_token_uri=None, source_nf_instance_id=None, vendor_id=None, analytics_ids=None, requester_inter_ind_list=None, source_vendor_id=None): # noqa: E501 """AccessTokenReq1 - a model defined in OpenAPI :param grant_type: The grant_type of this AccessTokenReq1. # noqa: E501 @@ -57,6 +59,14 @@ class AccessTokenReq1(Model): :type hnrf_access_token_uri: str :param source_nf_instance_id: The source_nf_instance_id of this AccessTokenReq1. # noqa: E501 :type source_nf_instance_id: str + :param vendor_id: The vendor_id of this AccessTokenReq1. # noqa: E501 + :type vendor_id: str + :param analytics_ids: The analytics_ids of this AccessTokenReq1. # noqa: E501 + :type analytics_ids: List[NwdafEvent] + :param requester_inter_ind_list: The requester_inter_ind_list of this AccessTokenReq1. # noqa: E501 + :type requester_inter_ind_list: List[MlModelInterInd] + :param source_vendor_id: The source_vendor_id of this AccessTokenReq1. # noqa: E501 + :type source_vendor_id: str """ self.openapi_types = { 'grant_type': str, @@ -77,7 +87,11 @@ class AccessTokenReq1(Model): 'target_nf_set_id': str, 'target_nf_service_set_id': str, 'hnrf_access_token_uri': str, - 'source_nf_instance_id': str + 'source_nf_instance_id': str, + 'vendor_id': str, + 'analytics_ids': List[NwdafEvent], + 'requester_inter_ind_list': List[MlModelInterInd], + 'source_vendor_id': str } self.attribute_map = { @@ -99,7 +113,11 @@ class AccessTokenReq1(Model): 'target_nf_set_id': 'targetNfSetId', 'target_nf_service_set_id': 'targetNfServiceSetId', 'hnrf_access_token_uri': 'hnrfAccessTokenUri', - 'source_nf_instance_id': 'sourceNfInstanceId' + 'source_nf_instance_id': 'sourceNfInstanceId', + 'vendor_id': 'vendorId', + 'analytics_ids': 'analyticsIds', + 'requester_inter_ind_list': 'requesterInterIndList', + 'source_vendor_id': 'sourceVendorId' } self._grant_type = grant_type @@ -121,6 +139,10 @@ class AccessTokenReq1(Model): self._target_nf_service_set_id = target_nf_service_set_id self._hnrf_access_token_uri = hnrf_access_token_uri self._source_nf_instance_id = source_nf_instance_id + self._vendor_id = vendor_id + self._analytics_ids = analytics_ids + self._requester_inter_ind_list = requester_inter_ind_list + self._source_vendor_id = source_vendor_id @classmethod def from_dict(cls, dikt) -> 'AccessTokenReq1': @@ -248,7 +270,7 @@ class AccessTokenReq1(Model): if scope is None: raise ValueError("Invalid value for `scope`, must not be `None`") # noqa: E501 if scope is not None and not re.search(r'^([a-zA-Z0-9_:-]+)( [a-zA-Z0-9_:-]+)*$', scope): # noqa: E501 - raise ValueError("Invalid value for `scope`, must be a follow pattern or equal to `/^([a-zA-Z0-9_:-]+)( [a-zA-Z0-9_:-]+)*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `scope`, must be a follow pattern or equal to `/^([a-zA-Z0-9_:-]+)( [a-zA-Z0-9_:-]+)*$/`") # noqa: E501 self._scope = scope @@ -367,7 +389,7 @@ class AccessTokenReq1(Model): if requester_fqdn is not None and len(requester_fqdn) < 4: raise ValueError("Invalid value for `requester_fqdn`, length must be greater than or equal to `4`") # noqa: E501 if requester_fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', requester_fqdn): # noqa: E501 - raise ValueError("Invalid value for `requester_fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `requester_fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._requester_fqdn = requester_fqdn @@ -573,3 +595,99 @@ class AccessTokenReq1(Model): """ self._source_nf_instance_id = source_nf_instance_id + + @property + def vendor_id(self) -> str: + """Gets the vendor_id of this AccessTokenReq1. + + Vendor ID of the NF Service instance (Private Enterprise Number assigned by IANA) # noqa: E501 + + :return: The vendor_id of this AccessTokenReq1. + :rtype: str + """ + return self._vendor_id + + @vendor_id.setter + def vendor_id(self, vendor_id: str): + """Sets the vendor_id of this AccessTokenReq1. + + Vendor ID of the NF Service instance (Private Enterprise Number assigned by IANA) # noqa: E501 + + :param vendor_id: The vendor_id of this AccessTokenReq1. + :type vendor_id: str + """ + if vendor_id is not None and not re.search(r'^[0-9]{6}$', vendor_id): # noqa: E501 + raise ValueError(r"Invalid value for `vendor_id`, must be a follow pattern or equal to `/^[0-9]{6}$/`") # noqa: E501 + + self._vendor_id = vendor_id + + @property + def analytics_ids(self) -> List[NwdafEvent]: + """Gets the analytics_ids of this AccessTokenReq1. + + + :return: The analytics_ids of this AccessTokenReq1. + :rtype: List[NwdafEvent] + """ + return self._analytics_ids + + @analytics_ids.setter + def analytics_ids(self, analytics_ids: List[NwdafEvent]): + """Sets the analytics_ids of this AccessTokenReq1. + + + :param analytics_ids: The analytics_ids of this AccessTokenReq1. + :type analytics_ids: List[NwdafEvent] + """ + if analytics_ids is not None and len(analytics_ids) < 1: + raise ValueError("Invalid value for `analytics_ids`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._analytics_ids = analytics_ids + + @property + def requester_inter_ind_list(self) -> List[MlModelInterInd]: + """Gets the requester_inter_ind_list of this AccessTokenReq1. + + + :return: The requester_inter_ind_list of this AccessTokenReq1. + :rtype: List[MlModelInterInd] + """ + return self._requester_inter_ind_list + + @requester_inter_ind_list.setter + def requester_inter_ind_list(self, requester_inter_ind_list: List[MlModelInterInd]): + """Sets the requester_inter_ind_list of this AccessTokenReq1. + + + :param requester_inter_ind_list: The requester_inter_ind_list of this AccessTokenReq1. + :type requester_inter_ind_list: List[MlModelInterInd] + """ + if requester_inter_ind_list is not None and len(requester_inter_ind_list) < 1: + raise ValueError("Invalid value for `requester_inter_ind_list`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._requester_inter_ind_list = requester_inter_ind_list + + @property + def source_vendor_id(self) -> str: + """Gets the source_vendor_id of this AccessTokenReq1. + + Vendor ID of the NF Service instance (Private Enterprise Number assigned by IANA) # noqa: E501 + + :return: The source_vendor_id of this AccessTokenReq1. + :rtype: str + """ + return self._source_vendor_id + + @source_vendor_id.setter + def source_vendor_id(self, source_vendor_id: str): + """Sets the source_vendor_id of this AccessTokenReq1. + + Vendor ID of the NF Service instance (Private Enterprise Number assigned by IANA) # noqa: E501 + + :param source_vendor_id: The source_vendor_id of this AccessTokenReq1. + :type source_vendor_id: str + """ + if source_vendor_id is not None and not re.search(r'^[0-9]{6}$', source_vendor_id): # noqa: E501 + raise ValueError(r"Invalid value for `source_vendor_id`, must be a follow pattern or equal to `/^[0-9]{6}$/`") # noqa: E501 + + self._source_vendor_id = source_vendor_id diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_rsp.py b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_rsp.py index deaf22ecf4b0582fa2ae0e8139f9d581c5c2b963..477f3a630d6a35db16fe8d4887f77a3941749c2c 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_rsp.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/access_token_rsp.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/cause.py b/services/TS29222_CAPIF_Security_API/capif_security/models/cause.py index 1b57bf4d57b05f9341e1b65c78a1adbc776e3222..b4fbd86ed3b5bc9a62ee44bc5376037ed65dc762 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/cause.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/cause.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/interface_description.py b/services/TS29222_CAPIF_Security_API/capif_security/models/interface_description.py index 47458b7bbdf994962f8c666b802e57a440ce8f37..b414ef8be3c37f2fbdec8091060fed13e0f15086 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/interface_description.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/interface_description.py @@ -1,9 +1,10 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model +from capif_security.models.o_auth_grant_type import OAuthGrantType # noqa: E501 from capif_security.models.security_method import SecurityMethod # noqa: E501 @@ -13,7 +14,7 @@ class InterfaceDescription(Model): Do not edit the class manually. """ - def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None): # noqa: E501 + def __init__(self, ipv4_addr=None, ipv6_addr=None, fqdn=None, port=None, api_prefix=None, security_methods=None, grant_types=None): # noqa: E501 """InterfaceDescription - a model defined in OpenAPI :param ipv4_addr: The ipv4_addr of this InterfaceDescription. # noqa: E501 @@ -28,6 +29,8 @@ class InterfaceDescription(Model): :type api_prefix: str :param security_methods: The security_methods of this InterfaceDescription. # noqa: E501 :type security_methods: List[SecurityMethod] + :param grant_types: The grant_types of this InterfaceDescription. # noqa: E501 + :type grant_types: List[OAuthGrantType] """ self.openapi_types = { 'ipv4_addr': str, @@ -35,7 +38,8 @@ class InterfaceDescription(Model): 'fqdn': str, 'port': int, 'api_prefix': str, - 'security_methods': List[SecurityMethod] + 'security_methods': List[SecurityMethod], + 'grant_types': List[OAuthGrantType] } self.attribute_map = { @@ -44,7 +48,8 @@ class InterfaceDescription(Model): 'fqdn': 'fqdn', 'port': 'port', 'api_prefix': 'apiPrefix', - 'security_methods': 'securityMethods' + 'security_methods': 'securityMethods', + 'grant_types': 'grantTypes' } self._ipv4_addr = ipv4_addr @@ -53,6 +58,7 @@ class InterfaceDescription(Model): self._port = port self._api_prefix = api_prefix self._security_methods = security_methods + self._grant_types = grant_types @classmethod def from_dict(cls, dikt) -> 'InterfaceDescription': @@ -136,7 +142,7 @@ class InterfaceDescription(Model): if fqdn is not None and len(fqdn) < 4: raise ValueError("Invalid value for `fqdn`, length must be greater than or equal to `4`") # noqa: E501 if fqdn is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', fqdn): # noqa: E501 - raise ValueError("Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `fqdn`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._fqdn = fqdn @@ -214,3 +220,26 @@ class InterfaceDescription(Model): raise ValueError("Invalid value for `security_methods`, number of items must be greater than or equal to `1`") # noqa: E501 self._security_methods = security_methods + + @property + def grant_types(self) -> List[OAuthGrantType]: + """Gets the grant_types of this InterfaceDescription. + + + :return: The grant_types of this InterfaceDescription. + :rtype: List[OAuthGrantType] + """ + return self._grant_types + + @grant_types.setter + def grant_types(self, grant_types: List[OAuthGrantType]): + """Sets the grant_types of this InterfaceDescription. + + + :param grant_types: The grant_types of this InterfaceDescription. + :type grant_types: List[OAuthGrantType] + """ + if grant_types is not None and len(grant_types) < 1: + raise ValueError("Invalid value for `grant_types`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._grant_types = grant_types diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param.py b/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param.py index ca4a094e20c698002c86403d02fe7f7a42f337d5..57a656957de03ca9db28000d81758e917a68fec0 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param1.py b/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param1.py index 3546df8df11b34d800c60a77027a211d4a1e2bb6..e7abd4e92f7f6270e45978705893f4ddedb4ea47 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param1.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/invalid_param1.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/ml_model_inter_ind.py b/services/TS29222_CAPIF_Security_API/capif_security/models/ml_model_inter_ind.py new file mode 100644 index 0000000000000000000000000000000000000000..c1ab27a7782a47fa16ee19d067320279785fff0d --- /dev/null +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/ml_model_inter_ind.py @@ -0,0 +1,93 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from capif_security import util +from capif_security.models.base_model import Model +from capif_security.models.nwdaf_event import NwdafEvent # noqa: E501 + + +class MlModelInterInd(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, analytics_id=None, vendor_list=None): # noqa: E501 + """MlModelInterInd - a model defined in OpenAPI + + :param analytics_id: The analytics_id of this MlModelInterInd. # noqa: E501 + :type analytics_id: NwdafEvent + :param vendor_list: The vendor_list of this MlModelInterInd. # noqa: E501 + :type vendor_list: List[str] + """ + self.openapi_types = { + 'analytics_id': NwdafEvent, + 'vendor_list': List[str] + } + + self.attribute_map = { + 'analytics_id': 'analyticsId', + 'vendor_list': 'vendorList' + } + + self._analytics_id = analytics_id + self._vendor_list = vendor_list + + @classmethod + def from_dict(cls, dikt) -> 'MlModelInterInd': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The MlModelInterInd of this MlModelInterInd. # noqa: E501 + :rtype: MlModelInterInd + """ + return util.deserialize_model(dikt, cls) + + @property + def analytics_id(self) -> NwdafEvent: + """Gets the analytics_id of this MlModelInterInd. + + + :return: The analytics_id of this MlModelInterInd. + :rtype: NwdafEvent + """ + return self._analytics_id + + @analytics_id.setter + def analytics_id(self, analytics_id: NwdafEvent): + """Sets the analytics_id of this MlModelInterInd. + + + :param analytics_id: The analytics_id of this MlModelInterInd. + :type analytics_id: NwdafEvent + """ + if analytics_id is None: + raise ValueError("Invalid value for `analytics_id`, must not be `None`") # noqa: E501 + + self._analytics_id = analytics_id + + @property + def vendor_list(self) -> List[str]: + """Gets the vendor_list of this MlModelInterInd. + + + :return: The vendor_list of this MlModelInterInd. + :rtype: List[str] + """ + return self._vendor_list + + @vendor_list.setter + def vendor_list(self, vendor_list: List[str]): + """Sets the vendor_list of this MlModelInterInd. + + + :param vendor_list: The vendor_list of this MlModelInterInd. + :type vendor_list: List[str] + """ + if vendor_list is None: + raise ValueError("Invalid value for `vendor_list`, must not be `None`") # noqa: E501 + if vendor_list is not None and len(vendor_list) < 1: + raise ValueError("Invalid value for `vendor_list`, number of items must be greater than or equal to `1`") # noqa: E501 + + self._vendor_list = vendor_list diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/nf_type.py b/services/TS29222_CAPIF_Security_API/capif_security/models/nf_type.py index 0f2e09b2e0bab651339f2cd65f494f889375bced..017f038407b5d6f1adf76f2cbb9947176db5dd7f 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/nf_type.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/nf_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_info.py b/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_info.py index c374ddeb15a33b92ff8c90e3f0127b1ccc5b7b8d..c7b85407994ed452215d57681a143f0c738b1e9f 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_info.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_info.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_reason.py b/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_reason.py index 511afb65c55e3578646cb99d2cd2a1cc29a952ed..5fe37d570bfca3d100c66284c7d1df31c18ab578 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_reason.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/no_profile_match_reason.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/nwdaf_event.py b/services/TS29222_CAPIF_Security_API/capif_security/models/nwdaf_event.py new file mode 100644 index 0000000000000000000000000000000000000000..d1701a39355274027f4cb014b33bd6a41d72f450 --- /dev/null +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/nwdaf_event.py @@ -0,0 +1,33 @@ +from datetime import date, datetime # noqa: F401 +from typing import Dict, List # noqa: F401 + +from capif_security import util +from capif_security.models.base_model import Model + + +class NwdafEvent(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """NwdafEvent - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'NwdafEvent': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The NwdafEvent of this NwdafEvent. # noqa: E501 + :rtype: NwdafEvent + """ + return util.deserialize_model(dikt, cls) diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/o_auth_grant_type.py b/services/TS29222_CAPIF_Security_API/capif_security/models/o_auth_grant_type.py index 9420cc5b79b8d444095b0f61c03bce8cff7d2c38..3813c0567751ec8ce28e8db5b7b6a2e365b8128e 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/o_auth_grant_type.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/o_auth_grant_type.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id.py b/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id.py index 82696e45abb6eb48a4294cb3aae537561027c1e5..c86104bbe9c49ebddb7277422d2a3fbb0ea33c49 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -67,7 +67,7 @@ class PlmnId(Model): if mcc is None: raise ValueError("Invalid value for `mcc`, must not be `None`") # noqa: E501 if mcc is not None and not re.search(r'^\d{3}$', mcc): # noqa: E501 - raise ValueError("Invalid value for `mcc`, must be a follow pattern or equal to `/^\d{3}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `mcc`, must be a follow pattern or equal to `/^\d{3}$/`") # noqa: E501 self._mcc = mcc @@ -94,6 +94,6 @@ class PlmnId(Model): if mnc is None: raise ValueError("Invalid value for `mnc`, must not be `None`") # noqa: E501 if mnc is not None and not re.search(r'^\d{2,3}$', mnc): # noqa: E501 - raise ValueError("Invalid value for `mnc`, must be a follow pattern or equal to `/^\d{2,3}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `mnc`, must be a follow pattern or equal to `/^\d{2,3}$/`") # noqa: E501 self._mnc = mnc diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id_nid.py b/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id_nid.py index eb9d1e25fb1ad0aae8e7b3d20b62633b6b77e2d7..9e41487672befd24b64b1bd8bb052bbd40a15fc8 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id_nid.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/plmn_id_nid.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -72,7 +72,7 @@ class PlmnIdNid(Model): if mcc is None: raise ValueError("Invalid value for `mcc`, must not be `None`") # noqa: E501 if mcc is not None and not re.search(r'^\d{3}$', mcc): # noqa: E501 - raise ValueError("Invalid value for `mcc`, must be a follow pattern or equal to `/^\d{3}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `mcc`, must be a follow pattern or equal to `/^\d{3}$/`") # noqa: E501 self._mcc = mcc @@ -99,7 +99,7 @@ class PlmnIdNid(Model): if mnc is None: raise ValueError("Invalid value for `mnc`, must not be `None`") # noqa: E501 if mnc is not None and not re.search(r'^\d{2,3}$', mnc): # noqa: E501 - raise ValueError("Invalid value for `mnc`, must be a follow pattern or equal to `/^\d{2,3}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `mnc`, must be a follow pattern or equal to `/^\d{2,3}$/`") # noqa: E501 self._mnc = mnc @@ -124,6 +124,6 @@ class PlmnIdNid(Model): :type nid: str """ if nid is not None and not re.search(r'^[A-Fa-f0-9]{11}$', nid): # noqa: E501 - raise ValueError("Invalid value for `nid`, must be a follow pattern or equal to `/^[A-Fa-f0-9]{11}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `nid`, must be a follow pattern or equal to `/^[A-Fa-f0-9]{11}$/`") # noqa: E501 self._nid = nid diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details.py b/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details.py index 50003d8edc6738e6cc4f2869ed5ee81bb135dd02..47dd078a7edd89eae8643e15f687aae3d86a705d 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -259,6 +259,6 @@ class ProblemDetails(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details1.py b/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details1.py index 777afe0d157acb199a51f88eb6e4c214e06af679..e0fbf4c1c96a65e6c3252f6494dc9c03ffe4cacd 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details1.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/problem_details1.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.access_token_err1 import AccessTokenErr1 # noqa: E501 @@ -281,7 +281,7 @@ class ProblemDetails1(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features @@ -352,7 +352,7 @@ class ProblemDetails1(Model): if nrf_id is not None and len(nrf_id) < 4: raise ValueError("Invalid value for `nrf_id`, length must be greater than or equal to `4`") # noqa: E501 if nrf_id is not None and not re.search(r'^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$', nrf_id): # noqa: E501 - raise ValueError("Invalid value for `nrf_id`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 + raise ValueError(r"Invalid value for `nrf_id`, must be a follow pattern or equal to `/^([0-9A-Za-z]([-0-9A-Za-z]{0,61}[0-9A-Za-z])?\.)+[A-Za-z]{2,63}\.?$/`") # noqa: E501 self._nrf_id = nrf_id diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/query_param_combination.py b/services/TS29222_CAPIF_Security_API/capif_security/models/query_param_combination.py index 962b251cb3f11966fca13593ed83108837b6c405..430eab7c485613e4e10b528f86f7f3d36340f872 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/query_param_combination.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/query_param_combination.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/query_parameter.py b/services/TS29222_CAPIF_Security_API/capif_security/models/query_parameter.py index b5d0a01d55a408f7c0d03c0c63f7d9c35e1b7c83..39302f5b54f2966ff964788c75043281c4beb822 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/query_parameter.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/query_parameter.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/res_owner_id.py b/services/TS29222_CAPIF_Security_API/capif_security/models/res_owner_id.py index d59b5a482b015d29981607583c6dd281adc22ba9..7ad71592d2b673a45ceee24e79b4313ea081cae8 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/res_owner_id.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/res_owner_id.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -60,6 +60,6 @@ class ResOwnerId(Model): :type gpsi: str """ if gpsi is not None and not re.search(r'^(msisdn-[0-9]{5,15}|extid-[^@]+@[^@]+|.+)$', gpsi): # noqa: E501 - raise ValueError("Invalid value for `gpsi`, must be a follow pattern or equal to `/^(msisdn-[0-9]{5,15}|extid-[^@]+@[^@]+|.+)$/`") # noqa: E501 + raise ValueError(r"Invalid value for `gpsi`, must be a follow pattern or equal to `/^(msisdn-[0-9]{5,15}|extid-[^@]+@[^@]+|.+)$/`") # noqa: E501 self._gpsi = gpsi diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/security_information.py b/services/TS29222_CAPIF_Security_API/capif_security/models/security_information.py index e678a36274780d48ed837600b989c242a24ed646..ab650a4a244870166b3ea1dd6c630362aad62f52 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/security_information.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/security_information.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/security_method.py b/services/TS29222_CAPIF_Security_API/capif_security/models/security_method.py index 1d5bfae95a2a73e568e4eeb368352c08c3eeed13..c3deabe5ae9811a582082aba27fd5e424b4af31d 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/security_method.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/security_method.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/security_notification.py b/services/TS29222_CAPIF_Security_API/capif_security/models/security_notification.py index 90e4e803465c61955773367a6849cfff1cc73ea4..fbf39b6da8002adb8809ab42db1b80c980c75753 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/security_notification.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/security_notification.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/service_security.py b/services/TS29222_CAPIF_Security_API/capif_security/models/service_security.py index 7556c8e730f0eace96c78c784bb89ff36f9012c4..10d26438f071121c9119bd888dd41d0ac7c8d7e7 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/service_security.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/service_security.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -174,6 +174,6 @@ class ServiceSecurity(Model): :type supported_features: str """ if supported_features is not None and not re.search(r'^[A-Fa-f0-9]*$', supported_features): # noqa: E501 - raise ValueError("Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 + raise ValueError(r"Invalid value for `supported_features`, must be a follow pattern or equal to `/^[A-Fa-f0-9]*$/`") # noqa: E501 self._supported_features = supported_features diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/snssai.py b/services/TS29222_CAPIF_Security_API/capif_security/models/snssai.py index 557c4bdefee53cd918a12740970fffc2f7b89542..90cde98ec45d99e5747842625e44d9b50fbb24c1 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/snssai.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/snssai.py @@ -1,6 +1,6 @@ import re # noqa: E501 from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model @@ -94,6 +94,6 @@ class Snssai(Model): :type sd: str """ if sd is not None and not re.search(r'^[A-Fa-f0-9]{6}$', sd): # noqa: E501 - raise ValueError("Invalid value for `sd`, must be a follow pattern or equal to `/^[A-Fa-f0-9]{6}$/`") # noqa: E501 + raise ValueError(r"Invalid value for `sd`, must be a follow pattern or equal to `/^[A-Fa-f0-9]{6}$/`") # noqa: E501 self._sd = sd diff --git a/services/TS29222_CAPIF_Security_API/capif_security/models/websock_notif_config.py b/services/TS29222_CAPIF_Security_API/capif_security/models/websock_notif_config.py index b72b264f4c1411234828bd2a2af341459d59609a..13109aa1543741d1e4e24465d804436c863bdfaa 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/models/websock_notif_config.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/models/websock_notif_config.py @@ -1,5 +1,5 @@ from datetime import date, datetime # noqa: F401 -from typing import List, Dict # noqa: F401 +from typing import Dict, List # noqa: F401 from capif_security import util from capif_security.models.base_model import Model diff --git a/services/TS29222_CAPIF_Security_API/capif_security/openapi/openapi.yaml b/services/TS29222_CAPIF_Security_API/capif_security/openapi/openapi.yaml index fe88c19931162b07c8de7a6f7a956eb55f96951b..71929d3de4564f9090f5af1333730b909828a888 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/openapi/openapi.yaml +++ b/services/TS29222_CAPIF_Security_API/capif_security/openapi/openapi.yaml @@ -3,9 +3,9 @@ info: description: "API for CAPIF security management. \n© 2024, 3GPP Organizational\ \ Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). \nAll rights reserved.\n" title: CAPIF_Security_API - version: 1.3.0-alpha.4 + version: 1.3.0 externalDocs: - description: 3GPP TS 29.222 V18.5.0 Common API Framework for 3GPP Northbound APIs + description: 3GPP TS 29.222 V18.6.0 Common API Framework for 3GPP Northbound APIs url: https://www.3gpp.org/ftp/Specs/archive/29_series/29.222/ servers: - url: "{apiRoot}/capif-security/v1" @@ -307,9 +307,9 @@ paths: put: callbacks: notificationDestination: - '{request.body#/notificationDestination}': + '{$request.body#/notificationDestination}': post: - operationId: notificationDestination_request_bodyNotificationDestinationPost + operationId: notification_destination_post requestBody: content: application/json: @@ -805,6 +805,9 @@ components: authorizationInfo: authorizationInfo interfaceDetails: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -817,14 +820,17 @@ components: - null aefId: aefId grantType: - - CLIENT_CREDENTIALS - - CLIENT_CREDENTIALS + - null + - null apiId: apiId - selSecurityMethod: null authenticationInfo: authenticationInfo authorizationInfo: authorizationInfo interfaceDetails: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -837,8 +843,8 @@ components: - null aefId: aefId grantType: - - CLIENT_CREDENTIALS - - CLIENT_CREDENTIALS + - null + - null apiId: apiId websockNotifConfig: requestWebsocketUri: true @@ -881,6 +887,9 @@ components: authorizationInfo: authorizationInfo interfaceDetails: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -893,15 +902,13 @@ components: - null aefId: aefId grantType: - - CLIENT_CREDENTIALS - - CLIENT_CREDENTIALS + - null + - null apiId: apiId nullable: true - oneOf: - - required: - - aefId - - required: - - interfaceDetails + oneOf: + - required: ["aefId"] + - required: ["interfaceDetails"] properties: interfaceDetails: $ref: '#/components/schemas/InterfaceDescription' @@ -1093,30 +1100,28 @@ components: title: AccessTokenErr type: object Cause: - anyOf: - - enum: + enum: - OVERLIMIT_USAGE - UNEXPECTED_REASON - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + - AUTHORIZATION_ISSUE + - OTHER_REASON + type: string description: "Indicates the cause for revoking the API invoker's authorization\ \ to the service API. \nPossible values are:\n- OVERLIMIT_USAGE:\n The\ \ revocation of the authorization of the API invoker is due to the overlimit\n\ \ usage of the service API\n- UNEXPECTED_REASON:\n The revocation\ - \ of the authorization of the API invoker is due to unexpected reason.\n" + \ of the authorization of the API invoker is due to unexpected reason.\n-\ + \ AUTHORIZATION_ISSUE:\n The revocation of the authorization of the API\ + \ invoker is due to API Invoker\n not being authorized anymore by the\ + \ API Provider.\n- OTHER_REASON:\n The revocation of the authorization\ + \ of the API invoker is due to other reason.\n" title: Cause OAuthGrantType: - anyOf: - - enum: + enum: - CLIENT_CREDENTIALS - AUTHORIZATION_CODE - AUTHORIZATION_CODE_WITH_PKCE - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration and is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the supported authorization flow (e.g. client credentials\ \ flow, authorization code flow, etc.) to the API invoker. \nPossible\ \ values are:\n- CLIENT_CREDENTIALS: Indicate that the grant type is is client\ @@ -1308,6 +1313,9 @@ components: description: Represents the description of an API's interface. example: ipv6Addr: ipv6Addr + grantTypes: + - CLIENT_CREDENTIALS + - CLIENT_CREDENTIALS securityMethods: - PSK - PSK @@ -1316,13 +1324,10 @@ components: apiPrefix: apiPrefix ipv4Addr: ipv4Addr nullable: true - oneOf: - - required: - - ipv4Addr - - required: - - ipv6Addr - - required: - - fqdn + oneOf: + - required: ["fqdn"] + - required: ["ipv4Addr"] + - required: ["ipv6Addr"] properties: ipv4Addr: description: | @@ -1361,18 +1366,20 @@ components: minItems: 1 title: securityMethods type: array + grantTypes: + items: + $ref: '#/components/schemas/OAuthGrantType' + minItems: 1 + title: grantTypes + type: array title: InterfaceDescription type: object SecurityMethod: - anyOf: - - enum: + enum: - PSK - PKI - OAUTH - type: string - - description: | - This string provides forward-compatibility with future extensions to the enumeration but is not used to encode content defined in the present version of this API. - type: string + type: string description: "Indicates the security method. \nPossible values are:\n- PSK:\ \ Security method 1 (Using TLS-PSK) as described in 3GPP TS 33.122.\n- PKI:\ \ Security method 2 (Using PKI) as described in 3GPP TS 33.122.\n- OAUTH:\ @@ -1530,12 +1537,52 @@ components: format: uuid title: NfInstanceId type: string + vendorId: + description: Vendor ID of the NF Service instance (Private Enterprise Number + assigned by IANA) + pattern: "^[0-9]{6}$" + title: VendorId + type: string + analyticsIds: + items: + $ref: '#/components/schemas/NwdafEvent' + minItems: 1 + title: analyticsIds + type: array + requesterInterIndList: + items: + $ref: '#/components/schemas/MlModelInterInd' + minItems: 1 + title: requesterInterIndList + type: array + sourceVendorId: + description: Vendor ID of the NF Service instance (Private Enterprise Number + assigned by IANA) + pattern: "^[0-9]{6}$" + title: VendorId + type: string required: - grant_type - nfInstanceId - scope title: AccessTokenReq_1 type: object + MlModelInterInd: + description: ML Model Interoperability Indicator per Analytics Id + properties: + analyticsId: + $ref: '#/components/schemas/NwdafEvent' + vendorList: + items: + $ref: '#/components/schemas/VendorId' + minItems: 1 + title: vendorList + type: array + required: + - analyticsId + - vendorList + title: MlModelInterInd + type: object NoProfileMatchInfo: description: Provides the reason for not finding NF matching the search criteria properties: @@ -1552,16 +1599,14 @@ components: title: NoProfileMatchInfo type: object NoProfileMatchReason: - anyOf: - - enum: + enum: - REQUESTER_PLMN_NOT_ALLOWED - TARGET_NF_SUSPENDED - TARGET_NF_UNDISCOVERABLE - QUERY_PARAMS_COMBINATION_NO_MATCH - TARGET_NF_TYPE_NOT_SUPPORTED - UNSPECIFIED - type: string - - type: string + type: string description: No Profile Match Reason title: NoProfileMatchReason QueryParamCombination: @@ -1615,8 +1660,7 @@ components: title: NfInstanceId type: string NFType: - anyOf: - - enum: + enum: - NRF - UDM - AMF @@ -1681,8 +1725,7 @@ components: - MF - SLPKMF - RH - type: string - - type: string + type: string description: NF types known to NRF title: NFType PlmnId: @@ -1809,3 +1852,62 @@ components: \ an alphabetic character or a digit.\n" title: NfServiceSetId type: string + VendorId: + description: Vendor ID of the NF Service instance (Private Enterprise Number + assigned by IANA) + pattern: "^[0-9]{6}$" + title: VendorId + type: string + NwdafEvent: + enum: + - SLICE_LOAD_LEVEL + - NETWORK_PERFORMANCE + - NF_LOAD + - SERVICE_EXPERIENCE + - UE_MOBILITY + - UE_COMMUNICATION + - QOS_SUSTAINABILITY + - ABNORMAL_BEHAVIOUR + - USER_DATA_CONGESTION + - NSI_LOAD_LEVEL + - DN_PERFORMANCE + - DISPERSION + - RED_TRANS_EXP + - WLAN_PERFORMANCE + - SM_CONGESTION + - PFD_DETERMINATION + - PDU_SESSION_TRAFFIC + - E2E_DATA_VOL_TRANS_TIME + - MOVEMENT_BEHAVIOUR + - LOC_ACCURACY + - RELATIVE_PROXIMITY + type: string + description: "Describes the NWDAF Events. \nPossible values are:\n- SLICE_LOAD_LEVEL:\ + \ Indicates that the event subscribed is load level information of Network\n\ + \ Slice.\n- NETWORK_PERFORMANCE: Indicates that the event subscribed is network\ + \ performance\n information.\n- NF_LOAD: Indicates that the event subscribed\ + \ is load level and status of one or several\n Network Functions.\n- SERVICE_EXPERIENCE:\ + \ Indicates that the event subscribed is service experience.\n- UE_MOBILITY:\ + \ Indicates that the event subscribed is UE mobility information.\n- UE_COMMUNICATION:\ + \ Indicates that the event subscribed is UE communication information.\n-\ + \ QOS_SUSTAINABILITY: Indicates that the event subscribed is QoS sustainability.\n\ + - ABNORMAL_BEHAVIOUR: Indicates that the event subscribed is abnormal behaviour.\n\ + - USER_DATA_CONGESTION: Indicates that the event subscribed is user data congestion\n\ + \ information.\n- NSI_LOAD_LEVEL: Indicates that the event subscribed is\ + \ load level information of Network\n Slice and the optionally associated\ + \ Network Slice Instance.\n- DN_PERFORMANCE: Indicates that the event subscribed\ + \ is DN performance information.\n- DISPERSION: Indicates that the event subscribed\ + \ is dispersion information.\n- RED_TRANS_EXP: Indicates that the event subscribed\ + \ is redundant transmission experience.\n- WLAN_PERFORMANCE: Indicates that\ + \ the event subscribed is WLAN performance.\n- SM_CONGESTION: Indicates the\ + \ Session Management Congestion Control Experience information\n for specific\ + \ DNN and/or S-NSSAI.\n- PFD_DETERMINATION: Indicates that the event subscribed\ + \ is the PFD Determination nformation\n for known application identifier(s).\n\ + - PDU_SESSION_TRAFFIC: Indicates that the event subscribed is the PDU Session\ + \ traffic\n information.\n- E2E_DATA_VOL_TRANS_TIME: Indicates that the event\ + \ subscribed is of E2E data volume \n transfer time.\n- MOVEMENT_BEHAVIOUR:\ + \ Indicates that the event subscribed is the Movement Behaviour\n information.\n\ + - LOC_ACCURACY: Indicates that the event subscribed is of location accuracy.\n\ + - RELATIVE_PROXIMITY: Indicates that the event subscribed is the Relative\ + \ Proximity\n information.\n" + title: NwdafEvent diff --git a/services/TS29222_CAPIF_Security_API/capif_security/test/test_default_controller.py b/services/TS29222_CAPIF_Security_API/capif_security/test/test_default_controller.py index 0fbd10e62626ed8f593c420322c65483c246f5ff..da26a6d60f9f873e168b53c95e80a271b395150e 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/test/test_default_controller.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/test/test_default_controller.py @@ -1,5 +1,11 @@ import unittest +from capif_security.models.access_token_err import AccessTokenErr # noqa: E501 +from capif_security.models.access_token_rsp import AccessTokenRsp # noqa: E501 +from capif_security.models.problem_details import ProblemDetails # noqa: E501 +from capif_security.models.res_owner_id import ResOwnerId # noqa: E501 +from capif_security.models.security_notification import SecurityNotification # noqa: E501 +from capif_security.models.service_security import ServiceSecurity # noqa: E501 from capif_security.test import BaseTestCase from flask import json @@ -90,7 +96,7 @@ class TestDefaultController(BaseTestCase): """ - service_security = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","securityInfo":[{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"apiId":"apiId"},{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"apiId":"apiId"}],"websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"requestTestNotification":True} + service_security = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","securityInfo":[{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":[null,null],"apiId":"apiId"},{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":[null,null],"apiId":"apiId"}],"websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"requestTestNotification":True} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', @@ -109,7 +115,7 @@ class TestDefaultController(BaseTestCase): """ - service_security = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","securityInfo":[{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"apiId":"apiId"},{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"apiId":"apiId"}],"websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"requestTestNotification":True} + service_security = {"notificationDestination":"notificationDestination","supportedFeatures":"supportedFeatures","securityInfo":[{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":[null,null],"apiId":"apiId"},{"authenticationInfo":"authenticationInfo","authorizationInfo":"authorizationInfo","interfaceDetails":{"ipv6Addr":"ipv6Addr","grantTypes":["CLIENT_CREDENTIALS","CLIENT_CREDENTIALS"],"securityMethods":["PSK","PSK"],"fqdn":"fqdn","port":5248,"apiPrefix":"apiPrefix","ipv4Addr":"ipv4Addr"},"prefSecurityMethods":[null,null],"aefId":"aefId","grantType":[null,null],"apiId":"apiId"}],"websockNotifConfig":{"requestWebsocketUri":True,"websocketUri":"websocketUri"},"requestTestNotification":True} headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', diff --git a/services/TS29222_CAPIF_Security_API/capif_security/typing_utils.py b/services/TS29222_CAPIF_Security_API/capif_security/typing_utils.py index d21c4f633653a0eae75d04b2f6eff684ff9d200d..74e3c913a7db6246bc765f147ca872996112c6bb 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/typing_utils.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/typing_utils.py @@ -1,6 +1,7 @@ import sys if sys.version_info < (3, 7): + import typing def is_generic(klass): """ Determine whether klass is a generic class """ diff --git a/services/TS29222_CAPIF_Security_API/prepare_security.sh b/services/TS29222_CAPIF_Security_API/prepare_security.sh index 86f10f24716dafa0d0f873cc40953f037fcdf9d7..c14609ad221170db6da6490cd3a77e85dd8f3ee3 100644 --- a/services/TS29222_CAPIF_Security_API/prepare_security.sh +++ b/services/TS29222_CAPIF_Security_API/prepare_security.sh @@ -3,17 +3,78 @@ VAULT_ADDR="http://$VAULT_HOSTNAME:$VAULT_PORT" VAULT_TOKEN=$VAULT_ACCESS_TOKEN +CERTS_FOLDER="/usr/src/app/capif_security" +# cd $CERTS_FOLDER +# Maximum number of retry attempts +MAX_RETRIES=30 +# Delay between retries (in seconds) +RETRY_DELAY=10 +# Attempt counter +ATTEMPT=0 -curl -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/server_cert/private" 2>/dev/null | jq -r '.data.data.key' -j > /usr/src/app/capif_security/server.key +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/ca" | jq -r '.data.data.ca') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > $CERTS_FOLDER/ca.crt + openssl verify -CAfile $CERTS_FOLDER/ca.crt $CERTS_FOLDER/ca.crt + echo "CA Root successfully saved." + SUCCES_OPERATION=true + break + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +if [ "$SUCCES_OPERATION" = false ]; then + echo "Error: Failed to retrieve ca root a valid response after $MAX_RETRIES attempts." + exit 1 # Exit with failure +fi + +# Setup inital value to ATTEMPT and SUCCESS_OPERATION +ATTEMPT=0 +SUCCES_OPERATION=false + +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/server_cert/private" | jq -r '.data.data.key') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > $CERTS_FOLDER/server.key + echo "Public key successfully saved." + SUCCES_OPERATION=true + break + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +if [ "$SUCCES_OPERATION" = false ]; then + echo "Error: Failed to retrieve server key valid response after $MAX_RETRIES attempts." + exit 1 # Exit with failure +fi gunicorn -k uvicorn.workers.UvicornH11Worker --bind 0.0.0.0:8080 \ - --chdir /usr/src/app/capif_security wsgi:app \ No newline at end of file + --chdir $CERTS_FOLDER wsgi:app diff --git a/services/TS29222_CAPIF_Security_API/requirements.txt b/services/TS29222_CAPIF_Security_API/requirements.txt index b3fd4f79e3b770f780fc9feba3d110657f189e87..cfd57783206b9456703ab7ca54ab729b2ac92428 100644 --- a/services/TS29222_CAPIF_Security_API/requirements.txt +++ b/services/TS29222_CAPIF_Security_API/requirements.txt @@ -21,5 +21,5 @@ opentelemetry-sdk == 1.19.0 Flask-APScheduler == 1.13.1 flask_executor == 1.0.0 werkzeug == 3.0.4 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 \ No newline at end of file diff --git a/services/TS29222_CAPIF_Security_API/setup.py b/services/TS29222_CAPIF_Security_API/setup.py index fc9b23b7d53422ce54abd698b7c191c2396b4fd2..f291508a42b991b1c21df0bb95c108472c38aea4 100644 --- a/services/TS29222_CAPIF_Security_API/setup.py +++ b/services/TS29222_CAPIF_Security_API/setup.py @@ -1,4 +1,5 @@ -from setuptools import setup, find_packages + +from setuptools import find_packages, setup NAME = "capif_security" VERSION = "1.0.0" diff --git a/services/celery/Dockerfile b/services/celery/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..ffad675f873609b54252c011d16cfa92cb244582 --- /dev/null +++ b/services/celery/Dockerfile @@ -0,0 +1,12 @@ +FROM labs.etsi.org:5050/ocf/capif/python:3-slim-bullseye + +WORKDIR /celery + +COPY requirements.txt /celery/ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . /celery + +RUN chmod +x /celery/start_celery.sh + +CMD ["/celery/start_celery.sh"] diff --git a/services/celery/__init__.py b/services/celery/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/services/celery/config.py b/services/celery/config.py new file mode 100644 index 0000000000000000000000000000000000000000..60d542a2fe7c8ed81b0a330732075101bf489ad6 --- /dev/null +++ b/services/celery/config.py @@ -0,0 +1,20 @@ +import os + +import yaml + + +#Config class to get config +class Config: + def __init__(self): + self.cached = 0 + self.file="./config.yaml" + self.my_config = {} + stamp = os.stat(self.file).st_mtime + if stamp != self.cached: + self.cached = stamp + f = open(self.file) + self.my_config = yaml.safe_load(f) + f.close() + + def get_config(self): + return self.my_config diff --git a/services/celery/config.yaml b/services/celery/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c1aa656aecf69ece1b9f04da73804dcb4c230e88 --- /dev/null +++ b/services/celery/config.yaml @@ -0,0 +1,8 @@ +mongo: { + 'user': 'root', + 'password': 'example', + 'db': 'capif', + 'notifications_col': 'notifications', + 'host': 'mongo', + 'port': "27017" +} diff --git a/services/celery/requirements.txt b/services/celery/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..32b0f0c6021ad8c149a4f87182cfe64f048e95b2 --- /dev/null +++ b/services/celery/requirements.txt @@ -0,0 +1,7 @@ +celery==5.4 +pymongo==4.2.0 +redis==4.5.4 +aiohttp == 3.10.5 +async-timeout == 4.0.3 +pyyaml == 6.0.2 +python_dateutil == 2.9.0 diff --git a/services/celery/start_celery.sh b/services/celery/start_celery.sh new file mode 100644 index 0000000000000000000000000000000000000000..778ae7b3e105a04e4860884ac73d5d692f34092b --- /dev/null +++ b/services/celery/start_celery.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ "$CELERY_MODE" = "worker" ]; then + echo "Starting Celery Worker..." + celery -A tasks worker +elif [ "$CELERY_MODE" = "beat" ]; then + echo "Iniciando Celery Beat..." + celery -A tasks beat +else + echo "ERROR: The environment variable CELERY_MODE is not set correctly (worker|beat)" + exit 1 +fi \ No newline at end of file diff --git a/services/celery/tasks.py b/services/celery/tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..212902671d31f430e47f4a0c6bd1536a044f5a58 --- /dev/null +++ b/services/celery/tasks.py @@ -0,0 +1,175 @@ +# celery/tasks.py +from celery import Celery +from datetime import datetime, timezone +import pymongo +import os +from bson.codec_options import CodecOptions +from config import Config +import aiohttp +import asyncio +import logging +from logging.handlers import RotatingFileHandler + +# Initialize Celery +celery = Celery( + "notifications", + broker=f"redis://{os.getenv("REDIS_HOST")}:{os.getenv("REDIS_PORT")}/0", + backend=f"redis://{os.getenv("REDIS_HOST")}:{os.getenv("REDIS_PORT")}/0" +) + +celery.conf.beat_schedule = { + "check_notifications_collection": { + "task": "celery.tasks.check_notifications_collection", + "schedule": 1.0, + "args": (), + }, +} + +celery.conf.timezone = "UTC" +celery.conf.update(worker_hijack_root_logger=False) + + +# Setting log level +# Set the log level based on the environment variable or default to INFO +log_level = os.getenv('LOG_LEVEL', 'INFO').upper() +numeric_level = getattr(logging, log_level, logging.INFO) + + +def verbose_formatter(): + return logging.Formatter( + '{"timestamp": "%(asctime)s", "level": "%(levelname)s", "logger": "%(name)s", "function": "%(funcName)s", "line": %(lineno)d, "message": %(message)s}', + datefmt='%d/%m/%Y %H:%M:%S' + ) + + +def configure_logging(): + + formatter = verbose_formatter() + + console_handler = logging.StreamHandler() + console_handler.setLevel(numeric_level) + console_handler.setFormatter(formatter) + + file_handler = RotatingFileHandler( + filename="celery_logs.log", + maxBytes=1024 * 1024 * 100, + backupCount=20 + ) + file_handler.setLevel(numeric_level) + file_handler.setFormatter(formatter) + + # Root logger configuration + root_logger = logging.getLogger() + root_logger.setLevel(numeric_level) + root_logger.handlers = [] + root_logger.addHandler(console_handler) + root_logger.addHandler(file_handler) + + # Optional: configure specific logger + logger = logging.getLogger(__name__) + logger.setLevel(numeric_level) + return logger + + +logger = configure_logging() + +# MongoDB Connection +config = Config().get_config() + +mongo_uri = f"mongodb://{config['mongo']['user']}:{config['mongo']['password']}@" \ + f"{config['mongo']['host']}:{config['mongo']['port']}" +client = pymongo.MongoClient(mongo_uri) +notifications_col = client[config['mongo']['db']][config['mongo']['notifications_col']].with_options(codec_options=CodecOptions(tz_aware=True)) + +def serialize_clean_camel_case(obj): + res = obj.to_dict() + res = clean_empty(res) + res = dict_to_camel_case(res) + + return res + +# Function to clean empty values from a dictionary +def clean_empty(d): + if isinstance(d, dict): + return { + k: v + for k, v in ((k, clean_empty(v)) for k, v in d.items()) + if v is not None or (isinstance(v, list) and len(v) == 0) + } + if isinstance(d, list): + return [v for v in map(clean_empty, d) if v is not None] + return d + +# Function to convert snake_case keys to camelCase +def dict_to_camel_case(my_dict): + + + result = {} + + for attr, value in my_dict.items(): + + if len(attr.split('_')) != 1: + my_key = ''.join(word.title() for word in attr.split('_')) + my_key = ''.join([my_key[0].lower(), my_key[1:]]) + else: + my_key = attr + + if my_key == "serviceApiCategory": + my_key = "serviceAPICategory" + elif my_key == "serviceApiDescriptions": + my_key = "serviceAPIDescriptions" + + if isinstance(value, list): + result[my_key] = list(map( + lambda x: dict_to_camel_case(x) if isinstance(x, dict) else x, value )) + + elif hasattr(value, "to_dict"): + result[my_key] = dict_to_camel_case(value) + + elif isinstance(value, dict): + value = dict_to_camel_case(value) + result[my_key] = value + else: + result[my_key] = value + + return result + +# Functions to send a request +async def send_request(url, data): + async with aiohttp.ClientSession() as session: + timeout = aiohttp.ClientTimeout(total=10) + headers = {'content-type': 'application/json'} + async with session.post(url, json=data, timeout=timeout, headers=headers) as response: + return await response.text() + +async def send(url, data): + try: + logger.info(f"Sending notification to {url} with data: {data}") + response = await send_request(url, data) + logger.info(response) + except asyncio.TimeoutError: + logger.info("Timeout: Request timeout") + except Exception as e: + logger.info("An exception occurred sending notification::" + str(e)) + return False + +# Periodic task to check the notifications collection +@celery.task(name="celery.tasks.check_notifications_collection") +def my_periodic_task(): + while True: + try: + notification_data = notifications_col.find_one_and_delete( + {"next_report_time": {"$lt": datetime.now(timezone.utc)}} + ) + if not notification_data: + break + except pymongo.errors.AutoReconnect: + logger.info("MongoDB connection failed. Retrying...") + continue + + try: + logger.info(f"Notification for suscription {notification_data["subscription_id"]} ready to send") + asyncio.run(send(notification_data["url"], notification_data["notification"])) + except Exception as e: + logger.info(f"Error sending notification: {e}") + diff --git a/services/check_architecture.sh b/services/check_architecture.sh new file mode 100755 index 0000000000000000000000000000000000000000..62cf2e35b2de8c15e6b4b37118c8ce6b06ed35f7 --- /dev/null +++ b/services/check_architecture.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +echo "Checking all images architecture" + +IMAGES=$(docker images|grep -v "REPOSITORY"|awk '{ print $1 ":" $2 }') + +for i in $IMAGES; do + Architecture=$(docker inspect $i|grep Architecture|awk '{ print $2 }') + + echo "Image $i with architecture $Architecture" +done diff --git a/services/check_services_are_running.sh b/services/check_services_are_running.sh index b7e7a7a18a21ea2803bd84687a6026801fd73ba7..a278793bea92a896381c62de626d5edc8d3140f0 100755 --- a/services/check_services_are_running.sh +++ b/services/check_services_are_running.sh @@ -1,11 +1,11 @@ #!/bin/bash +source $(dirname "$(readlink -f "$0")")/variables.sh + export CAPIF_PRIV_KEY= export CAPIF_PRIV_KEY_BASE_64= -export MONITORING= -export LOG_LEVEL=DEBUG -running="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-vault.yml ps --services --all --filter "status=running")" -services="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-vault.yml ps --services --all)" +running="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME docker compose -f docker-compose-vault.yml ps --services --all --filter "status=running")" +services="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME docker compose -f docker-compose-vault.yml ps --services --all)" if [ "$running" != "$services" ]; then echo "Following Vault services are not running:" # Bash specific @@ -15,8 +15,8 @@ else echo "All Vault services are running" fi -running="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-capif.yml ps --services --all --filter "status=running")" -services="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-capif.yml ps --services --all)" +running="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-capif.yml ps --services --all --filter "status=running")" +services="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-capif.yml ps --services --all)" if [ "$running" != "$services" ]; then echo "Following CCF services are not running:" # Bash specific @@ -26,8 +26,8 @@ else echo "All CCF services are running" fi -running="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-register.yml ps --services --all --filter "status=running")" -services="$(LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-register.yml ps --services --all)" +running="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-register.yml ps --services --all --filter "status=running")" +services="$(REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 LOG_LEVEL=$LOG_LEVEL docker compose -f docker-compose-register.yml ps --services --all)" if [ "$running" != "$services" ]; then echo "Following Register services are not running:" # Bash specific diff --git a/services/clean_capif_docker_services.sh b/services/clean_capif_docker_services.sh index dec71b8276795f5e87f3465723389f21442c717c..171bc55f2c31575c003e431a2319b438709cdb94 100755 --- a/services/clean_capif_docker_services.sh +++ b/services/clean_capif_docker_services.sh @@ -1,8 +1,5 @@ #!/bin/bash - -# Directories variables setup (no modification needed) -export SERVICES_DIR=$(dirname "$(readlink -f "$0")") -export CAPIF_BASE_DIR=$(dirname "$SERVICES_DIR") +source $(dirname "$(readlink -f "$0")")/variables.sh help() { echo "Usage: $1 " @@ -12,6 +9,7 @@ help() { echo " -m : Clean monitoring service" echo " -s : Clean Robot Mock service" echo " -a : Clean all services" + echo " -z : Clean images generated by docker-compose. Boolean. Default false" echo " -h : show this help" exit 1 } @@ -26,7 +24,7 @@ FILES=() echo "${FILES[@]}" # Read params -while getopts "cvrahms" opt; do +while getopts "cvrahmsz:" opt; do case $opt in c) echo "Remove Capif services" @@ -52,6 +50,10 @@ while getopts "cvrahms" opt; do echo "Remove all services" FILES=("$SERVICES_DIR/docker-compose-capif.yml" "$SERVICES_DIR/docker-compose-vault.yml" "$SERVICES_DIR/docker-compose-register.yml" "$SERVICES_DIR/docker-compose-mock-server.yml" "$SERVICES_DIR//monitoring/docker-compose.yml") ;; + z) + echo "Remove images generated by docker-compose" + REMOVE_IMAGES=$OPTARG + ;; h) help ;; @@ -70,9 +72,19 @@ done echo "after check" echo "${FILES[@]}" +echo "Remove images set to $REMOVE_IMAGES" +if [ $REMOVE_IMAGES == "true" ] ; then + echo "Removing images generated by docker-compose" + REMOVE_IMAGES="--rmi all" +else + echo "Not removing images generated by docker-compose" + REMOVE_IMAGES="" +fi + + for FILE in "${FILES[@]}"; do echo "Executing 'docker compose down' for file $FILE" - CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 DUID=$DUID DGID=$DGID MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f "$FILE" down --rmi all + REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 DUID=$DUID DGID=$DGID MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f "$FILE" down $REMOVE_IMAGES status=$? if [ $status -eq 0 ]; then echo "*** Removed Service from $FILE ***" @@ -81,6 +93,17 @@ for FILE in "${FILES[@]}"; do fi done +# Path to the register config.yaml file +REGISTER_CONFIG_FILE="$SERVICES_DIR/register/config.yaml" +# Check if the backup config.yaml file exists before restoring +if [ -f "$REGISTER_CONFIG_FILE.bak" ]; then + git update-index --no-assume-unchanged "$REGISTER_CONFIG_FILE.bak" + mv "$REGISTER_CONFIG_FILE.bak" "$REGISTER_CONFIG_FILE" + git update-index --no-assume-unchanged "$REGISTER_CONFIG_FILE" +else + echo "Backup config file not found, skipping restore." +fi + docker network rm capif-network docker volume prune --all --force diff --git a/services/clean_mock_server.sh b/services/clean_mock_server.sh index 157e39afdcc45888244966b137ab6b8eace842d7..31b654125ea6f24187d84a165a37b1515c6708ca 100755 --- a/services/clean_mock_server.sh +++ b/services/clean_mock_server.sh @@ -1,8 +1,7 @@ #!/bin/bash +source $(dirname "$(readlink -f "$0")")/variables.sh # Directories variables setup (no modification needed) -export SERVICES_DIR=$(dirname "$(readlink -f "$0")") - FILE="$SERVICES_DIR/docker-compose-mock-server.yml" echo "Executing 'docker compose down' for file $FILE" diff --git a/services/create_users.sh b/services/create_users.sh index d285bd1e1c3b5f7013ea9f835e0c433b4f6cc048..c740deb8c9e53c54353d515f9e81b3c847392a94 100755 --- a/services/create_users.sh +++ b/services/create_users.sh @@ -1,4 +1,5 @@ #!/bin/bash +source $(dirname "$(readlink -f "$0")")/variables.sh # User to create TOTAL_USERS=1 @@ -58,30 +59,6 @@ then exit -1 fi -# Other Stuff -DOCKER_ROBOT_IMAGE=labs.etsi.org:5050/ocf/capif/robot-tests-image -DOCKER_ROBOT_IMAGE_VERSION=1.0 -cd .. -REPOSITORY_BASE_FOLDER=${PWD} -TEST_FOLDER=$REPOSITORY_BASE_FOLDER/tests -RESULT_FOLDER=$REPOSITORY_BASE_FOLDER/results -ROBOT_DOCKER_FILE_FOLDER=$REPOSITORY_BASE_FOLDER/tools/robot - -# nginx Hostname and http port (80 by default) to reach for tests -CAPIF_REGISTER=capifcore -CAPIF_REGISTER_PORT=8084 -CAPIF_HOSTNAME=capifcore -CAPIF_HTTP_PORT=8080 -CAPIF_HTTPS_PORT=443 - -# VAULT access configuration -CAPIF_VAULT=vault -CAPIF_VAULT_PORT=8200 -CAPIF_VAULT_TOKEN=read-ca-token - -# Mock Server -MOCK_SERVER_URL=http://mock-server:9100 -NOTIFICATION_DESTINATION_URL=$MOCK_SERVER_URL PLATFORM=$(uname -m) if [ "x86_64" == "$PLATFORM" ]; then @@ -131,11 +108,13 @@ fi mkdir -p $RESULT_FOLDER -docker run -ti --rm --network="host" \ +docker run $DOCKER_ROBOT_TTY_OPTIONS --rm --network="host" \ --add-host host.docker.internal:host-gateway \ --add-host vault:host-gateway \ --add-host register:host-gateway \ --add-host mock-server:host-gateway \ + --add-host $CAPIF_HOSTNAME:host-gateway \ + --add-host $CAPIF_REGISTER:host-gateway \ -v $TEST_FOLDER:/opt/robot-tests/tests \ -v $RESULT_FOLDER:/opt/robot-tests/results ${DOCKER_ROBOT_IMAGE}:${DOCKER_ROBOT_IMAGE_VERSION} \ --variable CAPIF_HOSTNAME:$CAPIF_HOSTNAME \ diff --git a/services/docker-compose-capif.yml b/services/docker-compose-capif.yml index 037d5f3524b28a9f14a66211096ed63a03027efa..e021aa52c815819c8508dab50c5de0fc5f76a2a3 100644 --- a/services/docker-compose-capif.yml +++ b/services/docker-compose-capif.yml @@ -1,25 +1,25 @@ services: redis: - image: "redis:alpine" + image: "labs.etsi.org:5050/ocf/capif/redis:7.4.2-alpine" command: redis-server ports: - "6379:6379" volumes: - - $PWD/redis-data:/var/lib/redis - - $PWD/redis.conf:/usr/local/etc/redis/redis.conf + - ${SERVICES_DIR}/redis-data:/var/lib/redis + - ${SERVICES_DIR}/redis.conf:/usr/local/etc/redis/redis.conf environment: - REDIS_REPLICATION_MODE=master helper: build: - context: ./helper + context: ${SERVICES_DIR}/helper expose: - "8080" container_name: helper restart: unless-stopped volumes: - - ./helper:/usr/src/app + - ${SERVICES_DIR}/helper/config.yaml:/usr/src/app/config.yaml extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway @@ -32,17 +32,17 @@ services: - VAULT_ACCESS_TOKEN=dev-only-token - VAULT_PORT=8200 - LOG_LEVEL=${LOG_LEVEL} - image: labs.etsi.org:5050/ocf/capif/helper:v2.x.x-release + image: ${REGISTRY_BASE_URL}/helper:${OCF_VERSION} depends_on: - nginx access-control-policy: build: - context: ./TS29222_CAPIF_Access_Control_Policy_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Access_Control_Policy_API expose: - "8080" - volumes: - - ./TS29222_CAPIF_Access_Control_Policy_API:/usr/src/app + # volumes: + # - ${SERVICES_DIR}/TS29222_CAPIF_Access_Control_Policy_API:/usr/src/app extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway @@ -53,18 +53,19 @@ services: - MONITORING=${MONITORING} - LOG_LEVEL=${LOG_LEVEL} restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/access-control-policy:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-access-control-policy-api:${OCF_VERSION} depends_on: - redis - nginx api-invoker-management: build: - context: ./TS29222_CAPIF_API_Invoker_Management_API + context: ${SERVICES_DIR}/TS29222_CAPIF_API_Invoker_Management_API expose: - "8080" volumes: - - ./TS29222_CAPIF_API_Invoker_Management_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_API_Invoker_Management_API/config.yaml:/usr/src/app/config.yaml + - ${SERVICES_DIR}/TS29222_CAPIF_API_Invoker_Management_API/prepare_invoker.sh:/usr/src/app/prepare_invoker.sh extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway @@ -79,24 +80,25 @@ services: - VAULT_PORT=8200 - LOG_LEVEL=${LOG_LEVEL} restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/api-invoker-management-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-api-invoker-management-api:${OCF_VERSION} depends_on: - redis - nginx api-provider-management: build: - context: ./TS29222_CAPIF_API_Provider_Management_API + context: ${SERVICES_DIR}/TS29222_CAPIF_API_Provider_Management_API expose: - "8080" volumes: - - ./TS29222_CAPIF_API_Provider_Management_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_API_Provider_Management_API/config.yaml:/usr/src/app/config.yaml + - ${SERVICES_DIR}/TS29222_CAPIF_API_Provider_Management_API/prepare_provider.sh:/usr/src/app/prepare_provider.sh extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway - otel-collector:host-gateway - vault:host-gateway - image: labs.etsi.org:5050/ocf/capif/api-provider-management-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-api-provider-management-api:${OCF_VERSION} environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - CONTAINER_NAME=api-provider-management @@ -111,17 +113,17 @@ services: logs: build: - context: ./TS29222_CAPIF_Auditing_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Auditing_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Auditing_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_Auditing_API/config.yaml:/usr/src/app/config.yaml extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway - otel-collector:host-gateway restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/auditing-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-auditing-api:${OCF_VERSION} environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - CONTAINER_NAME=api-auditing @@ -132,17 +134,17 @@ services: service-apis: build: - context: ./TS29222_CAPIF_Discover_Service_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Discover_Service_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Discover_Service_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_Discover_Service_API/config.yaml:/usr/src/app/config.yaml restart: unless-stopped extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway - otel-collector:host-gateway - image: labs.etsi.org:5050/ocf/capif/discover-service-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-discover-service-api:${OCF_VERSION} environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - CONTAINER_NAME=services-apis @@ -153,12 +155,12 @@ services: capif-events: build: - context: ./TS29222_CAPIF_Events_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Events_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Events_API:/usr/src/app - image: labs.etsi.org:5050/ocf/capif/events-api:v2.x.x-release + - ${SERVICES_DIR}/TS29222_CAPIF_Events_API/config.yaml:/usr/src/app/config.yaml + image: ${REGISTRY_BASE_URL}/ocf-events-api:${OCF_VERSION} environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - CONTAINER_NAME=api-events @@ -173,15 +175,38 @@ services: - redis - mongo + celery_worker: + build: + context: ${SERVICES_DIR}/celery + environment: + - CELERY_MODE=worker + - REDIS_HOST=redis + - REDIS_PORT=6379 + - LOG_LEVEL=${LOG_LEVEL} + depends_on: + - redis + - mongo + + celery_beat: + build: + context: ${SERVICES_DIR}/celery + environment: + - CELERY_MODE=beat + - REDIS_HOST=redis + - REDIS_PORT=6379 + - LOG_LEVEL=${LOG_LEVEL} + depends_on: + - redis + - mongo api-invocation-logs: build: - context: ./TS29222_CAPIF_Logging_API_Invocation_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Logging_API_Invocation_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Logging_API_Invocation_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_Logging_API_Invocation_API/config.yaml:/usr/src/app/config.yaml restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/api-invocation-logs-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-logging-api-invocation-api:${OCF_VERSION} extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway @@ -196,13 +221,13 @@ services: published-apis: build: - context: ./TS29222_CAPIF_Publish_Service_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Publish_Service_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Publish_Service_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_Publish_Service_API/config.yaml:/usr/src/app/config.yaml restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/publish-service-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-publish-service-api:${OCF_VERSION} extra_hosts: - host.docker.internal:host-gateway - fluent-bit:host-gateway @@ -218,20 +243,21 @@ services: capif-routing-info: build: - context: ./TS29222_CAPIF_Routing_Info_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Routing_Info_API expose: - "8080" - image: labs.etsi.org:5050/ocf/capif/routing-info-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-routing-info-api:${OCF_VERSION} capif-security: build: - context: ./TS29222_CAPIF_Security_API + context: ${SERVICES_DIR}/TS29222_CAPIF_Security_API expose: - "8080" volumes: - - ./TS29222_CAPIF_Security_API:/usr/src/app + - ${SERVICES_DIR}/TS29222_CAPIF_Security_API/config.yaml:/usr/src/app/config.yaml + - ${SERVICES_DIR}/TS29222_CAPIF_Security_API/prepare_security.sh:/usr/src/app/prepare_security.sh restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/security-api:v2.x.x-release + image: ${REGISTRY_BASE_URL}/ocf-security-api:${OCF_VERSION} environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - CONTAINER_NAME=api-security @@ -251,7 +277,7 @@ services: - nginx mongo: - image: mongo:6.0.2 + image: labs.etsi.org:5050/ocf/capif/mongo:6.0.2 logging: driver: 'none' restart: unless-stopped @@ -260,7 +286,7 @@ services: MONGO_INITDB_ROOT_PASSWORD: example mongo-express: - image: mongo-express:1.0.0-alpha.4 + image: labs.etsi.org:5050/ocf/capif/mongo-express:1.0.0-alpha.4 logging: driver: 'none' restart: unless-stopped @@ -278,11 +304,11 @@ services: nginx: build: - context: ./nginx + context: ${SERVICES_DIR}/nginx ports: - "8080:8080" - "443:443" - image: labs.etsi.org:5050/ocf/capif/nginx:v2.x.x-release + image: labs.etsi.org:5050/ocf/capif/nginx-ocf-patched:1.27.1 environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - VAULT_HOSTNAME=vault @@ -291,7 +317,8 @@ services: - LOG_LEVEL=${LOG_LEVEL} hostname: ${CAPIF_HOSTNAME} volumes: - - ./nginx/certs:/etc/nginx/certs + - ${SERVICES_DIR}/nginx/certs:/etc/nginx/certs + - ${SERVICES_DIR}/nginx/nginx_prepare.sh:/nginx_prepare.sh extra_hosts: - host.docker.internal:host-gateway - vault:host-gateway diff --git a/services/docker-compose-mock-server.yml b/services/docker-compose-mock-server.yml index d769505c6b202843691aa29d2fe432a7dc9300b7..851f9f28a7b35c2200a5eb480409c9d9dda2a4e7 100644 --- a/services/docker-compose-mock-server.yml +++ b/services/docker-compose-mock-server.yml @@ -1,17 +1,17 @@ services: mock-server: build: - context: ./mock_server + context: ${SERVICES_DIR}/mock_server ports: - 9100:9100 volumes: - - ./mock_server:/usr/src/app + - ${SERVICES_DIR}/mock_server:/usr/src/app extra_hosts: - host.docker.internal:host-gateway environment: - DEBUG_MODE=True restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/mock_server:latest + image: ${REGISTRY_BASE_URL}/mock-server:${OCF_VERSION} networks: default: diff --git a/services/docker-compose-register.yml b/services/docker-compose-register.yml index 011e906367ad3f3491a1bdaeb15986f41ef2966f..4abed673d40d27ee70399e7de97d4895d9c82070 100644 --- a/services/docker-compose-register.yml +++ b/services/docker-compose-register.yml @@ -1,11 +1,11 @@ services: register: build: - context: ./register + context: ${SERVICES_DIR}/register ports: - 8084:8080 volumes: - - ./register:/usr/src/app + - ${SERVICES_DIR}/register/config.yaml:/usr/src/app/config.yaml environment: - CAPIF_PRIV_KEY=${CAPIF_PRIV_KEY} - VAULT_HOSTNAME=vault @@ -13,16 +13,17 @@ services: - VAULT_PORT=8200 - LOG_LEVEL=${LOG_LEVEL} - TIMEOUT=10 + - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} extra_hosts: - host.docker.internal:host-gateway - vault:host-gateway restart: unless-stopped - image: labs.etsi.org:5050/ocf/capif/register:v2.x.x-release + image: ${REGISTRY_BASE_URL}/register:${OCF_VERSION} depends_on: - mongo_register mongo_register: - image: mongo:6.0.2 + image: labs.etsi.org:5050/ocf/capif/mongo:6.0.2 logging: driver: 'none' restart: unless-stopped @@ -31,7 +32,7 @@ services: MONGO_INITDB_ROOT_PASSWORD: example mongo_register_express: - image: mongo-express:1.0.0-alpha.4 + image: labs.etsi.org:5050/ocf/capif/mongo-express:1.0.0-alpha.4 logging: driver: 'none' restart: unless-stopped diff --git a/services/docker-compose-vault.yml b/services/docker-compose-vault.yml index 82a38d0a8dd9d728c74a44ffe131ae272c34f211..f14391228d47ac8745c492228fac71cb1e6f17af 100644 --- a/services/docker-compose-vault.yml +++ b/services/docker-compose-vault.yml @@ -1,7 +1,8 @@ services: vault: + image: ${REGISTRY_BASE_URL}/vault:${OCF_VERSION} build: - context: ./vault + context: ${SERVICES_DIR}/vault restart: unless-stopped ports: - 8200:8200 @@ -10,6 +11,8 @@ services: environment: - VAULT_DEV_ROOT_TOKEN_ID=dev-only-token - VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 + - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} volumes: - - ./vault/data:/vault/data - - ./vault/config:/vault/config + - ${SERVICES_DIR}/vault/data:/vault/data + - ${SERVICES_DIR}/vault/config:/vault/config + - ${SERVICES_DIR}/vault/vault_prepare_certs.sh:/vault_prepare_certs.sh diff --git a/services/helper/config.yaml b/services/helper/config.yaml index bb090f086263a17001d9952b13befc7030696ef6..1efa369e54fb0a17672e0a8ff0fc54136c07fe74 100644 --- a/services/helper/config.yaml +++ b/services/helper/config.yaml @@ -7,6 +7,7 @@ mongo: { 'col_services': "serviceapidescriptions", 'col_security': "security", 'col_event': "eventsdetails", + 'col_capif_configuration': "capif_configuration", 'host': 'mongo', 'port': "27017" } @@ -17,3 +18,21 @@ ca_factory: { "token": "dev-only-token", "verify": False } + +capif_configuration: + config_description: Default CAPIF Configuration + config_name: default + config_version: "1.0" + settings: + acl_policy_settings: + allowed_invocation_time_range_days: 365 + allowed_invocations_per_second: 10 + allowed_total_invocations: 5 + certificates_expiry: + ttl_invoker_cert: 4300h + ttl_provider_cert: 4300h + ttl_superadmin_cert: 4300h + security_method_priority: + oauth: 1 + pki: 2 + psk: 3 diff --git a/services/helper/helper_service/app.py b/services/helper/helper_service/app.py index 3f9ae5c189c93467365eee63d6b393973c31d5ee..8525aa1ab09f629398313a20c80fd61164626e4f 100644 --- a/services/helper/helper_service/app.py +++ b/services/helper/helper_service/app.py @@ -1,20 +1,27 @@ import json import logging import os - import requests -from OpenSSL.crypto import PKey, TYPE_RSA, X509Req, dump_certificate_request, FILETYPE_PEM, dump_privatekey -from flask import Flask - from config import Config from controllers.helper_controller import helper_routes +from db.db import MongoDatabse +from flask import Flask +from OpenSSL.crypto import FILETYPE_PEM, TYPE_RSA, PKey, X509Req, dump_certificate_request, dump_privatekey +from asgiref.wsgi import WsgiToAsgi app = Flask(__name__) config = Config().get_config() +# Connect MongoDB and get TTL for superadmin certificate +db = MongoDatabse() +capif_config = db.get_col_by_name("capif_configuration").find_one({}) +ttl_superadmin_cert = capif_config["settings"]["certificates_expiry"].get("ttl_superadmin_cert", "43000h") + # Setting log level log_level = os.getenv('LOG_LEVEL', 'INFO').upper() numeric_level = getattr(logging, log_level, logging.INFO) +logging.basicConfig(level=numeric_level) +logger = logging.getLogger(__name__) # Create a superadmin CSR and keys key = PKey() @@ -35,6 +42,7 @@ private_key = dump_privatekey(FILETYPE_PEM, key) # Save superadmin private key key_file = open("certs/superadmin.key", 'wb+') key_file.write(bytes(private_key)) +logger.info(f"Superadmin key:\n{private_key}") key_file.close() # Request superadmin certificate @@ -42,13 +50,14 @@ url = 'http://{}:{}/v1/pki_int/sign/my-ca'.format(config["ca_factory"]["url"], c headers = {'X-Vault-Token': f"{config["ca_factory"]["token"]}"} data = { 'format':'pem_bundle', - 'ttl': '43000h', + 'ttl': ttl_superadmin_cert, 'csr': csr_request, 'common_name': "superadmin" } response = requests.request("POST", url, headers=headers, data=data, verify = config["ca_factory"].get("verify", False)) superadmin_cert = json.loads(response.text)['data']['certificate'] +logger.info(f"Superadmin Cert:\n{superadmin_cert}") # Save the superadmin certificate cert_file = open("certs/superadmin.crt", 'wb') @@ -63,6 +72,7 @@ headers = { response = requests.request("GET", url, headers=headers, verify = config["ca_factory"].get("verify", False)) ca_root = json.loads(response.text)['data']['data']['ca'] +logger.info(f"CA root:\n{ca_root}") cert_file = open("certs/ca_root.crt", 'wb') cert_file.write(bytes(ca_root, 'utf-8')) cert_file.close() @@ -70,3 +80,4 @@ cert_file.close() app.register_blueprint(helper_routes) app.logger.setLevel(numeric_level) +asgi_app = WsgiToAsgi(app) \ No newline at end of file diff --git a/services/helper/helper_service/controllers/helper_controller.py b/services/helper/helper_service/controllers/helper_controller.py index 03d276b78dc4744a35b60022e7c931a6a6d264dc..19b11160cc621d0b2a86b9bdc7ac0f50fe83065a 100644 --- a/services/helper/helper_service/controllers/helper_controller.py +++ b/services/helper/helper_service/controllers/helper_controller.py @@ -2,7 +2,7 @@ from config import Config from core.helper_operations import HelperOperations -from flask import Blueprint, request, current_app, jsonify +from flask import Blueprint, current_app, jsonify, request config = Config().get_config() @@ -113,3 +113,81 @@ def getEvents(): @helper_routes.route("/helper/deleteEntities/", methods=["DELETE"]) def deleteUserEntities(uuid): return helper_operation.remove_entities(uuid) + + +@helper_routes.route("/helper/getConfiguration", methods=["GET"]) +def getConfiguration(): + """Returns the current configuration""" + return helper_operation.get_configuration() + + +@helper_routes.route("/helper/updateConfigParam", methods=["PATCH"]) +def updateConfigParam(): + """Updates a single configuration parameter""" + data = request.json + param_path = data.get("param_path") + new_value = data.get("new_value") + + if not param_path or new_value is None: + return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400 + + return helper_operation.update_config_param(param_path, new_value) + + +@helper_routes.route("/helper/replaceConfiguration", methods=["PUT"]) +def replaceConfiguration(): + """Replaces the entire configuration with a new one""" + new_config = request.json + if not new_config: + return jsonify(message="Missing new configuration in request body"), 400 + + return helper_operation.replace_configuration(new_config) + + +@helper_routes.route("/helper/addNewConfiguration", methods=["POST"]) +def add_new_configuration(): + """Adds a new category inside 'settings'.""" + data = request.json + category_name = data.get("category_name") + category_values = data.get("category_values") + + if not category_name or not category_values: + return jsonify(message="Missing 'category_name' or 'category_values' in request body"), 400 + + return helper_operation.add_new_configuration(category_name, category_values) + +@helper_routes.route("/helper/addNewConfigSetting", methods=["PATCH"]) +def add_new_config_setting(): + """Adds a new configuration inside 'settings'.""" + data = request.json + param_path = data.get("param_path") + new_value = data.get("new_value") + + if not param_path or new_value is None: + return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400 + + return helper_operation.add_new_config_setting(param_path, new_value) + + +@helper_routes.route("/helper/removeConfigParam", methods=["DELETE"]) +def remove_config_param(): + """Deletes a specific parameter inside 'settings'.""" + data = request.json + param_path = data.get("param_path") + + if not param_path: + return jsonify(message="Missing 'param_path' in request body"), 400 + + return helper_operation.remove_config_param(param_path) + + +@helper_routes.route("/helper/removeConfigCategory", methods=["DELETE"]) +def remove_config_category(): + """Deletes an entire category inside 'settings'.""" + data = request.json + category_name = data.get("category_name") + + if not category_name: + return jsonify(message="Missing 'category_name' in request body"), 400 + + return helper_operation.remove_config_category(category_name) diff --git a/services/helper/helper_service/core/helper_operations.py b/services/helper/helper_service/core/helper_operations.py index d8a49c01a48b05255347f767ace16732ef3dd053..f0c1f6d3bcaa5243e7b6529b13114aa0b5b00c0a 100644 --- a/services/helper/helper_service/core/helper_operations.py +++ b/services/helper/helper_service/core/helper_operations.py @@ -4,7 +4,15 @@ import pymongo import requests from config import Config from db.db import MongoDatabse -from flask import jsonify, current_app +from flask import current_app, jsonify +from utils.utils import ( + convert_dict_keys_to_snake_case, + convert_nested_values, + convert_value_to_original_type, + get_nested_value, + to_snake_case, + validate_snake_case_keys +) class HelperOperations: @@ -201,6 +209,140 @@ class HelperOperations: current_app.logger.debug(f"User entities removed successfully") return jsonify(message="User entities removed successfully"), 200 + def get_configuration(self): + """Get all current settings.""" + current_app.logger.debug("Retrieving current CAPIF configuration") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + config = config_col.find_one({}, {"_id": 0}) + + if not config: + return jsonify(message="No CAPIF configuration found"), 404 + + return jsonify(config), 200 + + + def update_config_param(self, param_path, new_value): + """ + Updates a single parameter in the configuration. + param_path: Path of the parameter (e.g., settings.acl_policy_settings.allowed_total_invocations) + """ + current_app.logger.debug(f"Updating configuration parameter: {param_path} with value: {new_value}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + existing_config = config_col.find_one({}, {"_id": 0}) + current_value = get_nested_value(existing_config, param_path) + + if current_value is None: + return jsonify(message=f"The parameter '{param_path}' does not exist in the configuration"), 404 + + converted_value = convert_value_to_original_type(new_value, current_value) + + if isinstance(converted_value, tuple): + return converted_value + + update_query = {"$set": {param_path: converted_value}} + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path}' not updated"), 404 + + return jsonify(message=f"Parameter '{param_path}' updated successfully"), 200 + + def replace_configuration(self, new_config): + """ + Replace all current settings with a new one. + """ + current_app.logger.debug("Replacing entire CAPIF configuration") + + error_response = validate_snake_case_keys(new_config) + if error_response: + return error_response + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + existing_config = config_col.find_one({}, {"_id": 0}) + + if existing_config: + new_config = convert_nested_values(new_config, existing_config) + + result = config_col.replace_one({}, new_config, upsert=True) + + if result.matched_count == 0: + return jsonify(message="No existing configuration found; a new one was created"), 201 + + return jsonify(message="Configuration replaced successfully"), 200 + + + + def add_new_configuration(self, category_name, category_values): + """ + Add a new category of parameters in 'settings'. + """ + current_app.logger.debug(f"Adding new category: {category_name} with values: {category_values}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + category_name_snake = to_snake_case(category_name) + category_values_snake = convert_dict_keys_to_snake_case(category_values) + + update_query = {"$set": {f"settings.{category_name_snake}": category_values_snake}} + + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or category '{category_name_snake}' not added"), 404 + + return jsonify(message=f"Category '{category_name_snake}' added successfully"), 200 + + + def add_new_config_setting(self, param_path, new_value): + """Add a new parameter in 'settings'.""" + current_app.logger.debug(f"Adding new configuration setting: {param_path} with value: {new_value}") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + param_path_snake = ".".join(to_snake_case(part) for part in param_path.split(".")) + + update_query = {"$set": {f"settings.{param_path_snake}": new_value}} + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path_snake}' not updated"), 404 + + return jsonify(message=f"Parameter '{param_path_snake}' added successfully"), 200 + + + def remove_config_param(self, param_path): + """Removes a specific parameter inside 'settings'.""" + current_app.logger.debug(f"Removing configuration parameter: {param_path}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + param_path_snake = ".".join(to_snake_case(part) for part in param_path.split(".")) + + update_query = {"$unset": {f"settings.{param_path_snake}": ""}} + + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path_snake}' not removed"), 404 + + return jsonify(message=f"Parameter '{param_path_snake}' removed successfully"), 200 + + + def remove_config_category(self, category_name): + """Removes an entire category inside 'settings'.""" + current_app.logger.debug(f"Removing configuration category: {category_name}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + category_name_snake = to_snake_case(category_name) + + update_query = {"$unset": {f"settings.{category_name_snake}": ""}} + + result = config_col.update_one({}, update_query) + if result.modified_count == 0: + return jsonify(message=f"No configuration found or category '{category_name_snake}' not removed"), 404 + return jsonify(message=f"Category '{category_name_snake}' removed successfully"), 200 diff --git a/services/helper/helper_service/db/db.py b/services/helper/helper_service/db/db.py index 57b9b72e1563dddfa31c34dbc2a8f3a5adce00ab..8a7ea94d705339f40341dd350041b4848ea49606 100644 --- a/services/helper/helper_service/db/db.py +++ b/services/helper/helper_service/db/db.py @@ -16,6 +16,9 @@ class MongoDatabse(): self.services_col = self.config['mongo']['col_services'] self.security_context_col = self.config['mongo']['col_security'] self.events = self.config['mongo']['col_event'] + self.capif_configuration = self.config['mongo']['col_capif_configuration'] + + self.initialize_capif_configuration() def get_col_by_name(self, name): @@ -45,3 +48,19 @@ class MongoDatabse(): if self.db.client: self.db.client.close() + def initialize_capif_configuration(self): + """ + Inserts default data into the capif_configuration collection if it is empty. + The data is taken from config.yaml. + """ + capif_col = self.get_col_by_name(self.capif_configuration) + + if capif_col.count_documents({}) == 0: + # Read configuration from config.yaml + default_config = self.config["capif_configuration"] + + capif_col.insert_one(default_config) + print("Default data inserted into the capif_configuration collection from config.yaml") + else: + print("The capif_configuration collection already contains data. No default values were inserted.") + diff --git a/services/helper/helper_service/utils/utils.py b/services/helper/helper_service/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..fce57a344dd18e1f57625ca3ff9eeefced0428e2 --- /dev/null +++ b/services/helper/helper_service/utils/utils.py @@ -0,0 +1,93 @@ +import re + +from flask import jsonify + + +def to_snake_case(text): + """ + Convert string to snake case. + """ + return re.sub(r'\s+', '_', text).lower() + +def convert_dict_keys_to_snake_case(data): + """ + Converts the keys of a dictionary to snake_case. + """ + if isinstance(data, dict): + return {to_snake_case(k): convert_dict_keys_to_snake_case(v) for k, v in data.items()} + return data + + +def is_snake_case(value): + """ + Checks if a key is in snake_case. + """ + return bool(re.match(r'^[a-z0-9_]+$', value)) + +def validate_snake_case_keys(obj, path="root"): + """ + Iterates through the JSON validating that all keys are in snake_case. + """ + for key, value in obj.items(): + if not is_snake_case(key): + return jsonify({"error": f"The key '{path}.{key}' is not in snake_case"}), 400 + if isinstance(value, dict): + error_response = validate_snake_case_keys(value, f"{path}.{key}") + if error_response: + return error_response + +def get_nested_value(config, path): + """ + Gets a value within a nested dictionary by following a path of keys separated by periods. + """ + keys = path.split('.') + for key in keys: + if isinstance(config, dict) and key in config: + config = config[key] + else: + return None + return config + +def convert_value_to_original_type(new_value, current_value): + """ + Convert new_value to the type of current_value. + """ + if isinstance(current_value, int): + try: + return int(new_value) + except ValueError: + return jsonify(message=f"Invalid value: {new_value} is not an integer"), 400 + elif isinstance(current_value, float): + try: + return float(new_value) + except ValueError: + return jsonify(message=f"Invalid value: {new_value} is not a float"), 400 + elif isinstance(current_value, bool): + if isinstance(new_value, str) and new_value.lower() in ["true", "false"]: + return new_value.lower() == "true" + elif not isinstance(new_value, bool): + return jsonify(message=f"Invalid value: {new_value} is not a boolean"), 400 + return new_value + +def convert_nested_values(new_data, reference_data): + """ + Recursively traverses new_data and converts values ​​back to the original type based on reference_data. + """ + if isinstance(new_data, dict) and isinstance(reference_data, dict): + for key, value in new_data.items(): + if key in reference_data: + new_data[key] = convert_nested_values(value, reference_data[key]) + elif isinstance(reference_data, int): + try: + return int(new_data) + except ValueError: + return new_data + elif isinstance(reference_data, float): + try: + return float(new_data) + except ValueError: + return new_data + elif isinstance(reference_data, bool): + if isinstance(new_data, str) and new_data.lower() in ["true", "false"]: + return new_data.lower() == "true" + return new_data \ No newline at end of file diff --git a/services/helper/helper_service/wsgi.py b/services/helper/helper_service/wsgi.py index 6026b0fa96078634d3455ab93d71dcdc78774276..55e6ab2d5441cbd2ab49f75d4ec3d670361820f4 100644 --- a/services/helper/helper_service/wsgi.py +++ b/services/helper/helper_service/wsgi.py @@ -1,4 +1,4 @@ -from app import app +from app import asgi_app if __name__ == "__main__": - app.run() + asgi_app.run() diff --git a/services/helper/prepare_helper.sh b/services/helper/prepare_helper.sh index d4297f6484ddfe6ee867338b7d19b7eb97fc4b7d..3fe4988c2a0c3c5c3acbd545e7274029a3f2028c 100644 --- a/services/helper/prepare_helper.sh +++ b/services/helper/prepare_helper.sh @@ -1,5 +1,5 @@ #!/bin/bash -gunicorn --bind 0.0.0.0:8080 \ - --chdir /usr/src/app/helper_service wsgi:app \ No newline at end of file +gunicorn -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8080 \ + --chdir /usr/src/app/helper_service wsgi:asgi_app \ No newline at end of file diff --git a/services/helper/requirements.txt b/services/helper/requirements.txt index 48b0fba6161e185929637b7288143660257aa8b0..14644ee7471885fbfa74eb2c23a6d0fe698e7709 100644 --- a/services/helper/requirements.txt +++ b/services/helper/requirements.txt @@ -6,5 +6,7 @@ flask_jwt_extended == 4.6.0 pyopenssl == 24.1.0 pyyaml == 6.0.1 requests == 2.32.2 -gunicorn == 22.0.0 +gunicorn == 23.0.0 +uvicorn == 0.34.2 +asgiref == 3.8.1 packaging == 24.0 diff --git a/services/monitoring/docker-compose.yml b/services/monitoring/docker-compose.yml index e71dff523f44176692e339f8b88d1ca1a9495c27..3a83d2396dd0f9b175a2491889fa3da281313040 100644 --- a/services/monitoring/docker-compose.yml +++ b/services/monitoring/docker-compose.yml @@ -32,7 +32,7 @@ services: - /var/run/docker.sock:/var/run/docker.sock:rw grafana: - image: grafana/grafana + image: grafana/grafana:11.5.2 user: "${DUID}:${DGID}" environment: - GF_SECURITY_ADMIN_PASSWORD=secure_pass @@ -68,7 +68,7 @@ services: # grafana image renderer renderer: - image: grafana/grafana-image-renderer:latest + image: grafana/grafana-image-renderer:3.12.1 container_name: grafana-image-renderer expose: - "8081" @@ -77,7 +77,7 @@ services: # fluent-bit send logs to loki fluent-bit: - image: grafana/fluent-bit-plugin-loki:latest + image: grafana/fluent-bit-plugin-loki:3.1.2 container_name: fluent-bit environment: - LOKI_URL=http://loki:3100/loki/api/v1/push @@ -89,7 +89,7 @@ services: # opentelemetry collector otel-collector: - image: otel/opentelemetry-collector:latest + image: otel/opentelemetry-collector:0.120.0 ports: - 55680:55680 - 4317:4317 @@ -99,7 +99,7 @@ services: # tempo is a distributed tracing backend tempo: - image: grafana/tempo:latest + image: grafana/tempo:r190-70f6095 command: [ "-config.file=/etc/tempo.yaml" ] volumes: - ./tempo/tempo.yaml:/etc/tempo.yaml diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index c87732c5ba562af7dac31974b62bc560a47faef1..b163386ec2e8883c87d09c768fe9edd1b6f35704 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -1,4 +1,4 @@ -FROM labs.etsi.org:5050/ocf/capif/nginx:1.27.1 +FROM labs.etsi.org:5050/ocf/capif/nginx-ocf-patched:1.27.1 RUN apt-get update && apt-get install -y jq && apt-get clean RUN apt-get install -y openssl RUN apt-get install -y curl diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index f51e177fd0fce53f6d151e3483fcd4802a5a1d3c..ecde2dc13855140e0b2cb70437149c297cf9bb46 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -142,6 +142,10 @@ http { return 401 $security_error_message; } + proxy_set_header X-TLS-Protocol $ssl_protocol; + proxy_set_header X-TLS-Session-ID $ssl_session_id; + proxy_set_header X-TLS-MKey $sslkeylog_mk; + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://capif-security:8080; } diff --git a/services/nginx/nginx_prepare.sh b/services/nginx/nginx_prepare.sh index 75fc9fd5e9a86d4dca66ef0b7124f08557b510ac..91884863cc069fc05e1ad71e018627143ed5aa88 100644 --- a/services/nginx/nginx_prepare.sh +++ b/services/nginx/nginx_prepare.sh @@ -5,34 +5,112 @@ cd $CERTS_FOLDER VAULT_ADDR="http://$VAULT_HOSTNAME:$VAULT_PORT" VAULT_TOKEN=$VAULT_ACCESS_TOKEN -curl -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/ca" 2>/dev/null | jq -r '.data.data.ca' -j > $CERTS_FOLDER/ca.crt - -openssl verify -CAfile $CERTS_FOLDER/ca.crt $CERTS_FOLDER/ca.crt - -curl -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/server_cert" 2>/dev/null | jq -r '.data.data.cert' -j > $CERTS_FOLDER/server.crt - -curl -k -retry 30 \ - --retry-all-errors \ - --connect-timeout 5 \ - --max-time 10 \ - --retry-delay 10 \ - --retry-max-time 300 \ - --header "X-Vault-Token: $VAULT_TOKEN" \ - --request GET "$VAULT_ADDR/v1/secret/data/server_cert/private" 2>/dev/null | jq -r '.data.data.key' -j > $CERTS_FOLDER/server.key +# Maximum number of retry attempts +MAX_RETRIES=30 +# Delay between retries (in seconds) +RETRY_DELAY=10 +# Attempt counter +ATTEMPT=0 +# Success check +SUCCES_OPERATION=false + +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/ca" | jq -r '.data.data.ca') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > $CERTS_FOLDER/ca.crt + openssl verify -CAfile $CERTS_FOLDER/ca.crt $CERTS_FOLDER/ca.crt + echo "CA Root successfully saved." + SUCCES_OPERATION=true + break + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +if [ "$SUCCES_OPERATION" = false ]; then + echo "Error: Failed to retrieve a valid response after $MAX_RETRIES attempts." + exit 1 # Exit with failure +fi + +# Setup inital value to ATTEMPT and SUCCESS_OPERATION +ATTEMPT=0 +SUCCES_OPERATION=false + +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/server_cert" | jq -r '.data.data.cert') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > $CERTS_FOLDER/server.crt + echo "Server Certificate successfully saved." + ATTEMPT=0 + SUCCES_OPERATION=true + break + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +if [ "$SUCCES_OPERATION" = false ]; then + echo "Error: Failed to retrieve a valid response after $MAX_RETRIES attempts." + exit 1 # Exit with failure +fi + +# Setup inital value to ATTEMPT and SUCCESS_OPERATION +ATTEMPT=0 +SUCCES_OPERATION=false + +while [ $ATTEMPT -lt $MAX_RETRIES ]; do + # Increment ATTEMPT using eval + eval "ATTEMPT=\$((ATTEMPT + 1))" + echo "Attempt $ATTEMPT of $MAX_RETRIES" + + # Make the request to Vault and store the response in a variable + RESPONSE=$(curl -s -k --connect-timeout 5 --max-time 10 \ + --header "X-Vault-Token: $VAULT_TOKEN" \ + --request GET "$VAULT_ADDR/v1/secret/data/server_cert/private" | jq -r '.data.data.key') + + echo "$RESPONSE" + + # Check if the response is "null" or empty + if [ -n "$RESPONSE" ] && [ "$RESPONSE" != "null" ]; then + echo "$RESPONSE" > $CERTS_FOLDER/server.key + echo "Server Key successfully saved." + ATTEMPT=0 + SUCCES_OPERATION=true + break + else + echo "Invalid response ('null' or empty), retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi +done + +if [ "$SUCCES_OPERATION" = false ]; then + echo "Error: Failed to retrieve a valid response after $MAX_RETRIES attempts." + exit 1 # Exit with failure +fi LOG_LEVEL=$(echo "${LOG_LEVEL}" | tr '[:upper:]' '[:lower:]') @@ -50,4 +128,4 @@ esac envsubst '$LOG_LEVEL' < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf -nginx \ No newline at end of file +nginx diff --git a/services/register/Dockerfile b/services/register/Dockerfile index bb03b219822ebcd8641e50013b0e6b84d72ece6e..24676e54345f768d50155c78a4d4a218aa46cfe0 100644 --- a/services/register/Dockerfile +++ b/services/register/Dockerfile @@ -17,8 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip3 install --no-cache-dir -r requirements.txt RUN apt-get update && apt-get install -y --no-install-recommends openssl curl redis -#ENV CAPIF_PRIV_KEY = $CAPIF_PRIV_KEY - COPY . /usr/src/app EXPOSE 8080 diff --git a/services/register/config.yaml b/services/register/config.yaml index f1e1a257290897585780b9fe5e8eac6ae5e2e0ee..85fb232ca577dbf18c873e74383d7f380463c9c5 100644 --- a/services/register/config.yaml +++ b/services/register/config.yaml @@ -3,6 +3,7 @@ mongo: { 'password': 'example', 'db': 'capif_users', 'col': 'user', + 'col_capif_configuration': "capif_configuration", 'admins': 'admins', 'host': 'mongo_register', 'port': '27017' @@ -25,4 +26,12 @@ register: { "token_expiration": 10, #mins "admin_users": {admin_user: "admin", admin_pass: "password123"} -} \ No newline at end of file +} + +capif_configuration: + config_description: Default Register Configuration + config_name: default + config_version: "1.0" + settings: + certificates_expiry: + ttl_superadmin_cert: 4300h \ No newline at end of file diff --git a/services/register/register_service/app.py b/services/register/register_service/app.py index 5e9c9a450b8b5a574030eb2de3ef41e626e68923..60447746c814411cd5659a2a70f810c8426e8277 100644 --- a/services/register/register_service/app.py +++ b/services/register/register_service/app.py @@ -4,13 +4,13 @@ import logging import os import requests -from OpenSSL.crypto import PKey, TYPE_RSA, X509Req, dump_certificate_request, FILETYPE_PEM, dump_privatekey -from flask import Flask -from flask_jwt_extended import JWTManager - from config import Config from controllers.register_controller import register_routes from db.db import MongoDatabse +from flask import Flask +from flask_jwt_extended import JWTManager +from OpenSSL.crypto import FILETYPE_PEM, TYPE_RSA, PKey, X509Req, dump_certificate_request, dump_privatekey +from utils.auth_utils import hash_password app = Flask(__name__) @@ -19,6 +19,11 @@ jwt_manager = JWTManager(app) config = Config().get_config() +# Connect MongoDB and get TTL for superadmin certificate +db = MongoDatabse() +capif_config = db.get_col_by_name("capif_configuration").find_one({}) +ttl_superadmin_cert = capif_config.get("settings", {}).get("certificates_expiry", {}).get("ttl_superadmin_cert", "43000h") + # Setting log level log_level = os.getenv('LOG_LEVEL', 'INFO').upper() numeric_level = getattr(logging, log_level, logging.INFO) @@ -49,7 +54,7 @@ url = 'http://{}:{}/v1/pki_int/sign/my-ca'.format(config["ca_factory"]["url"], c headers = {'X-Vault-Token': f"{config["ca_factory"]["token"]}"} data = { 'format':'pem_bundle', - 'ttl': '43000h', + 'ttl': ttl_superadmin_cert, 'csr': csr_request, 'common_name': "superadmin" } @@ -83,9 +88,13 @@ key_data = json.loads(response.text)["data"]["data"]["key"] # Create an Admin in the Admin Collection client = MongoDatabse() -if not client.get_col_by_name(client.capif_admins).find_one({"admin_name": config["register"]["admin_users"]["admin_user"], "admin_pass": config["register"]["admin_users"]["admin_pass"]}): - print(f'Inserting Initial Admin admin_name: {config["register"]["admin_users"]["admin_user"]}, admin_pass: {config["register"]["admin_users"]["admin_pass"]}') - client.get_col_by_name(client.capif_admins).insert_one({"admin_name": config["register"]["admin_users"]["admin_user"], "admin_pass": config["register"]["admin_users"]["admin_pass"]}) +admin_username = config["register"]["admin_users"]["admin_user"] +admin_password = config["register"]["admin_users"]["admin_pass"] + +if not client.get_col_by_name(client.capif_admins).find_one({"admin_name": admin_username}): + print(f'Inserting Initial Admin admin_name: {config["register"]["admin_users"]["admin_user"]}') + + client.get_col_by_name(client.capif_admins).insert_one({"admin_name": config["register"]["admin_users"]["admin_user"], "admin_pass": hash_password(config["register"]["admin_users"]["admin_pass"])}) app.config['JWT_ALGORITHM'] = 'RS256' diff --git a/services/register/register_service/controllers/register_controller.py b/services/register/register_service/controllers/register_controller.py index ff3a5618349f3cb20a1172403b41aeb9e6a90797..031185eb516748932dd5b402e5b9223bc9e5cdbb 100644 --- a/services/register/register_service/controllers/register_controller.py +++ b/services/register/register_service/controllers/register_controller.py @@ -7,8 +7,9 @@ import jwt from config import Config from core.register_operations import RegisterOperations from db.db import MongoDatabse -from flask import current_app, jsonify, request, Blueprint +from flask import Blueprint, current_app, jsonify, request from flask_httpauth import HTTPBasicAuth +from utils.auth_utils import check_password auth = HTTPBasicAuth() @@ -39,15 +40,16 @@ def verify_password(username, password): current_app.logger.debug("Checking user credentials...") users = register_operation.get_users()[0].json["users"] client = MongoDatabse() - admin = client.get_col_by_name(client.capif_admins).find_one({"admin_name": username, "admin_pass": password}) - if admin: + admin = client.get_col_by_name(client.capif_admins).find_one({"admin_name": username}) + if admin and check_password(password, admin["admin_pass"]): current_app.logger.debug(f"Verified admin {username}") return username, "admin" for user in users: - if user["username"] == username and user["password"]==password: + if user["username"] == username and check_password(password, user["password"]): current_app.logger.debug(f"Verified user {username}") return username, "client" + # Function responsible for verifying the token def admin_required(): def decorator(f): @@ -156,3 +158,93 @@ def remove(username, uuid): def getUsers(username): current_app.logger.debug(f"Returning list of users to admin {username}") return register_operation.get_users() + + +@register_routes.route("/configuration", methods=["GET"]) +@admin_required() +def get_register_configuration(username): + """Retrieve the current register configuration""" + current_app.logger.debug(f"Admin {username} is retrieving the register configuration") + return register_operation.get_register_configuration() + + +@register_routes.route("/configuration", methods=["PATCH"]) +@admin_required() +def update_register_config_param(username): + """Update a single parameter in the register configuration""" + data = request.json + param_path = data.get("param_path") + new_value = data.get("new_value") + + if not param_path or new_value is None: + return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400 + + current_app.logger.debug(f"Admin {username} is updating parameter {param_path} with value {new_value}") + return register_operation.update_register_config_param(param_path, new_value) + + +@register_routes.route("/configuration", methods=["PUT"]) +@admin_required() +def replace_register_configuration(username): + """Replace the entire register configuration""" + new_config = request.json + if not new_config: + return jsonify(message="Missing new configuration in request body"), 400 + + current_app.logger.debug(f"Admin {username} is replacing the entire register configuration") + return register_operation.replace_register_configuration(new_config) + + +@register_routes.route("/configuration/addNewCategory", methods=["POST"]) +def add_new_category(): + """Adds a new category inside 'settings'.""" + data = request.json + category_name = data.get("category_name") + category_values = data.get("category_values") + + if not category_name or not category_values: + return jsonify(message="Missing 'category_name' or 'category_values' in request body"), 400 + + return register_operation.add_new_category(category_name, category_values) + + +@register_routes.route("/configuration/addNewParamConfigSetting", methods=["PATCH"]) +def add_new_config_setting(): + """Adds a new configuration inside a category in 'settings'.""" + data = request.json + param_path = data.get("param_path") + new_value = data.get("new_value") + + if not param_path or new_value is None: + return jsonify(message="Missing 'param_path' or 'new_value' in request body"), 400 + + return register_operation.add_new_config_setting(param_path, new_value) + + +@register_routes.route("/configuration/removeConfigParam", methods=["DELETE"]) +@admin_required() +def remove_register_config_param(username): + """Remove a specific parameter in the register configuration""" + data = request.json + param_path = data.get("param_path") + + if not param_path: + return jsonify(message="Missing 'param_path' in request body"), 400 + + current_app.logger.debug(f"Admin {username} is removing parameter {param_path}") + return register_operation.remove_register_config_param(param_path) + + +@register_routes.route("/configuration/removeConfigCategory", methods=["DELETE"]) +@admin_required() +def remove_register_config_category(username): + """Remove an entire category in the register configuration""" + data = request.json + category_name = data.get("category_name") + + if not category_name: + return jsonify(message="Missing 'category_name' in request body"), 400 + + current_app.logger.debug(f"Admin {username} is removing category {category_name}") + return register_operation.remove_register_config_category(category_name) + diff --git a/services/register/register_service/core/register_operations.py b/services/register/register_service/core/register_operations.py index 937ce0bd068af2e4281d4aab5835510668c8267b..8dc4a2eaea93bec8f4826ef69f20538b01e5b6d4 100644 --- a/services/register/register_service/core/register_operations.py +++ b/services/register/register_service/core/register_operations.py @@ -5,8 +5,10 @@ from datetime import datetime import requests from config import Config from db.db import MongoDatabse -from flask import jsonify, current_app +from flask import current_app, jsonify from flask_jwt_extended import create_access_token +from utils.utils import convert_dict_keys_to_snake_case, to_snake_case, validate_snake_case_keys +from utils.auth_utils import hash_password class RegisterOperations: @@ -30,6 +32,7 @@ class RegisterOperations: user_info["uuid"] = user_uuid user_info["onboarding_date"]=datetime.now() + user_info["password"] = hash_password(user_info["password"]) mycol.insert_one(user_info) current_app.logger.debug(f"User with uuid {user_uuid} and username {user_info["username"]} registered successfully") @@ -89,8 +92,123 @@ class RegisterOperations: mycol = self.db.get_col_by_name(self.db.capif_users) try: + current_app.logger.debug(f"users") users=list(mycol.find({}, {"_id":0})) + current_app.logger.debug(f"{users}") return jsonify(message="Users successfully obtained", users=users), 200 except Exception as e: return jsonify(message=f"Error trying to get users: {e}"), 500 + + def get_register_configuration(self): + """Retrieve the current register configuration from MongoDB""" + current_app.logger.debug("Retrieving register configuration") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + config = config_col.find_one({}, {"_id": 0}) + + if not config: + return jsonify(message="No register configuration found"), 404 + + return jsonify(config), 200 + + def update_register_config_param(self, param_path, new_value): + """Update a specific parameter in the register configuration""" + current_app.logger.debug(f"Updating register configuration parameter: {param_path} with value: {new_value}") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + update_query = {"$set": {param_path: new_value}} + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path}' not updated"), 404 + + return jsonify(message=f"Parameter '{param_path}' updated successfully"), 200 + + def replace_register_configuration(self, new_config): + """Replace the entire register configuration""" + current_app.logger.debug("Replacing entire register configuration") + + error_response = validate_snake_case_keys(new_config) + if error_response: + return error_response + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + result = config_col.replace_one({}, new_config, upsert=True) + + if result.matched_count == 0: + return jsonify(message="No existing configuration found; a new one was created"), 201 + + return jsonify(message="Register configuration replaced successfully"), 200 + + + def add_new_category(self, category_name, category_values): + """Adds a new category of parameters in 'settings'.""" + current_app.logger.debug(f"Adding new category: {category_name} with values: {category_values}") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + category_name_snake = to_snake_case(category_name) + category_values_snake = convert_dict_keys_to_snake_case(category_values) + + update_query = {"$set": {f"settings.{category_name_snake}": category_values_snake}} + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or category '{category_name_snake}' not added"), 404 + + return jsonify(message=f"Category '{category_name_snake}' added successfully"), 200 + + + def add_new_config_setting(self, param_path, new_value): + """Adds a new parameter inside a category in 'settings'.""" + current_app.logger.debug(f"Adding new configuration setting: {param_path} with value: {new_value}") + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + param_path_snake = ".".join(to_snake_case(part) for part in param_path.split(".")) + update_query = {"$set": {f"settings.{param_path_snake}": new_value}} + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path_snake}' not updated"), 404 + + return jsonify(message=f"Parameter '{param_path_snake}' added successfully"), 200 + + + def remove_register_config_param(self, param_path): + """ + Removes a specific parameter in the registry settings. + """ + current_app.logger.debug(f"Removing configuration parameter: {param_path}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + param_path_snake = ".".join(to_snake_case(part) for part in param_path.split(".")) + update_query = {"$unset": {f"settings.{param_path_snake}": ""}} + + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or parameter '{param_path_snake}' not removed"), 404 + + return jsonify(message=f"Parameter '{param_path_snake}' removed successfully"), 200 + + + def remove_register_config_category(self, category_name): + """ + Deletes an entire category within 'settings'. + """ + current_app.logger.debug(f"Removing configuration category: {category_name}") + + config_col = self.db.get_col_by_name(self.db.capif_configuration) + + category_name_snake = to_snake_case(category_name) + update_query = {"$unset": {f"settings.{category_name_snake}": ""}} + + result = config_col.update_one({}, update_query) + + if result.modified_count == 0: + return jsonify(message=f"No configuration found or category '{category_name_snake}' not removed"), 404 + + return jsonify(message=f"Category '{category_name_snake}' removed successfully"), 200 + + diff --git a/services/register/register_service/db/db.py b/services/register/register_service/db/db.py index e1db51bd979abfdc185e9abb492cde05ddac410f..a93cdeaaad9b52ae7e5099b648b0309838be8f4b 100644 --- a/services/register/register_service/db/db.py +++ b/services/register/register_service/db/db.py @@ -12,7 +12,9 @@ class MongoDatabse(): self.db = self.__connect() self.capif_users = self.config['mongo']['col'] self.capif_admins = self.config['mongo']['admins'] - + self.capif_configuration = self.config['mongo']['col_capif_configuration'] + + self.initialize_capif_configuration() def get_col_by_name(self, name): return self.db[name] @@ -33,6 +35,15 @@ class MongoDatabse(): time.sleep(retry_delay) return None + def initialize_capif_configuration(self): + capif_col = self.get_col_by_name(self.capif_configuration) + if capif_col.count_documents({}) == 0: + default_config = self.config["capif_configuration"] + capif_col.insert_one(default_config) + print("Default data inserted into the capif_configuration collection from config.yaml") + else: + print("The capif_configuration collection already contains data. No default values were inserted.") + def close_connection(self): if self.db.client: self.db.client.close() diff --git a/services/register/register_service/utils/auth_utils.py b/services/register/register_service/utils/auth_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1216989b413309c119c494e95519c0de34c62163 --- /dev/null +++ b/services/register/register_service/utils/auth_utils.py @@ -0,0 +1,10 @@ +import bcrypt + + +def hash_password(password): + hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) + return hashed_password.decode('utf-8') + + +def check_password(input_password, stored_password): + return bcrypt.checkpw(input_password.encode('utf-8'), stored_password.encode('utf-8')) \ No newline at end of file diff --git a/services/register/register_service/utils/utils.py b/services/register/register_service/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..4b38761f1eef55f90e78291910d492b54d2ba09f --- /dev/null +++ b/services/register/register_service/utils/utils.py @@ -0,0 +1,36 @@ +import re + +from flask import jsonify + + +def to_snake_case(text): + """ + Convert string to snake case. + """ + return re.sub(r'\s+', '_', text).lower() + +def convert_dict_keys_to_snake_case(data): + """ + Converts the keys of a dictionary to snake_case. + """ + if isinstance(data, dict): + return {to_snake_case(k): convert_dict_keys_to_snake_case(v) for k, v in data.items()} + return data + +def is_snake_case(value): + """ + Checks if a key is in snake_case. + """ + return bool(re.match(r'^[a-z0-9_]+$', value)) + +def validate_snake_case_keys(obj, path="root"): + """ + Iterates through the JSON validating that all keys are in snake_case. + """ + for key, value in obj.items(): + if not is_snake_case(key): + return jsonify({"error": f"The key '{path}.{key}' is not in snake_case"}), 400 + if isinstance(value, dict): + error_response = validate_snake_case_keys(value, f"{path}.{key}") + if error_response: + return error_response diff --git a/services/register/requirements.txt b/services/register/requirements.txt index 1c1cb217ddd6a995353a26853f7df53bd2148e6b..dc9b58d927d0c1928015d35feeb6d242dee4ac49 100644 --- a/services/register/requirements.txt +++ b/services/register/requirements.txt @@ -6,7 +6,7 @@ flask_jwt_extended == 4.6.0 pyopenssl == 24.1.0 pyyaml == 6.0.1 requests == 2.32.2 -bcrypt == 4.0.1 +bcrypt == 4.3.0 flask_httpauth == 4.8.0 -gunicorn == 22.0.0 +gunicorn == 23.0.0 packaging == 24.0 diff --git a/services/remove_users.sh b/services/remove_users.sh index 7221981410fb101f4f5ec779142731d0b2d3db2a..01cceb4f15fd6f9d42fa963261f941a6948115a1 100755 --- a/services/remove_users.sh +++ b/services/remove_users.sh @@ -1,4 +1,5 @@ #!/bin/bash +source $(dirname "$(readlink -f "$0")")/variables.sh # User to remove USERNAME_PREFIX= @@ -37,31 +38,6 @@ then exit -1 fi -# Other Stuff -DOCKER_ROBOT_IMAGE=labs.etsi.org:5050/ocf/capif/robot-tests-image -DOCKER_ROBOT_IMAGE_VERSION=1.0 -cd .. -REPOSITORY_BASE_FOLDER=${PWD} -TEST_FOLDER=$REPOSITORY_BASE_FOLDER/tests -RESULT_FOLDER=$REPOSITORY_BASE_FOLDER/results -ROBOT_DOCKER_FILE_FOLDER=$REPOSITORY_BASE_FOLDER/tools/robot - -# nginx Hostname and http port (80 by default) to reach for tests -CAPIF_REGISTER=capifcore -CAPIF_REGISTER_PORT=8084 -CAPIF_HOSTNAME=capifcore -CAPIF_HTTP_PORT=8080 -CAPIF_HTTPS_PORT=443 - -# VAULT access configuration -CAPIF_VAULT=vault -CAPIF_VAULT_PORT=8200 -CAPIF_VAULT_TOKEN=read-ca-token - -# Mock Server -MOCK_SERVER_URL=http://mock-server:9100 -NOTIFICATION_DESTINATION_URL=$MOCK_SERVER_URL - PLATFORM=$(uname -m) if [ "x86_64" == "$PLATFORM" ]; then DOCKER_ROBOT_IMAGE_VERSION=$DOCKER_ROBOT_IMAGE_VERSION-amd64 @@ -109,11 +85,13 @@ fi mkdir -p $RESULT_FOLDER -docker run -ti --rm --network="host" \ +docker run $DOCKER_ROBOT_TTY_OPTIONS --rm --network="host" \ --add-host host.docker.internal:host-gateway \ --add-host vault:host-gateway \ --add-host register:host-gateway \ --add-host mock-server:host-gateway \ + --add-host $CAPIF_HOSTNAME:host-gateway \ + --add-host $CAPIF_REGISTER:host-gateway \ -v $TEST_FOLDER:/opt/robot-tests/tests \ -v $RESULT_FOLDER:/opt/robot-tests/results ${DOCKER_ROBOT_IMAGE}:${DOCKER_ROBOT_IMAGE_VERSION} \ --variable CAPIF_HOSTNAME:$CAPIF_HOSTNAME \ diff --git a/services/run.sh b/services/run.sh index 8a0094e6febdb0fa8ba3b3fbb8abfa959d3b4116..9f2983bb3c3d79045a1f22764eaa5e5e9a296ffb 100755 --- a/services/run.sh +++ b/services/run.sh @@ -1,34 +1,21 @@ #!/bin/bash - -# Directories variables setup (no modification needed) -export SERVICES_DIR=$(dirname "$(readlink -f "$0")") -export CAPIF_BASE_DIR=$(dirname "$SERVICES_DIR") +source $(dirname "$(readlink -f "$0")")/variables.sh help() { echo "Usage: $1 " echo " -c : Setup different hostname for capif" - echo " -s : Run Mock server" + echo " -s : Run Mock server. Default true" echo " -m : Run monitoring service" echo " -l : Set Log Level (default DEBUG). Select one of: [CRITICAL, FATAL, ERROR, WARNING, WARN, INFO, DEBUG, NOTSET]" echo " -r : Remove cached information on build" + echo " -v : Set OCF version of images" + echo " -f : Services directory. (Default $SERVICES_DIR)" + echo " -g : Gitlab base URL. (Default $REGISTRY_BASE_URL)" + echo " -b : Build docker images. Default TRUE" echo " -h : show this help" exit 1 } -HOSTNAME=capifcore -MONITORING_STATE=false -DEPLOY=all -LOG_LEVEL=DEBUG -CACHED_INFO="" - -# Needed to avoid write permissions on bind volumes with prometheus and grafana -DUID=$(id -u) -DGID=$(id -g) - -# Mock Server configuration -IP=0.0.0.0 -PORT=9100 - # Get docker compose version docker_version=$(docker compose version --short | cut -d',' -f1) IFS='.' read -ra version_components <<< "$docker_version" @@ -40,17 +27,36 @@ else exit 1 fi +# Check if yq is installed +if ! command -v yq &> /dev/null +then + echo "yq is not installed. Please install it first." + exit 1 +fi + # Read params -while getopts ":c:l:mshr" opt; do +while getopts ":c:l:ms:hrv:f:g:b:" opt; do case $opt in c) - HOSTNAME="$OPTARG" + CAPIF_HOSTNAME="$OPTARG" ;; m) MONITORING_STATE=true ;; s) - ROBOT_MOCK_SERVER=true + ROBOT_MOCK_SERVER="$OPTARG" + ;; + v) + OCF_VERSION="$OPTARG" + ;; + f) + SERVICES_DIR="$OPTARG" + ;; + g) + REGISTRY_BASE_URL="$OPTARG" + ;; + b) + BUILD_DOCKER_IMAGES="$OPTARG" ;; h) help @@ -72,12 +78,21 @@ while getopts ":c:l:mshr" opt; do esac done -echo Nginx hostname will be $HOSTNAME, deploy $DEPLOY, monitoring $MONITORING_STATE +echo Nginx hostname will be $CAPIF_HOSTNAME, deploy $DEPLOY, monitoring $MONITORING_STATE + +if [ "$BUILD_DOCKER_IMAGES" == "true" ] ; then + echo '***Building Docker images set as true***' + BUILD="--build" +else + echo '***Building Docker images set as false***' + BUILD="--no-build" +fi +# Deploy Monitoring stack if [ "$MONITORING_STATE" == "true" ] ; then echo '***Monitoring set as true***' echo '***Creating Monitoring stack***' - DUID=$DUID DGID=$DGID docker compose -f "$SERVICES_DIR/monitoring/docker-compose.yml" up --detach --build $CACHED_INFO + DUID=$DUID DGID=$DGID docker compose -f "$SERVICES_DIR/monitoring/docker-compose.yml" up --detach $BUILD $CACHED_INFO status=$? if [ $status -eq 0 ]; then @@ -90,7 +105,8 @@ fi docker network create capif-network -docker compose -f "$SERVICES_DIR/docker-compose-vault.yml" up --detach --build $CACHED_INFO +# Deploy Vault service +REGISTRY_BASE_URL=$REGISTRY_BASE_URL OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME docker compose -f "$SERVICES_DIR/docker-compose-vault.yml" up --detach $BUILD $CACHED_INFO status=$? if [ $status -eq 0 ]; then @@ -100,7 +116,8 @@ else exit $status fi -CAPIF_HOSTNAME=$HOSTNAME MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f "$SERVICES_DIR/docker-compose-capif.yml" up --detach --build $CACHED_INFO +# Deploy Capif services +REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_HOSTNAME=$CAPIF_HOSTNAME MONITORING=$MONITORING_STATE LOG_LEVEL=$LOG_LEVEL docker compose -f "$SERVICES_DIR/docker-compose-capif.yml" up --detach $BUILD $CACHED_INFO status=$? if [ $status -eq 0 ]; then @@ -110,8 +127,19 @@ else exit $status fi -CAPIF_PRIV_KEY_BASE_64=$(echo "$(cat nginx/certs/server.key)") -CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 LOG_LEVEL=$LOG_LEVEL docker compose -f "$SERVICES_DIR/docker-compose-register.yml" up --detach --build $CACHED_INFO +# Path to the register config.yaml file +REGISTER_CONFIG_FILE="$SERVICES_DIR/register/config.yaml" +# Backup Original config.yaml file +cp $REGISTER_CONFIG_FILE $REGISTER_CONFIG_FILE.bak +# Mark the file as assume-unchanged +git update-index --assume-unchanged "$REGISTER_CONFIG_FILE" + +# Edit Register Service URL within ccf in the config.yaml file +yq eval ".ccf.url = \"$CAPIF_HOSTNAME\"" -i "$REGISTER_CONFIG_FILE" -P + +# Deploy Register service +CAPIF_PRIV_KEY_BASE_64=$(echo "$(cat ${SERVICES_DIR}/nginx/certs/server.key)") +REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION CAPIF_PRIV_KEY=$CAPIF_PRIV_KEY_BASE_64 LOG_LEVEL=$LOG_LEVEL docker compose -f "$SERVICES_DIR/docker-compose-register.yml" up --detach $BUILD $CACHED_INFO status=$? if [ $status -eq 0 ]; then @@ -121,16 +149,17 @@ else exit $status fi +# Deploy Robot Mock Server if [ "$ROBOT_MOCK_SERVER" == "true" ] ; then echo '***Robot Mock Server set as true***' echo '***Creating Robot Mock Server stack***' - IP=$IP PORT=$PORT docker compose -f "$SERVICES_DIR/docker-compose-mock-server.yml" up --detach --build $CACHED_INFO + REGISTRY_BASE_URL=$REGISTRY_BASE_URL SERVICES_DIR=$SERVICES_DIR OCF_VERSION=$OCF_VERSION IP=$MOCK_SERVER_IP PORT=$MOCK_SERVER_PORT docker compose -f "$SERVICES_DIR/docker-compose-mock-server.yml" up --detach $BUILD $CACHED_INFO status=$? if [ $status -eq 0 ]; then - echo "*** Monitoring Stack Runing ***" + echo "*** Mock Server Runing ***" else - echo "*** Monitoring Stack failed to start ***" + echo "*** Mock Server failed to start ***" exit $status fi fi diff --git a/services/run_capif_tests.sh b/services/run_capif_tests.sh index 65749bf3f9514fae2ead580962777a1292a0cf76..65c9a45f92783a7be913edc452ac8534b2d6280f 100755 --- a/services/run_capif_tests.sh +++ b/services/run_capif_tests.sh @@ -1,27 +1,5 @@ #!/bin/bash - -DOCKER_ROBOT_IMAGE=labs.etsi.org:5050/ocf/capif/robot-tests-image -DOCKER_ROBOT_IMAGE_VERSION=1.0 -cd .. -REPOSITORY_BASE_FOLDER=${PWD} -TEST_FOLDER=$REPOSITORY_BASE_FOLDER/tests -RESULT_FOLDER=$REPOSITORY_BASE_FOLDER/results -ROBOT_DOCKER_FILE_FOLDER=$REPOSITORY_BASE_FOLDER/tools/robot - -# nginx Hostname and http port (80 by default) to reach for tests -CAPIF_REGISTER=capifcore -CAPIF_REGISTER_PORT=8084 -CAPIF_HOSTNAME=capifcore -CAPIF_HTTP_PORT=8080 -CAPIF_HTTPS_PORT=443 - -# VAULT access configuration -CAPIF_VAULT=vault -CAPIF_VAULT_PORT=8200 -CAPIF_VAULT_TOKEN=dev-only-token - -MOCK_SERVER_URL=http://mock-server:9100 -NOTIFICATION_DESTINATION_URL=http://mock-server:9100 +source $(dirname "$(readlink -f "$0")")/variables.sh PLATFORM=$(uname -m) if [ "x86_64" == "$PLATFORM" ]; then @@ -72,7 +50,7 @@ fi mkdir -p $RESULT_FOLDER -docker run -ti --rm --network="host" \ +docker run $DOCKER_ROBOT_TTY_OPTIONS --rm --network="host" \ --add-host host.docker.internal:host-gateway \ --add-host vault:host-gateway \ --add-host register:host-gateway \ diff --git a/services/run_mock_server.sh b/services/run_mock_server.sh index c7393861a7b7e3e96cc10d2e80a5b7a196c5b767..5f62cf5c48d67ef5be2903db22f3f53d8d995dea 100755 --- a/services/run_mock_server.sh +++ b/services/run_mock_server.sh @@ -1,8 +1,5 @@ #!/bin/bash - -# Directories variables setup (no modification needed) -export SERVICES_DIR=$(dirname "$(readlink -f "$0")") -export CAPIF_BASE_DIR=$(dirname "$SERVICES_DIR") +source $(dirname "$(readlink -f "$0")")/variables.sh help() { echo "Usage: $1 " @@ -12,17 +9,17 @@ help() { exit 1 } -IP=0.0.0.0 -PORT=9100 +MOCK_SERVER_IP=0.0.0.0 +MOCK_SERVER_PORT=9100 # Read params while getopts ":i:p:h" opt; do case $opt in i) - IP="$OPTARG" + MOCK_SERVER_IP="$OPTARG" ;; p) - PORT=$OPTARG + MOCK_SERVER_PORT=$OPTARG ;; h) help @@ -38,11 +35,11 @@ while getopts ":i:p:h" opt; do esac done -echo Robot Framework Mock Server will listen on $IP:$PORT +echo Robot Framework Mock Server will listen on $MOCK_SERVER_IP:$MOCK_SERVER_PORT docker network create capif-network || echo "capif-network previously created on docker networks" -IP=$IP PORT=$PORT docker compose -f "$SERVICES_DIR/docker-compose-mock-server.yml" up --detach --build +MOCK_SERVER_IP=$IP MOCK_SERVER_PORT=$PORT docker compose -f "$SERVICES_DIR/docker-compose-mock-server.yml" up --detach --build status=$? if [ $status -eq 0 ]; then diff --git a/services/variables.sh b/services/variables.sh new file mode 100755 index 0000000000000000000000000000000000000000..dd99ae30fc2e7c7a9f21ba00d2011b8aed54f361 --- /dev/null +++ b/services/variables.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Directories variables setup (no modification needed) +export SERVICES_DIR=$(dirname "$(readlink -f "$0")") +export CAPIF_BASE_DIR=$(dirname "$SERVICES_DIR") +export TEST_FOLDER=$CAPIF_BASE_DIR/tests +export RESULT_FOLDER=$CAPIF_BASE_DIR/results +export ROBOT_DOCKER_FILE_FOLDER=$CAPIF_BASE_DIR/tools/robot + +# Image URL and version +export REGISTRY_BASE_URL="labs.etsi.org:5050/ocf/capif/prod" +export OCF_VERSION="v2.x.x-release" + +# Capif hostname +export CAPIF_HOSTNAME=capifcore +export CAPIF_HTTP_PORT=8080 +export CAPIF_HTTPS_PORT=443 + +# Register hostname and port +export CAPIF_REGISTER=register +export CAPIF_REGISTER_PORT=8084 + +# VAULT access configuration +export CAPIF_VAULT=vault +export CAPIF_VAULT_PORT=8200 +export CAPIF_VAULT_TOKEN=dev-only-token + +# Build and Deployment variables +export MONITORING_STATE=false +export DEPLOY=all +export LOG_LEVEL=DEBUG +export CACHED_INFO="" +export BUILD_DOCKER_IMAGES=true +export REMOVE_IMAGES=false +export ROBOT_MOCK_SERVER=true + +# Needed to avoid write permissions on bind volumes with prometheus and grafana +export DUID=$(id -u) +export DGID=$(id -g) + +# Mock Server configuration +export MOCK_SERVER_IP=0.0.0.0 +export MOCK_SERVER_PORT=9100 + +# Robot tests variables +export DOCKER_ROBOT_IMAGE=labs.etsi.org:5050/ocf/capif/robot-tests-image +export DOCKER_ROBOT_IMAGE_VERSION=1.0 +export DOCKER_ROBOT_TTY_OPTIONS="-ti" + +# Mock server variables +export MOCK_SERVER_URL=http://mock-server:${MOCK_SERVER_PORT} +export NOTIFICATION_DESTINATION_URL=http://mock-server:${MOCK_SERVER_PORT} + diff --git a/services/vault/vault_prepare_certs.sh b/services/vault/vault_prepare_certs.sh old mode 100644 new mode 100755 index dbec8fdb3730c0a73cd4be682d162dd25f3fcc79..f1e1c5aaa1eff9c7eebef4509df5b65261126a85 --- a/services/vault/vault_prepare_certs.sh +++ b/services/vault/vault_prepare_certs.sh @@ -1,13 +1,17 @@ #!/bin/sh -# Establecer las variables de entorno de Vault +# Setup environment variables for Vault +export VAULT_ADDR="http://$VAULT_DEV_LISTEN_ADDRESS" +export VAULT_TOKEN=$VAULT_DEV_ROOT_TOKEN_ID +CAPIF_HOSTNAME="${CAPIF_HOSTNAME:-capifcore}" -export VAULT_ADDR='http://0.0.0.0:8200' -export VAULT_TOKEN="dev-only-token" +echo "CAPIF_HOSTNAME: $CAPIF_HOSTNAME" +echo "VAULT_ADDR: $VAULT_ADDR" +echo "VAULT_TOKEN: $VAULT_TOKEN" vault secrets enable pki -# Generar una CA en Vault +# Generate a root CA vault secrets tune -max-lease-ttl=87600h pki vault write -field=certificate pki/root/generate/internal \ @@ -19,7 +23,7 @@ vault write pki/config/urls \ issuing_certificates="$VAULT_ADDR/v1/pki/ca" \ crl_distribution_points="$VAULT_ADDR/v1/pki/crl" -# # Generar una CA intermedia en Vault +# Generate an intermediate CA vault secrets enable -path=pki_int pki vault secrets tune -max-lease-ttl=43800h pki_int @@ -29,34 +33,20 @@ vault write -format=json pki_int/intermediate/generate/internal \ issuer_name="capif-intermediate" \ | jq -r '.data.csr' > pki_intermediate.csr -# Firmar la CA intermedia con la CA raíz +# Sign the intermediate CA vault write -format=json pki/root/sign-intermediate \ issuer_ref="root-2023" \ csr=@pki_intermediate.csr \ format=pem_bundle ttl="43800h" \ | jq -r '.data.certificate' > capif_intermediate.cert.pem -# Configurar la CA intermedia en Vault +# Configure the intermediate CA vault write pki_int/intermediate/set-signed certificate=@capif_intermediate.cert.pem -#Crear rol en Vault -vault write pki_int/roles/my-ca use_csr_common_name=false require_cn=true use_csr_sans=false allowed_domains=capifcore allow_any_name=true allow_bare_domains=true allow_glob_domains=true allow_subdomains=true max_ttl=4300h ttl=4300h +# Configure the role for the intermediate CA +vault write pki_int/roles/my-ca use_csr_common_name=false require_cn=true use_csr_sans=false allowed_domains=$CAPIF_HOSTNAME allow_any_name=true allow_bare_domains=true allow_glob_domains=true allow_subdomains=true max_ttl=4300h -# Emitir un certificado firmado por la CA intermedia -# vault write -format=json pki_int/issue/my-ca \ -# common_name="capifcore" \ -# format=pem_bundle ttl="438h" \ -# | jq -r '.data.certificate' > ccf_cert.crt.pem \ -# && jq -r '.data.issuing_ca' > root_ca.crt.pem \ -# && jq -r '.data.private_key' > private_key.pem - -# vault write -format=json pki_int/issue/my-ca \ -# common_name="capifcore" \ -# format=pem_bundle ttl="438h" \ -# | jq -r '.data.private_key as $private_key | .data.issuing_ca as $issuing_ca | .data.certificate as $certificate | [$private_key, $issuing_ca, $certificate]' > cert_data.json - - -#Create CSR +# Generate a certificate openssl genrsa -out ./server.key 2048 @@ -65,7 +55,7 @@ STATE="Madrid" # state or province name LOCALITY="Madrid" # Locality Name (e.g. city) ORGNAME="Telefonica I+D" # Organization Name (eg, company) ORGUNIT="Innovation" # Organizational Unit Name (eg. section) -COMMONNAME="capifcore" +COMMONNAME="$CAPIF_HOSTNAME" EMAIL="inno@tid.es" # certificate's email address # optional extra details CHALLENGE="" # challenge password @@ -74,7 +64,6 @@ COMPANY="" # company name # DAYS="-days 365" # create the certificate request -#cat <<__EOF__ | openssl req -new $DAYS -nodes -keyout client.key -out client.csr cat <<__EOF__ | openssl req -new $DAYS -key ./server.key -out ./server.csr $COUNTRY $STATE @@ -87,31 +76,20 @@ $CHALLENGE $COMPANY __EOF__ -# vault write -format=json pki_int/issue/my-ca \ -# csr=@server.csr \ -# format=pem_bundle ttl="438h" \ -# | jq -r '.data.private_key as $private_key | .data.issuing_ca as $issuing_ca | .data.certificate as $certificate | [$private_key, $issuing_ca, $certificate]' > cert_data.json -vault write -format=json pki_int/sign/my-ca format=pem_bundle ttl="43000h" csr=@server.csr common_name="capifcore" | jq -r '.data.issuing_ca as $issuing_ca | .data.certificate as $certificate | [$issuing_ca, $certificate]' > cert_data.json +vault write -format=json pki_int/sign/my-ca format=pem_bundle ttl="43000h" csr=@server.csr common_name="$CAPIF_HOSTNAME" | jq -r '.data.issuing_ca as $issuing_ca | .data.certificate as $certificate | [$issuing_ca, $certificate]' > cert_data.json jq -r '.[0]' cert_data.json > root_ca.crt.pem jq -r '.[1]' cert_data.json > server_certificate.crt.pem openssl x509 -pubkey -noout -in server_certificate.crt.pem > server_certificate_pub.pem -# Guardar la clave privada en Vault - -#vault kv put secret/ca ca=@root_ca.crt.pem root_2023_ca.crt - -#cat root_2023_ca.crt root_2023_ca.crt > ca.crt - +# Concatenate the root and intermediate CA certificates cat > certificados_concatenados.crt << EOF $(cat "root_2023_ca.crt") $(cat "root_ca.crt.pem") EOF - -# vault kv put secret/ca ca=@root_2023_ca.crt vault kv put secret/ca ca=@certificados_concatenados.crt vault kv put secret/server_cert cert=@server_certificate.crt.pem @@ -124,15 +102,15 @@ POLICY_NAME="my-policy" POLICY_FILE="my-policy.hcl" TOKEN_ID="read-ca-token" -# Crear la política en Vault +# Create a policy to read the CA echo "path \"secret/data/ca\" { capabilities = [\"read\"] }" > "$POLICY_FILE" vault policy write "$POLICY_NAME" "$POLICY_FILE" -# Generar un nuevo token y asignar la política +# Create a token with the policy TOKEN=$(vault token create -id="$TOKEN_ID" -policy="$POLICY_NAME" -format=json | jq -r '.auth.client_token') -echo "Token generado:" +echo "Generated Token:" echo "$TOKEN" \ No newline at end of file diff --git a/tests/features/Api Status/api_status.robot b/tests/features/Api Status/api_status.robot index 9e9f92f9a7cccaa4010502e9e13810b177670a20..d4798e765dc31f7b8df6fca41e1b2ae4dba095d4 100644 --- a/tests/features/Api Status/api_status.robot +++ b/tests/features/Api Status/api_status.robot @@ -1155,7 +1155,7 @@ Update published API with apiStatus empty and apiStatusMonitoring active ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_empty_list} ${resp}= Put Request Capif ... ${resource_url.path} @@ -1260,7 +1260,7 @@ Update published API with apiStatus only aef2 and apiStatusMonitoring active ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_id_2} ${resp}= Put Request Capif ... ${resource_url.path} @@ -1357,7 +1357,7 @@ Published API without aefs available updated to one aef available ${service_api_description_modified}= Create Service Api Description ... service_1 ... aef_id=${aef_ids} - ... supported_features=20 + ... supported_features=020 ... api_status=${aef_id_2} ${resp}= Put Request Capif ... ${resource_url.path} diff --git a/tests/features/CAPIF Api Access Control Policy/capif_api_access_control_policy.robot b/tests/features/CAPIF Api Access Control Policy/capif_api_access_control_policy.robot index 05716c20a5c3c846ccc649300183597f7f3d36f8..12844d5116ebfd0dfb7aea39bc16f1cc2fc96ccf 100644 --- a/tests/features/CAPIF Api Access Control Policy/capif_api_access_control_policy.robot +++ b/tests/features/CAPIF Api Access Control Policy/capif_api_access_control_policy.robot @@ -364,12 +364,8 @@ Retrieve ACL filtered by api-invoker-id ... ${resp.json()['apiInvokerPolicies'][0]['apiInvokerId']} ... ${register_user_info_invoker_2['api_invoker_id']} -Retrieve ACL filtered by supported-features - [Tags] capif_api_acl-5 - Skip Test ${TEST_NAME} is not currently supported by CAPIF - Retrieve ACL with aef-id not valid - [Tags] capif_api_acl-6 + [Tags] capif_api_acl-5 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -393,7 +389,7 @@ Retrieve ACL with aef-id not valid ... cause=Wrong id Retrieve ACL with service-id not valid - [Tags] capif_api_acl-7 + [Tags] capif_api_acl-6 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -416,7 +412,7 @@ Retrieve ACL with service-id not valid ... cause=Wrong id Retrieve ACL with service-api-id and aef-id not valid - [Tags] capif_api_acl-8 + [Tags] capif_api_acl-7 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -439,7 +435,7 @@ Retrieve ACL with service-api-id and aef-id not valid ... cause=Wrong id Retrieve ACL without SecurityContext created previously by Invoker - [Tags] capif_api_acl-9 + [Tags] capif_api_acl-8 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -463,7 +459,7 @@ Retrieve ACL without SecurityContext created previously by Invoker ... cause=Wrong id Retrieve ACL filtered by api-invoker-id not present - [Tags] capif_api_acl-10 + [Tags] capif_api_acl-9 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -486,7 +482,7 @@ Retrieve ACL filtered by api-invoker-id not present ... cause=Wrong id Retrieve ACL with APF Certificate - [Tags] capif_api_acl-11 + [Tags] capif_api_acl-10 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -506,7 +502,7 @@ Retrieve ACL with APF Certificate ... cause=Certificate not authorized Retrieve ACL with AMF Certificate - [Tags] capif_api_acl-12 + [Tags] capif_api_acl-11 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -526,7 +522,7 @@ Retrieve ACL with AMF Certificate ... cause=Certificate not authorized Retrieve ACL with Invoker Certificate - [Tags] capif_api_acl-13 smoke + [Tags] capif_api_acl-12 smoke ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= @@ -546,7 +542,7 @@ Retrieve ACL with Invoker Certificate ... cause=Certificate not authorized No ACL for invoker after be removed - [Tags] capif_api_acl-14 + [Tags] capif_api_acl-13 ${register_user_info_invoker} ... ${register_user_info_provider} ... ${service_api_description_published}= diff --git a/tests/features/CAPIF Api Events/capif_events_api.robot b/tests/features/CAPIF Api Events/capif_events_api.robot index 9f8b4e23a00c272fa4b8cfdc80d77b3e71e24177..4da4228d806396aad0188ea7cb78a321804e3a2e 100644 --- a/tests/features/CAPIF Api Events/capif_events_api.robot +++ b/tests/features/CAPIF Api Events/capif_events_api.robot @@ -167,7 +167,7 @@ Invoker receives Service API Invocation events ${events_list}= Create List SERVICE_API_INVOCATION_SUCCESS SERVICE_API_INVOCATION_FAILURE ${aef_ids}= Create List ${register_user_info['aef_id']} ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} - ${event_filters}= Create List ${event_filter} + ${event_filters}= Create List ${event_filter} ${event_filter} ${request_body}= Create Events Subscription ... events=@{events_list} @@ -238,14 +238,10 @@ Invoker subscribe to Service API Available and Unavailable events # Subscribe to events ${events_list}= Create List SERVICE_API_AVAILABLE SERVICE_API_UNAVAILABLE - ${aef_ids}= Create List ${register_user_info_provider['aef_id']} - ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} - ${event_filters}= Create List ${event_filter} ${request_body}= Create Events Subscription ... events=@{events_list} ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing - ... event_filters=${event_filters} ... supported_features=4 ${resp}= Post Request Capif ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions @@ -296,6 +292,7 @@ Invoker subscribe to Service API Update # Publish one api ${service_api_description_published} ${resource_url} ${request_body}= Publish Service Api ... ${register_user_info_provider} + ${service_api_id_1}= Set Variable ${service_api_description_published['apiId']} # Register INVOKER ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding @@ -310,8 +307,8 @@ Invoker subscribe to Service API Update # Subscribe to events ${events_list}= Create List SERVICE_API_UPDATE - ${aef_ids}= Create List ${register_user_info_provider['aef_id']} - ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} + ${api_ids}= Create List ${service_api_id_1} + ${event_filter}= Create Capif Event Filter apiIds=${api_ids} ${event_filters}= Create List ${event_filter} ${request_body}= Create Events Subscription @@ -378,7 +375,7 @@ Provider subscribe to API Invoker events ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} # Register INVOKER - ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + ${register_user_info_invoker} ${invoker_url} ${request_body}= Invoker Default Onboarding # Update Invoker onboarded information ${new_notification_destination}= Set Variable @@ -387,7 +384,7 @@ Provider subscribe to API Invoker events ... ${request_body} ... notificationDestination=${new_notification_destination} ${resp}= Put Request Capif - ... ${url.path} + ... ${invoker_url.path} ... ${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt @@ -399,21 +396,24 @@ Provider subscribe to API Invoker events # Remove Invoker from CCF ${resp}= Delete Request Capif - ... ${url.path} + ... ${invoker_url.path} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt ... username=${INVOKER_USERNAME} - Call Method ${CAPIF_USERS} remove_capif_users_entry ${url.path} + Call Method ${CAPIF_USERS} remove_capif_users_entry ${invoker_url.path} # Check Remove Should Be Equal As Strings ${resp.status_code} 204 # Check Event Notifications ## Create check Events to ensure all notifications were received + ${invoker_urls}= Create List ${invoker_url} ${events_expected}= Create Expected Api Invoker Events ... ${subscription_id} - ... ${register_user_info_invoker['api_invoker_id']} + ... api_invoker_onboarded_resources=${invoker_urls} + ... api_invoker_updated_resources=${invoker_urls} + ... api_invoker_offboarded_resources=${invoker_urls} ## Check Events Expected towards received notifications at mock server Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} @@ -532,7 +532,7 @@ Provider receives an ACL unavailable event when invoker remove Security Context. ... json=${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt - ... username=${INVOKER_USERNAME} + ... username=${AMF_PROVIDER_USERNAME} # Check Results Check Response Variable Type And Values ${resp} 201 EventSubscription @@ -603,7 +603,7 @@ Invoker receives an Invoker Authorization Revoked and ACL unavailable event when ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing ... supported_features=4 ${resp}= Post Request Capif - ... /capif-events/v1/${register_user_info_provider['amf_id']}/subscriptions + ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions ... json=${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt @@ -710,14 +710,9 @@ Invoker receives Service API Invocation events without Enhanced Event Report # Subscribe to events ${events_list}= Create List SERVICE_API_INVOCATION_SUCCESS SERVICE_API_INVOCATION_FAILURE - ${aef_ids}= Create List ${register_user_info['aef_id']} - ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} - ${event_filters}= Create List ${event_filter} - ${request_body}= Create Events Subscription ... events=@{events_list} ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing - ... event_filters=${event_filters} ... supported_features=0 ${resp}= Post Request Capif ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions @@ -784,14 +779,9 @@ Invoker subscribe to Service API Available and Unavailable events without Enhanc # Subscribe to events ${events_list}= Create List SERVICE_API_AVAILABLE SERVICE_API_UNAVAILABLE - ${aef_ids}= Create List ${register_user_info_provider['aef_id']} - ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} - ${event_filters}= Create List ${event_filter} - ${request_body}= Create Events Subscription ... events=@{events_list} ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing - ... event_filters=${event_filters} ... supported_features=0 ${resp}= Post Request Capif ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions @@ -856,14 +846,9 @@ Invoker subscribe to Service API Update without Enhanced Event Report # Subscribe to events ${events_list}= Create List SERVICE_API_UPDATE - ${aef_ids}= Create List ${register_user_info_provider['aef_id']} - ${event_filter}= Create Capif Event Filter aefIds=${aef_ids} - ${event_filters}= Create List ${event_filter} - ${request_body}= Create Events Subscription ... events=@{events_list} ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing - ... event_filters=${event_filters} ... supported_features=0 ${resp}= Post Request Capif ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions @@ -925,7 +910,7 @@ Provider subscribe to API Invoker events without Enhanced Event Report ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} # Register INVOKER - ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + ${register_user_info_invoker} ${invoker_url} ${request_body}= Invoker Default Onboarding # Update Invoker onboarded information ${new_notification_destination}= Set Variable @@ -934,7 +919,7 @@ Provider subscribe to API Invoker events without Enhanced Event Report ... ${request_body} ... notificationDestination=${new_notification_destination} ${resp}= Put Request Capif - ... ${url.path} + ... ${invoker_url.path} ... ${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt @@ -946,21 +931,24 @@ Provider subscribe to API Invoker events without Enhanced Event Report # Remove Invoker from CCF ${resp}= Delete Request Capif - ... ${url.path} + ... ${invoker_url.path} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt ... username=${INVOKER_USERNAME} - Call Method ${CAPIF_USERS} remove_capif_users_entry ${url.path} + Call Method ${CAPIF_USERS} remove_capif_users_entry ${invoker_url.path} # Check Remove Should Be Equal As Strings ${resp.status_code} 204 # Check Event Notifications ## Create check Events to ensure all notifications were received + ${invoker_urls}= Create List ${invoker_url} ${events_expected}= Create Expected Api Invoker Events ... ${subscription_id} - ... ${register_user_info_invoker['api_invoker_id']} + ... api_invoker_onboarded_resources=${invoker_urls} + ... api_invoker_updated_resources=${invoker_urls} + ... api_invoker_offboarded_resources=${invoker_urls} ... event_detail_expected=${FALSE} ## Check Events Expected towards received notifications at mock server Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} @@ -1081,7 +1069,7 @@ Provider receives an ACL unavailable event when invoker remove Security Context ... json=${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt - ... username=${INVOKER_USERNAME} + ... username=${AMF_PROVIDER_USERNAME} # Check Results Check Response Variable Type And Values ${resp} 201 EventSubscription @@ -1153,7 +1141,7 @@ Invoker receives an Invoker Authorization Revoked and ACL unavailable event when ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing ... supported_features=0 ${resp}= Post Request Capif - ... /capif-events/v1/${register_user_info_provider['amf_id']}/subscriptions + ... /capif-events/v1/${register_user_info_invoker['api_invoker_id']}/subscriptions ... json=${request_body} ... server=${CAPIF_HTTPS_URL} ... verify=ca.crt diff --git a/tests/features/CAPIF Security Api/capif_security_api.robot b/tests/features/CAPIF Security Api/capif_security_api.robot index 85b26ee335bc29def3b8054701dfc42dfaf121f5..c3a966f0752ff9d8f8e969f31ab42c49c3b77a7f 100644 --- a/tests/features/CAPIF Security Api/capif_security_api.robot +++ b/tests/features/CAPIF Security Api/capif_security_api.robot @@ -14,6 +14,7 @@ Test Teardown Reset Testing Environment ${APF_ID_NOT_VALID} apf-example ${SERVICE_API_ID_NOT_VALID} not-valid ${API_INVOKER_NOT_VALID} not-valid +${AEF_ID_NOT_VALID} not-valid *** Test Cases *** @@ -22,8 +23,22 @@ Create a security context for an API invoker # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + # Create Security Context - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -41,10 +56,21 @@ Create a security context for an API invoker with Provider role ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding # Register Provider - ${register_user_info_publisher}= Provider Default Registration + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} # Create Security Context - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -62,10 +88,21 @@ Create a security context for an API invoker with Provider role Create a security context for an API invoker with Provider entity role and invalid apiInvokerId [Tags] capif_security_api-3 # Register APF - ${register_user_info_publisher}= Provider Default Registration + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} # Create Security Context - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${API_INVOKER_NOT_VALID} ... json=${request_body} @@ -85,7 +122,22 @@ Create a security context for an API invoker with Invalid apiInvokerID # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register APF + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${API_INVOKER_NOT_VALID} ... json=${request_body} @@ -101,11 +153,28 @@ Create a security context for an API invoker with Invalid apiInvokerID ... cause=API Invoker not exists or invalid ID Retrieve the Security Context of an API Invoker - [Tags] capif_security_api-5 smoke + [Tags] capif_security_api-5 smoke # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} + ... authentication_info=authenticationInfo + ... authorization_info=authorizationInfo ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -118,9 +187,6 @@ Retrieve the Security Context of an API Invoker ${service_security_context}= Set Variable ${resp.json()} - # Register APF - ${register_user_info_publisher}= Provider Default Registration - # Retrieve Security context can setup by parameters if authenticationInfo and authorizationInfo are needed at response. # ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']}?authenticationInfo=true&authorizationInfo=true ${resp}= Get Request Capif @@ -161,7 +227,22 @@ Retrieve the Security Context of an API Invoker with invalid apfId # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -186,11 +267,26 @@ Retrieve the Security Context of an API Invoker with invalid apfId ... cause=User role must be aef Delete the Security Context of an API Invoker - [Tags] capif_security_api-8 smoke + [Tags] capif_security_api-8 smoke # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -200,9 +296,6 @@ Delete the Security Context of an API Invoker Check Response Variable Type And Values ${resp} 201 ServiceSecurity - # Register APF - ${register_user_info_publisher}= Provider Default Registration - # Remove Security Context ${resp}= Delete Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} @@ -230,7 +323,22 @@ Delete the Security Context of an API Invoker with Invoker entity role # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -290,14 +398,27 @@ Delete the Security Context of an API Invoker with invalid apiInvokerID ... cause=API Invoker not exists or invalid ID Update the Security Context of an API Invoker - [Tags] capif_security_api-12 smoke + [Tags] capif_security_api-12 smoke # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding # Register Provider - ${register_user_info_publisher}= Provider Default Registration + # Register Provider + ${register_user_info_provider}= Provider Default Registration - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -312,7 +433,12 @@ Update the Security Context of an API Invoker ${security_context}= Set Variable ${resp.json()} # Update Security Context - ${request_body}= Create Service Security Body http://robot.testing2 + ${request_body}= Create Service Security Default Body + ... http://robot.testing2 + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} + ... authentication_info=authenticationInfo + ... authorization_info=authorizationInfo ${resp}= Post Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']}/update ... json=${request_body} @@ -341,7 +467,22 @@ Update the Security Context of an API Invoker with Provider entity role # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -351,9 +492,6 @@ Update the Security Context of an API Invoker with Provider entity role Check Response Variable Type And Values ${resp} 201 ServiceSecurity - # Register Provider - ${register_user_info_publisher}= Provider Default Registration - ${resp}= Post Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']}/update ... json=${request_body} @@ -371,9 +509,21 @@ Update the Security Context of an API Invoker with Provider entity role Update the Security Context of an API Invoker with AEF entity role and invalid apiInvokerId [Tags] capif_security_api-14 # Register Provider - ${register_user_info_publisher}= Provider Default Registration + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Post Request Capif ... /capif-security/v1/trustedInvokers/${API_INVOKER_NOT_VALID}/update ... json=${request_body} @@ -392,7 +542,22 @@ Update the Security Context of an API Invoker with invalid apiInvokerID # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} ${resp}= Post Request Capif ... /capif-security/v1/trustedInvokers/${API_INVOKER_NOT_VALID}/update ... json=${request_body} @@ -408,7 +573,7 @@ Update the Security Context of an API Invoker with invalid apiInvokerID ... cause=API Invoker not exists or invalid ID Revoke the authorization of the API invoker for APIs - [Tags] capif_security_api-16 smoke + [Tags] capif_security_api-16 smoke # Register APF ${register_user_info_provider}= Provider Default Registration @@ -478,7 +643,24 @@ Revoke the authorization of the API invoker for APIs without valid apfID. # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} + ... authorization_info=authorizationInfo + ... authentication_info=authenticationInfo ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -490,9 +672,6 @@ Revoke the authorization of the API invoker for APIs without valid apfID. ${security_context}= Set Variable ${resp.json()} - # Register Provider - ${register_user_info_publisher}= Provider Default Registration - # Revoke Security Context by Invoker ${request_body}= Create Security Notification Body ${register_user_info_invoker['api_invoker_id']} 1234 ${resp}= Post Request Capif @@ -528,7 +707,25 @@ Revoke the authorization of the API invoker for APIs with invalid apiInvokerId # Default Invoker Registration and Onboarding ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding - ${request_body}= Create Service Security Body ${NOTIFICATION_DESTINATION_URL} + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} + ... authentication_info=authenticationInfo + ... authorization_info=authorizationInfo + ... authorization_info=authorizationInfo ${resp}= Put Request Capif ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} ... json=${request_body} @@ -540,9 +737,6 @@ Revoke the authorization of the API invoker for APIs with invalid apiInvokerId ${security_context}= Set Variable ${resp.json()} - # Register Provider - ${register_user_info_publisher}= Provider Default Registration - ${request_body}= Create Security Notification Body ${API_INVOKER_NOT_VALID} 1234 ${resp}= Post Request Capif ... /capif-security/v1/trustedInvokers/${API_INVOKER_NOT_VALID}/delete @@ -569,7 +763,7 @@ Revoke the authorization of the API invoker for APIs with invalid apiInvokerId Dictionaries Should Be Equal ${resp.json()} ${security_context} Retrieve access token - [Tags] capif_security_api-19 smoke + [Tags] capif_security_api-19 smoke # Register APF ${register_user_info_provider}= Provider Default Registration @@ -1058,3 +1252,68 @@ Retrieve access token with invalid apiName at scope Check Response Variable Type And Values ${resp} 400 AccessTokenErr ... error=invalid_scope ... error_description=One of the api names does not exist or is not associated with the aef id provided + + +Retrieve Security Context from AEF using PKI-secured API Invoker + [Tags] capif_security_api-28 smoke + # Default Invoker Registration and Onboarding + ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + + # Register Provider + ${register_user_info_provider}= Provider Default Registration + + # Publish Service API + # Create list with security methods + ${security_methods}= Create List PKI + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider} + ... service_1 + ... security_methods=${security_methods} + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Create Security Context + ${request_body}= Create Service Security Default Body + ... ${NOTIFICATION_DESTINATION_URL} + ... aef_id=${register_user_info_provider['aef_id']} + ... api_id=${service_api_id_1} + ${resp}= Put Request Capif + ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']} + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME} + + Check Response Variable Type And Values ${resp} 201 ServiceSecurity + ${resource_url}= Check Location Header ${resp} ${LOCATION_SECURITY_RESOURCE_REGEX} + + ${service_security_context}= Set Variable ${resp.json()} + + # Retrieve Security context can setup by parameters if authenticationInfo and authorizationInfo are needed at response. + ${resp}= Get Request Capif + ... /capif-security/v1/trustedInvokers/${register_user_info_invoker['api_invoker_id']}?authenticationInfo=true&authorizationInfo=true + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${AEF_PROVIDER_USERNAME} + + # Check Results + Check Response Variable Type And Values ${resp} 200 ServiceSecurity + + # Response must accomplish: + # aefProfile must contain authenticationInfo with CA root certificate + # aefProfile must NOT CONTAIN authorizationInfo + + # Create security_info to compare with response + ## Read CA root certificate + ${ca_root}= Read File Utf8 ca.crt + ## Create a securityInfo with authenticationInfo with CA root certificate + ${security_info_expected}= Add Key To Object ${service_security_context['securityInfo'][0]} authenticationInfo ${ca_root} + ## Create List of securityInfo + ${security_info_list}= Create List ${security_info_expected} + ## Set expected securityInfo list in service_security_context + ${service_security_context_filtered}= Add Key To Object ${service_security_context} securityInfo ${security_info_list} + Log Dictionary ${service_security_context_filtered} + + # Check Results + Dictionaries Should Be Equal ${resp.json()} ${service_security_context_filtered} diff --git a/tests/features/Event Filter/__init__.robot b/tests/features/Event Filter/__init__.robot new file mode 100644 index 0000000000000000000000000000000000000000..2b28f2062f897e7403d0a4dc7e6f1a3408bb4776 --- /dev/null +++ b/tests/features/Event Filter/__init__.robot @@ -0,0 +1,2 @@ +*** Settings *** +Force Tags event_filter \ No newline at end of file diff --git a/tests/features/Event Filter/event_filter.robot b/tests/features/Event Filter/event_filter.robot new file mode 100644 index 0000000000000000000000000000000000000000..a480248eee5c4060d41813ece614d854810c0df9 --- /dev/null +++ b/tests/features/Event Filter/event_filter.robot @@ -0,0 +1,1031 @@ +*** Settings *** +Resource /opt/robot-tests/tests/resources/common.resource +Library /opt/robot-tests/tests/libraries/bodyRequests.py +Library XML +Library String +Resource /opt/robot-tests/tests/resources/common/basicRequests.robot +Resource ../../resources/common.resource +Resource ../../resources/common/basicRequests.robot + +Suite Teardown Reset Testing Environment +Test Setup Reset Testing Environment +Test Teardown Reset Testing Environment + + +*** Variables *** +${API_INVOKER_NOT_REGISTERED} not-valid +${SUBSCRIBER_ID_NOT_VALID} not-valid +${SUBSCRIPTION_ID_NOT_VALID} not-valid + + +*** Test Cases *** +Invoker subscribed to SERVICE_API_AVAILABLE, SERVICE_API_UNAVAILABLE and SERVICE_API_UPDATE events filtered by apiIds + [Tags] event_filter-1 mockserver + + # Initialize Mock server + Init Mock Server + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + + # Create Provider1 with 2 AEF roles and publish API + ${register_user_info_provider_1}= Provider Default Registration total_aef_roles=2 + ${aef_id_1}= Set Variable ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}']['aef_id']} + ${aef_id_2}= Set Variable + ... ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}_1']['aef_id']} + ${aef_ids}= Create List ${aef_id_1} ${aef_id_2} + ${aef_empty_list}= Create List + + ## Publish API service_1 with 2 aefIds + ${service_api_description_published_1} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider_1} + ... service_1 + ... aef_id=${aef_ids} + ... api_status=${aef_empty_list} + ... supported_features=020 + + # Create Provider2 with 1 AEF role and publish API + ${register_user_info_provider_2}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_NEW + ${aef2_id_1}= Set Variable + ... ${register_user_info_provider_2['aef_roles']['${AEF_PROVIDER_USERNAME}_NEW']['aef_id']} + + ## Publish API service_2 with Provider2 + ${service_api_description_published_2} ${resource_url_2} ${request_body_2}= Publish Service Api + ... ${register_user_info_provider_2} + ... service_2 + ... aef_id=${aef2_id_1} + ... api_status=${aef2_id_1} + ... supported_features=020 + + # Discover APIs by Invoker filtering by aefId1 of Provider1 + ${resp}= Get Request Capif + ... ${DISCOVER_URL}${register_user_info_invoker['api_invoker_id']}&aef-id=${aef_id_1} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME} + + Check Response Variable Type And Values ${resp} 200 DiscoveredAPIs + Dictionary Should Contain Key ${resp.json()} serviceAPIDescriptions + Should Not Be Empty ${resp.json()['serviceAPIDescriptions']} + Length Should Be ${resp.json()['serviceAPIDescriptions']} 1 + List Should Contain Value ${resp.json()['serviceAPIDescriptions']} ${service_api_description_published_1} + + ## Store apiId for further use + ${api_id}= Set Variable ${resp.json()['serviceAPIDescriptions'][0]['apiId']} + + # Subscribe to events and setup event filter with api_id + ${events_list}= Create List SERVICE_API_AVAILABLE SERVICE_API_UNAVAILABLE SERVICE_API_UPDATE + ${event_filter}= Create Capif Event Filter apiIds=${api_id} + ${event_filters}= Create List ${event_filter} ${event_filter} ${event_filter} + ${subscription_id}= + ... Subscribe invoker ${register_user_info_invoker} to events ${events_list} with event filters ${event_filters} + + # Update Request to published API + ${service_api_description_modified}= Create Service Api Description + ... service_1 + ... aef_id=${aef_ids} + ... supported_features=020 + ... api_status=${aef_ids} + ${resp}= Put Request Capif + ... ${resource_url.path} + ... json=${service_api_description_modified} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${APF_PROVIDER_USERNAME} + + Check Response Variable Type And Values ${resp} 200 ServiceAPIDescription + ... apiName=service_1 + Dictionary Should Contain Key ${resp.json()} apiStatus + + # Remove Providers + ## Remove Provider1 + ${resp}= Delete Request Capif + ... ${resource_url.path} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${APF_PROVIDER_USERNAME} + Status Should Be 204 ${resp} + + ## Remove Provider2 + ${resp}= Delete Request Capif + ... ${resource_url_2.path} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${APF_PROVIDER_USERNAME}_NEW + Status Should Be 204 ${resp} + + # Create check Events to ensure all notifications were received + ## Service API Available event + ${service_api_available_resources}= Create List ${resource_url} + ${events_expected}= Create Expected Events For Service API Notifications + ... subscription_id=${subscription_id} + ... service_api_available_resources=${service_api_available_resources} + ... event_detail_expected=${TRUE} + ... service_api_description_expected=${TRUE} + ... service_api_description=${service_api_description_modified} + Log List ${events_expected} + + ## Service API Update event + ${events_expected}= Create Expected Service Update Event + ... subscription_id=${subscription_id} + ... service_api_resource=${resource_url} + ... service_api_descriptions=${service_api_description_modified} + ... events_expected=${events_expected} + Log List ${events_expected} + + ## Service API Unavailable event + ${service_api_unavailable_resources}= Create List ${resource_url} + ${events_expected}= Create Expected Events For Service API Notifications + ... subscription_id=${subscription_id} + ... service_api_unavailable_resources=${service_api_unavailable_resources} + ... event_detail_expected=${TRUE} + ... service_api_description_expected=${TRUE} + ... service_api_description=${service_api_description_modified} + ... events_expected=${events_expected} + Log List ${events_expected} + + # Check Events Expected towards received notifications at mock server + Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} + +Invoker subscribed to SERVICE_API_AVAILABLE, SERVICE_API_UNAVAILABLE and SERVICE_API_UPDATE events filtered by not valid filters + [Tags] event_filter-2 smoke + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + + # Create Provider1 with 2 AEF roles and publish API + ${register_user_info_provider_1}= Provider Default Registration total_aef_roles=2 + ${aef_id_1}= Set Variable ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}']['aef_id']} + ${aef_id_2}= Set Variable + ... ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}_1']['aef_id']} + ${aef_ids}= Create List ${aef_id_1} ${aef_id_2} + ${aef_empty_list}= Create List + + ## Publish API service_1 with 2 aefIds + ${service_api_description_published} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider_1} + ... service_1 + ... aef_id=${aef_ids} + ... api_status=${aef_empty_list} + ... supported_features=020 + + # Create Provider2 and publish API + ${register_user_info_provider_2}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_NEW + ${aef2_id_1}= Set Variable + ... ${register_user_info_provider_2['aef_roles']['${AEF_PROVIDER_USERNAME}_NEW']['aef_id']} + + ## Publish API service_2 + ${service_api_description_published_2} ${resource_url_2} ${request_body_2}= Publish Service Api + ... ${register_user_info_provider_2} + ... service_2 + ... aef_id=${aef2_id_1} + ... api_status=${aef2_id_1} + ... supported_features=020 + + # Discover APIs by invoker + ${resp}= Get Request Capif + ... ${DISCOVER_URL}${register_user_info_invoker['api_invoker_id']}&aef-id=${aef_id_1} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME} + Check Response Variable Type And Values ${resp} 200 DiscoveredAPIs + Dictionary Should Contain Key ${resp.json()} serviceAPIDescriptions + Should Not Be Empty ${resp.json()['serviceAPIDescriptions']} + Length Should Be ${resp.json()['serviceAPIDescriptions']} 1 + List Should Contain Value ${resp.json()['serviceAPIDescriptions']} ${service_api_description_published} + + ## Store apiId for further use + ${api_id}= Set Variable ${resp.json()['serviceAPIDescriptions'][0]['apiId']} + + # Event Subscription + ## Events list + ${events_list}= Create List SERVICE_API_AVAILABLE SERVICE_API_UNAVAILABLE SERVICE_API_UPDATE + + ## Event filters + ${event_filter_empty}= Create Capif Event Filter + ${event_filter_aef_ids}= Create Capif Event Filter aefIds=${aef_ids} + ${event_filter_api_ids}= Create Capif Event Filter apiIds=${service_api_description_published['apiId']} + ${event_filter_api_invoker_ids}= Create Capif Event Filter + ... apiInvokerIds=${register_user_info_invoker['api_invoker_id']} + + ## Subscription to Events filtering by aefIds SERVICE_API_AVAILABLE event + ${event_filters}= Create List ${event_filter_aef_ids} ${event_filter_empty} ${event_filter_empty} + ${resp}= + ... Subscribe ${register_user_info_invoker['api_invoker_id']} with ${register_user_info_invoker['management_cert']} to ${events_list} with ${event_filters} + + ### Check Error Response + Check not valid ${resp} with event filter aef_ids for event SERVICE_API_AVAILABLE + + ## Subscription to Events filtering by aefIds SERVICE_API_UNAVAILABLE event + ${event_filters}= Create List ${event_filter_empty} ${event_filter_aef_ids} ${event_filter_empty} + ${resp}= + ... Subscribe ${register_user_info_invoker['api_invoker_id']} with ${register_user_info_invoker['management_cert']} to ${events_list} with ${event_filters} + + ### Check Error Response + Check not valid ${resp} with event filter aef_ids for event SERVICE_API_UNAVAILABLE + + ## Subscription to Events filtering by aefIds SERVICE_API_UPDATE event + ${event_filters}= Create List ${event_filter_empty} ${event_filter_empty} ${event_filter_aef_ids} + ${resp}= + ... Subscribe ${register_user_info_invoker['api_invoker_id']} with ${register_user_info_invoker['management_cert']} to ${events_list} with ${event_filters} + + ### Check Error Response + Check not valid ${resp} with event filter aef_ids for event SERVICE_API_UPDATE + + ## Subscription to Events filtering by api invoker ids SERVICE_API_UPDATE event + ${event_filters}= Create List + ... ${event_filter_empty} + ... ${event_filter_empty} + ... ${event_filter_api_invoker_ids} + ${resp}= + ... Subscribe ${register_user_info_invoker['api_invoker_id']} with ${register_user_info_invoker['management_cert']} to ${events_list} with ${event_filters} + + ### Check Error Response + Check not valid ${resp} with event filter api_invoker_ids for event SERVICE_API_UPDATE + +Provider subscribed to API_INVOKER_ONBOARDED, API_INVOKER_OFFBOARDED and API_INVOKER_UPDATED events filtered by invokerIds + [Tags] event_filter-3 mockserver + + # Initialize Mock server + Init Mock Server + + # Create Provider1 with 2 AEF roles and publish API + ## Create Provider with 2 AEF roles + ${register_user_info_provider_1}= Provider Default Registration + + # Event Subscription + ## Event list + ${events_list}= Create List API_INVOKER_ONBOARDED + ## Event filters + ${event_filter}= Create Capif Event Filter + ## Subscribe API_INVOKER_ONBOARDED event without filters + ${event_filters}= Create List ${event_filter} + ${subscription_id_1}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + # Default Invokers Registration and Onboarding + # Default Invoker 1 Registration and Onboarding + ${register_user_info_invoker_1} ${invoker_url_1} ${invoker_request_body_1}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_1 + ${api_invoker_id_1}= Set Variable ${register_user_info_invoker_1['api_invoker_id']} + + # Default Invoker 2 Registration and Onboarding + ${register_user_info_invoker_2} ${invoker_url_2} ${invoker_request_body_2}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_2 + ${api_invoker_id_2}= Set Variable ${register_user_info_invoker_2['api_invoker_id']} + + # Subscribe to events and setup event filter with api_invoker_id + ## Events list + ${events_list}= Create List API_INVOKER_ONBOARDED API_INVOKER_OFFBOARDED API_INVOKER_UPDATED + ## Event filters + ${event_filter_empty}= Create Capif Event Filter + ${event_filter_invoker_id_1}= Create Capif Event Filter apiInvokerIds=${api_invoker_id_1} + ${event_filter_invoker_id_2}= Create Capif Event Filter apiInvokerIds=${api_invoker_id_2} + + ## Subscribe to Invoker events. API_INVOKER_ONBOARDED event can be filtered by apiInvokerId but is not possible to get it before the invoker is registered + ${event_filters}= Create List + ... ${event_filter_empty} + ... ${event_filter_invoker_id_1} + ... ${event_filter_invoker_id_2} + ${subscription_id_2}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + # Update Invokers + ## Update Invoker 1 + ${new_notification_destination}= Set Variable + ... http://${CAPIF_CALLBACK_IP}:${CAPIF_CALLBACK_PORT}/netapp_new_callback_1 + Set To Dictionary + ... ${invoker_request_body_1} + ... notificationDestination=${new_notification_destination} + ${resp}= Put Request Capif + ... ${invoker_url_1.path} + ... ${invoker_request_body_1} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME}_1 + Check Response Variable Type And Values ${resp} 200 APIInvokerEnrolmentDetails + ... notificationDestination=${new_notification_destination} + + ## Update Invoker 1 + ${new_notification_destination}= Set Variable + ... http://${CAPIF_CALLBACK_IP}:${CAPIF_CALLBACK_PORT}/netapp_new_callback_2 + Set To Dictionary + ... ${invoker_request_body_2} + ... notificationDestination=${new_notification_destination} + ${resp}= Put Request Capif + ... ${invoker_url_2.path} + ... ${invoker_request_body_2} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME}_2 + Check Response Variable Type And Values ${resp} 200 APIInvokerEnrolmentDetails + ... notificationDestination=${new_notification_destination} + + # Remove invokers + ## Remove Invoker 1 + ${resp}= Delete Request Capif + ... ${invoker_url_1.path} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME}_1 + Call Method ${CAPIF_USERS} remove_capif_users_entry ${invoker_url_1.path} + Should Be Equal As Strings ${resp.status_code} 204 + + ## Remove Invoker 2 + ${resp}= Delete Request Capif + ... ${invoker_url_2.path} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${INVOKER_USERNAME}_2 + Call Method ${CAPIF_USERS} remove_capif_users_entry ${invoker_url_2.path} + Should Be Equal As Strings ${resp.status_code} 204 + + # Check Event Notifications + ## Create check Events to ensure all notifications were received + ${invoker_urls_both}= Create List ${invoker_url_1} ${invoker_url_2} + ${invoker_urls_1}= Create List ${invoker_url_1} + ${invoker_urls_2}= Create List ${invoker_url_2} + ${events_expected}= Create Expected Api Invoker Events + ... ${subscription_id_1} + ... api_invoker_onboarded_resources=${invoker_urls_both} + ... event_detail_expected=${TRUE} + ${events_expected}= Create Expected Api Invoker Events + ... ${subscription_id_2} + ... events_expected=${events_expected} + ... api_invoker_updated_resources=${invoker_urls_2} + ... api_invoker_offboarded_resources=${invoker_urls_1} + ... event_detail_expected=${TRUE} + Log List ${events_expected} + ## Check Events Expected towards received notifications at mock server + Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} + +Provider subscribed to API_INVOKER_ONBOARDED, API_INVOKER_OFFBOARDED and API_INVOKER_UPDATED events filtered by not valid filters + [Tags] event_filter-4 + + # Register APF + ${register_user_info_provider_1}= Provider Default Registration total_aef_roles=2 + + ${aef_id_1}= Set Variable ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}']['aef_id']} + ${aef_id_2}= Set Variable + ... ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}_1']['aef_id']} + ${aef_ids}= Create List ${aef_id_1} ${aef_id_2} + ${aef_empty_list}= Create List + + # Publish api with 2 aefIds + ${service_api_description_published} ${resource_url} ${request_body}= Publish Service Api + ... ${register_user_info_provider_1} + ... service_1 + ... aef_id=${aef_ids} + ... api_status=${aef_empty_list} + ... supported_features=020 + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker_1} ${invoker_url_1} ${invoker_request_body_1}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_1 + ${api_invoker_id_1}= Set Variable ${register_user_info_invoker_1['api_invoker_id']} + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker_2} ${invoker_url_2} ${invoker_request_body_2}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_2 + ${api_invoker_id_2}= Set Variable ${register_user_info_invoker_2['api_invoker_id']} + + # Subscribe to events + ${events_list}= Create List API_INVOKER_ONBOARDED API_INVOKER_OFFBOARDED API_INVOKER_UPDATED + ${event_filter_empty}= Create Capif Event Filter + ${event_filter_aef_ids}= Create Capif Event Filter aefIds=${aef_ids} + ${event_filter_api_ids}= Create Capif Event Filter apiIds=${service_api_description_published['apiId']} + ${event_filter_invoker_id_2}= Create Capif Event Filter apiInvokerIds=${api_invoker_id_2} + + ## Event subscription with event filters by aef_ids + ${event_filters}= Create List ${event_filter_aef_ids} ${event_filter_empty} ${event_filter_empty} + ${resp}= + ... Subscribe ${register_user_info_provider_1['amf_id']} with ${register_user_info_provider_1['amf_username']} to ${events_list} with ${event_filters} + + ### Check Results + Check not valid ${resp} with event filter aef_ids for event API_INVOKER_ONBOARDED + + ## Event subcription API_INVOKER_OFFBOARDED filtered by aef_ids + ${event_filters}= Create List ${event_filter_empty} ${event_filter_aef_ids} ${event_filter_empty} + ${resp}= + ... Subscribe ${register_user_info_provider_1['amf_id']} with ${register_user_info_provider_1['amf_username']} to ${events_list} with ${event_filters} + + ### Check Results + Check not valid ${resp} with event filter aef_ids for event API_INVOKER_OFFBOARDED + + ## Event subcription API_INVOKER_UPDATED filtered by aef_ids + ${event_filters}= Create List ${event_filter_empty} ${event_filter_empty} ${event_filter_aef_ids} + ${resp}= + ... Subscribe ${register_user_info_provider_1['amf_id']} with ${register_user_info_provider_1['amf_username']} to ${events_list} with ${event_filters} + + ### Check Results + Check not valid ${resp} with event filter aef_ids for event API_INVOKER_UPDATED + + ## Event subcription API_INVOKER_UPDATED filtered by api_ids + ${event_filters}= Create List ${event_filter_empty} ${event_filter_empty} ${event_filter_api_ids} + ${resp}= + ... Subscribe ${register_user_info_provider_1['amf_id']} with ${register_user_info_provider_1['amf_username']} to ${events_list} with ${event_filters} + + ### Check Results + Check not valid ${resp} with event filter api_ids for event API_INVOKER_UPDATED + +Provider subscribed to ACCESS_CONTROL_POLICY_UPDATE event filtered by only apiId, only invokerId and both + [Tags] event_filter-5 mockserver smoke + + # Initialize Mock server + Init Mock Server + + # Create Providers + ## Default Provider 1 Registration + ${register_user_info_provider_1}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_1 + + ## Publish service_1 API + ${service_api_description_published_1} + ... ${provider_resource_url_1} + ... ${provider_request_body_1}= + ... Publish Service Api + ... ${register_user_info_provider_1} + ... service_name=service_1 + + ## Default Provider 2 Registration + ${register_user_info_provider_2}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_2 + + ## Publish service_2 API + ${service_api_description_published_2} + ... ${provider_resource_url_2} + ... ${provider_request_body_2}= + ... Publish Service Api + ... ${register_user_info_provider_2} + ... service_name=service_2 + + ## Store apiId1 and apiId2 for further use + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + ${service_api_id_2}= Set Variable ${service_api_description_published_2['apiId']} + + # Register Invokers + ## Default Invoker1 onboarding + ${register_user_info_invoker_1} ${invoker_url_1} ${request_body_1}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_1 + + ## Default Invoker1 onboarding + ${register_user_info_invoker_2} ${invoker_url_2} ${request_body_2}= Invoker Default Onboarding + ... invoke_username=${INVOKER_USERNAME}_2 + + ## Store apiInvokerIds for further use + ${api_invoker_id_1}= Set Variable ${register_user_info_invoker_1['api_invoker_id']} + ${api_invoker_id_2}= Set Variable ${register_user_info_invoker_2['api_invoker_id']} + + # Subscribe to events + ## Events list + ${events_list}= Create List ACCESS_CONTROL_POLICY_UPDATE + + ## Create Event filters + ${event_filter_api_invoker_ids}= Create Capif Event Filter apiInvokerIds=${api_invoker_id_1} + ${event_filter_api_ids}= Create Capif Event Filter apiIds=${service_api_id_1} + ${event_filter_api_invoker_ids_and_api_ids}= Create Capif Event Filter + ... apiInvokerIds=${api_invoker_id_2} + ... apiIds=${service_api_id_2} + + ## Subscription to Events 1 + ${event_filters}= Create List ${event_filter_api_ids} + ${subscription_id_1}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 2 + ${event_filters}= Create List ${event_filter_api_invoker_ids} + ${subscription_id_2}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 3 + ${event_filters}= Create List ${event_filter_api_invoker_ids_and_api_ids} + ${subscription_id_3}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Create Security Contexts and ACLs + ${acl_provider_1}= + ... Create Security Context between ${register_user_info_invoker_1} and ${register_user_info_provider_1} + ${acl_provider_1}= + ... Create Security Context between ${register_user_info_invoker_2} and ${register_user_info_provider_1} + + ${acl_provider_2}= + ... Update Security Context between ${register_user_info_invoker_1} and ${register_user_info_provider_2} + ${acl_provider_2}= + ... Update Security Context between ${register_user_info_invoker_2} and ${register_user_info_provider_2} + + # Check Event Notifications + ## Create check Events to ensure all notifications were received + ### Subscription 1 Checks + ${acl_to_check}= Create List ${acl_provider_1[0]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_1} + ... ${service_api_id_1} + ... ${acl_to_check} + + ${acl_to_check}= Create List ${acl_provider_1[1]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_1} + ... ${service_api_id_1} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ${acl_to_check}= Create List ${acl_provider_1[0]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_1} + ... ${service_api_id_1} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ${acl_to_check}= Create List ${acl_provider_1[1]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_1} + ... ${service_api_id_1} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ### Subscription 2 checks + ${acl_to_check}= Create List ${acl_provider_1[0]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_2} + ... ${service_api_id_1} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ${acl_to_check}= Create List ${acl_provider_1[0]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_2} + ... ${service_api_id_1} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ${acl_to_check}= Create List ${acl_provider_2[0]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_2} + ... ${service_api_id_2} + ... ${acl_to_check} + ... events_expected=${events_expected} + + ### Subscription 3 checks + ${acl_to_check}= Create List ${acl_provider_2[1]} + ${events_expected}= Create Expected Access Control Policy Update Event + ... ${subscription_id_3} + ... ${service_api_id_2} + ... ${acl_to_check} + ... events_expected=${events_expected} + + Log List ${events_expected} + + ## Check Events Expected towards received notifications at mock server + Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} + +Provider subscribed to ACCESS_CONTROL_POLICY_UPDATE event filtered by aefId + [Tags] event_filter-6 + + # Create Provider + ## Default Provider 1 Registration + ${register_user_info_provider_1}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_1 + ${aef_id_1}= Set Variable + ... ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}_1']['aef_id']} + + # Publish one api + ${service_api_description_published_1} + ... ${provider_resource_url_1} + ... ${provider_request_body_1}= + ... Publish Service Api + ... ${register_user_info_provider_1} + ... service_name=service_1 + + # Store apiId1 + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + + # Subscribe to events + ## Event lists + ${events_list}= Create List ACCESS_CONTROL_POLICY_UPDATE + + ## Event filters + ${event_filter_aef_id}= Create Capif Event Filter aefIds=${aef_id_1} + + ## Subscription to Events 1 + ${event_filters}= Create List ${event_filter_aef_id} + ${resp}= + ... Subscribe ${register_user_info_provider_1['amf_id']} with ${register_user_info_provider_1['amf_username']} to ${events_list} with ${event_filters} + + ### Check Error Response + Check not valid ${resp} with event filter aef_ids for event ACCESS_CONTROL_POLICY_UPDATE + +Provider subscribed to SERVICE_API_INVOCATION_SUCCESS and SERVICE_API_INVOCATION_FAILURE filtered by apiId, invokerId, aefId and all of them + [Tags] event_filter-7 mockserver smoke + + # Initialize Mock server + Init Mock Server + + # Register Providers + ## Default Provider 1 Registration + ${register_user_info_provider_1}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_1 + ${aef_id_1}= Set Variable + ... ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}_1']['aef_id']} + + ## Publish service_1 API + ${service_api_description_published_1} + ... ${provider_resource_url_1} + ... ${provider_request_body_1}= + ... Publish Service Api + ... ${register_user_info_provider_1} + ... service_name=service_1 + + ## Default Provider 2 Registration + ${register_user_info_provider_2}= Provider Default Registration provider_username=${PROVIDER_USERNAME}_2 + ${aef_id_2}= Set Variable + ... ${register_user_info_provider_2['aef_roles']['${AEF_PROVIDER_USERNAME}_2']['aef_id']} + + ## Publish service_2 API + ${service_api_description_published_2} + ... ${provider_resource_url_2} + ... ${provider_request_body_2}= + ... Publish Service Api + ... ${register_user_info_provider_2} + ... service_name=service_2 + + ## Store apiId1 and apiId2 for further use + ${service_api_id_1}= Set Variable ${service_api_description_published_1['apiId']} + ${service_api_id_2}= Set Variable ${service_api_description_published_2['apiId']} + + # Register Invokers + ## Default Invoker 1 Registration and Onboarding + ${register_user_info_invoker_1} ${invoker_url_1} ${request_body_1}= Invoker Default Onboarding + ... invoker_username=${INVOKER_USERNAME}_1 + + ## Default Invoker 2 Registration and Onboarding + ${register_user_info_invoker_2} ${invoker_url_2} ${request_body_2}= Invoker Default Onboarding + ... invoke_username=${INVOKER_USERNAME}_2 + + ## Store apiInvokerIds for further use + ${api_invoker_id_1}= Set Variable ${register_user_info_invoker_1['api_invoker_id']} + ${api_invoker_id_2}= Set Variable ${register_user_info_invoker_2['api_invoker_id']} + + # Subscribe to events + ## Event lists + ${events_list}= Create List SERVICE_API_INVOCATION_SUCCESS SERVICE_API_INVOCATION_FAILURE + + ## Event filters + ${event_filter_empty}= Create Capif Event Filter + ${event_filter_api_invoker_ids}= Create Capif Event Filter apiInvokerIds=${api_invoker_id_1} + ${event_filter_api_ids}= Create Capif Event Filter apiIds=${service_api_id_1} + ${event_filter_aef_ids}= Create Capif Event Filter aefIds=${aef_id_2} + ${event_filter_api_ids_and_aef_ids}= Create Capif Event Filter + ... apiIds=${service_api_id_2} + ... aefIds=${aef_id_2} + ${event_filter_api_ids_and_api_invoker_ids}= Create Capif Event Filter + ... apiInvokerIds=${api_invoker_id_2} + ... apiIds=${service_api_id_2} + ${event_filter_aef_ids_and_api_invoker_ids}= Create Capif Event Filter + ... apiInvokerIds=${api_invoker_id_2} + ... aefIds=${aef_id_1} + ${event_filter_api_ids_aef_ids_and_api_invoker_ids}= Create Capif Event Filter + ... apiInvokerIds=${api_invoker_id_2} + ... aefIds=${aef_id_2} + ... apiIds=${service_api_id_2} + + ## Subscription to Events 1 + ${event_filters}= Create List ${event_filter_api_ids} ${event_filter_api_ids} + ${subscription_id_1}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 2 + ${event_filters}= Create List ${event_filter_aef_ids} ${event_filter_aef_ids} + ${subscription_id_2}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 3 + ${event_filters}= Create List ${event_filter_api_invoker_ids} ${event_filter_api_invoker_ids} + ${subscription_id_3}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 4 + ${event_filters}= Create List ${event_filter_api_ids_and_aef_ids} ${event_filter_api_ids_and_aef_ids} + ${subscription_id_4}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 5 + ${event_filters}= Create List + ... ${event_filter_api_ids_and_api_invoker_ids} + ... ${event_filter_api_ids_and_api_invoker_ids} + ${subscription_id_5}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 6 + ${event_filters}= Create List + ... ${event_filter_aef_ids_and_api_invoker_ids} + ... ${event_filter_aef_ids_and_api_invoker_ids} + ${subscription_id_6}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + ## Subscription to Events 7 + ${event_filters}= Create List + ... ${event_filter_api_ids_aef_ids_and_api_invoker_ids} + ... ${event_filter_api_ids_aef_ids_and_api_invoker_ids} + ${subscription_id_7}= + ... Subscribe provider ${register_user_info_provider_1} to events ${events_list} with event filters ${event_filters} + + # 1.Log entry for service_1 and invoker_1 + ${request_body_log_1}= Send Log Message to CAPIF + ... ${service_api_id_1} + ... service_1 + ... ${register_user_info_invoker_1} + ... ${register_user_info_provider_1} + ... 200 + ... 400 + + # 2.Log entry for service_2 and invoker_1 + ${request_body_log_2}= Send Log Message to CAPIF + ... ${service_api_id_2} + ... service_2 + ... ${register_user_info_invoker_1} + ... ${register_user_info_provider_2} + ... 200 + + # 3.Log entry for service_2 and invoker_2 + ${request_body_log_3}= Send Log Message to CAPIF + ... ${service_api_id_2} + ... service_2 + ... ${register_user_info_invoker_2} + ... ${register_user_info_provider_2} + ... 200 + + # 4.Log entry for service_1 and invoker_2 + ${request_body_log_4}= Send Log Message to CAPIF + ... ${service_api_id_1} + ... service_1 + ... ${register_user_info_invoker_2} + ... ${register_user_info_provider_1} + ... 400 + + # Check Event Notifications + ## Create check Events to ensure all notifications were received + ### Subscription 1 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_1} + ... ${request_body_log_1} + + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_1} + ... ${request_body_log_4} + ... events_expected=${events_expected} + + ### Subcription 2 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_2} + ... ${request_body_log_2} + ... events_expected=${events_expected} + + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_2} + ... ${request_body_log_3} + ... events_expected=${events_expected} + + # Subscription 3 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_3} + ... ${request_body_log_1} + ... events_expected=${events_expected} + + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_3} + ... ${request_body_log_2} + ... events_expected=${events_expected} + + # Subscription 4 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_4} + ... ${request_body_log_2} + ... events_expected=${events_expected} + + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_4} + ... ${request_body_log_3} + ... events_expected=${events_expected} + + # Subscription 5 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_5} + ... ${request_body_log_3} + ... events_expected=${events_expected} + + # Subscription 6 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_6} + ... ${request_body_log_4} + ... events_expected=${events_expected} + + # Subscription 7 Checks + ${events_expected}= Create Events From InvocationLogs + ... ${subscription_id_7} + ... ${request_body_log_3} + ... events_expected=${events_expected} + + Log List ${events_expected} + ## Check Events Expected towards received notifications at mock server + Wait Until Keyword Succeeds 5x 5s Check Mock Server Notification Events ${events_expected} + +Event Filter present with Enhanced_event_report feature not active + [Tags] event_filter-8 smoke + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + + # Event Subscription + ## Events list + ${events_list}= Create List SERVICE_API_AVAILABLE SERVICE_API_UNAVAILABLE SERVICE_API_UPDATE + + ## Event filters + ${event_filter_empty}= Create Capif Event Filter + + ## Subscription to Events filtering by aefIds SERVICE_API_AVAILABLE event + ${event_filters}= Create List ${event_filter_empty} ${event_filter_empty} ${event_filter_empty} + ${resp}= Subscribe Events ${register_user_info_invoker['api_invoker_id']} ${register_user_info_invoker['management_cert']} ${events_list} ${event_filters} 0 + + ### Check Error Response + ${invalid_param}= Create Dictionary + ... param=eventFilters + ... reason=EnhancedEventReport is not enabled + ${invalid_param_list}= Create List ${invalid_param} + Check Response Variable Type And Values + ... ${resp} + ... 400 + ... ProblemDetails + ... title=Bad Request + ... status=400 + ... detail=Bad Param + ... cause=Event filters provided but EnhancedEventReport is not enabled + ... invalidParams=${invalid_param_list} + + +*** Keywords *** +Create Security Context between ${invoker_info} and ${provider_info} + # Discover APIs by invoker + ${discover_response}= Get Request Capif + ... ${DISCOVER_URL}${invoker_info['api_invoker_id']}&aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Check Response Variable Type And Values ${discover_response} 200 DiscoveredAPIs + + # create Security Context + ${request_service_security_body} ${api_ids}= Create Service Security From Discover Response + ... http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/test + ... ${discover_response} + ... legacy=${FALSE} + ${resp}= Put Request Capif + ... /capif-security/v1/trustedInvokers/${invoker_info['api_invoker_id']} + ... json=${request_service_security_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Set To Dictionary ${invoker_info} security_body=${request_service_security_body} + # Check Service Security + Check Response Variable Type And Values ${resp} 201 ServiceSecurity + ${resource_url}= Check Location Header ${resp} ${LOCATION_SECURITY_RESOURCE_REGEX} + + ${api_invoker_policies_list}= Create List + + FOR ${api_id} IN @{api_ids} + Log ${api_id} + ${resp}= Get Request Capif + ... /access-control-policy/v1/accessControlPolicyList/${api_id}?aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['aef_username']} + Check Response Variable Type And Values ${resp} 200 AccessControlPolicyList + Should Not Be Empty ${resp.json()['apiInvokerPolicies']} + ${api_invoker_policies}= Set Variable ${resp.json()['apiInvokerPolicies']} + ${api_invoker_policies_list}= Set Variable ${api_invoker_policies} + END + + Log List ${api_invoker_policies_list} + + RETURN ${api_invoker_policies_list} + +Update Security Context between ${invoker_info} and ${provider_info} + # Discover APIs by invoker + ${discover_response}= Get Request Capif + ... ${DISCOVER_URL}${invoker_info['api_invoker_id']}&aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Check Response Variable Type And Values ${discover_response} 200 DiscoveredAPIs + + # create Security Context + ${request_service_security_body} ${api_ids}= Update Service Security With Discover Response + ... ${invoker_info['security_body']} + ... ${discover_response} + ... legacy=${FALSE} + ${resp}= Post Request Capif + ... /capif-security/v1/trustedInvokers/${invoker_info['api_invoker_id']}/update + ... json=${request_service_security_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + # Check Service Security + Check Response Variable Type And Values ${resp} 200 ServiceSecurity + ${resource_url}= Check Location Header ${resp} ${LOCATION_SECURITY_RESOURCE_REGEX} + + ${api_invoker_policies_list}= Create List + + ${api_id}= Get From List ${api_ids} -1 + Log ${api_id} + ${resp}= Get Request Capif + ... /access-control-policy/v1/accessControlPolicyList/${api_id}?aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['aef_username']} + + Check Response Variable Type And Values ${resp} 200 AccessControlPolicyList + # Check returned values + Should Not Be Empty ${resp.json()['apiInvokerPolicies']} + + ${api_invoker_policies}= Set Variable ${resp.json()['apiInvokerPolicies']} + # Append To List ${api_invoker_policies_list} ${api_invoker_policies} + ${api_invoker_policies_list}= Set Variable ${api_invoker_policies} + + Log List ${api_invoker_policies_list} + + RETURN ${api_invoker_policies_list} + +Subscribe provider ${provider_info} to events ${events_list} with event filters ${event_filters} + ${resp}= + ... Subscribe ${provider_info['amf_id']} with ${provider_info['amf_username']} to ${events_list} with ${event_filters} + + Check Response Variable Type And Values ${resp} 201 EventSubscription + ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} + + RETURN ${subscription_id} + +Subscribe invoker ${invoker_info} to events ${events_list} with event filters ${event_filters} + ${resp}= + ... Subscribe ${invoker_info['api_invoker_id']} with ${invoker_info['management_cert']} to ${events_list} with ${event_filters} + + Check Response Variable Type And Values ${resp} 201 EventSubscription + ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} + + RETURN ${subscription_id} + +Subscribe ${subscriber_id} with ${username} to ${events_list} with ${event_filters} + ${supported_features}= Set Variable C + ${resp}= Subscribe Events ${subscriber_id} ${username} ${events_list} ${event_filters} ${supported_features} + RETURN ${resp} + +Subscribe Events + [Arguments] ${subscriber_id} ${username} ${events_list} ${event_filters}=${NONE} ${supported_features}=0 + ${request_body}= Create Events Subscription + ... events=@{events_list} + ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing + ... supported_features=${supported_features} + ... event_filters=${event_filters} + ${resp}= Post Request Capif + ... /capif-events/v1/${subscriber_id}/subscriptions + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${username} + + RETURN ${resp} + +Send Log Message to CAPIF + [Arguments] ${api_id} ${service_name} ${invoker_info} ${provider_info} @{results} + ${api_ids}= Create List ${api_id} + ${api_names}= Create List ${service_name} + ${request_body}= Create Log Entry + ... ${provider_info['aef_id']} + ... ${invoker_info['api_invoker_id']} + ... ${api_ids} + ... ${api_names} + ... results=@{results} + ${resp}= Post Request Capif + ... /api-invocation-logs/v1/${provider_info['aef_id']}/logs + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['aef_username']} + + Check Response Variable Type And Values ${resp} 201 InvocationLog + ${resource_url}= Check Location Header ${resp} ${LOCATION_LOGGING_RESOURCE_REGEX} + + RETURN ${request_body} + +Check not valid ${resp} with event filter ${attribute_snake_case} for event ${event} + # Check Results + ${invalid_param}= Create Dictionary + ... param=eventFilter + ... reason=The eventFilter {'${attribute_snake_case}'} for event ${event} are not applicable. + ${invalid_param_list}= Create List ${invalid_param} + Check Response Variable Type And Values + ... ${resp} + ... 400 + ... ProblemDetails + ... title=Bad Request + ... status=400 + ... detail=Bad Param + ... cause=Invalid eventFilter for event ${event} + ... invalidParams=${invalid_param_list} diff --git a/tests/features/Event Req/__init__.robot b/tests/features/Event Req/__init__.robot new file mode 100644 index 0000000000000000000000000000000000000000..2b28f2062f897e7403d0a4dc7e6f1a3408bb4776 --- /dev/null +++ b/tests/features/Event Req/__init__.robot @@ -0,0 +1,2 @@ +*** Settings *** +Force Tags event_filter \ No newline at end of file diff --git a/tests/features/Event Req/event_req.robot b/tests/features/Event Req/event_req.robot new file mode 100644 index 0000000000000000000000000000000000000000..26b1b635fbc56f52015337e9f79ff74ad83f2807 --- /dev/null +++ b/tests/features/Event Req/event_req.robot @@ -0,0 +1,228 @@ +*** Settings *** +Resource /opt/robot-tests/tests/resources/common.resource +Library /opt/robot-tests/tests/libraries/bodyRequests.py +Library XML +Library String +Resource /opt/robot-tests/tests/resources/common/basicRequests.robot +Resource ../../resources/common.resource +Resource ../../resources/common/basicRequests.robot + +Suite Teardown Reset Testing Environment +Test Setup Reset Testing Environment +Test Teardown Reset Testing Environment + + +*** Variables *** +${API_INVOKER_NOT_REGISTERED} not-valid +${SUBSCRIBER_ID_NOT_VALID} not-valid +${SUBSCRIPTION_ID_NOT_VALID} not-valid + + +*** Test Cases *** +Invoker subscribe to Service API Available + [Tags] event_req-1 mockserver + + # Initialize Mock server + Init Mock Server + + # Default Invoker Registration and Onboarding + ${register_user_info_invoker} ${url} ${request_body}= Invoker Default Onboarding + + # Create Provider1 with 2 AEF roles and publish API + ${register_user_info_provider_1}= Provider Default Registration + ${aef_id_1}= Set Variable ${register_user_info_provider_1['aef_roles']['${AEF_PROVIDER_USERNAME}']['aef_id']} + ${aef_empty_list}= Create List + + # Subscribe to events and setup event filter with api_id + ${events_list}= Create List API_INVOKER_ONBOARDED + ${event_req}= Create Event Req notif_method=PERIODIC max_report_nbr=${2} rep_period=${1} + + ${subscription_ids}= Create List + + FOR ${counter} IN RANGE 1 1 1 + Log ${counter} + ${subscription_id}= + ... Subscribe invoker ${register_user_info_invoker} to events ${events_list} with event req ${event_req} + Append To List ${subscription_ids} ${subscription_id} + END + + Sleep 5s + + ${resp}= Get Mock Server Messages + + # ${notification_events_on_mock_server}= Set Variable ${resp.json()} + +*** Keywords *** +Create Security Context between ${invoker_info} and ${provider_info} + # Discover APIs by invoker + ${discover_response}= Get Request Capif + ... ${DISCOVER_URL}${invoker_info['api_invoker_id']}&aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Check Response Variable Type And Values ${discover_response} 200 DiscoveredAPIs + + # create Security Context + ${request_service_security_body} ${api_ids}= Create Service Security From Discover Response + ... http://${CAPIF_HOSTNAME}:${CAPIF_HTTP_PORT}/test + ... ${discover_response} + ... legacy=${FALSE} + ${resp}= Put Request Capif + ... /capif-security/v1/trustedInvokers/${invoker_info['api_invoker_id']} + ... json=${request_service_security_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Set To Dictionary ${invoker_info} security_body=${request_service_security_body} + # Check Service Security + Check Response Variable Type And Values ${resp} 201 ServiceSecurity + ${resource_url}= Check Location Header ${resp} ${LOCATION_SECURITY_RESOURCE_REGEX} + + ${api_invoker_policies_list}= Create List + + FOR ${api_id} IN @{api_ids} + Log ${api_id} + ${resp}= Get Request Capif + ... /access-control-policy/v1/accessControlPolicyList/${api_id}?aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['aef_username']} + Check Response Variable Type And Values ${resp} 200 AccessControlPolicyList + Should Not Be Empty ${resp.json()['apiInvokerPolicies']} + ${api_invoker_policies}= Set Variable ${resp.json()['apiInvokerPolicies']} + ${api_invoker_policies_list}= Set Variable ${api_invoker_policies} + END + + Log List ${api_invoker_policies_list} + + RETURN ${api_invoker_policies_list} + +Update Security Context between ${invoker_info} and ${provider_info} + # Discover APIs by invoker + ${discover_response}= Get Request Capif + ... ${DISCOVER_URL}${invoker_info['api_invoker_id']}&aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + Check Response Variable Type And Values ${discover_response} 200 DiscoveredAPIs + + # create Security Context + ${request_service_security_body} ${api_ids}= Update Service Security With Discover Response + ... ${invoker_info['security_body']} + ... ${discover_response} + ... legacy=${FALSE} + ${resp}= Post Request Capif + ... /capif-security/v1/trustedInvokers/${invoker_info['api_invoker_id']}/update + ... json=${request_service_security_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${invoker_info['management_cert']} + + # Check Service Security + Check Response Variable Type And Values ${resp} 200 ServiceSecurity + ${resource_url}= Check Location Header ${resp} ${LOCATION_SECURITY_RESOURCE_REGEX} + + ${api_invoker_policies_list}= Create List + + ${api_id}= Get From List ${api_ids} -1 + Log ${api_id} + ${resp}= Get Request Capif + ... /access-control-policy/v1/accessControlPolicyList/${api_id}?aef-id=${provider_info['aef_id']} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['aef_username']} + + Check Response Variable Type And Values ${resp} 200 AccessControlPolicyList + # Check returned values + Should Not Be Empty ${resp.json()['apiInvokerPolicies']} + + ${api_invoker_policies}= Set Variable ${resp.json()['apiInvokerPolicies']} + # Append To List ${api_invoker_policies_list} ${api_invoker_policies} + ${api_invoker_policies_list}= Set Variable ${api_invoker_policies} + + Log List ${api_invoker_policies_list} + + RETURN ${api_invoker_policies_list} + +Subscribe provider ${provider_info} to events ${events_list} with event filters ${event_filters} + ${resp}= + ... Subscribe ${provider_info['amf_id']} with ${provider_info['amf_username']} to ${events_list} with ${event_filters} + + Check Response Variable Type And Values ${resp} 201 EventSubscription + ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} + + RETURN ${subscription_id} + +Subscribe invoker ${invoker_info} to events ${events_list} with event filters ${event_filters} + ${resp}= + ... Subscribe ${invoker_info['api_invoker_id']} with ${invoker_info['management_cert']} to ${events_list} with ${event_filters} + + Check Response Variable Type And Values ${resp} 201 EventSubscription + ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} + + RETURN ${subscription_id} + +Subscribe invoker ${invoker_info} to events ${events_list} with event req ${event_req} + ${resp}= + ... Subscribe ${invoker_info['api_invoker_id']} with ${invoker_info['management_cert']} to ${events_list} with ${event_req} + + Check Response Variable Type And Values ${resp} 201 EventSubscription + ${subscriber_id} ${subscription_id}= Check Event Location Header ${resp} + + RETURN ${subscription_id} + +Subscribe ${subscriber_id} with ${username} to ${events_list} with ${event_req} + ${request_body}= Create Events Subscription + ... events=@{events_list} + ... notification_destination=${NOTIFICATION_DESTINATION_URL}/testing + ... supported_features=C + ... event_req=${event_req} + ${resp}= Post Request Capif + ... /capif-events/v1/${subscriber_id}/subscriptions + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${username} + + RETURN ${resp} + +Send Log Message to CAPIF + [Arguments] ${api_id} ${service_name} ${invoker_info} ${provider_info} @{results} + ${api_ids}= Create List ${api_id} + ${api_names}= Create List ${service_name} + ${request_body}= Create Log Entry + ... ${provider_info['aef_id']} + ... ${invoker_info['api_invoker_id']} + ... ${api_ids} + ... ${api_names} + ... results=@{results} + ${resp}= Post Request Capif + ... /api-invocation-logs/v1/${provider_info['aef_id']}/logs + ... json=${request_body} + ... server=${CAPIF_HTTPS_URL} + ... verify=ca.crt + ... username=${provider_info['amf_username']} + + Check Response Variable Type And Values ${resp} 201 InvocationLog + ${resource_url}= Check Location Header ${resp} ${LOCATION_LOGGING_RESOURCE_REGEX} + + RETURN ${request_body} + +Check not valid ${resp} with event filter ${attribute_snake_case} for event ${event} + # Check Results + ${invalid_param}= Create Dictionary + ... param=eventFilter + ... reason=The eventFilter {'${attribute_snake_case}'} for event ${event} are not applicable. + ${invalid_param_list}= Create List ${invalid_param} + Check Response Variable Type And Values + ... ${resp} + ... 400 + ... ProblemDetails + ... title=Bad Request + ... status=400 + ... detail=Bad Param + ... cause=Invalid eventFilter for event ${event} + ... invalidParams=${invalid_param_list} diff --git a/tests/libraries/api_events/bodyRequests.py b/tests/libraries/api_events/bodyRequests.py index 20d82a40a551f51a6ae0d8b1a29bac1d88676897..4e853a624f0d1b719adb03b88aa16d5617e2d1d9 100644 --- a/tests/libraries/api_events/bodyRequests.py +++ b/tests/libraries/api_events/bodyRequests.py @@ -18,18 +18,42 @@ def create_events_subscription(events=["SERVICE_API_AVAILABLE", "API_INVOKER_ONB def create_capif_event_filter(aefIds=None, apiIds=None, apiInvokerIds=None): - if aefIds == None and apiIds == None and apiInvokerIds: - raise ("Error, no data present to create event filter") + # if aefIds == None and apiIds == None and apiInvokerIds: + # raise ("Error, no data present to create event filter") capif_event_filter = dict() - if aefIds != None: - capif_event_filter['aefIds'] = aefIds - if apiIds != None: - capif_event_filter['apiIds'] = apiIds - if apiInvokerIds != None: - capif_event_filter['apiInvokerIds'] = apiInvokerIds + if aefIds is not None: + if isinstance(aefIds, list): + capif_event_filter['aefIds'] = aefIds + else: + capif_event_filter['aefIds'] = [aefIds] + if apiIds is not None: + if isinstance(apiIds, list): + capif_event_filter['apiIds'] = apiIds + else: + capif_event_filter['apiIds'] = [apiIds] + if apiInvokerIds is not None: + if isinstance(apiInvokerIds, list): + capif_event_filter['apiInvokerIds'] = apiInvokerIds + else: + capif_event_filter['apiInvokerIds'] = [apiInvokerIds] return capif_event_filter +def create_event_req(imm_rep=None, notif_method=None, max_report_nbr=None, mon_dur=None, rep_period=None): + data = dict() + if imm_rep is not None: + data['immRep'] = imm_rep + if notif_method is not None: + data['notifMethod'] = notif_method + if max_report_nbr is not None: + data['maxReportNbr'] = max_report_nbr + if mon_dur is not None: + data['monDur'] = mon_dur + if rep_period is not None: + data['repPeriod'] = rep_period + return data + + def create_default_event_req(): return { "grpRepTime": 5, @@ -42,6 +66,7 @@ def create_default_event_req(): } + def create_websock_notif_config_default(): return { "requestWebsocketUri": True, diff --git a/tests/libraries/api_logging_service/bodyRequests.py b/tests/libraries/api_logging_service/bodyRequests.py index a4d2a18770dca3d2d43742010bf9d336aaf728d3..0de84c28bbeda3087d86826cd18cb9dc03c78085 100644 --- a/tests/libraries/api_logging_service/bodyRequests.py +++ b/tests/libraries/api_logging_service/bodyRequests.py @@ -3,7 +3,7 @@ def create_log_entry(aefId, apiInvokerId, apiId, apiName, results=['200','500'], "aefId": aefId, "apiInvokerId": apiInvokerId, "logs": [], - "supportedFeatures": "ffff" + "supportedFeatures": "0" } if len(results) > 0: count=0 @@ -52,7 +52,7 @@ def create_log_entry_bad_service(aefId, apiInvokerId, result='500'): "fwdInterface": "string" } ], - "supportedFeatures": "ffff" + "supportedFeatures": "0" } return data @@ -89,4 +89,4 @@ def create_log(apiId, apiName, result, api_version='v1'): ] } } - return log \ No newline at end of file + return log diff --git a/tests/libraries/api_publish_service/bodyRequests.py b/tests/libraries/api_publish_service/bodyRequests.py index f76fe9d219660c8ed697bf652dcc63a0c89b94dc..5f969a548f9fa8e5dd578933dc97f3e92610ae63 100644 --- a/tests/libraries/api_publish_service/bodyRequests.py +++ b/tests/libraries/api_publish_service/bodyRequests.py @@ -1,9 +1,12 @@ def create_service_api_description(api_name="service_1", aef_id="aef_id", - supported_features="0", + supported_features="000", vendor_specific_service_api_description=None, vendor_specific_aef_profile=None, - api_status=None): + api_status=None, + security_methods="default", + domain_name=None, + interface_descriptions=None): aef_ids = list() if isinstance(aef_id, list): aef_ids = aef_id @@ -12,7 +15,33 @@ def create_service_api_description(api_name="service_1", print("aef_id parameter is a string") aef_ids.append(aef_id) - profiles = create_aef_profiles(aef_ids) + security_methods_normalized = list() + if security_methods is not None: + if isinstance(security_methods, list): + print("security_methods parameter is a list") + if len(security_methods) > 0: + if isinstance(security_methods[0], list): + security_methods_normalized = security_methods + else: + security_methods_normalized.append(security_methods) + elif isinstance(security_methods, str): + print("security_methods parameter is a string") + if security_methods == "default": + for idx in range(len(aef_ids)): + security_methods_normalized.append(["OAUTH"]) + else: + security_methods_normalized.append([security_methods]) + else: + print(f"security_methods is {security_methods}") + print(f"security_methods_normalized: {security_methods_normalized}") + else: + print("security_methods parameter is None") + + profiles = create_aef_profiles( + aef_ids, + security_methods_normalized, + domain_name, + interface_descriptions) body = { "apiName": api_name, @@ -58,16 +87,46 @@ def create_service_api_description(api_name="service_1", return body -def create_aef_profiles(aef_ids): +def create_aef_profiles( + aef_ids, + security_methods, + domain_name=None, + interface_descriptions=None): profiles = list() index = 1 for aef_id in aef_ids: - profiles.append(create_aef_profile(aef_id, "resource_" + str(index))) + security_method = get_value(security_methods, index-1) + print(f"aef_id: {aef_id}, security_method: {security_method}") + profiles.append( + create_aef_profile( + aef_id, + "resource_" + str(index), + security_method, + domain_name, + interface_descriptions)) index = index+1 return profiles -def create_aef_profile(aef_id, resource_name): +def create_aef_profile(aef_id, + resource_name, + security_method=None, + domain_name=None, + interface_descriptions=None): + # "mandatory_attributes": { + # "aefId": "string", + # "versions": "Version" + # }, + # "optional_attributes": { + # "protocol": "Protocol", + # "dataFormat": "DataFormat", + # "securityMethods": "SecurityMethod", + # "grantTypes": "OAuthGrantType", + # "domainName": "string", + # "interfaceDescriptions": "InterfaceDescription", + # "aefLocation": "AefLocation", + # "serviceKpis": "ServiceKpis", + # "ueIpRange": "IpAddrRange" data = { "aefId": aef_id, "versions": [ @@ -90,15 +149,23 @@ def create_aef_profile(aef_id, resource_name): ], "protocol": "HTTP_1_1", "dataFormat": "JSON", - "securityMethods": ["PSK"], - "interfaceDescriptions": [ - { - "ipv4Addr": "string", - "port": 65535, - "securityMethods": ["PSK"] - } - ] } + + if domain_name is not None: + data['domainName'] = domain_name + elif interface_descriptions is not None: + data['interfaceDescriptions'] = interface_descriptions + elif domain_name is None and interface_descriptions is None: + data['interfaceDescriptions'] = [ + create_interface_description( + ipv4_addr="string", + port=65535, + security_methods=security_method + ) + ] + + if security_method is not None: + data['securityMethods'] = security_method return data @@ -109,7 +176,10 @@ def create_service_api_description_patch(aef_id=None, service_api_category=None, api_supp_feats=None, pub_api_path=None, - ccf_id=None): + ccf_id=None, + security_methods=None, + domain_name=None, + interface_descriptions=None): body = dict() # aef profiles @@ -122,10 +192,28 @@ def create_service_api_description_patch(aef_id=None, elif isinstance(aef_id, str): print("aef_id parameter is a string") aef_ids.append(aef_id) + + security_methods_normalized = list() + if security_methods is not None: + if isinstance(security_methods, list): + print("security_methods parameter is a list") + if len(security_methods) > 0: + if isinstance(security_methods[0], list): + security_methods_normalized = security_methods + else: + security_methods_normalized.append(security_methods) + elif isinstance(security_methods, str): + print("security_methods parameter is a string") + security_methods_normalized.append([security_methods]) + if aef_ids is not None: - profiles = create_aef_profiles(aef_ids) + profiles = create_aef_profiles( + aef_ids, + security_methods_normalized, + domain_name, + interface_descriptions) body['aefProfiles'] = profiles - + # description if description is not None: body['description'] = description @@ -163,3 +251,41 @@ def create_service_api_description_patch(aef_id=None, body['apiStatus']['aefIds'] = aef_ids_active return body + + +def get_value(lst, index): + return lst[index] if index < len(lst) else None + + +def create_interface_description(ipv4_addr=None, + ipv6_addr=None, + fqdn=None, + port=None, + api_prefix=None, + security_methods=None, + grant_types=None): + """ + Create an interface description with the given parameters. + """ + # Create the interface description dictionary + data = dict() + if ipv4_addr is not None: + data['ipv4Addr'] = ipv4_addr + elif ipv6_addr is not None: + data['ipv6Addr'] = ipv6_addr + elif fqdn is not None: + data['fqdn'] = fqdn + else: + raise ValueError( + "At least one of ipv4_addr, ipv6_addr, or fqdn must be provided.") + + if port is not None: + data['port'] = port + if api_prefix is not None: + data['apiPrefix'] = api_prefix + if security_methods is not None: + data['securityMethods'] = security_methods + if grant_types is not None: + data['grantTypes'] = grant_types + # Return the interface description + return data diff --git a/tests/libraries/common/types.json b/tests/libraries/common/types.json index 5d67162ccac720901bed11748ad558ff5a17f26f..076d833f8ff251c52575d926de53fa93dff0a98b 100644 --- a/tests/libraries/common/types.json +++ b/tests/libraries/common/types.json @@ -75,6 +75,7 @@ }, "optional_attributes": { "apiId": "string", + "apiStatus": "ApiStatus", "aefProfiles": "AefProfile", "description": "string", "supportedFeatures": "SupportedFeatures", @@ -83,7 +84,7 @@ "apiSuppFeats": "SupportedFeatures", "pubApiPath": "PublishedApiPath", "ccfId": "string", - "apiStatus": "ApiStatus" + "apiProvName": "string" }, "regex_attributes": { "^vendorSpecific-(.*)": "VendorSpecificObject" @@ -120,15 +121,45 @@ "protocol": "Protocol", "dataFormat": "DataFormat", "securityMethods": "SecurityMethod", + "grantTypes": "OAuthGrantType", "domainName": "string", "interfaceDescriptions": "InterfaceDescription", - "aefLocation": "AefLocation" + "aefLocation": "AefLocation", + "serviceKpis": "ServiceKpis", + "ueIpRange": "IpAddrRange" }, "regex_attributes": { "^vendorSpecific-(.*)": "VendorSpecificObject" }, "oneOf": ["interfaceDescriptions", "domainName"] }, + "ServiceKpis": { + "mandatory_attributes": {}, + "optional_attributes": { + "maxReqRate": "integer", + "maxRestime": "integer", + "availability": "integer", + "avalComp": "Flops", + "avalGraComp": "Flops", + "avalMem": "Memory", + "avalStor": "Memory", + "conBand": "integer" + } + }, + "Flops": { + "regex": "^[0-9]+(\\.[0-9]+)? (kFLOPS|MFLOPS|GFLOPS|TFLOPS|PFLOPS|EFLOPS|ZFLOPS)$" + }, + "Memory": { + "regex": "^[0-9]+(\\.[0-9]+)? (KB|MB|GB|TB|PB|EB|ZB|YB)$" + }, + "IpAddrRange": { + "mandatory_attributes": {}, + "optional_attributes": { + "ueIpv4AddrRanges": "Ipv4AddressRange", + "ueIpv6AddrRanges": "Ipv6AddressRange" + }, + "oneOf": ["ueIpv4AddrRanges", "ueIpv6AddrRanges"] + }, "Version": { "mandatory_attributes": { "apiVersion": "string" @@ -181,10 +212,13 @@ "optional_attributes": { "ipv4Addr": "string", "ipv6Addr": "string", + "fqdn": "Fqdn", "port": "integer", - "securityMethods": "SecurityMethod" + "apiPrefix": "string", + "securityMethods": "SecurityMethod", + "grantTypes": "OAuthGrantType" }, - "oneOf": ["ipv4Addr", "ipv6Addr"] + "oneOf": ["ipv4Addr", "ipv6Addr", "fqdn"] }, "AefLocation": { "mandatory_attributes": {}, @@ -336,7 +370,7 @@ "mandatory_attributes": {}, "optional_attributes": { "start": "Ipv4Addr", - "stop": "Ipv4Addr" + "end": "Ipv4Addr" } }, "Ipv4Addr": { @@ -375,7 +409,8 @@ "DiscoveredAPIs": { "mandatory_attributes": {}, "optional_attributes": { - "serviceAPIDescriptions": "ServiceAPIDescription" + "serviceAPIDescriptions": "ServiceAPIDescription", + "suppFeat": "SupportedFeatures" } }, "ServiceSecurity": { @@ -576,7 +611,10 @@ } }, "GrantType": { - "enum": ["client_credentials"] + "enum": ["client_credentials","authorization_code"] + }, + "OAuthGrantType": { + "enum": ["CLIENT_CREDENTIALS", "AUTHORIZATION_CODE", "AUTHORIZATION_CODE_WITH_PKCE"] }, "TokenType": { "enum": ["Bearer"] diff --git a/tests/libraries/helpers.py b/tests/libraries/helpers.py index ae6337342a455dbf5155e76bd446528a686fc796..eac2594aa73c8a44aa185ff4eaa6b37d656e835d 100644 --- a/tests/libraries/helpers.py +++ b/tests/libraries/helpers.py @@ -50,6 +50,12 @@ def store_in_file(file_path, data): f.write(bytes(data, 'utf-8')) f.close() +def read_file_utf8(file_path: str) -> str: + try: + with open(file_path, 'r', encoding='utf-8') as file: + return file.read() + except Exception as error: + raise Exception(f"Error al leer el archivo: {error}") def cert_tuple(cert_file, key_file): return (cert_file, key_file) @@ -134,6 +140,12 @@ def remove_key_from_object(input, key_to_remove): return input_copy +def add_key_to_object(input, key_to_add, value_to_add): + input_copy = copy.deepcopy(input) + input_copy[key_to_add] = value_to_add + return input_copy + + def create_scope(aef_id, api_name): data = "3gpp#" + aef_id + ":" + api_name diff --git a/tests/libraries/interrupt_listener.py b/tests/libraries/interrupt_listener.py index 0a86a58b25636c025f2ed77460bb8de87bf4706e..dd241a8a75e2c9423a18ca73bfee437ac285b980 100644 --- a/tests/libraries/interrupt_listener.py +++ b/tests/libraries/interrupt_listener.py @@ -24,4 +24,7 @@ class InterruptListener: print(f"Ending suite: {name}") -INTERRUPT_LISTENER=InterruptListener() \ No newline at end of file +INTERRUPT_LISTENER=InterruptListener() + +def hello_world(): + print("Hello, world!") \ No newline at end of file diff --git a/tests/libraries/security_api/bodyRequests.py b/tests/libraries/security_api/bodyRequests.py index dabee876cd9aaf379f3438080399bbe84d8b6d2e..bf9cda31fab68e73c8ef646a3197fa726fc68dea 100644 --- a/tests/libraries/security_api/bodyRequests.py +++ b/tests/libraries/security_api/bodyRequests.py @@ -1,38 +1,80 @@ -def create_service_security_body(notification_destination, aef_id=None, api_id=None): +def create_service_security_default_body( + notification_destination, + supported_features="0", + interface_details=None, + aef_id=None, + api_id=None, + authentication_info=None, + authorization_info=None, + grant_type=None, + pref_security_methods=["OAUTH", "PKI", "PSK"], + sel_security_method=None, + request_websocket_uri=None, + websocket_uri=None): data = { "notificationDestination": notification_destination, - "supportedFeatures": "fffffff", - "securityInfo": [{ - "authenticationInfo": "authenticationInfo", - "authorizationInfo": "authorizationInfo", - "interfaceDetails": { - "ipv4Addr": "127.0.0.1", - "securityMethods": ["PSK"], - "port": 5248 - }, - "prefSecurityMethods": ["PSK", "PKI", "OAUTH"], - } - ], - "websockNotifConfig": { - "requestWebsocketUri": True, - "websocketUri": "websocketUri" - }, - "requestTestNotification": True + "supportedFeatures": supported_features } + security_info = list() + security_info.append( + create_security_info(aef_id=aef_id, + interface_details=interface_details, + api_id=api_id, + authentication_info=authentication_info, + authorization_info=authorization_info, + grant_type=grant_type, + pref_security_methods=pref_security_methods, + sel_security_method=sel_security_method)) + data['securityInfo'] = security_info + if request_websocket_uri is not None or websocket_uri is not None: + data['websockNotifConfig'] = create_web_sock_notif_config( + request_websocket_uri, websocket_uri) + return data + - if aef_id != None and api_id != None: - data['securityInfo'].append({ - "authenticationInfo": "authenticationInfo", - "authorizationInfo": "authorizationInfo", - "prefSecurityMethods": ["PSK", "PKI", "OAUTH"], - "aefId": aef_id, - "apiId": api_id - }) +def create_security_info( + aef_id=None, + interface_details=None, + api_id=None, + authentication_info=None, + authorization_info=None, + grant_type=None, + pref_security_methods=None, + sel_security_method=None): + # aef_id or interface_details must be set. + # authentication_info, authorization_info, grant_type, sel_security_method + # only should be present in repsonse from CCF + data = dict() + if aef_id is not None: + data["aefId"] = aef_id + if interface_details is not None: + data['interfaceDetails'] = interface_details + if api_id is not None: + data['apiId'] = api_id + if authentication_info is not None: + data['authenticationInfo'] = authentication_info + if authorization_info is not None: + data['authorizationInfo'] = authorization_info + if grant_type is not None: + data['grantType'] = grant_type + if pref_security_methods is not None: + data['prefSecurityMethods'] = pref_security_methods + if sel_security_method is not None: + data['selSecurityMethod'] = sel_security_method return data -def create_service_security_from_discover_response(notification_destination, discover_response): +def create_web_sock_notif_config(request_websocket_uri=None, websocket_uri=None): + data = dict() + if request_websocket_uri is not None: + data['requestWebsocketUri'] = request_websocket_uri + if websocket_uri is not None: + data['websocketUri'] = websocket_uri + return data + + +def create_service_security_from_discover_response(notification_destination, discover_response, legacy=True): data = { "notificationDestination": notification_destination, "supportedFeatures": "fffffff", @@ -43,6 +85,7 @@ def create_service_security_from_discover_response(notification_destination, dis }, "requestTestNotification": True } + api_ids=list() service_api_descriptions = discover_response.json()['serviceAPIDescriptions'] for service_api_description in service_api_descriptions: for aef_profile in service_api_description['aefProfiles']: @@ -53,7 +96,33 @@ def create_service_security_from_discover_response(notification_destination, dis "aefId": aef_profile['aefId'], "apiId": service_api_description['apiId'] }) - return data + api_ids.append(service_api_description['apiId']) + if legacy: + return data + else: + return data, api_ids + + +def update_service_security_with_discover_response(security_body, discover_response, legacy=True): + api_ids = list() + service_api_descriptions = discover_response.json()['serviceAPIDescriptions'] + for service_api_description in service_api_descriptions: + for aef_profile in service_api_description['aefProfiles']: + security_body['securityInfo'].append({ + "authenticationInfo": "authenticationInfo", + "authorizationInfo": "authorizationInfo", + "prefSecurityMethods": ["PSK", "PKI", "OAUTH"], + "aefId": aef_profile['aefId'], + "apiId": service_api_description['apiId'] + }) + + for security_info in security_body['securityInfo']: + api_ids.append(security_info['apiId']) + + if legacy: + return security_body + else: + return security_body, api_ids def create_security_notification_body(api_invoker_id, api_ids, cause="OVERLIMIT_USAGE", aef_id=None): @@ -64,14 +133,13 @@ def create_security_notification_body(api_invoker_id, api_ids, cause="OVERLIMIT_ "cause": cause } - if isinstance(api_ids,list): + if isinstance(api_ids, list): data['apiIds'] = api_ids else: - data['apiIds'] = [ api_ids ] + data['apiIds'] = [api_ids] if aef_id != None: data['aefId'] = aef_id - return data @@ -88,9 +156,11 @@ def create_access_token_req_body(client_id, scope, client_secret=None, grant_typ return data + def get_api_ids_from_discover_response(discover_response): - api_ids=[] - service_api_descriptions = discover_response.json()['serviceAPIDescriptions'] + api_ids = [] + service_api_descriptions = discover_response.json()[ + 'serviceAPIDescriptions'] for service_api_description in service_api_descriptions: api_ids.append(service_api_description['apiId']) return api_ids diff --git a/tests/resources/common.resource b/tests/resources/common.resource index bf596b33c0f5f3747e160ccdcee9a77ef751f09a..96b09429702ec75e38ad3f122823f10213012055 100644 --- a/tests/resources/common.resource +++ b/tests/resources/common.resource @@ -84,7 +84,11 @@ Check Response Variable Type And Values Check Variable ${resp.json()} ${variable_type} FOR ${input} IN @{input_parameters} Log ${input}=${input_parameters['${input}']} - Should Match Regexp "${resp.json()['${input}']}" "${input_parameters['${input}']}" + IF "${input}"=="invalidParams" + Should Be Equal ${resp.json()['${input}']} ${input_parameters['${input}']} + ELSE + Should Match Regexp "${resp.json()['${input}']}" "${input_parameters['${input}']}" + END END Remove Keys From Object diff --git a/tests/resources/common/basicRequests.robot b/tests/resources/common/basicRequests.robot index 149535597324c9ac22ae16c4d56877cdafcad0e8..2fcd189414190fd1af2e8d42cccfd01720c0484b 100644 --- a/tests/resources/common/basicRequests.robot +++ b/tests/resources/common/basicRequests.robot @@ -796,6 +796,9 @@ Publish Service Api Request ... ${vendor_specific_aef_profile}=${None} ... ${aef_id}=${NONE} ... ${api_status}=${NONE} + ... ${security_methods}=default + ... ${domain_name}=${NONE} + ... ${interface_descriptions}=${NONE} ${aef_ids}= Create List IF "${aef_id}" == "${NONE}" @@ -826,6 +829,10 @@ Publish Service Api Request ... ${vendor_specific_service_api_description} ... ${vendor_specific_aef_profile} ... ${api_status} + ... ${security_methods} + ... ${domain_name} + ... ${interface_descriptions} + ${resp}= Post Request Capif ... /published-apis/v1/${apf_id_to_use}/service-apis ... json=${request_body} @@ -846,6 +853,9 @@ Publish Service Api ... ${vendor_specific_aef_profile}=${None} ... ${aef_id}=${NONE} ... ${api_status}=${NONE} + ... ${security_methods}=default + ... ${domain_name}=${NONE} + ... ${interface_descriptions}=${NONE} ${resp} ${request_body}= Publish Service Api Request ... ${register_user_info_provider} @@ -857,6 +867,9 @@ Publish Service Api ... ${vendor_specific_aef_profile} ... ${aef_id} ... ${api_status} + ... ${security_methods} + ... ${domain_name} + ... ${interface_descriptions} Check Response Variable Type And Values ${resp} 201 ServiceAPIDescription Dictionary Should Contain Key ${resp.json()} apiId diff --git a/tests/resources/common/expectedMessages.robot b/tests/resources/common/expectedMessages.robot index 128f9831e4dbc5f403a6e818e8b2c363c422c982..346dfd76c94d88d4e90fdfabcf5571ef5bbffaed 100644 --- a/tests/resources/common/expectedMessages.robot +++ b/tests/resources/common/expectedMessages.robot @@ -12,6 +12,7 @@ Create Events From InvocationLogs ... ${invocation_log} ... ${events_expected}=${NONE} ... ${event_detail_expected}=${TRUE} + IF ${events_expected} == ${NONE} ${events_expected}= Create List END @@ -113,7 +114,9 @@ Create Expected Events For Service API Notifications Create Expected Api Invoker Events [Arguments] ... ${subscription_id} - ... ${api_invoker_id} + ... ${api_invoker_onboarded_resources}=${NONE} + ... ${api_invoker_updated_resources}=${NONE} + ... ${api_invoker_offboarded_resources}=${NONE} ... ${events_expected}=${NONE} ... ${event_detail_expected}=${TRUE} @@ -121,31 +124,59 @@ Create Expected Api Invoker Events ${events_expected}= Create List END - ${api_invoker_id_used}= Set Variable ${api_invoker_id} - IF "${event_detail_expected}" != "${TRUE}" - ${api_invoker_id_used}= Set Variable ${NONE} + # Create Notification Events expected to be received for Onboarded event + IF "${api_invoker_onboarded_resources}" != "${NONE}" + FOR ${api_invoker_onboarded_resource} IN @{api_invoker_onboarded_resources} + Log ${api_invoker_onboarded_resource} + ${api_invoker_id}= Fetch From Right ${api_invoker_onboarded_resource.path} / + + IF "${event_detail_expected}" != "${TRUE}" + ${api_invoker_id}= Set Variable ${NONE} + END + + ${event_expected}= Create Notification Event + ... ${subscription_id} + ... API_INVOKER_ONBOARDED + ... apiInvokerIds=${api_invoker_id} + Append To List ${events_expected} ${event_expected} + END END - ## Create events expected - # Create Notification Events expected to be received for Onboard event - ${event_expected}= Create Notification Event - ... ${subscription_id} - ... API_INVOKER_ONBOARDED - ... apiInvokerIds=${api_invoker_id_used} - Append To List ${events_expected} ${event_expected} # Create Notification Events expected to be received for Updated event - ${event_expected}= Create Notification Event - ... ${subscription_id} - ... API_INVOKER_UPDATED - ... apiInvokerIds=${api_invoker_id_used} - Append To List ${events_expected} ${event_expected} + IF "${api_invoker_updated_resources}" != "${NONE}" + FOR ${api_invoker_updated_resource} IN @{api_invoker_updated_resources} + Log ${api_invoker_updated_resource} + ${api_invoker_id}= Fetch From Right ${api_invoker_updated_resource.path} / - # Create Notification Events expected to be received for Offboard event - ${event_expected}= Create Notification Event - ... ${subscription_id} - ... API_INVOKER_OFFBOARDED - ... apiInvokerIds=${api_invoker_id_used} - Append To List ${events_expected} ${event_expected} + IF "${event_detail_expected}" != "${TRUE}" + ${api_invoker_id}= Set Variable ${NONE} + END + + ${event_expected}= Create Notification Event + ... ${subscription_id} + ... API_INVOKER_UPDATED + ... apiInvokerIds=${api_invoker_id} + Append To List ${events_expected} ${event_expected} + END + END + + # Create Notification Events expected to be received for Offboarded event + IF "${api_invoker_offboarded_resources}" != "${NONE}" + FOR ${api_invoker_offboarded_resource} IN @{api_invoker_offboarded_resources} + Log ${api_invoker_offboarded_resource} + ${api_invoker_id}= Fetch From Right ${api_invoker_offboarded_resource.path} / + + IF "${event_detail_expected}" != "${TRUE}" + ${api_invoker_id}= Set Variable ${NONE} + END + + ${event_expected}= Create Notification Event + ... ${subscription_id} + ... API_INVOKER_OFFBOARDED + ... apiInvokerIds=${api_invoker_id} + Append To List ${events_expected} ${event_expected} + END + END RETURN ${events_expected} diff --git a/tools/base_images_scripts/create_nginx_patched_images.sh b/tools/base_images_scripts/create_nginx_patched_images.sh new file mode 100755 index 0000000000000000000000000000000000000000..07dd769d81f6bcbf37a1db38b2425d4f2692e551 --- /dev/null +++ b/tools/base_images_scripts/create_nginx_patched_images.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +set -euo pipefail + +NGINX_VERSION=1.27.1 +PLATFORMS=("linux/arm64" +"linux/amd64") +PATCH_REPO="https://labs.etsi.org/rep/ocf/tools/nginx-sslkeylog.git" +REGISTRY="labs.etsi.org:5050/ocf/capif" + +MANIFEST_AMEND="" +for platform in "${PLATFORMS[@]}";do + image_name="nginx-ocf-patched:$NGINX_VERSION" + echo "$image_name pulled for platform $platform" + + container_id=$(docker run -d --platform=$platform --name build-nginx debian:bullseye sleep infinity) + + docker exec $container_id bash -c " + set -e + + echo 'Installing build dependencies...' + apt-get update && apt-get install -y \ + build-essential \ + libpcre3-dev \ + libssl-dev \ + zlib1g-dev \ + curl \ + patch \ + ca-certificates \ + openssl \ + git \ + jq \ + gettext + + echo 'Creating nginx user...' + useradd -r -d /etc/nginx -s /sbin/nologin nginx + + echo 'Downloading NGINX $NGINX_VERSION...' + curl -LO https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz + tar -xzf nginx-${NGINX_VERSION}.tar.gz + cd nginx-${NGINX_VERSION} + + echo 'Cloning and applying patch...' + git clone ${PATCH_REPO} ../nginx-sslkeylog + patch -p1 < ../nginx-sslkeylog/nginx-patches/${NGINX_VERSION}.patch + + echo 'Configuring NGINX...' + ./configure \ + --prefix=/etc/nginx \ + --sbin-path=/usr/sbin/nginx \ + --modules-path=/usr/lib/nginx/modules \ + --conf-path=/etc/nginx/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --pid-path=/var/run/nginx.pid \ + --lock-path=/var/run/nginx.lock \ + --http-client-body-temp-path=/var/cache/nginx/client_temp \ + --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ + --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ + --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ + --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ + --user=nginx \ + --group=nginx \ + --with-compat \ + --with-file-aio \ + --with-threads \ + --with-http_addition_module \ + --with-http_auth_request_module \ + --with-http_dav_module \ + --with-http_flv_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_mp4_module \ + --with-http_random_index_module \ + --with-http_realip_module \ + --with-http_secure_link_module \ + --with-http_slice_module \ + --with-http_ssl_module \ + --with-http_stub_status_module \ + --with-http_sub_module \ + --with-http_v2_module \ + --with-http_v3_module \ + --with-mail \ + --with-mail_ssl_module \ + --with-stream \ + --with-stream_realip_module \ + --with-stream_ssl_module \ + --with-stream_ssl_preread_module \ + --with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-${NGINX_VERSION}/debian/debuild-base/nginx-${NGINX_VERSION}=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ + --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \ + --add-module=../nginx-sslkeylog + + echo 'Building NGINX...' + make -j\$(nproc) && make install + + echo 'Creating required temporary directories...' + mkdir -p /var/cache/nginx/{client_temp,proxy_temp,fastcgi_temp,uwsgi_temp,scgi_temp} + + echo '✅ NGINX build completed.' + " + + tag=$(echo $platform | awk -F'/' '{print $NF}') + + docker commit $container_id $image_name + docker tag $image_name $REGISTRY/$image_name-$tag + echo "$REGISTRY/$image_name-$tag tagged" + docker push $REGISTRY/$image_name-$tag + echo "$REGISTRY/$image_name-$tag pushed" + MANIFEST_AMEND="$MANIFEST_AMEND --amend $REGISTRY/$image_name-$tag" + docker stop $container_id + docker rm $container_id + +done + +docker manifest create $REGISTRY/$image_name $MANIFEST_AMEND +echo "$REGISTRY/$image_name Manifest created with amend $MANIFEST_AMEND" +docker manifest push $REGISTRY/$image_name +echo "$REGISTRY/$image_name Manifest pushed" + +echo "🎉 All builds completed successfully." diff --git a/tools/base_images_scripts/push_base_images_ocf.sh b/tools/base_images_scripts/push_base_images_ocf.sh index 0407dae67c19f89983742ec5b14781cd4af9aa84..2a9d472e49fa4006646d05e10bd4c3caacf7b596 100755 --- a/tools/base_images_scripts/push_base_images_ocf.sh +++ b/tools/base_images_scripts/push_base_images_ocf.sh @@ -7,8 +7,10 @@ PLATFORMS=("linux/arm64" BASIC_IMAGES=("python:3-slim-bullseye" "nginx:1.27.1" "vault:1.13.2" -"ubuntu:20.04") - +"ubuntu:20.04" +"redis:7.4.2-alpine" +"mongo-express:1.0.0-alpha.4" +"mongo:6.0.2") docker login labs.etsi.org:5050 for basic_image in "${BASIC_IMAGES[@]}"; do