diff options
author | Mike Lewis <mlewis@gitlab.com> | 2019-06-07 20:13:17 +0000 |
---|---|---|
committer | Mike Lewis <mlewis@gitlab.com> | 2019-06-07 20:13:17 +0000 |
commit | 99df0218f82b851b017bd0eea1b8351dc89df6ed (patch) | |
tree | b01f884fbd1418dd5465fc1741f1620061ae8c5c /app/services/prometheus/proxy_service.rb | |
parent | 3eea6906747d10bea501426febaf15d2c209e06a (diff) | |
parent | e07b2b277f79bc25cdce22ca2defba1ba80791aa (diff) | |
download | gitlab-ce-99df0218f82b851b017bd0eea1b8351dc89df6ed.tar.gz |
Merge branch 'master' into 'docs/fix-example-dot-net'
# Conflicts:
# doc/user/project/clusters/serverless/index.md
Diffstat (limited to 'app/services/prometheus/proxy_service.rb')
-rw-r--r-- | app/services/prometheus/proxy_service.rb | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/app/services/prometheus/proxy_service.rb b/app/services/prometheus/proxy_service.rb new file mode 100644 index 00000000000..c5d2b84878b --- /dev/null +++ b/app/services/prometheus/proxy_service.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +module Prometheus + class ProxyService < BaseService + include ReactiveCaching + include Gitlab::Utils::StrongMemoize + + self.reactive_cache_key = ->(service) { service.cache_key } + self.reactive_cache_lease_timeout = 30.seconds + self.reactive_cache_refresh_interval = 30.seconds + self.reactive_cache_lifetime = 1.minute + self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) } + + attr_accessor :proxyable, :method, :path, :params + + PROXY_SUPPORT = { + 'query' => { + method: ['GET'], + params: %w(query time timeout) + }, + 'query_range' => { + method: ['GET'], + params: %w(query start end step timeout) + } + }.freeze + + def self.from_cache(proxyable_class_name, proxyable_id, method, path, params) + proxyable_class = begin + proxyable_class_name.constantize + rescue NameError + nil + end + return unless proxyable_class + + proxyable = proxyable_class.find(proxyable_id) + + new(proxyable, method, path, params) + end + + # proxyable can be any model which responds to .prometheus_adapter + # like Environment. + def initialize(proxyable, method, path, params) + @proxyable = proxyable + @path = path + + # Convert ActionController::Parameters to hash because reactive_cache_worker + # does not play nice with ActionController::Parameters. + @params = filter_params(params, path).to_hash + + @method = method + end + + def id + nil + end + + def execute + return cannot_proxy_response unless can_proxy? + return no_prometheus_response unless can_query? + + with_reactive_cache(*cache_key) do |result| + result + end + end + + def calculate_reactive_cache(proxyable_class_name, proxyable_id, method, path, params) + return no_prometheus_response unless can_query? + + response = prometheus_client_wrapper.proxy(path, params) + + success(http_status: response.code, body: response.body) + rescue Gitlab::PrometheusClient::Error => err + service_unavailable_response(err) + end + + def cache_key + [@proxyable.class.name, @proxyable.id, @method, @path, @params] + end + + private + + def service_unavailable_response(exception) + error(exception.message, :service_unavailable) + end + + def no_prometheus_response + error('No prometheus server found', :service_unavailable) + end + + def cannot_proxy_response + error('Proxy support for this API is not available currently') + end + + def prometheus_adapter + strong_memoize(:prometheus_adapter) do + @proxyable.prometheus_adapter + end + end + + def prometheus_client_wrapper + prometheus_adapter&.prometheus_client_wrapper + end + + def can_query? + prometheus_adapter&.can_query? + end + + def filter_params(params, path) + params.slice(*PROXY_SUPPORT.dig(path, :params)) + end + + def can_proxy? + PROXY_SUPPORT.dig(@path, :method)&.include?(@method) + end + end +end |