Merge branch '58375-api-controller' into 'master'
Add a prometheus proxy API per environment Closes #58375 See merge request gitlab-org/gitlab-ce!26841
This commit is contained in:
commit
5b273d355f
7 changed files with 204 additions and 0 deletions
|
@ -0,0 +1,37 @@
|
||||||
|
# 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
|
||||||
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
|
||||||
|
|
5
changelogs/unreleased/58375-api-controller.yml
Normal file
5
changelogs/unreleased/58375-api-controller.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Add a Prometheus API per environment
|
||||||
|
merge_request: 26841
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -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 ""
|
||||||
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 ""
|
||||||
msgid "private"
|
msgid "private"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "processing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "project"
|
msgid "project"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
# 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
|
||||||
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue