Commit 52f0ec46 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '32351-create-controller' into 'master'

API to create self monitoring project and monitor status

See merge request gitlab-org/gitlab!21428
parents c1154a73 fcc87070
...@@ -6,10 +6,21 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -6,10 +6,21 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
before_action :set_application_setting before_action :set_application_setting
before_action :whitelist_query_limiting, only: [:usage_data] before_action :whitelist_query_limiting, only: [:usage_data]
before_action do
push_frontend_feature_flag(:self_monitoring_project)
end
VALID_SETTING_PANELS = %w(general integrations repository VALID_SETTING_PANELS = %w(general integrations repository
ci_cd reporting metrics_and_profiling ci_cd reporting metrics_and_profiling
network preferences).freeze network preferences).freeze
# The current size of a sidekiq job's jid is 24 characters. The size of the
# jid is an internal detail of Sidekiq, and they do not guarantee that it'll
# stay the same. We chose 50 to give us room in case the size of the jid
# increases. The jid is alphanumeric, so 50 is very generous. There is a spec
# that ensures that the constant value is more than the size of an actual jid.
PARAM_JOB_ID_MAX_SIZE = 50
VALID_SETTING_PANELS.each do |action| VALID_SETTING_PANELS.each do |action|
define_method(action) { perform_update if submitted? } define_method(action) { perform_update if submitted? }
end end
...@@ -62,8 +73,64 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -62,8 +73,64 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
redirect_to ::Gitlab::LetsEncrypt.terms_of_service_url redirect_to ::Gitlab::LetsEncrypt.terms_of_service_url
end end
def create_self_monitoring_project
return self_monitoring_project_not_implemented unless Feature.enabled?(:self_monitoring_project)
job_id = SelfMonitoringProjectCreateWorker.perform_async
render status: :accepted, json: {
job_id: job_id,
monitor_status: status_create_self_monitoring_project_admin_application_settings_path
}
end
def status_create_self_monitoring_project
return self_monitoring_project_not_implemented unless Feature.enabled?(:self_monitoring_project)
job_id = params[:job_id].to_s
unless job_id.length <= PARAM_JOB_ID_MAX_SIZE
return render status: :bad_request, json: {
message: _('Parameter "job_id" cannot exceed length of %{job_id_max_size}' %
{ job_id_max_size: PARAM_JOB_ID_MAX_SIZE })
}
end
if Gitlab::CurrentSettings.instance_administration_project_id.present?
render status: :ok, json: self_monitoring_data
elsif SelfMonitoringProjectCreateWorker.in_progress?(job_id)
::Gitlab::PollingInterval.set_header(response, interval: 3_000)
render status: :accepted, json: { message: _('Job is in progress') }
else
render status: :bad_request, json: {
message: _('Self-monitoring project does not exist. Please check logs ' \
'for any error messages')
}
end
end
private private
def self_monitoring_data
{
project_id: Gitlab::CurrentSettings.instance_administration_project_id,
project_full_path: Gitlab::CurrentSettings.instance_administration_project&.full_path
}
end
def self_monitoring_project_not_implemented
render(
status: :not_implemented,
json: {
message: _('Self-monitoring is not enabled on this GitLab server, contact your administrator.'),
documentation_url: help_page_path('administration/monitoring/gitlab_instance_administration_project/index')
}
)
end
def set_application_setting def set_application_setting
@application_setting = ApplicationSetting.current_without_cache @application_setting = ApplicationSetting.current_without_cache
end end
......
...@@ -334,6 +334,22 @@ module ApplicationSettingsHelper ...@@ -334,6 +334,22 @@ module ApplicationSettingsHelper
def omnibus_protected_paths_throttle? def omnibus_protected_paths_throttle?
Rack::Attack.throttles.key?('protected paths') Rack::Attack.throttles.key?('protected paths')
end end
def self_monitoring_project_data
{
'create_self_monitoring_project_path' =>
create_self_monitoring_project_admin_application_settings_path,
'status_create_self_monitoring_project_path' =>
status_create_self_monitoring_project_admin_application_settings_path,
'self_monitoring_project_exists' =>
Gitlab::CurrentSettings.instance_administration_project.present?,
'self_monitoring_project_full_path' =>
Gitlab::CurrentSettings.instance_administration_project&.full_path
}
end
end end
ApplicationSettingsHelper.prepend_if_ee('EE::ApplicationSettingsHelper') # rubocop: disable Cop/InjectEnterpriseEditionModule ApplicationSettingsHelper.prepend_if_ee('EE::ApplicationSettingsHelper') # rubocop: disable Cop/InjectEnterpriseEditionModule
......
...@@ -116,6 +116,9 @@ namespace :admin do ...@@ -116,6 +116,9 @@ namespace :admin do
put :clear_repository_check_states put :clear_repository_check_states
match :general, :integrations, :repository, :ci_cd, :reporting, :metrics_and_profiling, :network, :preferences, via: [:get, :patch] match :general, :integrations, :repository, :ci_cd, :reporting, :metrics_and_profiling, :network, :preferences, via: [:get, :patch]
get :lets_encrypt_terms_of_service get :lets_encrypt_terms_of_service
post :create_self_monitoring_project
get :status_create_self_monitoring_project
end end
resources :labels resources :labels
......
...@@ -10197,6 +10197,9 @@ msgstr "" ...@@ -10197,6 +10197,9 @@ msgstr ""
msgid "Job has wrong arguments format." msgid "Job has wrong arguments format."
msgstr "" msgstr ""
msgid "Job is in progress"
msgstr ""
msgid "Job is missing the `model_type` argument." msgid "Job is missing the `model_type` argument."
msgstr "" msgstr ""
...@@ -12714,6 +12717,9 @@ msgstr "" ...@@ -12714,6 +12717,9 @@ msgstr ""
msgid "Parameter" msgid "Parameter"
msgstr "" msgstr ""
msgid "Parameter \"job_id\" cannot exceed length of %{job_id_max_size}"
msgstr ""
msgid "Parent epic doesn't exist." msgid "Parent epic doesn't exist."
msgstr "" msgstr ""
...@@ -16217,6 +16223,12 @@ msgstr "" ...@@ -16217,6 +16223,12 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By <a href=\"#\">@johnsmith</a>\"). It will also associate and/or assign these issues and comments with the selected user." msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By <a href=\"#\">@johnsmith</a>\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "" msgstr ""
msgid "Self-monitoring is not enabled on this GitLab server, contact your administrator."
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr ""
msgid "Send a separate email notification to Developers." msgid "Send a separate email notification to Developers."
msgstr "" msgstr ""
......
...@@ -59,4 +59,54 @@ describe ApplicationSettingsHelper do ...@@ -59,4 +59,54 @@ describe ApplicationSettingsHelper do
expect(helper.integration_expanded?('plantuml_')).to be_falsey expect(helper.integration_expanded?('plantuml_')).to be_falsey
end end
end end
describe '.self_monitoring_project_data' do
context 'when self monitoring project does not exist' do
it 'returns create_self_monitoring_project_path' do
expect(helper.self_monitoring_project_data).to include(
'create_self_monitoring_project_path' =>
create_self_monitoring_project_admin_application_settings_path
)
end
it 'returns status_create_self_monitoring_project_path' do
expect(helper.self_monitoring_project_data).to include(
'status_create_self_monitoring_project_path' =>
status_create_self_monitoring_project_admin_application_settings_path
)
end
it 'returns self_monitoring_project_exists false' do
expect(helper.self_monitoring_project_data).to include(
'self_monitoring_project_exists' => false
)
end
it 'returns nil for project full_path' do
expect(helper.self_monitoring_project_data).to include(
'self_monitoring_project_full_path' => nil
)
end
end
context 'when self monitoring project exists' do
let(:project) { build(:project) }
before do
stub_application_setting(instance_administration_project: project)
end
it 'returns self_monitoring_project_exists true' do
expect(helper.self_monitoring_project_data).to include(
'self_monitoring_project_exists' => true
)
end
it 'returns project full_path' do
expect(helper.self_monitoring_project_data).to include(
'self_monitoring_project_full_path' => project.full_path
)
end
end
end
end end
# frozen_string_literal: true
require 'spec_helper'
describe 'Self-Monitoring project requests' do
let(:admin) { create(:admin) }
describe 'POST #create_self_monitoring_project' do
let(:worker_class) { SelfMonitoringProjectCreateWorker }
subject { post create_self_monitoring_project_admin_application_settings_path }
it_behaves_like 'not accessible to non-admin users'
context 'with admin user' do
before do
login_as(admin)
end
context 'with feature flag disabled' do
it_behaves_like 'not accessible if feature flag is disabled'
end
context 'with feature flag enabled' do
it 'returns sidekiq job_id of expected length' do
subject
job_id = json_response['job_id']
aggregate_failures do
expect(job_id).to be_present
expect(job_id.length).to be <= Admin::ApplicationSettingsController::PARAM_JOB_ID_MAX_SIZE
end
end
it 'triggers async worker' do
expect(worker_class).to receive(:perform_async)
subject
end
it 'returns accepted response' do
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:accepted)
expect(json_response.keys).to contain_exactly('job_id', 'monitor_status')
expect(json_response).to include(
'monitor_status' => status_create_self_monitoring_project_admin_application_settings_path
)
end
end
it 'returns job_id' do
fake_job_id = 'b5b28910d97563e58c2fe55f'
expect(worker_class).to receive(:perform_async).and_return(fake_job_id)
subject
response_job_id = json_response['job_id']
expect(response_job_id).to eq fake_job_id
end
end
end
end
describe 'GET #status_create_self_monitoring_project' do
let(:worker_class) { SelfMonitoringProjectCreateWorker }
let(:job_id) { 'job_id' }
subject do
get status_create_self_monitoring_project_admin_application_settings_path,
params: { job_id: job_id }
end
it_behaves_like 'not accessible to non-admin users'
context 'with admin user' do
before do
login_as(admin)
end
context 'with feature flag disabled' do
it_behaves_like 'not accessible if feature flag is disabled'
end
context 'with feature flag enabled' do
context 'with invalid job_id' do
it 'returns bad_request if job_id too long' do
get status_create_self_monitoring_project_admin_application_settings_path,
params: { job_id: 'a' * 51 }
aggregate_failures do
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response).to eq('message' => 'Parameter "job_id" cannot ' \
"exceed length of #{Admin::ApplicationSettingsController::PARAM_JOB_ID_MAX_SIZE}")
end
end
end
context 'when self-monitoring project exists' do
let(:project) { build(:project) }
before do
stub_application_setting(instance_administration_project_id: 1)
stub_application_setting(instance_administration_project: project)
end
it 'does not need job_id' do
get status_create_self_monitoring_project_admin_application_settings_path
aggregate_failures do
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to eq(
'project_id' => 1,
'project_full_path' => project.full_path
)
end
end
it 'returns success' do
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to eq(
'project_id' => 1,
'project_full_path' => project.full_path
)
end
end
end
context 'when job is in progress' do
before do
allow(worker_class).to receive(:in_progress?)
.with(job_id)
.and_return(true)
end
it 'sets polling header' do
expect(::Gitlab::PollingInterval).to receive(:set_header)
subject
end
it 'returns accepted' do
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:accepted)
expect(json_response).to eq('message' => 'Job is in progress')
end
end
end
context 'when self-monitoring project and job do not exist' do
let(:job_id) { nil }
it 'returns bad_request' do
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response).to eq(
'message' => 'Self-monitoring project does not exist. Please check ' \
'logs for any error messages'
)
end
end
end
end
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'not accessible if feature flag is disabled' do
before do
stub_feature_flags(self_monitoring_project: false)
end
it 'returns not_implemented' do
subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:not_implemented)
expect(json_response).to eq(
'message' => _('Self-monitoring is not enabled on this GitLab server, contact your administrator.'),
'documentation_url' => help_page_path('administration/monitoring/gitlab_instance_administration_project/index')
)
end
end
end
RSpec.shared_examples 'not accessible to non-admin users' do
context 'with unauthenticated user' do
it 'redirects to signin page' do
subject
expect(response).to redirect_to(new_user_session_path)
end
end
context 'with authenticated non-admin user' do
before do
login_as(create(:user))
end
it 'returns status not_found' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
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