Commit c4c22b06 authored by Thong Kuah's avatar Thong Kuah

Merge branch 'application-limits-with-defaults' into 'master'

Update ApplicationLimits to prefer defaults

See merge request gitlab-org/gitlab!27574
parents f935f5ea 797bb4c0
---
title: Update ApplicationLimits to prefer defaults
merge_request: 27574
author:
type: changed
# frozen_string_literal: true
class UpdatePlanLimitsDefaults < ActiveRecord::Migration[6.0]
DOWNTIME = false
def up
change_column_default :plan_limits, :project_hooks, 100
change_column_default :plan_limits, :group_hooks, 50
change_column_default :plan_limits, :ci_project_subscriptions, 2
change_column_default :plan_limits, :ci_pipeline_schedules, 10
end
def down
change_column_default :plan_limits, :project_hooks, 0
change_column_default :plan_limits, :group_hooks, 0
change_column_default :plan_limits, :ci_project_subscriptions, 0
change_column_default :plan_limits, :ci_pipeline_schedules, 0
end
end
...@@ -4508,10 +4508,10 @@ CREATE TABLE public.plan_limits ( ...@@ -4508,10 +4508,10 @@ CREATE TABLE public.plan_limits (
ci_active_pipelines integer DEFAULT 0 NOT NULL, ci_active_pipelines integer DEFAULT 0 NOT NULL,
ci_pipeline_size integer DEFAULT 0 NOT NULL, ci_pipeline_size integer DEFAULT 0 NOT NULL,
ci_active_jobs integer DEFAULT 0 NOT NULL, ci_active_jobs integer DEFAULT 0 NOT NULL,
project_hooks integer DEFAULT 0 NOT NULL, project_hooks integer DEFAULT 100 NOT NULL,
group_hooks integer DEFAULT 0 NOT NULL, group_hooks integer DEFAULT 50 NOT NULL,
ci_project_subscriptions integer DEFAULT 0 NOT NULL, ci_project_subscriptions integer DEFAULT 2 NOT NULL,
ci_pipeline_schedules integer DEFAULT 0 NOT NULL ci_pipeline_schedules integer DEFAULT 10 NOT NULL
); );
CREATE SEQUENCE public.plan_limits_id_seq CREATE SEQUENCE public.plan_limits_id_seq
...@@ -12747,6 +12747,7 @@ INSERT INTO "schema_migrations" (version) VALUES ...@@ -12747,6 +12747,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200318164448'), ('20200318164448'),
('20200318165448'), ('20200318165448'),
('20200318175008'), ('20200318175008'),
('20200319123041'),
('20200319203901'), ('20200319203901'),
('20200323075043'), ('20200323075043'),
('20200323122201'); ('20200323122201');
......
...@@ -20,40 +20,45 @@ limits](https://about.gitlab.com/handbook/product/#introducing-application-limit ...@@ -20,40 +20,45 @@ limits](https://about.gitlab.com/handbook/product/#introducing-application-limit
In the `plan_limits` table, you have to create a new column and insert the In the `plan_limits` table, you have to create a new column and insert the
limit values. It's recommended to create separate migration script files. limit values. It's recommended to create separate migration script files.
1. Add new column to the `plan_limits` table with non-null default value 0, eg: 1. Add new column to the `plan_limits` table with non-null default value
that represents desired limit, eg:
```ruby
add_column(:plan_limits, :project_hooks, :integer, default: 0, null: false) ```ruby
``` add_column(:plan_limits, :project_hooks, :integer, default: 100, null: false)
```
NOTE: **Note:** Plan limits entries set to `0` mean that limits are not
enabled. NOTE: **Note:** Plan limits entries set to `0` mean that limits are not
enabled. You should use this setting only in special and documented circumstances.
1. Insert plan limits values into the database using
`create_or_update_plan_limit` migration helper, eg: 1. (Optionally) Create the database migration that fine-tunes each level with
a desired limit using `create_or_update_plan_limit` migration helper, eg:
```ruby
def up ```ruby
return unless Gitlab.com? class InsertProjectHooksPlanLimits < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
create_or_update_plan_limit('project_hooks', 'free', 100)
create_or_update_plan_limit('project_hooks', 'bronze', 100) DOWNTIME = false
create_or_update_plan_limit('project_hooks', 'silver', 100)
create_or_update_plan_limit('project_hooks', 'gold', 100) def up
end create_or_update_plan_limit('project_hooks', 'default', 0)
create_or_update_plan_limit('project_hooks', 'free', 10)
def down create_or_update_plan_limit('project_hooks', 'bronze', 20)
return unless Gitlab.com? create_or_update_plan_limit('project_hooks', 'silver', 30)
create_or_update_plan_limit('project_hooks', 'gold', 100)
create_or_update_plan_limit('project_hooks', 'free', 0) end
create_or_update_plan_limit('project_hooks', 'bronze', 0)
create_or_update_plan_limit('project_hooks', 'silver', 0) def down
create_or_update_plan_limit('project_hooks', 'gold', 0) create_or_update_plan_limit('project_hooks', 'default', 0)
end 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)
NOTE: **Note:** Some plans exist only on GitLab.com. You can check if the create_or_update_plan_limit('project_hooks', 'gold', 0)
migration is running on GitLab.com with `Gitlab.com?`. end
end
```
NOTE: **Note:** Some plans exist only on GitLab.com. This will be no-op
for plans that do not exist.
### Plan limits validation ### Plan limits validation
......
...@@ -45,4 +45,30 @@ describe PlanLimits do ...@@ -45,4 +45,30 @@ describe PlanLimits do
end end
end end
end end
context 'validates default values' do
let(:columns_with_zero) do
%w[
ci_active_pipelines
ci_pipeline_size
ci_active_jobs
]
end
it "has positive values for enabled limits" do
attributes = plan_limits.attributes
attributes = attributes.except(described_class.primary_key)
attributes = attributes.except(described_class.reflections.values.map(&:foreign_key))
attributes = attributes.except(*columns_with_zero)
expect(attributes).to all(include(be_positive))
end
it "has zero values for disabled limits" do
attributes = plan_limits.attributes
attributes = attributes.slice(*columns_with_zero)
expect(attributes).to all(include(be_zero))
end
end
end end
...@@ -310,10 +310,10 @@ describe Namespace do ...@@ -310,10 +310,10 @@ describe Namespace do
expect(subject).to be_kind_of(PlanLimits) expect(subject).to be_kind_of(PlanLimits)
end end
it 'has all limits disabled' do it 'has all limits defined' do
limits = subject.attributes.except('id', 'plan_id') limits = subject.attributes.except('id', 'plan_id')
limits.each do |_attribute, limit| limits.each do |_attribute, limit|
expect(limit).to be_zero expect(limit).not_to be_nil
end end
end end
end end
......
...@@ -1121,11 +1121,14 @@ into similar problems in the future (e.g. when new tables are created). ...@@ -1121,11 +1121,14 @@ into similar problems in the future (e.g. when new tables are created).
end end
def create_or_update_plan_limit(limit_name, plan_name, limit_value) def create_or_update_plan_limit(limit_name, plan_name, limit_value)
limit_name_quoted = quote_column_name(limit_name)
plan_name_quoted = quote(plan_name)
limit_value_quoted = quote(limit_value)
execute <<~SQL execute <<~SQL
INSERT INTO plan_limits (plan_id, #{quote_column_name(limit_name)}) INSERT INTO plan_limits (plan_id, #{limit_name_quoted})
VALUES SELECT id, #{limit_value_quoted} FROM plans WHERE name = #{plan_name_quoted} LIMIT 1
((SELECT id FROM plans WHERE name = #{quote(plan_name)} LIMIT 1), #{quote(limit_value)}) ON CONFLICT (plan_id) DO UPDATE SET #{limit_name_quoted} = EXCLUDED.#{limit_name_quoted};
ON CONFLICT (plan_id) DO UPDATE SET #{quote_column_name(limit_name)} = EXCLUDED.#{quote_column_name(limit_name)};
SQL SQL
end end
......
...@@ -1542,16 +1542,54 @@ describe Gitlab::Database::MigrationHelpers do ...@@ -1542,16 +1542,54 @@ describe Gitlab::Database::MigrationHelpers do
end end
describe '#create_or_update_plan_limit' do describe '#create_or_update_plan_limit' do
it 'creates or updates plan limits' do class self::Plan < ActiveRecord::Base
self.table_name = 'plans'
end
class self::PlanLimits < ActiveRecord::Base
self.table_name = 'plan_limits'
end
it 'properly escapes names' do
expect(model).to receive(:execute).with <<~SQL expect(model).to receive(:execute).with <<~SQL
INSERT INTO plan_limits (plan_id, "project_hooks") INSERT INTO plan_limits (plan_id, "project_hooks")
VALUES SELECT id, '10' FROM plans WHERE name = 'free' LIMIT 1
((SELECT id FROM plans WHERE name = 'free' LIMIT 1), '10')
ON CONFLICT (plan_id) DO UPDATE SET "project_hooks" = EXCLUDED."project_hooks"; ON CONFLICT (plan_id) DO UPDATE SET "project_hooks" = EXCLUDED."project_hooks";
SQL SQL
model.create_or_update_plan_limit('project_hooks', 'free', 10) model.create_or_update_plan_limit('project_hooks', 'free', 10)
end end
context 'when plan does not exist' do
it 'does not create any plan limits' do
expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 10) }
.not_to change { self.class::PlanLimits.count }
end
end
context 'when plan does exist' do
let!(:plan) { self.class::Plan.create!(name: 'plan_name') }
context 'when limit does not exist' do
it 'inserts a new plan limits' do
expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 10) }
.to change { self.class::PlanLimits.count }.by(1)
expect(self.class::PlanLimits.pluck(:project_hooks)).to contain_exactly(10)
end
end
context 'when limit does exist' do
let!(:plan_limit) { self.class::PlanLimits.create!(plan_id: plan.id) }
it 'updates an existing plan limits' do
expect { model.create_or_update_plan_limit('project_hooks', 'plan_name', 999) }
.not_to change { self.class::PlanLimits.count }
expect(plan_limit.reload.project_hooks).to eq(999)
end
end
end
end end
describe '#with_lock_retries' do describe '#with_lock_retries' do
......
...@@ -46,7 +46,7 @@ describe API::PipelineSchedules do ...@@ -46,7 +46,7 @@ describe API::PipelineSchedules do
get api("/projects/#{project.id}/pipeline_schedules", developer) get api("/projects/#{project.id}/pipeline_schedules", developer)
end.count end.count
create_pipeline_schedules(10) create_pipeline_schedules(5)
expect do expect do
get api("/projects/#{project.id}/pipeline_schedules", developer) get api("/projects/#{project.id}/pipeline_schedules", developer)
......
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