提交 a821bd6a 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 f6e985db
import $ from 'jquery';
import Cookies from 'js-cookie';
import _ from 'underscore';
import bp from './breakpoints';
import { GlBreakpointInstance as bp, breakpoints } from '@gitlab/ui/dist/utils';
import { parseBoolean } from '~/lib/utils/common_utils';
// NOTE: at 1200px nav sidebar should not overlap the content
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24555#note_134136110
const NAV_SIDEBAR_BREAKPOINT = 1200;
export const SIDEBAR_COLLAPSED_CLASS = 'js-sidebar-collapsed';
export default class ContextualSidebar {
......@@ -50,9 +46,10 @@ export default class ContextualSidebar {
$(window).on('resize', () => _.debounce(this.render(), 100));
}
// TODO: use the breakpoints from breakpoints.js once they have been updated for bootstrap 4
// See documentation: https://design.gitlab.com/regions/navigation#contextual-navigation
static isDesktopBreakpoint = () => bp.windowWidth() >= NAV_SIDEBAR_BREAKPOINT;
// NOTE: at 1200px nav sidebar should not overlap the content
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24555#note_134136110
static isDesktopBreakpoint = () => bp.windowWidth() >= breakpoints.xl;
static setCollapsedCookie(value) {
if (!ContextualSidebar.isDesktopBreakpoint()) {
return;
......@@ -63,12 +60,13 @@ export default class ContextualSidebar {
toggleSidebarNav(show) {
const breakpoint = bp.getBreakpointSize();
const dbp = ContextualSidebar.isDesktopBreakpoint();
const supportedSizes = ['xs', 'sm', 'md'];
this.$sidebar.toggleClass(SIDEBAR_COLLAPSED_CLASS, !show);
this.$sidebar.toggleClass('sidebar-expanded-mobile', !dbp ? show : false);
this.$overlay.toggleClass(
'mobile-nav-open',
breakpoint === 'xs' || breakpoint === 'sm' ? show : false,
supportedSizes.includes(breakpoint) ? show : false,
);
this.$sidebar.removeClass('sidebar-collapsed-desktop');
}
......@@ -76,13 +74,14 @@ export default class ContextualSidebar {
toggleCollapsedSidebar(collapsed, saveCookie) {
const breakpoint = bp.getBreakpointSize();
const dbp = ContextualSidebar.isDesktopBreakpoint();
const supportedSizes = ['xs', 'sm', 'md'];
if (this.$sidebar.length) {
this.$sidebar.toggleClass(`sidebar-collapsed-desktop ${SIDEBAR_COLLAPSED_CLASS}`, collapsed);
this.$sidebar.toggleClass('sidebar-expanded-mobile', !dbp ? !collapsed : false);
this.$page.toggleClass(
'page-with-icon-sidebar',
breakpoint === 'xs' || breakpoint === 'sm' ? true : collapsed,
supportedSizes.includes(breakpoint) ? true : collapsed,
);
}
......
......@@ -6,10 +6,21 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
before_action :set_application_setting
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
ci_cd reporting metrics_and_profiling
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|
define_method(action) { perform_update if submitted? }
end
......@@ -62,8 +73,64 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
redirect_to ::Gitlab::LetsEncrypt.terms_of_service_url
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
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
@application_setting = ApplicationSetting.current_without_cache
end
......
......@@ -23,7 +23,7 @@ module Projects
private
def prometheus_adapter
@prometheus_adapter ||= ::Prometheus::AdapterService.new(project, project.deployment_platform&.cluster).prometheus_adapter
@prometheus_adapter ||= ::Gitlab::Prometheus::Adapter.new(project, project.deployment_platform&.cluster).prometheus_adapter
end
def require_prometheus_metrics!
......
......@@ -334,6 +334,22 @@ module ApplicationSettingsHelper
def omnibus_protected_paths_throttle?
Rack::Attack.throttles.key?('protected paths')
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
ApplicationSettingsHelper.prepend_if_ee('EE::ApplicationSettingsHelper') # rubocop: disable Cop/InjectEnterpriseEditionModule
......
......@@ -34,20 +34,10 @@ class DeploymentMetrics
def prometheus_adapter
strong_memoize(:prometheus_adapter) do
service = project.find_or_initialize_service('prometheus')
if service.can_query?
service
else
cluster_prometheus
end
Gitlab::Prometheus::Adapter.new(project, cluster).prometheus_adapter
end
end
def cluster_prometheus
cluster.application_prometheus if cluster&.application_prometheus_available?
end
def has_metrics_and_can_query?
has_metrics? && prometheus_adapter.can_query?
end
......
......@@ -225,11 +225,9 @@ class Environment < ApplicationRecord
prometheus_adapter.query(:additional_metrics_environment, self, *args.map(&:to_f))
end
# rubocop: disable CodeReuse/ServiceClass
def prometheus_adapter
@prometheus_adapter ||= Prometheus::AdapterService.new(project, deployment_platform&.cluster).prometheus_adapter
@prometheus_adapter ||= Gitlab::Prometheus::Adapter.new(project, deployment_platform&.cluster).prometheus_adapter
end
# rubocop: enable CodeReuse/ServiceClass
def slug
super.presence || generate_slug
......
# frozen_string_literal: true
module Prometheus
class AdapterService
attr_reader :project, :cluster
def initialize(project, cluster)
@project = project
@cluster = cluster
end
def prometheus_adapter
@prometheus_adapter ||= if service_prometheus_adapter.can_query?
service_prometheus_adapter
else
cluster_prometheus_adapter
end
end
def service_prometheus_adapter
project.find_or_initialize_service('prometheus')
end
def cluster_prometheus_adapter
application = cluster&.application_prometheus
application if application&.available?
end
end
end
......@@ -116,6 +116,9 @@ namespace :admin do
put :clear_repository_check_states
match :general, :integrations, :repository, :ci_cd, :reporting, :metrics_and_profiling, :network, :preferences, via: [:get, :patch]
get :lets_encrypt_terms_of_service
post :create_self_monitoring_project
get :status_create_self_monitoring_project
end
resources :labels
......
---
type: reference
---
# GitLab application limits
GitLab, like most large applications, enforces limits within certain features to maintain a
minimum quality of performance. Allowing some features to be limitless could affect security,
performance, data, or could even exhaust the allocated resources for the application.
## Number of comments per issue, merge request or commit
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/22388) in GitLab 12.4.
There's a limit to the number of comments that can be submitted on an issue,
merge request, or commit. When the limit is reached, system notes can still be
added so that the history of events is not lost, but user-submitted comments
will fail.
- **Max limit:** 5.000 comments
......@@ -398,6 +398,9 @@ To configure the `s3` storage driver in Omnibus:
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
NOTE: **Note:**
`your-s3-bucket` should only be the name of a bucket that exists, and can't include subdirectories.
**Installations from source**
Configuring the storage driver is done in your registry config YML file created
......@@ -408,9 +411,9 @@ when you [deployed your docker registry](https://docs.docker.com/registry/deploy
```yml
storage:
s3:
accesskey: 'AKIAKIAKI'
secretkey: 'secret123'
bucket: 'gitlab-registry-bucket-AKIAKIAKI'
accesskey: 's3-access-key'
secretkey: 's3-secret-key-for-access-key'
bucket: 'your-s3-bucket'
region: 'your-s3-region'
regionendpoint: 'your-s3-regionendpoint'
cache:
......@@ -419,6 +422,9 @@ storage:
enabled: true
```
NOTE: **Note:**
`your-s3-bucket` should only be the name of a bucket that exists, and can't include subdirectories.
## Change the registry's internal port
NOTE: **Note:**
......
......@@ -78,6 +78,12 @@ This setting is set per job and can be overridden in
[`.gitlab-ci.yml`](../../../ci/yaml/README.md#artifactsexpire_in).
To disable the expiration, set it to `0`. The default unit is in seconds.
NOTE: **Note**
Any changes to this setting will apply to new artifacts only. The expiration time will not
be updated for artifacts created before this setting was changed.
The administrator may need to manually search for and expire previously-created
artifacts, as described in the [troubleshooting documentation](../../../administration/troubleshooting/gitlab_rails_cheat_sheet.md#remove-artifacts-more-than-a-week-old).
## Shared Runners pipeline minutes quota **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/1078)
......
# frozen_string_literal: true
module Gitlab
module Prometheus
class Adapter
attr_reader :project, :cluster
def initialize(project, cluster)
@project = project
@cluster = cluster
end
def prometheus_adapter
@prometheus_adapter ||= if service_prometheus_adapter.can_query?
service_prometheus_adapter
else
cluster_prometheus_adapter
end
end
def cluster_prometheus_adapter
application = cluster&.application_prometheus
application if application&.available?
end
private
def service_prometheus_adapter
project.find_or_initialize_service('prometheus')
end
end
end
end
......@@ -10197,6 +10197,9 @@ msgstr ""
msgid "Job has wrong arguments format."
msgstr ""
msgid "Job is in progress"
msgstr ""
msgid "Job is missing the `model_type` argument."
msgstr ""
......@@ -12714,6 +12717,9 @@ msgstr ""
msgid "Parameter"
msgstr ""
msgid "Parameter \"job_id\" cannot exceed length of %{job_id_max_size}"
msgstr ""
msgid "Parent epic doesn't exist."
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."
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."
msgstr ""
......
......@@ -85,7 +85,7 @@ describe Projects::Prometheus::MetricsController do
end
it 'calls prometheus adapter service' do
expect_next_instance_of(::Prometheus::AdapterService) do |instance|
expect_next_instance_of(::Gitlab::Prometheus::Adapter) do |instance|
expect(instance).to receive(:prometheus_adapter)
end
......
......@@ -108,7 +108,7 @@ describe Projects::Serverless::FunctionsFinder do
let(:finder) { described_class.new(project) }
before do
allow(Prometheus::AdapterService).to receive(:new).and_return(double(prometheus_adapter: prometheus_adapter))
allow(Gitlab::Prometheus::Adapter).to receive(:new).and_return(double(prometheus_adapter: prometheus_adapter))
allow(prometheus_adapter).to receive(:query).and_return(prometheus_empty_body('matrix'))
end
......
......@@ -59,4 +59,54 @@ describe ApplicationSettingsHelper do
expect(helper.integration_expanded?('plantuml_')).to be_falsey
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
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe Prometheus::AdapterService do
describe Gitlab::Prometheus::Adapter do
let_it_be(:project) { create(:project) }
let_it_be(:cluster, reload: true) { create(:cluster, :provided_by_user, environment_scope: '*', projects: [project]) }
......
......@@ -1112,7 +1112,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
describe '#prometheus_adapter' do
it 'calls prometheus adapter service' do
expect_next_instance_of(Prometheus::AdapterService) do |instance|
expect_next_instance_of(Gitlab::Prometheus::Adapter) do |instance|
expect(instance).to receive(:prometheus_adapter)
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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册