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:
Sean McGivern 2019-04-05 09:21:08 +00:00
commit 5b273d355f
7 changed files with 204 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
---
title: Add a Prometheus API per environment
merge_request: 26841
author:
type: added

View file

@ -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

View file

@ -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 ""

View file

@ -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

View file

@ -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