X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/497ea8e6fd12ce91cad108af78df5e3802a79d69..7223231e30b3e0e0b488f8db6d7b1749117a05e9:/apps/workbench/app/models/arvados_api_client.rb diff --git a/apps/workbench/app/models/arvados_api_client.rb b/apps/workbench/app/models/arvados_api_client.rb index 25c54d1e9c..78d3beef3c 100644 --- a/apps/workbench/app/models/arvados_api_client.rb +++ b/apps/workbench/app/models/arvados_api_client.rb @@ -2,13 +2,61 @@ require 'httpclient' require 'thread' class ArvadosApiClient - class NotLoggedInException < StandardError + class ApiError < StandardError + attr_reader :api_response, :api_response_s, :api_status, :request_url + + def initialize(request_url, errmsg) + @request_url = request_url + @api_response ||= {} + errors = @api_response[:errors] + if not errors.is_a?(Array) + @api_response[:errors] = [errors || errmsg] + end + super(errmsg) + end end - class InvalidApiResponseException < StandardError + + class NoApiResponseException < ApiError + def initialize(request_url, exception) + @api_response_s = exception.to_s + super(request_url, + "#{exception.class.to_s} error connecting to API server") + end end - class AccessForbiddenException < StandardError + + class InvalidApiResponseException < ApiError + def initialize(request_url, api_response) + @api_status = api_response.status_code + @api_response_s = api_response.content + super(request_url, "Unparseable response from API server") + end + end + + class ApiErrorResponseException < ApiError + def initialize(request_url, api_response) + @api_status = api_response.status_code + @api_response_s = api_response.content + @api_response = Oj.load(@api_response_s, :symbol_keys => true) + errors = @api_response[:errors] + if errors.respond_to?(:join) + errors = errors.join("\n\n") + else + errors = errors.to_s + end + super(request_url, "#{errors} [API: #{@api_status}]") + end end + class AccessForbiddenException < ApiErrorResponseException; end + class NotFoundException < ApiErrorResponseException; end + class NotLoggedInException < ApiErrorResponseException; end + + ERROR_CODE_CLASSES = { + 401 => NotLoggedInException, + 403 => AccessForbiddenException, + 404 => NotFoundException, + } + @@profiling_enabled = Rails.configuration.profiling_enabled @@discovery = nil @@ -78,35 +126,27 @@ class ArvadosApiClient profile_checkpoint { "Prepare request #{url} #{query[:uuid]} #{query[:where]} #{query[:filters]}" } msg = @client_mtx.synchronize do - @api_client.post(url, - query, - header: header) + begin + @api_client.post(url, query, header: header) + rescue => exception + raise NoApiResponseException.new(url, exception) + end end profile_checkpoint 'API transaction' - if msg.status_code == 401 - raise NotLoggedInException.new - end - - json = msg.content - begin - resp = Oj.load(json, :symbol_keys => true) + resp = Oj.load(msg.content, :symbol_keys => true) rescue Oj::ParseError - raise InvalidApiResponseException.new json + resp = nil end if not resp.is_a? Hash - raise InvalidApiResponseException.new json - end - if msg.status_code != 200 - errors = resp[:errors] - errors = errors.join("\n\n") if errors.is_a? Array - if msg.status_code == 403 - raise AccessForbiddenException.new "#{errors} [API: #{msg.status_code}]" - else - raise "#{errors} [API: #{msg.status_code}]" - end + raise InvalidApiResponseException.new(url, msg) + elsif msg.status_code != 200 + error_class = ERROR_CODE_CLASSES.fetch(msg.status_code, + ApiErrorResponseException) + raise error_class.new(url, msg) end + if resp[:_profile] Rails.logger.info "API client: " \ "#{resp.delete(:_profile)[:request_time]} request_time"