diff --git a/.gitignore b/.gitignore index 8e22339a..b5127de0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ /share/ /static/ /db.sqlite3 -/.env +/.*env* /keys /logs /profiles diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b4cedd..fe34e93d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- TDB +- Bumped nuclio version to 1.8.14 () ### Deprecated - TDB diff --git a/components/serverless/docker-compose.serverless.yml b/components/serverless/docker-compose.serverless.yml index 34414dfc..a46e87ff 100644 --- a/components/serverless/docker-compose.serverless.yml +++ b/components/serverless/docker-compose.serverless.yml @@ -2,7 +2,7 @@ version: '3.3' services: nuclio: container_name: nuclio - image: quay.io/nuclio/dashboard:1.5.16-amd64 + image: quay.io/nuclio/dashboard:1.8.14-amd64 restart: always networks: - cvat diff --git a/cvat/apps/lambda_manager/tests/test_lambda.py b/cvat/apps/lambda_manager/tests/test_lambda.py index 831ff682..4abfcf3b 100644 --- a/cvat/apps/lambda_manager/tests/test_lambda.py +++ b/cvat/apps/lambda_manager/tests/test_lambda.py @@ -75,66 +75,65 @@ class LambdaTestCase(APITestCase): def setUp(self): self.client = APIClient() - patcher = mock.patch('cvat.apps.lambda_manager.views.LambdaGateway._http', side_effect = self.__get_response_data_from_lambda_gateway_http) - self.addCleanup(patcher.stop) - patcher.start() + http_patcher = mock.patch('cvat.apps.lambda_manager.views.LambdaGateway._http', side_effect = self.__get_data_from_lambda_manager_http) + self.addCleanup(http_patcher.stop) + http_patcher.start() + + invoke_patcher = mock.patch('cvat.apps.lambda_manager.views.LambdaGateway.invoke', side_effect = self.__invoke_function) + self.addCleanup(invoke_patcher.stop) + invoke_patcher.start() images_main_task = self._generate_task_images(3) images_assigneed_to_user_task = self._generate_task_images(3) self.main_task = self._create_task(tasks["main"], images_main_task) self.assigneed_to_user_task = self._create_task(tasks["assigneed_to_user"], images_assigneed_to_user_task) - - def __get_response_data_from_lambda_gateway_http(self, *args, **kwargs): + def __get_data_from_lambda_manager_http(self, **kwargs): url = kwargs["url"] - # POST query for get annotations - if url == "/api/function_invocations": - data = [] - id_function = kwargs["headers"]["x-nuclio-function-name"] - type_function = functions["positive"][id_function]["metadata"]["annotations"]["type"] - if type_function == "reid": - if id_function == id_function_reid_response_data: - data = [0, 1] - else: - data = [] - elif type_function == "tracker": - data = { - "shape": [12.34, 34.0, 35.01, 41.99], - "state": {"key": "value"}, - } - elif type_function == "interactor": - data = [ - [8, 12], - [34, 56], - [77, 77], - ] - elif type_function == "detector": - data = [ - {'confidence': '0.9959098', 'label': 'car', 'points': [3, 3, 15, 15], 'type': 'rectangle'}, - {'confidence': '0.89535173', 'label': 'car', 'points': [20, 25, 30, 35], 'type': 'rectangle'}, - {'confidence': '0.59464583', 'label': 'car', 'points': [12.17, 45.0, 69.80, 18.99], 'type': 'polygon'}, - ] - return data - # GET query for get all functions - elif url == "/api/functions": + if url == "/api/functions": return functions["positive"] - # GET query for get function else: - id_function = url.split("/")[-1] - if id_function in functions["positive"]: - # raise 500 Internal_Server error - if id_function in [id_function_state_building, id_function_state_error]: + func_id = url.split("/")[-1] + if func_id in functions["positive"]: + if func_id in [id_function_state_building, id_function_state_error]: r = requests.RequestException() r.response = HttpResponseServerError() - raise r - # return values - return functions["positive"][id_function] - # raise 404 Not Found error + raise r # raise 500 Internal_Server error + + return functions["positive"][func_id] else: r = requests.HTTPError() r.response = HttpResponseNotFound() - raise r - + raise r # raise 404 Not Found error + + def __invoke_function(self, func, payload): + data = [] + func_id = func.id + type_function = functions["positive"][func_id]["metadata"]["annotations"]["type"] + if type_function == "reid": + if func_id == id_function_reid_response_data: + data = [0, 1] + else: + data = [] + elif type_function == "tracker": + data = { + "shape": [12.34, 34.0, 35.01, 41.99], + "state": {"key": "value"}, + } + elif type_function == "interactor": + data = [ + [8, 12], + [34, 56], + [77, 77], + ] + elif type_function == "detector": + data = [ + {'confidence': '0.9959098', 'label': 'car', 'points': [3, 3, 15, 15], 'type': 'rectangle'}, + {'confidence': '0.89535173', 'label': 'car', 'points': [20, 25, 30, 35], 'type': 'rectangle'}, + {'confidence': '0.59464583', 'label': 'car', 'points': [12.17, 45.0, 69.80, 18.99], 'type': 'polygon'}, + ] + + return data @classmethod def _create_db_users(cls): diff --git a/cvat/apps/lambda_manager/views.py b/cvat/apps/lambda_manager/views.py index 47b80e1f..6bdf5d14 100644 --- a/cvat/apps/lambda_manager/views.py +++ b/cvat/apps/lambda_manager/views.py @@ -11,6 +11,7 @@ from copy import deepcopy import django_rq import requests import rq +import os from django.conf import settings from django.core.exceptions import ObjectDoesNotExist, ValidationError from rest_framework import status, viewsets @@ -75,17 +76,18 @@ class LambdaGateway: return response def invoke(self, func, payload): - # NOTE: it is overhead to invoke a function using nuclio - # dashboard REST API. Better to call host.docker.internal: - # Look at https://github.com/docker/for-linux/issues/264. - # host.docker.internal isn't supported by docker on Linux. - # There are many workarounds but let's try to use the - # simple solution. - return self._http(method="post", url='/api/function_invocations', - data=payload, headers={ - 'x-nuclio-function-name': func.id, - 'x-nuclio-path': '/' - }) + # Note: call the function directly without the nuclio dashboard + # host.docker.internal for Linux will work only with Docker 20.10+ + NUCLIO_TIMEOUT = settings.NUCLIO['DEFAULT_TIMEOUT'] + if os.path.exists('/.dockerenv'): # inside a docker container + url = f'http://host.docker.internal:{func.port}' + else: + url = f'http://localhost:{func.port}' + reply = requests.post(url, timeout=NUCLIO_TIMEOUT, json=payload) + reply.raise_for_status() + response = reply.json() + + return response class LambdaFunction: def __init__(self, gateway, data): diff --git a/docker-compose.yml b/docker-compose.yml index dc09494f..f0a6cacf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,6 +52,8 @@ services: - cvat_logs:/home/django/logs networks: - cvat + extra_hosts: + - "host.docker.internal:host-gateway" cvat_ui: container_name: cvat_ui diff --git a/site/content/en/docs/administration/advanced/installation_automatic_annotation.md b/site/content/en/docs/administration/advanced/installation_automatic_annotation.md index 0457631a..bdc1c355 100644 --- a/site/content/en/docs/administration/advanced/installation_automatic_annotation.md +++ b/site/content/en/docs/administration/advanced/installation_automatic_annotation.md @@ -29,7 +29,7 @@ description: 'Information about the installation of components needed for semi-a ``` - You have to install `nuctl` command line tool to build and deploy serverless - functions. Download [version 1.5.16](https://github.com/nuclio/nuclio/releases/tag/1.5.16). + functions. Download [version 1.8.14](https://github.com/nuclio/nuclio/releases/tag/1.8.14). It is important that the version you download matches the version in [docker-compose.serverless.yml](https://github.com/openvinotoolkit/cvat/blob/develop/components/serverless/docker-compose.serverless.yml). For example, using wget.