Fix schema for Task.runtime

Add infrastructure for API calls limits handling
This commit is contained in:
allegroai 2021-05-03 18:11:46 +03:00
parent add3f011a0
commit 27d086bca2
4 changed files with 52 additions and 28 deletions

View File

@ -617,6 +617,11 @@ _definitions {
"$ref": "#/definitions/configuration_item" "$ref": "#/definitions/configuration_item"
} }
} }
runtime {
description: "Task runtime mapping"
type: object
additionalProperties: true
}
} }
} }
task_urls { task_urls {
@ -1361,6 +1366,11 @@ edit {
type: object type: object
additionalProperties { type: string } additionalProperties { type: string }
} }
runtime {
description: "Task runtime mapping"
type: object
additionalProperties: true
}
} }
} }
} }

View File

@ -1,6 +1,9 @@
from functools import partial
from flask import request, Response, redirect from flask import request, Response, redirect
from werkzeug.exceptions import BadRequest from werkzeug.exceptions import BadRequest
from apiserver.apierrors import APIError
from apiserver.apierrors.base import BaseError from apiserver.apierrors.base import BaseError
from apiserver.config_repo import config from apiserver.config_repo import config
from apiserver.service_repo import ServiceRepo, APICall from apiserver.service_repo import ServiceRepo, APICall
@ -25,7 +28,10 @@ class RequestHandlers:
try: try:
call = self._create_api_call(request) call = self._create_api_call(request)
content, content_type = ServiceRepo.handle_call(call) load_data_callback = partial(self._load_call_data, req=request)
content, content_type = ServiceRepo.handle_call(
call, load_data_callback=load_data_callback
)
if call.result.redirect: if call.result.redirect:
response = redirect(call.result.redirect.url, call.result.redirect.code) response = redirect(call.result.redirect.url, call.result.redirect.code)
@ -137,9 +143,6 @@ class RequestHandlers:
auth_cookie=auth_cookie, auth_cookie=auth_cookie,
) )
# Update call data from request
self._update_call_data(call, req)
except PathParsingError as ex: except PathParsingError as ex:
call = self._call_or_empty_with_error(call, req, ex.args[0], 400) call = self._call_or_empty_with_error(call, req, ex.args[0], 400)
call.log_api = False call.log_api = False
@ -156,3 +159,18 @@ class RequestHandlers:
) )
return call return call
def _load_call_data(self, call: APICall, req):
"""Update call data from request"""
try:
self._update_call_data(call, req)
except BadRequest as ex:
call.set_error_result(msg=ex.description, code=400)
except BaseError as ex:
call.set_error_result(msg=ex.msg, code=ex.code, subcode=ex.subcode)
except APIError as ex:
call.set_error_result(
msg=ex.msg, code=ex.code, subcode=ex.subcode, error_data=ex.error_data
)
except Exception as ex:
call.set_error_result(msg=ex.args[0] if ex.args else type(ex).__name__)

View File

@ -13,7 +13,12 @@ from .apicall import APICall
from .endpoint import Endpoint from .endpoint import Endpoint
from .errors import MalformedPathError, InvalidVersionError, CallFailedError from .errors import MalformedPathError, InvalidVersionError, CallFailedError
from .util import parse_return_stack_on_code from .util import parse_return_stack_on_code
from .validators import validate_all from .validators import (
validate_data,
validate_auth,
validate_role,
validate_impersonation,
)
log = config.logger(__file__) log = config.logger(__file__)
@ -227,18 +232,6 @@ class ServiceRepo(object):
return True return True
return subcode in subcode_list return subcode in subcode_list
@classmethod
def _validate_call(cls, call: APICall) -> Optional[Endpoint]:
endpoint = cls._resolve_endpoint_from_call(call)
if call.failed:
return
validate_all(call, endpoint)
return endpoint
@classmethod
def validate_call(cls, call: APICall):
cls._validate_call(call)
@classmethod @classmethod
def _get_company( def _get_company(
cls, call: APICall, endpoint: Endpoint = None, ignore_error: bool = False cls, call: APICall, endpoint: Endpoint = None, ignore_error: bool = False
@ -252,7 +245,7 @@ class ServiceRepo(object):
return call.identity.company return call.identity.company
@classmethod @classmethod
def handle_call(cls, call: APICall): def handle_call(cls, call: APICall, load_data_callback: Callable = None):
try: try:
if call.failed: if call.failed:
raise CallFailedError() raise CallFailedError()
@ -262,7 +255,18 @@ class ServiceRepo(object):
if call.failed: if call.failed:
raise CallFailedError() raise CallFailedError()
validate_all(call, endpoint) validate_auth(endpoint, call)
validate_role(endpoint, call)
if validate_impersonation(endpoint, call):
# if impersonating, validate role again
validate_role(endpoint, call)
if load_data_callback:
load_data_callback(call)
if call.failed:
raise CallFailedError()
validate_data(call, endpoint)
if call.failed: if call.failed:
raise CallFailedError() raise CallFailedError()

View File

@ -14,17 +14,9 @@ from .errors import CallParsingError
log = config.logger(__file__) log = config.logger(__file__)
def validate_all(call: APICall, endpoint: Endpoint): def validate_data(call: APICall, endpoint: Endpoint):
""" Perform all required call/endpoint validation, update call result appropriately """ """ Perform all required call/endpoint validation, update call result appropriately """
try: try:
validate_auth(endpoint, call)
validate_role(endpoint, call)
if validate_impersonation(endpoint, call):
# if impersonating, validate role again
validate_role(endpoint, call)
# todo: remove vaildate_required_fields once all endpoints have json schema # todo: remove vaildate_required_fields once all endpoints have json schema
validate_required_fields(endpoint, call) validate_required_fields(endpoint, call)