Commit badb9c1d authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 5bd24a54
......@@ -74,7 +74,6 @@ gitlab:assets:compile pull-cache:
- .default-before_script
- .assets-compile-cache
- .only:changes-code-backstage-qa
- .use-pg9
stage: prepare
script:
- node --version
......@@ -83,6 +82,7 @@ gitlab:assets:compile pull-cache:
- retry bundle exec rake gitlab:assets:compile
- scripts/clean-old-cached-assets
variables:
SETUP_DB: "false"
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
cache:
......
......@@ -68,6 +68,8 @@ export default () => {
Board,
BoardSidebar,
BoardAddIssuesModal,
BoardSettingsSidebar: () =>
import('ee_component/boards/components/board_settings_sidebar.vue'),
},
store,
data: {
......
export default () => ({
isShowingLabels: true,
activeListId: 0,
});
......@@ -334,7 +334,7 @@ class Project < ApplicationRecord
delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team
delegate :add_master, to: :team # @deprecated
delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings
delegate :root_ancestor, to: :namespace, allow_nil: true
delegate :root_ancestor, :actual_limits, to: :namespace, allow_nil: true
delegate :last_pipeline, to: :commit, allow_nil: true
delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
......
......@@ -24,7 +24,7 @@ get the commit comment added to it.
You can also close a task with a message containing: `fix #123456`.
You can create a Personal Access Token here:
http://app.asana.com/-/account_api'
https://app.asana.com/0/developer-console'
end
def self.to_param
......
# frozen_string_literal: true
module Metrics
module Dashboard
class PodDashboardService < ::Metrics::Dashboard::PredefinedDashboardService
DASHBOARD_PATH = 'config/prometheus/pod_metrics.yml'
DASHBOARD_NAME = 'Pod Health'
end
end
end
......@@ -29,6 +29,7 @@
":board-id" => "boardId",
":key" => "list.id" }
= render "shared/boards/components/sidebar", group: group
= render_if_exists 'shared/boards/components/board_settings_sidebar'
- if @project
%board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project),
"milestone-path" => milestones_filter_dropdown_path,
......
---
title: Links to design comments now lead to specific note
merge_request: 21724
author:
type: fixed
---
title: Ensure namespace is present for Managed-Cluster-Applications CI template
merge_request: 21903
author:
type: fixed
dashboard: 'Pod metrics'
priority: 10
panel_groups:
- group: CPU metrics
panels:
- title: "CPU usage"
type: "line-chart"
y_label: "Cores per pod"
metrics:
- id: pod_cpu_usage_seconds_total
query_range: 'rate(container_cpu_usage_seconds_total{pod_name="{{pod_name}}",container_name="POD"}[5m])'
unit: "cores"
label: pod_name
- group: Memory metrics
panels:
- title: "Memory usage working set"
type: "line-chart"
y_label: "Working set memory (MiB)"
metrics:
- id: pod_memory_working_set
query_range: 'container_memory_working_set_bytes{pod_name="{{pod_name}}",container_name="POD"}/1024/1024'
unit: "MiB"
label: pod_name
- group: Network metrics
panels:
- title: "Network Receive (In)"
type: "line-chart"
y_label: "Received (KiB/sec)"
metrics:
- id: pod_network_receive
query_range: 'rate(container_network_receive_bytes_total{pod_name="{{pod_name}}",container_name="POD"}[5m])/1024'
unit: "KiB / sec"
label: pod_name
- title: "Network Transmit (Out)"
type: "line-chart"
y_label: "Transmitted (KiB/sec)"
metrics:
- id: pod_network_transmit
query_range: 'rate(container_network_transmit_bytes_total{pod_name="{{pod_name}}",container_name="POD"}[5m])/1024'
unit: "KiB / sec"
label: pod_name
- group: Disk metrics
panels:
- title: "Disk Reads"
type: "line-chart"
y_label: "Disk reads (KiB/sec)"
metrics:
- id: pod_disk_reads
query_range: 'rate(container_fs_reads_bytes_total{container_name="POD",pod_name="{{pod_name}}"}[5m])/1024'
unit: "KiB / sec"
label: pod_name
- title: "Disk Writes"
type: "line-chart"
y_label: "Disk writes (KiB/sec)"
metrics:
- id: pod_disk_writes
query_range: 'rate(container_fs_writes_bytes_total{container_name="POD",pod_name="{{pod_name}}"}[5m])/1024'
unit: "KiB / sec"
label: pod_name
# frozen_string_literal: true
class AddIdToPlanLimits < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
add_column(:plan_limits, :id, :primary_key) unless column_exists?(:plan_limits, :id)
end
def down
remove_column(:plan_limits, :id)
end
end
# frozen_string_literal: true
class AddProjectHooksToPlanLimits < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
add_column(:plan_limits, :project_hooks, :integer, default: 0, null: false)
end
end
# frozen_string_literal: true
class InsertProjectHooksPlanLimits < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
return unless Gitlab.com?
create_or_update_plan_limit('project_hooks', 'free', 10)
create_or_update_plan_limit('project_hooks', 'bronze', 20)
create_or_update_plan_limit('project_hooks', 'silver', 30)
create_or_update_plan_limit('project_hooks', 'gold', 100)
end
def down
return unless Gitlab.com?
create_or_update_plan_limit('project_hooks', 'free', 0)
create_or_update_plan_limit('project_hooks', 'bronze', 0)
create_or_update_plan_limit('project_hooks', 'silver', 0)
create_or_update_plan_limit('project_hooks', 'gold', 0)
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_12_14_175727) do
ActiveRecord::Schema.define(version: 2019_12_16_183532) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
......@@ -2987,6 +2987,7 @@ ActiveRecord::Schema.define(version: 2019_12_14_175727) do
t.integer "ci_active_pipelines", default: 0, null: false
t.integer "ci_pipeline_size", default: 0, null: false
t.integer "ci_active_jobs", default: 0, null: false
t.integer "project_hooks", default: 0, null: false
t.index ["plan_id"], name: "index_plan_limits_on_plan_id", unique: true
end
......
......@@ -719,6 +719,105 @@ result as you did in the beginning:
Note that `enforced="true"`, meaning that authentication is being enforced.
## Direct Git access in GitLab Rails
Also known as "the Rugged patches".
### History
Before Gitaly existed, the things that are now Gitaly clients used to
access Git repositories directly. Either on a local disk in the case of
e.g. a single-machine Omnibus GitLab installation, or via NFS in the
case of a horizontally scaled GitLab installation.
Besides running plain `git` commands, in GitLab Rails we also used to
use a Ruby gem (library) called
[Rugged](https://github.com/libgit2/rugged). Rugged is a wrapper around
[libgit2](https://libgit2.org/), a stand-alone implementation of Git in
the form of a C library.
Over time it has become clear to use that Rugged, and particularly
Rugged in combination with the [Unicorn](https://bogomips.org/unicorn/)
web server, is extremely efficient. Because libgit2 is a *library* and
not an external process, there was very little overhead between GitLab
application code that tried to look up data in Git repositories, and the
Git implementation itself.
Because Rugged+Unicorn was so efficient, GitLab's application code ended
up with lots of duplicate Git object lookups (like looking up the
`master` commmit a dozen times in one request). We could write
inefficient code without being punished for it.
When we migrated these Git lookups to Gitaly calls, we were suddenly
getting a much higher fixed cost per Git lookup. Even when Gitaly is
able to re-use an already-running `git` process to look up e.g. a commit
you still have the cost of a network roundtrip to Gitaly, and within
Gitaly a write/read roundtrip on the Unix pipes that connect Gitaly to
the `git` process.
Using GitLab.com performance as our yardstick, we pushed down the number
of Gitaly calls per request until the loss of Rugged's efficiency was no
longer felt. It also helped that we run Gitaly itself directly on the
Git file severs, rather than via NFS mounts: this gave us a speed boost
that counteracted the negative effect of not using Rugged anymore.
Unfortunately, some *other* deployments of GitLab could not ditch NFS
like we did on GitLab.com and they got the worst of both worlds: the
slowness of NFS and the increased inherent overhead of Gitaly.
As a performance band-aid for these stuck-on-NFS deployments, we
re-introduced some of the old Rugged code that got deleted from
GitLab Rails during the Gitaly migration project. These pieces of
re-introduced code are informally referred to as "the Rugged patches".
### Activation of direct Git access in GitLab Rails
The Ruby methods that perform direct Git access are hidden behind [feature
flags](../../development/gitaly.md#legacy-rugged-code). These feature
flags are off by default. It is not good if you need to know about
feature flags to get the best performance so in a second iteration, we
added an automatic mechanism that will enable direct Git access.
When GitLab Rails calls a function that has a Rugged patch it performs
two checks. The result of both of these checks is cached.
1. Is the feature flag for this patch set in the database? If so, do
what the feature flag says.
1. If the feature flag is not set (i.e. neither true nor false), try to
see if we can access filesystem underneath the Gitaly server
directly. If so, use the Rugged patch.
To see if GitLab Rails can access the repo filesystem directly, we use
the following heuristic:
- Gitaly ensures that the filesystem has a metadata file in its root
with a UUID in it.
- Gitaly reports this UUID to GitLab Rails via the `ServerInfo` RPC.
- GitLab Rails tries to read the metadata file directly. If it exists,
and if the UUID's match, assume we have direct access.
Because of the way the UUID check works, and because Omnibus GitLab will
fill in the correct repository paths in the GitLab Rails config file
`config/gitlab.yml`, **direct Git access in GitLab Rails is on by default in
Omnibus**.
### Plans to remove direct Git access in GitLab Rails
For the sake of removing complexity it is desirable that we get rid of
direct Git access in GitLab Rails. For as long as some GitLab installations are stuck
with Git repositories on slow NFS, however, we cannot just remove them.
There are two prongs to our efforts to remove direct Git access in GitLab Rails:
1. Reduce the number of (inefficient) Gitaly queries made by
GitLab Rails.
1. Persuade everybody who runs a Highly Available / horizontally scaled
GitLab installation to move off of NFS.
The second prong is the only real solution. For this we need [Gitaly
HA](https://gitlab.com/groups/gitlab-org/-/epics?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=Gitaly%20HA),
which is still under development as of December 2019.
## Troubleshooting Gitaly
### Checking versions when using standalone Gitaly nodes
......
......@@ -142,7 +142,6 @@ that could change behavior in the next major release.
To ensure background migrations are successful, increment by one minor version during the version jump before installing newer releases.
For example: `11.11.x` -> `12.0.x`
Please see the table below for some examples:
| Latest stable version | Your version | Recommended upgrade path | Note |
......@@ -152,6 +151,9 @@ Please see the table below for some examples:
| 11.3.4 | 8.13.4 | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version `8`, `9.5.10` is the last version in version `9`, `10.8.7` is the last version in version `10` |
| 12.5.8 | 11.3.4 | `11.3.4` -> `11.11.8` -> `12.0.9` -> `12.5.8` | `11.11.8` is the last version in version `11` |
To check the size of `background_migration` queue and to learn more about background migrations
see [Upgrading without downtime](../update/README.md#upgrading-without-downtime).
More information about the release procedures can be found in our
[release documentation](https://gitlab.com/gitlab-org/release/docs). You may also want to read our
[Responsible Disclosure Policy](https://about.gitlab.com/security/disclosure/).
......@@ -47,6 +47,20 @@ and **per project and per group** for **GitLab Enterprise Edition**.
Navigate to the webhooks page by going to your project's
**Settings ➔ Integrations**.
## Maximum number of webhooks (per tier)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/20730) in GitLab 12.6.
A maximum number of project webhooks applies to each [GitLab.com
tier](https://about.gitlab.com/pricing/), as shown in the following table:
| Tier | Number of webhooks per project |
|----------|--------------------------------|
| Free | 10 |
| Bronze | 20 |
| Silver | 30 |
| Gold | 100 |
## Use-cases
- You can set up a webhook in GitLab to send a notification to
......
......@@ -42,9 +42,9 @@ NOTE: **Note:**
You will need at least Reporter [permissions](../../permissions.md) to view the Error Tracking list.
The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar.
Errors can be filtered by title.
Errors can be filtered by title or sorted by Frequency, First Seen or Last Seen. Errors are always sorted in descending order by the field specified.
![Error Tracking list](img/error_tracking_list.png)
![Error Tracking list](img/error_tracking_list_v12_6.png)
## Error Details
......
......@@ -7,7 +7,7 @@ code_quality:
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/security-products/codequality:12-5-stable"
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/security-products/codequality:0.85.5"
script:
- |
if ! docker info &>/dev/null; then
......
......@@ -9,6 +9,7 @@ apply:
INGRESS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/ingress/values.yaml
SENTRY_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/sentry/values.yaml
script:
- kubectl get namespace "$TILLER_NAMESPACE" || kubectl create namespace "$TILLER_NAMESPACE"
- gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml
only:
refs:
......
......@@ -1052,6 +1052,15 @@ into similar problems in the future (e.g. when new tables are created).
connection.select_value(index_sql).to_i > 0
end
def create_or_update_plan_limit(limit_name, plan_name, limit_value)
execute <<~SQL
INSERT INTO plan_limits (plan_id, #{quote_column_name(limit_name)})
VALUES
((SELECT id FROM plans WHERE name = #{quote(plan_name)} LIMIT 1), #{quote(limit_value)})
ON CONFLICT (plan_id) DO UPDATE SET #{quote_column_name(limit_name)} = EXCLUDED.#{quote_column_name(limit_name)};
SQL
end
private
def tables_match?(target_table, foreign_key_table)
......
......@@ -22,6 +22,7 @@ module Gitlab
return SERVICES::DynamicEmbedService if dynamic_embed?(params)
return SERVICES::DefaultEmbedService if params[:embedded]
return SERVICES::SystemDashboardService if system_dashboard?(params[:dashboard_path])
return SERVICES::PodDashboardService if pod_dashboard?(params[:dashboard_path])
return SERVICES::ProjectDashboardService if params[:dashboard_path]
default_service
......@@ -37,6 +38,10 @@ module Gitlab
SERVICES::SystemDashboardService.matching_dashboard?(filepath)
end
def pod_dashboard?(filepath)
SERVICES::PodDashboardService.matching_dashboard?(filepath)
end
def custom_metric_embed?(params)
SERVICES::CustomMetricEmbedService.valid_params?(params)
end
......
......@@ -10223,6 +10223,9 @@ msgstr ""
msgid "Label"
msgstr ""
msgid "Label List"
msgstr ""
msgid "Label actions dropdown"
msgstr ""
......@@ -10982,6 +10985,9 @@ msgstr ""
msgid "Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}."
msgstr ""
msgid "Maximum number of %{name} (%{count}) exceeded"
msgstr ""
msgid "Maximum number of comments exceeded"
msgstr ""
......@@ -18887,6 +18893,12 @@ msgstr ""
msgid "Too many changes to show."
msgstr ""
msgid "Too many namespaces enabled. You will need to manage them via the console or the API."
msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
msgid "Topics"
msgstr ""
......
......@@ -8,7 +8,10 @@ module RuboCop
class AddColumn < RuboCop::Cop::Cop
include MigrationHelpers
WHITELISTED_TABLES = [:application_settings].freeze
WHITELISTED_TABLES = %i[
application_settings
plan_limits
].freeze
MSG = '`add_column` with a default value requires downtime, ' \
'use `add_column_with_default` instead'.freeze
......
......@@ -2,7 +2,6 @@
"type": "object",
"required": [
"group",
"priority",
"panels"
],
"properties": {
......
......@@ -330,46 +330,46 @@ describe('URL utility', () => {
expect(urlUtils.escapeFileUrl('foo/bar/file.md')).toBe('foo/bar/file.md');
});
});
});
describe('setUrlParams', () => {
it('adds new params as query string', () => {
const url = 'https://gitlab.com/test';
describe('setUrlParams', () => {
it('adds new params as query string', () => {
const url = 'https://gitlab.com/test';
expect(
urlUtils.setUrlParams({ group_id: 'gitlab-org', project_id: 'my-project' }, url),
).toEqual('https://gitlab.com/test?group_id=gitlab-org&project_id=my-project');
});
expect(
urlUtils.setUrlParams({ group_id: 'gitlab-org', project_id: 'my-project' }, url),
).toEqual('https://gitlab.com/test?group_id=gitlab-org&project_id=my-project');
});
it('updates an existing parameter', () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
it('updates an existing parameter', () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
expect(urlUtils.setUrlParams({ project_id: 'gitlab-test' }, url)).toEqual(
'https://gitlab.com/test?group_id=gitlab-org&project_id=gitlab-test',
);
});
expect(urlUtils.setUrlParams({ project_id: 'gitlab-test' }, url)).toEqual(
'https://gitlab.com/test?group_id=gitlab-org&project_id=gitlab-test',
);
});
it("removes the project_id param when it's value is null", () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
it("removes the project_id param when it's value is null", () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
expect(urlUtils.setUrlParams({ project_id: null }, url)).toEqual(
'https://gitlab.com/test?group_id=gitlab-org',
);
});
expect(urlUtils.setUrlParams({ project_id: null }, url)).toEqual(
'https://gitlab.com/test?group_id=gitlab-org',
);
});
it('handles arrays properly', () => {
const url = 'https://gitlab.com/test';
it('handles arrays properly', () => {
const url = 'https://gitlab.com/test';
expect(urlUtils.setUrlParams({ label_name: ['foo', 'bar'] }, url)).toEqual(
'https://gitlab.com/test?label_name=foo&label_name=bar',
);
});
expect(urlUtils.setUrlParams({ label_name: ['foo', 'bar'] }, url)).toEqual(
'https://gitlab.com/test?label_name=foo&label_name=bar',
);
});
it('removes all existing URL params and sets a new param when cleanParams=true', () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
it('removes all existing URL params and sets a new param when cleanParams=true', () => {
const url = 'https://gitlab.com/test?group_id=gitlab-org&project_id=my-project';
expect(urlUtils.setUrlParams({ foo: 'bar' }, url, true)).toEqual(
'https://gitlab.com/test?foo=bar',
);
expect(urlUtils.setUrlParams({ foo: 'bar' }, url, true)).toEqual(
'https://gitlab.com/test?foo=bar',
);
});
});
});
......@@ -1440,4 +1440,17 @@ describe Gitlab::Database::MigrationHelpers do
end
end
end
describe '#create_or_update_plan_limit' do
it 'creates or updates plan limits' do
expect(model).to receive(:execute).with <<~SQL
INSERT INTO plan_limits (plan_id, "project_hooks")
VALUES
((SELECT id FROM plans WHERE name = 'free' LIMIT 1), '10')
ON CONFLICT (plan_id) DO UPDATE SET "project_hooks" = EXCLUDED."project_hooks";
SQL
model.create_or_update_plan_limit('project_hooks', 'free', 10)
end
end
end
......@@ -22,6 +22,12 @@ describe Gitlab::Metrics::Dashboard::ServiceSelector do
it { is_expected.to be Metrics::Dashboard::SystemDashboardService }
end
context 'when the path is for the pod dashboard' do
let(:arguments) { { dashboard_path: pod_dashboard_path } }
it { is_expected.to be Metrics::Dashboard::PodDashboardService }
end
end
context 'when the embedded flag is provided' do
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20191216183532_insert_project_hooks_plan_limits.rb')
describe InsertProjectHooksPlanLimits, :migration do
let(:migration) { described_class.new }
let(:plans) { table(:plans) }
let(:plan_limits) { table(:plan_limits) }
before do
plans.create(id: 34, name: 'free')
plans.create(id: 2, name: 'bronze')
plans.create(id: 3, name: 'silver')
plans.create(id: 4, name: 'gold')
plan_limits.create(plan_id: 34, ci_active_jobs: 5)
end
context 'when on Gitlab.com' do
before do
expect(Gitlab).to receive(:com?).at_most(:twice).and_return(true)
end
describe '#up' do
it 'updates the project_hooks plan limits' do
migration.up
expect(plan_limits.pluck(:plan_id, :project_hooks, :ci_active_jobs))
.to match_array([[34, 10, 5], [2, 20, 0], [3, 30, 0], [4, 100, 0]])
end
end
describe '#down' do
it 'updates the project_hooks plan limits to 0' do
migration.up
migration.down
expect(plan_limits.pluck(:plan_id, :project_hooks, :ci_active_jobs))
.to match_array([[34, 0, 5], [2, 0, 0], [3, 0, 0], [4, 0, 0]])
end
end
end
context 'when on self-hosted' do
before do
expect(Gitlab).to receive(:com?).and_return(false)
end
describe '#up' do
it 'does not update the plan limits' do
migration.up
expect(plan_limits.pluck(:plan_id, :project_hooks, :ci_active_jobs))
.to match_array([[34, 0, 5]])
end
end
describe '#down' do
it 'does not update the plan limits' do
migration.down
expect(plan_limits.pluck(:plan_id, :project_hooks, :ci_active_jobs))
.to match_array([[34, 0, 5]])
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) }
before do
project.add_maintainer(user)
end
describe 'get_dashboard' do
let(:dashboard_path) { described_class::DASHBOARD_PATH }
let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] }
let(:service_call) { described_class.new(*service_params).get_dashboard }
it_behaves_like 'valid dashboard service response'
it_behaves_like 'caches the unprocessed dashboard for subsequent calls'
end
end
......@@ -22,6 +22,10 @@ module MetricsDashboardHelpers
Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH
end
def pod_dashboard_path
Metrics::Dashboard::PodDashboardService::DASHBOARD_PATH
end
def business_metric_title
PrometheusMetricEnums.group_details[:business][:group_title]
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