diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0da5a74316fb348af940eeb142f085f35d53677d..37d5fa2b54e2bd779a5ef64ebdd03cf763635a69 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,7 @@ include: - local: '/src/vnt_manager/.gitlab-ci.yml' - local: '/src/e2e_orchestrator/.gitlab-ci.yml' - local: '/src/ztp_server/.gitlab-ci.yml' + - local: '/src/osm_client/.gitlab-ci.yml' # This should be last one: end-to-end integration tests - local: '/src/tests/.gitlab-ci.yml' diff --git a/src/osm_client/.gitlab-ci.yml b/src/osm_client/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..0ebb12f5261e10e8fd62f410195163aa0d7c74db --- /dev/null +++ b/src/osm_client/.gitlab-ci.yml @@ -0,0 +1,116 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build, tag, and push the Docker image to the GitLab Docker registry +build osm_client: + variables: + IMAGE_NAME: 'osm_client' # name of the microservice + MOCK_IMAGE_NAME: 'mock_osm_nbi' # name of the mock + IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) + stage: build + before_script: + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + script: + - docker buildx build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile . + - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + # Build mock images + - docker buildx build -t "$MOCK_IMAGE_NAME:$IMAGE_TAG" -f ./src/tests/tools/$MOCK_IMAGE_NAME/Dockerfile . + - docker tag "$MOCK_IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$MOCK_IMAGE_NAME:$IMAGE_TAG" + - docker push "$CI_REGISTRY_IMAGE/$MOCK_IMAGE_NAME:$IMAGE_TAG" + after_script: + - docker images --filter="dangling=true" --quiet | xargs -r docker rmi + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' + - changes: + - src/common/**/*.py + - proto/*.proto + - src/$IMAGE_NAME/**/*.{py,in,yml} + - src/$IMAGE_NAME/Dockerfile + - src/$IMAGE_NAME/tests/*.py + - manifests/${IMAGE_NAME}service.yaml + - src/tests/tools/$MOCK_IMAGE_NAME/**/*.{py,in,yml} + - src/tests/tools/$MOCK_IMAGE_NAME/Dockerfile + - .gitlab-ci.yml + +# Apply unit test to the component +unit_test osm_client: + variables: + IMAGE_NAME: 'osm_client' # name of the microservice + MOCK_IMAGE_NAME: 'mock_osm_nbi' + IMAGE_TAG: 'latest' # tag of the container image (production, development, etc) + stage: unit_test + needs: + - build osm_client + before_script: + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + - docker ps -aq | xargs -r docker rm -f + - > + if docker network list | grep teraflowbridge; then + echo "teraflowbridge is already created"; + else + docker network create -d bridge teraflowbridge; + fi + - > + if docker container ls | grep $IMAGE_NAME; then + docker rm -f $IMAGE_NAME; + else + echo "$IMAGE_NAME image is not in the system"; + fi + - docker container prune -f + script: + - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" + - docker images --filter="dangling=true" --quiet | xargs -r docker rmi + - > + docker run --name $IMAGE_NAME -d -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" + --network=teraflowbridge + --env LOG_LEVEL=DEBUG + --env FLASK_ENV=development + --env OSM_ADDRESS=mock_osm_nbi + $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG + - > + docker run --name $MOCK_IMAGE_NAME -d + --network=teraflowbridge + --env LOG_LEVEL=DEBUG + --env FLASK_ENV=development + $CI_REGISTRY_IMAGE/$MOCK_IMAGE_NAME:$IMAGE_TAG + - while ! docker logs $IMAGE_NAME 2>&1 | grep -q 'Configured Rules'; do sleep 1; done + - sleep 5 # Give extra time to container to get ready + - docker ps -a + - docker logs $IMAGE_NAME + - docker logs $MOCK_IMAGE_NAME + - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_unitary.py --junitxml=/opt/results/${IMAGE_NAME}_report_unitary.xml" + - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing" + coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' + after_script: + - docker logs $IMAGE_NAME + - docker rm -f $IMAGE_NAME + - docker rm -f $MOCK_IMAGE_NAME + - docker network rm teraflowbridge + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' + - changes: + - src/common/**/*.py + - proto/*.proto + - src/$IMAGE_NAME/**/*.{py,in,yml} + - src/$IMAGE_NAME/Dockerfile + - src/$IMAGE_NAME/tests/*.py + - manifests/${IMAGE_NAME}service.yaml + - .gitlab-ci.yml + artifacts: + when: always + reports: + junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report_*.xml diff --git a/src/osm_client/Dockerfile b/src/osm_client/Dockerfile index 3c885973cfe5d2a43fec0033979375c5141a7f83..579972127ac8a1cdacc163222a00a1b145cbab2b 100644 --- a/src/osm_client/Dockerfile +++ b/src/osm_client/Dockerfile @@ -18,7 +18,7 @@ FROM python:3.10.16-slim # Install dependencies RUN apt-get --yes --quiet --quiet update RUN apt-get --yes --quiet --quiet install wget g++ git build-essential cmake make git \ - libpcre2-dev python3-dev python3-pip python3-cffi curl software-properties-common && \ + libpcre2-dev python3-dev python3-pip python3-cffi curl software-properties-common libmagic1 libmagic-dev && \ rm -rf /var/lib/apt/lists/* # Set Python to show logs as they occur diff --git a/src/osm_client/tests/PrepareTestScenario.py b/src/osm_client/tests/PrepareTestScenario.py new file mode 100644 index 0000000000000000000000000000000000000000..16b17266e7193fdf26bbcb7019a562a1d74adf50 --- /dev/null +++ b/src/osm_client/tests/PrepareTestScenario.py @@ -0,0 +1,43 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest, os + +from common.Settings import ( + ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, + ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name, get_service_port_grpc +) + +from common.Constants import ServiceNameEnum +from osm_client.client.OsmClient import OsmClient +from osm_client.service.OsmClientService import OsmClientService + +LOCAL_HOST = '127.0.0.1' +GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.OSMCLIENT)) + +os.environ[get_env_var_name(ServiceNameEnum.OSMCLIENT, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) +os.environ[get_env_var_name(ServiceNameEnum.OSMCLIENT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(GRPC_PORT) + +@pytest.fixture(scope='session') +def osm_client_service(): # pylint: disable=redefined-outer-name + _service = OsmClientService() + _service.start() + yield _service + _service.stop() + +@pytest.fixture(scope='session') +def osm_client(osm_client_service : OsmClientService): # pylint: disable=redefined-outer-name + _client = OsmClient() + yield _client + _client.close() diff --git a/src/osm_client/tests/__init__.py b/src/osm_client/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3ccc21c7db78aac26daa1f8c5ff8e1ffd3f35460 --- /dev/null +++ b/src/osm_client/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/osm_client/tests/test_unitary.py b/src/osm_client/tests/test_unitary.py new file mode 100644 index 0000000000000000000000000000000000000000..738b7eb06ab6ed5dbf07b6485fa9948119189f2d --- /dev/null +++ b/src/osm_client/tests/test_unitary.py @@ -0,0 +1,44 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import grpc, pytest +from osm_client.client.OsmClient import OsmClient +from common.proto.osm_client_pb2 import CreateRequest, CreateResponse, NsiListResponse +from common.proto.context_pb2 import Empty + + +from .PrepareTestScenario import ( # pylint: disable=unused-import + # be careful, order of symbols is important here! + osm_client_service, osm_client +) + +def test_OsmClient( + osm_client : OsmClient, +): # pylint: disable=redefined-outer-name + + nbi_list_request = Empty() + + osm_list_reply = osm_client.NsiList(nbi_list_request) + assert len(osm_list_reply.id) == 0 + + nbi_create_request = CreateRequest() + nbi_create_request.nst_name = "nst1" + nbi_create_request.nsi_name = "nsi1" + nbi_create_request.account = "account1" + + osm_create_reply = osm_client.NsiCreate(nbi_create_request) + assert osm_create_reply.succeded == True + + osm_list_reply2 = osm_client.NsiList(nbi_list_request) + assert len(osm_list_reply2.id) == 1 diff --git a/src/tests/tools/mock_osm_nbi/Dockerfile b/src/tests/tools/mock_osm_nbi/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..9efd362d4bf6991971955840e11314993cc47b99 --- /dev/null +++ b/src/tests/tools/mock_osm_nbi/Dockerfile @@ -0,0 +1,45 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.10.16-slim + +# Install dependencies +RUN apt-get --yes --quiet --quiet update && \ + apt-get --yes --quiet --quiet install wget g++ git build-essential cmake libpcre2-dev python3-dev python3-cffi && \ + rm -rf /var/lib/apt/lists/* + +# Set Python to show logs as they occur +ENV PYTHONUNBUFFERED=0 + +# Get generic Python packages +RUN python3 -m pip install --upgrade pip +RUN python3 -m pip install --upgrade setuptools wheel +RUN python3 -m pip install --upgrade pip-tools + +# Create component sub-folders, and copy content +RUN mkdir -p /var/teraflow/mock_osm_nbi +WORKDIR /var/teraflow/mock_osm_nbi +COPY src/tests/tools/mock_osm_nbi/requirements.in requirements.in + +# Get specific Python packages +RUN pip-compile --quiet --output-file=requirements.txt requirements.in +RUN python3 -m pip install -r requirements.txt + +RUN python3 -m pip list + +WORKDIR /var/teraflow +COPY src/tests/tools/mock_osm_nbi/. mock_osm_nbi/ + +# Start the service +ENTRYPOINT ["python", "-m", "mock_osm_nbi"] diff --git a/src/tests/tools/mock_osm_nbi/ResourceOsmClient.py b/src/tests/tools/mock_osm_nbi/ResourceOsmClient.py new file mode 100644 index 0000000000000000000000000000000000000000..51047c93bbd2b1a7f6cd7eb7baecfb9732fe5f43 --- /dev/null +++ b/src/tests/tools/mock_osm_nbi/ResourceOsmClient.py @@ -0,0 +1,175 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +from flask import abort, jsonify, make_response, request +from flask_restful import Resource +from uuid import uuid4 + +LOG_LEVEL = logging.DEBUG + +logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") +LOGGER = logging.getLogger(__name__) + +logging.getLogger('werkzeug').setLevel(logging.INFO) + +OSM_NSI = [] + +OSM_VIM_DB = [ + { + "_id": "account1", + "name": "account1", + "vim_type": "account1", + "tenant": "account1", + "vim_url": "http://account1.local" + } + ] + + +class OsmNST(Resource): + def get(self): + LOGGER.info("get NST request received") + mock_nsts = [ + { + "_id": "nst1", + "name": "nst1", + "description": "Nst_Mock", + "vendor": "ExampleVendor", + "version": "1.0" + }, + { + "_id": "nst2", + "name": "nst2", + "description": "Nst_Mock", + "vendor": "AnotherVendor", + "version": "2.1" + } + ] + return make_response(jsonify(mock_nsts), 200) + +class OsmNBI(Resource): + def get(self): + LOGGER.info("get NBI request received") + + LOGGER.info(str(OSM_NSI)) + + return [nsi["id"] for nsi in OSM_NSI] + + def post(self): + LOGGER.info("post request received") + + LOGGER.info(str(request)) + + payload = request.get_json(silent=True) or {} + qs = request.args + + nst_id = payload.get("nstId") or qs.get("nstId") + name = payload.get("nsiName") or qs.get("nsiName") + desc = payload.get("nsiDescription") or qs.get("nsiDescription", "") + + new_nsi = { + "id": str(uuid4()), + "name": name, + "nstId": nst_id, + "description": desc, + "operationalStatus": "CREATED" + } + + OSM_NSI.append(new_nsi) + + return make_response(jsonify(new_nsi), 201) + + +class VimAccounts(Resource): + """ + Mock -> /osm/admin/v1/vim_accounts + Support: + • GET → get all VIM Account + • POST → Create a VIM Account + """ + def get(self): + return jsonify(OSM_VIM_DB) + + def post(self): + payload = request.get_json(silent=True) or {} + name = payload.get("name") + vim_type = payload.get("vim_type") + + if not name or not vim_type: + return {"error": "name and vim_type are required"}, 400 + + new_vim = { + "_id": str(uuid4()), + "name": name, + "vim_type": vim_type, + "tenant": payload.get("tenant", "admin"), + "vim_url": payload.get("vim_url", "http://mock.local") + } + + # Store new_vim in local DDBB + OSM_VIM_DB.append(new_vim) + return jsonify(new_vim), 201 + + +class VimAccountItem(Resource): + """ + Mock -> /osm/admin/v1/vim_accounts/ + Support: + • GET → get VIM Account + • PUT → Upadate fields + • DELETE → Delete VIM Account + """ + + @staticmethod + def _find(account_id): + """Search VIM account""" + return next( + (acc for acc in OSM_VIM_DB if acc["_id"] == account_id), + None + ) + + # ------------------------ + # GET /vim_accounts/ + # ------------------------ + def get(self, account_id): + account = self._find(account_id) + if not account: + return {"error": "not found"}, 404 + return jsonify(account) + + # ------------------------ + # PUT /vim_accounts/ + # ------------------------ + def put(self, account_id): + account = self._find(account_id) + if not account: + return {"error": "not found"}, 404 + + payload = request.get_json(silent=True) or {} + for field in ("name", "vim_type", "tenant", "vim_url"): + if field in payload: + account[field] = payload[field] + + return jsonify(account) + + # ------------------------ + # DELETE /vim_accounts/ + # ------------------------ + def delete(self, account_id): + account = self._find(account_id) + if not account: + return {"error": "not found"}, 404 + + OSM_VIM_DB.remove(account) + return "", 204 diff --git a/src/tests/tools/mock_osm_nbi/__init__.py b/src/tests/tools/mock_osm_nbi/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3ccc21c7db78aac26daa1f8c5ff8e1ffd3f35460 --- /dev/null +++ b/src/tests/tools/mock_osm_nbi/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/tests/tools/mock_osm_nbi/__main__.py b/src/tests/tools/mock_osm_nbi/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..2d15c0c3d2a3bf01ee7edf00de1c9fa5a4f58c04 --- /dev/null +++ b/src/tests/tools/mock_osm_nbi/__main__.py @@ -0,0 +1,88 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools, logging, sys, time +from flask import Flask, jsonify, make_response, request +from flask_restful import Api, Resource +from uuid import uuid4 + +from .ResourceOsmClient import OsmNBI, OsmNST, VimAccounts, VimAccountItem + + +BIND_ADDRESS = '0.0.0.0' +BIND_PORT = 443 +BASE_URL = '/osm' +STR_ENDPOINT = 'https://{:s}:{:s}{:s}'.format(str(BIND_ADDRESS), str(BIND_PORT), str(BASE_URL)) +LOG_LEVEL = logging.DEBUG + +logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s") +LOGGER = logging.getLogger(__name__) + +logging.getLogger('werkzeug').setLevel(logging.WARNING) + +def log_request(logger : logging.Logger, response): + timestamp = time.strftime('[%Y-%b-%d %H:%M]') + logger.info('%s %s %s %s %s', timestamp, request.remote_addr, request.method, request.full_path, response.status) + return response + +class Health(Resource): + def get(self): + LOGGER.info('health request received') + return make_response(jsonify({"hola"}), 200) + +class OsmAdmin(Resource): + def post(self): + LOGGER.info('token request received') + data = request.get_json(silent=True) or {} + + token = str(uuid4()) + + return jsonify({"id": token}) + +def main(): + LOGGER.info('Starting...') + + app = Flask(__name__) + app.after_request(functools.partial(log_request, LOGGER)) + + api = Api(app, prefix=BASE_URL) + + api.add_resource( + Health, '/' + ) + api.add_resource( + OsmNBI, '/nsilcm/v1/netslice_instances_content' + ) + api.add_resource( + OsmAdmin, '/admin/v1/tokens' + ) + api.add_resource( + OsmNST, '/nst/v1/netslice_templates' + ) + api.add_resource( + VimAccounts, '/admin/v1/vim_accounts' + ) + + api.add_resource( + VimAccountItem, '/admin/v1/vim_accounts/' + ) + + LOGGER.info('Listening on {:s}...'.format(str(STR_ENDPOINT))) + app.run(debug=True, host=BIND_ADDRESS, port=BIND_PORT, ssl_context='adhoc') + + LOGGER.info('Bye') + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/tests/tools/mock_osm_nbi/requirements.in b/src/tests/tools/mock_osm_nbi/requirements.in new file mode 100644 index 0000000000000000000000000000000000000000..dbb8e95d65cfd0f1ee60d9bb4f840393ac893725 --- /dev/null +++ b/src/tests/tools/mock_osm_nbi/requirements.in @@ -0,0 +1,22 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cryptography==39.0.1 +pyopenssl==23.0.0 +Flask==2.1.3 +Flask-HTTPAuth==4.5.0 +Flask-RESTful==0.3.9 +jsonschema==4.4.0 +requests==2.27.1 +werkzeug==2.3.7