Commit 5b273d35 authored by Sean McGivern's avatar Sean McGivern

Merge branch '58375-api-controller' into 'master'

Add a prometheus proxy API per environment

Closes #58375

See merge request gitlab-org/gitlab-ce!26841
parents eff97941 20594de8
# frozen_string_literal: true
class Projects::Environments::PrometheusApiController < Projects::ApplicationController
before_action :authorize_read_prometheus!
before_action :environment
def proxy
result = Prometheus::ProxyService.new(
environment,
request.method,
params[:proxy_path],
params.permit!
).execute
if result.nil?
return render status: :accepted, json: {
status: _('processing'),
message: _('Not ready yet. Try again later.')
}
end
if result[:status] == :success
render status: result[:http_status], json: result[:body]
else
render(
status: result[:http_status] || :bad_request,
json: { status: result[:status], message: result[:message] }
)
end
end
private
def environment
@environment ||= project.environments.find(params[:id])
end
end
...@@ -204,6 +204,7 @@ class ProjectPolicy < BasePolicy ...@@ -204,6 +204,7 @@ class ProjectPolicy < BasePolicy
enable :read_merge_request enable :read_merge_request
enable :read_sentry_issue enable :read_sentry_issue
enable :read_release enable :read_release
enable :read_prometheus
end end
# We define `:public_user_access` separately because there are cases in gitlab-ee # We define `:public_user_access` separately because there are cases in gitlab-ee
......
---
title: Add a Prometheus API per environment
merge_request: 26841
author:
type: added
...@@ -219,6 +219,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -219,6 +219,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :metrics get :metrics
get :additional_metrics get :additional_metrics
get '/terminal.ws/authorize', to: 'environments#terminal_websocket_authorize', constraints: { format: nil } get '/terminal.ws/authorize', to: 'environments#terminal_websocket_authorize', constraints: { format: nil }
get '/prometheus/api/v1/*proxy_path', to: 'environments/prometheus_api#proxy'
end end
collection do collection do
......
...@@ -5492,6 +5492,9 @@ msgstr "" ...@@ -5492,6 +5492,9 @@ msgstr ""
msgid "Not now" msgid "Not now"
msgstr "" msgstr ""
msgid "Not ready yet. Try again later."
msgstr ""
msgid "Not started" msgid "Not started"
msgstr "" msgstr ""
...@@ -10049,6 +10052,9 @@ msgstr "" ...@@ -10049,6 +10052,9 @@ msgstr ""
msgid "private" msgid "private"
msgstr "" msgstr ""
msgid "processing"
msgstr ""
msgid "project" msgid "project"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
describe Projects::Environments::PrometheusApiController do
set(:project) { create(:project) }
set(:environment) { create(:environment, project: project) }
set(:user) { create(:user) }
before do
project.add_reporter(user)
sign_in(user)
end
describe 'GET #proxy' do
let(:prometheus_proxy_service) { instance_double(Prometheus::ProxyService) }
let(:expected_params) do
ActionController::Parameters.new(
environment_params(
proxy_path: 'query',
controller: 'projects/environments/prometheus_api',
action: 'proxy'
)
).permit!
end
context 'with valid requests' do
before do
allow(Prometheus::ProxyService).to receive(:new)
.with(environment, 'GET', 'query', expected_params)
.and_return(prometheus_proxy_service)
allow(prometheus_proxy_service).to receive(:execute)
.and_return(service_result)
end
context 'with success result' do
let(:service_result) { { status: :success, body: prometheus_body } }
let(:prometheus_body) { '{"status":"success"}' }
let(:prometheus_json_body) { JSON.parse(prometheus_body) }
it 'returns prometheus response' do
get :proxy, params: environment_params
expect(Prometheus::ProxyService).to have_received(:new)
.with(environment, 'GET', 'query', expected_params)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq(prometheus_json_body)
end
end
context 'with nil result' do
let(:service_result) { nil }
it 'returns 202 accepted' do
get :proxy, params: environment_params
expect(json_response['status']).to eq('processing')
expect(json_response['message']).to eq('Not ready yet. Try again later.')
expect(response).to have_gitlab_http_status(:accepted)
end
end
context 'with 404 result' do
let(:service_result) { { http_status: 404, status: :success, body: '{"body": "value"}' } }
it 'returns body' do
get :proxy, params: environment_params
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['body']).to eq('value')
end
end
context 'with error result' do
context 'with http_status' do
let(:service_result) do
{ http_status: :service_unavailable, status: :error, message: 'error message' }
end
it 'sets the http response status code' do
get :proxy, params: environment_params
expect(response).to have_gitlab_http_status(:service_unavailable)
expect(json_response['status']).to eq('error')
expect(json_response['message']).to eq('error message')
end
end
context 'without http_status' do
let(:service_result) { { status: :error, message: 'error message' } }
it 'returns bad_request' do
get :proxy, params: environment_params
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['status']).to eq('error')
expect(json_response['message']).to eq('error message')
end
end
end
end
context 'with inappropriate requests' do
context 'with anonymous user' do
before do
sign_out(user)
end
it 'redirects to signin page' do
get :proxy, params: environment_params
expect(response).to redirect_to(new_user_session_path)
end
end
context 'without correct permissions' do
before do
project.team.truncate
end
it 'returns 404' do
get :proxy, params: environment_params
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'with invalid environment id' do
let(:other_environment) { create(:environment) }
it 'returns 404' do
get :proxy, params: environment_params(id: other_environment.id)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
private
def environment_params(params = {})
{
id: environment.id.to_s,
namespace_id: project.namespace.name,
project_id: project.name,
proxy_path: 'query',
query: '1'
}.merge(params)
end
end
...@@ -25,6 +25,7 @@ RSpec.shared_context 'ProjectPolicy context' do ...@@ -25,6 +25,7 @@ RSpec.shared_context 'ProjectPolicy context' do
admin_issue admin_label admin_list read_commit_status read_build admin_issue admin_label admin_list read_commit_status read_build
read_container_image read_pipeline read_environment read_deployment read_container_image read_pipeline read_environment read_deployment
read_merge_request download_wiki_code read_sentry_issue read_release read_merge_request download_wiki_code read_sentry_issue read_release
read_prometheus
] ]
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment