Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/tasks/gitlab/backup_rake_spec.rb')
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb302
1 files changed, 194 insertions, 108 deletions
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index dc112b885ae..dc74f25db87 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -4,9 +4,10 @@ require 'rake_helper'
RSpec.describe 'gitlab:app namespace rake task', :delete do
let(:enable_registry) { true }
- let(:backup_tasks) { %w{db repo uploads builds artifacts pages lfs terraform_state registry packages} }
+ let(:backup_restore_pid_path) { "#{Rails.application.root}/tmp/backup_restore.pid" }
+ let(:backup_tasks) { %w[db repo uploads builds artifacts pages lfs terraform_state registry packages] }
let(:backup_types) do
- %w{main_db repositories uploads builds artifacts pages lfs terraform_state registry packages}.tap do |array|
+ %w[main_db repositories uploads builds artifacts pages lfs terraform_state registry packages].tap do |array|
array.insert(1, 'ci_db') if Gitlab::Database.has_config?(:ci)
end
end
@@ -20,11 +21,19 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
def backup_files
- %w(backup_information.yml artifacts.tar.gz builds.tar.gz lfs.tar.gz terraform_state.tar.gz pages.tar.gz packages.tar.gz)
+ %w[
+ backup_information.yml
+ artifacts.tar.gz
+ builds.tar.gz
+ lfs.tar.gz
+ terraform_state.tar.gz
+ pages.tar.gz
+ packages.tar.gz
+ ]
end
def backup_directories
- %w(db repositories)
+ %w[db repositories]
end
before(:all) do
@@ -58,11 +67,88 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
end
+ describe 'lock parallel backups' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'when a process is running' do
+ let(:pid_file) { instance_double(File) }
+
+ it 'exits the new process' do
+ allow(File).to receive(:open).and_call_original
+ allow(File).to receive(:open).with(backup_restore_pid_path, any_args).and_yield(pid_file)
+ allow(pid_file).to receive(:read).and_return('123456')
+ allow(pid_file).to receive(:flock).with(any_args)
+
+ expect { run_rake_task('gitlab:backup:create') }.to raise_error(SystemExit).and output(
+ <<~HEREDOC
+ Backup and restore in progress:
+ There is a backup and restore task in progress. Please, try to run the current task once the previous one ends.
+ If there is no other process running, please remove the PID file manually: rm #{backup_restore_pid_path}
+ HEREDOC
+ ).to_stdout
+ end
+ end
+
+ context 'when no processes are running' do
+ let(:progress) { $stdout }
+ let(:pid_file) { instance_double(File, write: 12345) }
+
+ where(:tasks_name, :rake_task) do
+ %w[main_db ci_db] | 'gitlab:backup:db:restore'
+ 'repositories' | 'gitlab:backup:repo:restore'
+ 'builds' | 'gitlab:backup:builds:restore'
+ 'uploads' | 'gitlab:backup:uploads:restore'
+ 'artifacts' | 'gitlab:backup:artifacts:restore'
+ 'pages' | 'gitlab:backup:pages:restore'
+ 'lfs' | 'gitlab:backup:lfs:restore'
+ 'terraform_state' | 'gitlab:backup:terraform_state:restore'
+ 'registry' | 'gitlab:backup:registry:restore'
+ 'packages' | 'gitlab:backup:packages:restore'
+ end
+
+ with_them do
+ before do
+ allow(Kernel).to receive(:system).and_return(true)
+ allow(YAML).to receive(:load_file).and_return({ gitlab_version: Gitlab::VERSION })
+ allow(File).to receive(:delete).with(backup_restore_pid_path).and_return(1)
+ allow(File).to receive(:open).and_call_original
+ allow(File).to receive(:open).with(backup_restore_pid_path, any_args).and_yield(pid_file)
+ allow(pid_file).to receive(:read).and_return('')
+ allow(pid_file).to receive(:flock).with(any_args)
+ allow(pid_file).to receive(:write).with(12345).and_return(true)
+ allow(pid_file).to receive(:flush)
+ allow(progress).to receive(:puts).at_least(:once)
+
+ allow_next_instance_of(::Backup::Manager) do |instance|
+ Array(tasks_name).each do |task|
+ allow(instance).to receive(:run_restore_task).with(task)
+ end
+ end
+ end
+
+ it 'locks the PID file' do
+ expect(pid_file).to receive(:flock).with(File::LOCK_EX)
+ expect(pid_file).to receive(:flock).with(File::LOCK_UN)
+
+ run_rake_task(rake_task)
+ end
+
+ it 'deletes the PID file and logs a message' do
+ expect(File).to receive(:delete).with(backup_restore_pid_path)
+ expect(progress).to receive(:puts).with(/-- Deleting backup and restore lock file/)
+
+ run_rake_task(rake_task)
+ end
+ end
+ end
+ end
+
describe 'backup_restore' do
- context 'gitlab version' do
+ context 'with gitlab version' do
before do
allow(Dir).to receive(:glob).and_return(['1_gitlab_backup.tar'])
allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:exist?).with(backup_restore_pid_path).and_return(false)
allow(Kernel).to receive(:system).and_return(true)
allow(FileUtils).to receive(:cp_r).and_return(true)
allow(FileUtils).to receive(:mv).and_return(true)
@@ -72,7 +158,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
let(:gitlab_version) { Gitlab::VERSION }
- context 'restore with matching gitlab version' do
+ context 'when restore matches gitlab version' do
before do
allow(YAML).to receive(:load_file)
.and_return({ gitlab_version: gitlab_version })
@@ -124,6 +210,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
backup_tar = Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar')).last
allow(Dir).to receive(:glob).and_return([backup_tar])
allow(File).to receive(:exist?).and_return(true)
+ allow(File).to receive(:exist?).with(backup_restore_pid_path).and_return(false)
allow(Kernel).to receive(:system).and_return(true)
allow(FileUtils).to receive(:cp_r).and_return(true)
allow(FileUtils).to receive(:mv).and_return(true)
@@ -161,74 +248,42 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
let!(:project) { create(:project, :repository) }
- describe 'backup creation and deletion using custom_hooks' do
- let(:user_backup_path) { "repositories/#{project.disk_path}" }
-
+ context 'with specific backup tasks' do
before do
stub_env('SKIP', 'db')
- path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(project.repository.path_to_repo, 'custom_hooks')
- end
- FileUtils.mkdir_p(path)
- FileUtils.touch(File.join(path, "dummy.txt"))
end
- context 'project uses custom_hooks and successfully creates backup' do
- it 'creates custom_hooks.tar and project bundle' do
- expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
-
- tar_contents, exit_status = Gitlab::Popen.popen(%W{tar -tvf #{backup_tar}})
-
- expect(exit_status).to eq(0)
- expect(tar_contents).to match(user_backup_path)
- expect(tar_contents).to match("#{user_backup_path}/.+/001.custom_hooks.tar")
- expect(tar_contents).to match("#{user_backup_path}/.+/001.bundle")
- end
-
- it 'restores files correctly' do
- expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
- expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout_from_any_process
-
- repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- project.repository.path
- end
- expect(Dir.entries(File.join(repo_path, 'custom_hooks'))).to include("dummy.txt")
+ it 'prints a progress message to stdout' do
+ backup_tasks.each do |task|
+ expect { run_rake_task("gitlab:backup:#{task}:create") }.to output(/Dumping /).to_stdout_from_any_process
end
end
- context 'specific backup tasks' do
- it 'prints a progress message to stdout' do
- backup_tasks.each do |task|
- expect { run_rake_task("gitlab:backup:#{task}:create") }.to output(/Dumping /).to_stdout_from_any_process
- end
- end
-
- it 'logs the progress to log file' do
- ci_database_status = Gitlab::Database.has_config?(:ci) ? "[SKIPPED]" : "[DISABLED]"
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping main_database ... [SKIPPED]")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping ci_database ... #{ci_database_status}")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping repositories ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping repositories ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping uploads ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping uploads ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping builds ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping builds ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping artifacts ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping artifacts ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping pages ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping pages ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... done")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... ")
- expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... done")
-
- backup_tasks.each do |task|
- run_rake_task("gitlab:backup:#{task}:create")
- end
+ it 'logs the progress to log file' do
+ ci_database_status = Gitlab::Database.has_config?(:ci) ? "[SKIPPED]" : "[DISABLED]"
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping main_database ... [SKIPPED]")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping ci_database ... #{ci_database_status}")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping repositories ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping repositories ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping uploads ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping uploads ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping builds ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping builds ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping artifacts ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping artifacts ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping pages ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping pages ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... done")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... ")
+ expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... done")
+
+ backup_tasks.each do |task|
+ run_rake_task("gitlab:backup:#{task}:create")
end
end
end
@@ -264,18 +319,18 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
end
- context 'tar creation' do
- context 'archive file permissions' do
+ context 'with tar creation' do
+ context 'with archive file permissions' do
it 'sets correct permissions on the tar file' do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
- expect(File.exist?(backup_tar)).to be_truthy
+ expect(File).to exist(backup_tar)
expect(File::Stat.new(backup_tar).mode.to_s(8)).to eq('100600')
end
context 'with custom archive_permissions' do
before do
- allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0651)
+ allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0o651)
end
it 'uses the custom permissions' do
@@ -290,11 +345,21 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz packages.tar.gz}
+ %W[
+ tar -tvf #{backup_tar}
+ db
+ uploads.tar.gz
+ repositories
+ builds.tar.gz
+ artifacts.tar.gz
+ pages.tar.gz
+ lfs.tar.gz
+ terraform_state.tar.gz
+ registry.tar.gz
+ packages.tar.gz
+ ]
)
- puts "CONTENT: #{tar_contents}"
-
expect(exit_status).to eq(0)
expect(tar_contents).to match('db')
expect(tar_contents).to match('uploads.tar.gz')
@@ -306,27 +371,31 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(tar_contents).to match('terraform_state.tar.gz')
expect(tar_contents).to match('registry.tar.gz')
expect(tar_contents).to match('packages.tar.gz')
- expect(tar_contents).not_to match(%r{^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|pages.tar.gz|artifacts.tar.gz|registry.tar.gz)/$})
+ expect(tar_contents).not_to match(%r{^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|
+ pages.tar.gz|artifacts.tar.gz|registry.tar.gz)/$})
end
it 'deletes temp directories' do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
temp_dirs = Dir.glob(
- File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry,packages}')
+ File.join(
+ Gitlab.config.backup.path,
+ '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry,packages}'
+ )
)
expect(temp_dirs).to be_empty
end
- context 'registry disabled' do
+ context 'when registry is disabled' do
let(:enable_registry) { false }
it 'does not create registry.tar.gz' do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar}}
+ %W[tar -tvf #{backup_tar}]
)
expect(exit_status).to eq(0)
@@ -335,7 +404,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
end
- context 'multiple repository storages' do
+ context 'with multiple repository storages' do
include StubConfiguration
let(:default_storage_name) { 'default' }
@@ -344,10 +413,10 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
before do
# We only need a backup of the repositories for this test
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
- stub_storage_settings( second_storage_name => {
- 'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address,
- 'path' => TestEnv::SECOND_STORAGE_PATH
- })
+ stub_storage_settings(second_storage_name => {
+ 'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address,
+ 'path' => TestEnv::SECOND_STORAGE_PATH
+ })
end
shared_examples 'includes repositories in all repository storages' do
@@ -368,27 +437,27 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar} repositories}
+ %W[tar -tvf #{backup_tar} repositories]
)
tar_lines = tar_contents.lines.grep(/\.bundle/)
expect(exit_status).to eq(0)
- [
- "#{project_a.disk_path}/.+/001.bundle",
- "#{project_a.disk_path}.wiki/.+/001.bundle",
- "#{project_a.disk_path}.design/.+/001.bundle",
- "#{project_b.disk_path}/.+/001.bundle",
- "#{project_snippet_a.disk_path}/.+/001.bundle",
- "#{project_snippet_b.disk_path}/.+/001.bundle"
+ %W[
+ #{project_a.disk_path}/.+/001.bundle
+ #{project_a.disk_path}.wiki/.+/001.bundle
+ #{project_a.disk_path}.design/.+/001.bundle
+ #{project_b.disk_path}/.+/001.bundle
+ #{project_snippet_a.disk_path}/.+/001.bundle
+ #{project_snippet_b.disk_path}/.+/001.bundle
].each do |repo_name|
expect(tar_lines).to include(a_string_matching(repo_name))
end
end
end
- context 'no concurrency' do
+ context 'with no concurrency' do
it_behaves_like 'includes repositories in all repository storages'
end
@@ -400,7 +469,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
it_behaves_like 'includes repositories in all repository storages'
end
- context 'REPOSITORIES_STORAGES set' do
+ context 'when REPOSITORIES_STORAGES is set' do
before do
stub_env('REPOSITORIES_STORAGES', default_storage_name)
end
@@ -422,25 +491,25 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar} repositories}
+ %W[tar -tvf #{backup_tar} repositories]
)
tar_lines = tar_contents.lines.grep(/\.bundle/)
expect(exit_status).to eq(0)
- [
- "#{project_a.disk_path}/.+/001.bundle",
- "#{project_a.disk_path}.wiki/.+/001.bundle",
- "#{project_a.disk_path}.design/.+/001.bundle",
- "#{project_snippet_a.disk_path}/.+/001.bundle"
+ %W[
+ #{project_a.disk_path}/.+/001.bundle
+ #{project_a.disk_path}.wiki/.+/001.bundle
+ #{project_a.disk_path}.design/.+/001.bundle
+ #{project_snippet_a.disk_path}/.+/001.bundle
].each do |repo_name|
expect(tar_lines).to include(a_string_matching(repo_name))
end
- [
- "#{project_b.disk_path}/.+/001.bundle",
- "#{project_snippet_b.disk_path}/.+/001.bundle"
+ %W[
+ #{project_b.disk_path}/.+/001.bundle
+ #{project_snippet_b.disk_path}/.+/001.bundle
].each do |repo_name|
expect(tar_lines).not_to include(a_string_matching(repo_name))
end
@@ -448,7 +517,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
end
- context 'concurrency settings' do
+ context 'with concurrency settings' do
before do
# We only need a backup of the repositories for this test
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
@@ -463,13 +532,18 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(::Backup::Repositories).to receive(:new)
.with(anything, strategy: anything, storages: [], paths: [])
.and_call_original
- expect(::Backup::GitalyBackup).to receive(:new).with(anything, max_parallelism: 5, storage_parallelism: 2, incremental: false).and_call_original
+ expect(::Backup::GitalyBackup).to receive(:new).with(
+ anything,
+ max_parallelism: 5,
+ storage_parallelism: 2,
+ incremental: false
+ ).and_call_original
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
end
end
- context 'CRON env is set' do
+ context 'when CRON env is set' do
before do
stub_env('CRON', '1')
end
@@ -481,7 +555,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
# backup_create task
- describe "Skipping items in a backup" do
+ describe "skipping items in a backup" do
before do
stub_env('SKIP', 'an-unknown-type,repositories,uploads,anotherunknowntype')
@@ -492,7 +566,19 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, _exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz registry.tar.gz packages.tar.gz}
+ %W[
+ tar -tvf #{backup_tar}
+ db
+ uploads.tar.gz
+ repositories
+ builds.tar.gz
+ artifacts.tar.gz
+ pages.tar.gz
+ lfs.tar.gz
+ terraform_state.tar.gz
+ registry.tar.gz
+ packages.tar.gz
+ ]
)
expect(tar_contents).to match('db/')
@@ -515,7 +601,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
.to receive(:invoke).and_return(true)
expect_next_instance_of(::Backup::Manager) do |instance|
- (backup_types - %w{repositories uploads}).each do |subtask|
+ (backup_types - %w[repositories uploads]).each do |subtask|
expect(instance).to receive(:run_restore_task).with(subtask).ordered
end
expect(instance).not_to receive(:run_restore_task)