Skip to content

Commit 5aa89af

Browse files
rutgerwbalasankarc
authored andcommitted
Add gitlab-ctl command for migrating to decomposed database setup
Changelog: added
1 parent 0482fb3 commit 5aa89af

File tree

3 files changed

+299
-0
lines changed

3 files changed

+299
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
require 'io/console'
2+
3+
class PostgreSQL
4+
class DecompositionMigration
5+
def initialize(ctl)
6+
@ctl = ctl
7+
end
8+
9+
def migrate!
10+
unless @ctl.service_enabled?('postgresql')
11+
puts 'There is no PostgreSQL instance enabled in Omnibus, exiting...'
12+
exit 1
13+
end
14+
15+
puts <<~MSG
16+
This script will migrate this GitLab instance to a two-database setup.
17+
18+
WARNING:
19+
- This script is experimental. See https://docs.gitlab.com/ee/administration/postgresql/multiple_databases.html
20+
- Once migrated to a two-database setup, you cannot migrate it back.
21+
22+
Ensure:
23+
- The new database 'gitlabhq_production_ci' has been created, for example:
24+
25+
gitlab-psql -c "CREATE DATABASE gitlabhq_production_ci WITH OWNER 'gitlab'"
26+
27+
- The following changes are added to /etc/gitlab/gitlab.rb configuration file
28+
but do **not** run 'gitlab-ctl reconfigure' yet:
29+
30+
gitlab_rails['env'] = { 'GITLAB_ALLOW_SEPARATE_CI_DATABASE' => 'true' }
31+
gitlab_rails['databases']['ci']['enable'] = true
32+
gitlab_rails['databases']['ci']['db_database'] = 'gitlabhq_production_ci'
33+
34+
This script will:
35+
- Disable background migrations because they should not be active during this migration
36+
See https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#enable-or-disable-background-migrations
37+
- Stop the Gitlab Instance
38+
- Copy data in gitlabhq_production to gitlabhq_production_ci (by dumping, then restoring)
39+
- Apply configuration changes in /etc/gitlab/gitlab.rb using 'gitlab-ctl reconfigure'
40+
- Prevent errorneous database access
41+
- Re-enable background migrations
42+
- Restart GitLab
43+
44+
This script will not:
45+
- Clean up data in the databases
46+
47+
Please confirm the upgrade by pressing 'y':
48+
MSG
49+
50+
prompt = $stdin.gets.chomp
51+
52+
exit(1) unless prompt.casecmp('y').zero?
53+
54+
disable_background_migrations unless background_migrations_initally_disabled?
55+
stop_gitlab_services
56+
run_migration
57+
post_migrate
58+
59+
puts <<~MSG
60+
GitLab is now running on two databases. Data related to CI is now written to the ci
61+
database.
62+
63+
You can also remove duplicated data by running:
64+
'sudo gitlab-rake gitlab:db:truncate_legacy_tables:main'
65+
'sudo gitlab-rake gitlab:db:truncate_legacy_tables:ci'
66+
67+
MSG
68+
end
69+
70+
private
71+
72+
def background_migrations_initally_disabled?
73+
@background_migrations_initally_disabled ||= GitlabCtl::Util.run_command(
74+
'gitlab-rails runner "puts (Feature.disabled?(:execute_background_migrations, type: :ops) && Feature.disabled?(:execute_batched_migrations_on_schedule, type: :ops)).to_s"'
75+
).stdout.chomp == "true"
76+
end
77+
78+
def disable_background_migrations
79+
puts "Disabling Background Migrations..."
80+
run_command <<~CMD
81+
gitlab-rails runner "Feature.disable(:execute_background_migrations) && Feature.disable(:execute_batched_migrations_on_schedule)"
82+
CMD
83+
end
84+
85+
def enable_background_migrations
86+
puts "Enabling Background Migrations..."
87+
run_command <<~CMD
88+
gitlab-rails runner "Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)"
89+
CMD
90+
end
91+
92+
def stop_gitlab_services
93+
puts "Stopping GitLab..."
94+
run_command("gitlab-ctl stop && gitlab-ctl start postgresql")
95+
end
96+
97+
def run_migration
98+
puts "Copying data to new database..."
99+
run_command("gitlab-rake gitlab:db:decomposition:migrate")
100+
end
101+
102+
def post_migrate
103+
puts "Reconfigure GitLab..."
104+
run_command("gitlab-ctl reconfigure")
105+
puts "Enable write locks..."
106+
run_command("gitlab-rake gitlab:db:lock_writes")
107+
enable_background_migrations unless background_migrations_initally_disabled?
108+
puts "Restarting GitLab..."
109+
run_command("gitlab-ctl restart")
110+
end
111+
112+
def run_command(cmd)
113+
GitlabCtl::Util.run_command(cmd).tap do |status|
114+
if status.error?
115+
enable_background_migrations unless background_migrations_initally_disabled?
116+
117+
puts status.stdout
118+
puts status.stderr
119+
puts "[ERROR] Failed to execute: #{cmd}"
120+
puts "This GitLab instance is still disabled."
121+
122+
exit 1
123+
end
124+
end
125+
end
126+
end
127+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require "#{base_path}/embedded/service/omnibus-ctl/lib/postgresql/decomposition_migration"
2+
3+
add_command_under_category('pg-decomposition-migration', 'database', 'Migrate database to two-database setup', 2) do |_cmd, user|
4+
PostgreSQL::DecompositionMigration.new(self).migrate!
5+
end
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
require 'spec_helper'
2+
$LOAD_PATH << File.join(__dir__, '../../../../files/gitlab-ctl-commands/lib')
3+
4+
require 'gitlab_ctl/util'
5+
require 'postgresql/decomposition_migration'
6+
7+
RSpec.describe PostgreSQL::DecompositionMigration do
8+
let(:ctl) { spy('gitlab ctl') }
9+
let(:confirmation) { StringIO.new('y') }
10+
let(:command_ok) { spy('command spy', error?: false) }
11+
let(:command_fail) { spy('command spy', error?: true) }
12+
let(:migrations_disabled) { false }
13+
14+
describe '#migrate!' do
15+
subject(:instance) { described_class.new(ctl) }
16+
17+
before do
18+
allow(ctl).to receive(:service_enabled?).with('postgresql').and_return(true)
19+
instance.instance_variable_set(:@background_migrations_initally_disabled, migrations_disabled)
20+
21+
$stdin = confirmation
22+
end
23+
24+
after do
25+
$stdin = STDIN
26+
end
27+
28+
context 'when PostgreSQL is not enabled' do
29+
before do
30+
allow(ctl).to receive(:service_enabled?).with('postgresql').and_return(false)
31+
end
32+
33+
it 'exits' do
34+
expect { instance.migrate! }.to raise_error(SystemExit)
35+
end
36+
end
37+
38+
context 'when user does not confirm running the script' do
39+
let(:confirmation) { StringIO.new('n') }
40+
41+
it 'exits' do
42+
expect { instance.migrate! }.to raise_error(SystemExit)
43+
end
44+
end
45+
46+
context 'when external command fails' do
47+
before do
48+
allow(GitlabCtl::Util).to receive(:run_command).and_return(command_fail)
49+
allow(GitlabCtl::Util).to receive(:run_command).with(
50+
"gitlab-rails runner \"Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)\"\n"
51+
).and_return(command_ok)
52+
end
53+
54+
context 'and background migrations are enabled before starting this script' do
55+
it 'enables background migrations and then exits' do
56+
expect(GitlabCtl::Util).to receive(:run_command).with(
57+
"gitlab-rails runner \"Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)\"\n"
58+
).and_return(command_ok)
59+
60+
expect { instance.migrate! }.to raise_error(SystemExit)
61+
end
62+
end
63+
64+
context 'and background migrations are disabled before starting this script' do
65+
let(:migrations_disabled) { true }
66+
67+
it 'exits without enabling background migrations' do
68+
expect(GitlabCtl::Util).not_to receive(:run_command).with(
69+
"gitlab-rails runner \"Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)\"\n"
70+
)
71+
72+
expect { instance.migrate! }.to raise_error(SystemExit)
73+
end
74+
end
75+
end
76+
77+
context 'runs commands needed for migration to decomposed setup' do
78+
before do
79+
allow(GitlabCtl::Util).to receive(:run_command).and_return(command_ok)
80+
end
81+
82+
context 'and background migrations are enabled before starting this script' do
83+
it 'disables background migrations' do
84+
expect(GitlabCtl::Util).to receive(:run_command).with(
85+
"gitlab-rails runner \"Feature.disable(:execute_background_migrations) && Feature.disable(:execute_batched_migrations_on_schedule)\"\n"
86+
).and_return(command_ok)
87+
88+
instance.migrate!
89+
end
90+
end
91+
92+
context 'and background migrations are disabled before starting this script' do
93+
let(:migrations_disabled) { true }
94+
95+
it 'does not not disable background migration' do
96+
expect(GitlabCtl::Util).not_to receive(:run_command).with(
97+
"gitlab-rails runner \"Feature.disable(:execute_background_migrations) && Feature.disable(:execute_batched_migrations_on_schedule)\"\n"
98+
)
99+
100+
instance.migrate!
101+
end
102+
end
103+
104+
it 'stops Gitlab except for PostgreSQL' do
105+
expect(GitlabCtl::Util).to receive(:run_command).with(
106+
"gitlab-ctl stop && gitlab-ctl start postgresql"
107+
).and_return(command_ok)
108+
109+
instance.migrate!
110+
end
111+
112+
it 'calls the migration rake task' do
113+
expect(GitlabCtl::Util).to receive(:run_command).with(
114+
"gitlab-rake gitlab:db:decomposition:migrate"
115+
).and_return(command_ok)
116+
117+
instance.migrate!
118+
end
119+
120+
it 'runs the reconfigure task' do
121+
expect(GitlabCtl::Util).to receive(:run_command).with(
122+
"gitlab-ctl reconfigure"
123+
).and_return(command_ok)
124+
125+
instance.migrate!
126+
end
127+
128+
it 'enables write locks' do
129+
expect(GitlabCtl::Util).to receive(:run_command).with(
130+
"gitlab-rake gitlab:db:lock_writes"
131+
).and_return(command_ok)
132+
133+
instance.migrate!
134+
end
135+
136+
it 'restarts GitLab' do
137+
expect(GitlabCtl::Util).to receive(:run_command).with(
138+
"gitlab-ctl restart"
139+
).and_return(command_ok)
140+
141+
instance.migrate!
142+
end
143+
144+
context 'and background migrations are enabled before starting this script' do
145+
it 'enables background migrations' do
146+
expect(GitlabCtl::Util).to receive(:run_command).with(
147+
"gitlab-rails runner \"Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)\"\n"
148+
).and_return(command_ok)
149+
150+
instance.migrate!
151+
end
152+
end
153+
154+
context 'and background migrations are disabled before starting this script' do
155+
let(:migrations_disabled) { true }
156+
157+
it 'does not not enable background migration' do
158+
expect(GitlabCtl::Util).not_to receive(:run_command).with(
159+
"gitlab-rails runner \"Feature.enable(:execute_background_migrations) && Feature.enable(:execute_batched_migrations_on_schedule)\"\n"
160+
)
161+
162+
instance.migrate!
163+
end
164+
end
165+
end
166+
end
167+
end

0 commit comments

Comments
 (0)