Commit 37cffa16 authored by Pavel Shutsin's avatar Pavel Shutsin

Merge branch '332006-backup-package-registry-files' into 'master'

Resolve "Backup Package registry files"

See merge request gitlab-org/gitlab!77532
parents 62403975 7d89a228
...@@ -463,7 +463,7 @@ db:backup_and_restore: ...@@ -463,7 +463,7 @@ db:backup_and_restore:
script: script:
- . scripts/prepare_build.sh - . scripts/prepare_build.sh
- bundle exec rake db:drop db:create db:structure:load db:seed_fu - bundle exec rake db:drop db:create db:structure:load db:seed_fu
- mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry} - mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry,packages}
- bundle exec rake gitlab:backup:create - bundle exec rake gitlab:backup:create
- date - date
- bundle exec rake gitlab:backup:restore - bundle exec rake gitlab:backup:restore
......
...@@ -61,12 +61,12 @@ including: ...@@ -61,12 +61,12 @@ including:
- Terraform states ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331806) in GitLab 14.7) - Terraform states ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/331806) in GitLab 14.7)
- Container Registry images - Container Registry images
- GitLab Pages content - GitLab Pages content
- Packages ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332006) in GitLab 14.7)
- Snippets - Snippets
- [Group wikis](../user/project/wiki/group.md) - [Group wikis](../user/project/wiki/group.md)
Backups do not include: Backups do not include:
- [Package registry files](../administration/packages/index.md)
- [Mattermost data](https://docs.mattermost.com/administration/config-settings.html#file-storage) - [Mattermost data](https://docs.mattermost.com/administration/config-settings.html#file-storage)
WARNING: WARNING:
...@@ -276,6 +276,7 @@ You can exclude specific directories from the backup by adding the environment v ...@@ -276,6 +276,7 @@ You can exclude specific directories from the backup by adding the environment v
- `registry` (Container Registry images) - `registry` (Container Registry images)
- `pages` (Pages content) - `pages` (Pages content)
- `repositories` (Git repositories data) - `repositories` (Git repositories data)
- `packages` (Packages)
All wikis are backed up as part of the `repositories` group. Non-existent wikis are skipped during a backup. All wikis are backed up as part of the `repositories` group. Non-existent wikis are skipped during a backup.
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module Backup module Backup
class Manager class Manager
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs terraform_state registry].freeze ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs terraform_state registry packages].freeze
FOLDERS_TO_BACKUP = %w[repositories db].freeze FOLDERS_TO_BACKUP = %w[repositories db].freeze
FILE_NAME_SUFFIX = '_gitlab_backup.tar' FILE_NAME_SUFFIX = '_gitlab_backup.tar'
......
# frozen_string_literal: true
module Backup
class Packages < Backup::Files
attr_reader :progress
def initialize(progress)
@progress = progress
super('packages', Settings.packages.storage_path, excludes: ['tmp'])
end
end
end
...@@ -9,15 +9,9 @@ namespace :gitlab do ...@@ -9,15 +9,9 @@ namespace :gitlab do
task create: :gitlab_environment do task create: :gitlab_environment do
warn_user_is_not_gitlab warn_user_is_not_gitlab
Rake::Task['gitlab:backup:db:create'].invoke %w(db repo uploads builds artifacts pages lfs terraform_state registry packages).each do |type|
Rake::Task['gitlab:backup:repo:create'].invoke Rake::Task["gitlab:backup:#{type}:create"].invoke
Rake::Task['gitlab:backup:uploads:create'].invoke end
Rake::Task['gitlab:backup:builds:create'].invoke
Rake::Task['gitlab:backup:artifacts:create'].invoke
Rake::Task['gitlab:backup:pages:create'].invoke
Rake::Task['gitlab:backup:lfs:create'].invoke
Rake::Task['gitlab:backup:terraform_state:create'].invoke
Rake::Task['gitlab:backup:registry:create'].invoke
backup = Backup::Manager.new(progress) backup = Backup::Manager.new(progress)
backup.write_info backup.write_info
...@@ -86,6 +80,7 @@ namespace :gitlab do ...@@ -86,6 +80,7 @@ namespace :gitlab do
Rake::Task['gitlab:backup:lfs:restore'].invoke unless backup.skipped?('lfs') Rake::Task['gitlab:backup:lfs:restore'].invoke unless backup.skipped?('lfs')
Rake::Task['gitlab:backup:terraform_state:restore'].invoke unless backup.skipped?('terraform_state') Rake::Task['gitlab:backup:terraform_state:restore'].invoke unless backup.skipped?('terraform_state')
Rake::Task['gitlab:backup:registry:restore'].invoke unless backup.skipped?('registry') Rake::Task['gitlab:backup:registry:restore'].invoke unless backup.skipped?('registry')
Rake::Task['gitlab:backup:packages:restore'].invoke unless backup.skipped?('packages')
Rake::Task['gitlab:shell:setup'].invoke Rake::Task['gitlab:shell:setup'].invoke
Rake::Task['cache:clear'].invoke Rake::Task['cache:clear'].invoke
...@@ -331,6 +326,25 @@ namespace :gitlab do ...@@ -331,6 +326,25 @@ namespace :gitlab do
end end
end end
namespace :packages do
task create: :gitlab_environment do
puts_time "Dumping packages ... ".color(:blue)
if ENV['SKIP'] && ENV['SKIP'].include?('packages')
puts_time "[SKIPPED]".color(:cyan)
else
Backup::Packages.new(progress).dump
puts_time "done".color(:green)
end
end
task restore: :gitlab_environment do
puts_time "Restoring packages ...".color(:blue)
Backup::Packages.new(progress).restore
puts_time "done".color(:green)
end
end
def puts_time(msg) def puts_time(msg)
progress.puts "#{Time.now} -- #{msg}" progress.puts "#{Time.now} -- #{msg}"
Gitlab::BackupLogger.info(message: "#{Rainbow.uncolor(msg)}") Gitlab::BackupLogger.info(message: "#{Rainbow.uncolor(msg)}")
......
...@@ -15,7 +15,7 @@ RSpec.describe Backup::Manager do ...@@ -15,7 +15,7 @@ RSpec.describe Backup::Manager do
end end
describe '#pack' do describe '#pack' do
let(:expected_backup_contents) { %w(repositories db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml) } let(:expected_backup_contents) { %w(repositories db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml) }
let(:tar_file) { '1546300800_2019_01_01_12.3_gitlab_backup.tar' } let(:tar_file) { '1546300800_2019_01_01_12.3_gitlab_backup.tar' }
let(:tar_system_options) { { out: [tar_file, 'w', Gitlab.config.backup.archive_permissions] } } let(:tar_system_options) { { out: [tar_file, 'w', Gitlab.config.backup.archive_permissions] } }
let(:tar_cmdline) { ['tar', '-cf', '-', *expected_backup_contents, tar_system_options] } let(:tar_cmdline) { ['tar', '-cf', '-', *expected_backup_contents, tar_system_options] }
...@@ -57,7 +57,7 @@ RSpec.describe Backup::Manager do ...@@ -57,7 +57,7 @@ RSpec.describe Backup::Manager do
end end
context 'when skipped is set in backup_information.yml' do context 'when skipped is set in backup_information.yml' do
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml} } let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml} }
let(:backup_information) do let(:backup_information) do
{ {
backup_created_at: Time.zone.parse('2019-01-01'), backup_created_at: Time.zone.parse('2019-01-01'),
...@@ -74,7 +74,7 @@ RSpec.describe Backup::Manager do ...@@ -74,7 +74,7 @@ RSpec.describe Backup::Manager do
end end
context 'when a directory does not exist' do context 'when a directory does not exist' do
let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz backup_information.yml} } let(:expected_backup_contents) { %w{db uploads.tar.gz builds.tar.gz artifacts.tar.gz pages.tar.gz lfs.tar.gz terraform_state.tar.gz packages.tar.gz backup_information.yml} }
before do before do
expect(Dir).to receive(:exist?).with(File.join(Gitlab.config.backup.path, 'repositories')).and_return(false) expect(Dir).to receive(:exist?).with(File.join(Gitlab.config.backup.path, 'repositories')).and_return(false)
......
...@@ -2,26 +2,35 @@ ...@@ -2,26 +2,35 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Backup::TerraformState do RSpec.shared_examples 'backup object' do |setting|
let(:progress) { StringIO.new } let(:progress) { StringIO.new }
let(:backup_path) { "/var/#{setting}" }
subject(:backup) { described_class.new(progress) } subject(:backup) { described_class.new(progress) }
describe '#dump' do describe '#dump' do
before do before do
allow(File).to receive(:realpath).and_call_original allow(File).to receive(:realpath).and_call_original
allow(File).to receive(:realpath).with('/var/terraform_state').and_return('/var/terraform_state') allow(File).to receive(:realpath).with(backup_path).and_return(backup_path)
allow(File).to receive(:realpath).with('/var/terraform_state/..').and_return('/var') allow(File).to receive(:realpath).with("#{backup_path}/..").and_return('/var')
allow(Settings.terraform_state).to receive(:storage_path).and_return('/var/terraform_state') allow(Settings.send(setting)).to receive(:storage_path).and_return(backup_path)
end end
it 'uses the correct storage dir in tar command and excludes tmp', :aggregate_failures do it 'uses the correct storage dir in tar command and excludes tmp', :aggregate_failures do
expect(backup.app_files_dir).to eq('/var/terraform_state') expect(backup.app_files_dir).to eq(backup_path)
expect(backup).to receive(:tar).and_return('blabla-tar') expect(backup).to receive(:tar).and_return('blabla-tar')
expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found --exclude=./tmp -C /var/terraform_state -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], '']) expect(backup).to receive(:run_pipeline!).with([%W(blabla-tar --exclude=lost+found --exclude=./tmp -C #{backup_path} -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], ''])
expect(backup).to receive(:pipeline_succeeded?).and_return(true) expect(backup).to receive(:pipeline_succeeded?).and_return(true)
backup.dump backup.dump
end end
end end
end end
RSpec.describe Backup::Packages do
it_behaves_like 'backup object', 'packages'
end
RSpec.describe Backup::TerraformState do
it_behaves_like 'backup object', 'terraform_state'
end
...@@ -150,6 +150,7 @@ module TestEnv ...@@ -150,6 +150,7 @@ module TestEnv
FileUtils.mkdir_p(artifacts_path) FileUtils.mkdir_p(artifacts_path)
FileUtils.mkdir_p(lfs_path) FileUtils.mkdir_p(lfs_path)
FileUtils.mkdir_p(terraform_state_path) FileUtils.mkdir_p(terraform_state_path)
FileUtils.mkdir_p(packages_path)
end end
def setup_gitlab_shell def setup_gitlab_shell
...@@ -424,6 +425,10 @@ module TestEnv ...@@ -424,6 +425,10 @@ module TestEnv
Gitlab.config.terraform_state.storage_path Gitlab.config.terraform_state.storage_path
end end
def packages_path
Gitlab.config.packages.storage_path
end
# When no cached assets exist, manually hit the root path to create them # When no cached assets exist, manually hit the root path to create them
# #
# Otherwise they'd be created by the first test, often timing out and # Otherwise they'd be created by the first test, often timing out and
......
...@@ -4,7 +4,7 @@ require 'rake_helper' ...@@ -4,7 +4,7 @@ require 'rake_helper'
RSpec.describe 'gitlab:app namespace rake task', :delete do RSpec.describe 'gitlab:app namespace rake task', :delete do
let(:enable_registry) { true } let(:enable_registry) { true }
let(:backup_types) { %w{db repo uploads builds artifacts pages lfs terraform_state registry} } let(:backup_types) { %w{db repo uploads builds artifacts pages lfs terraform_state registry packages} }
def tars_glob def tars_glob
Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar')) Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar'))
...@@ -15,7 +15,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -15,7 +15,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end end
def backup_files def backup_files
%w(backup_information.yml artifacts.tar.gz builds.tar.gz lfs.tar.gz terraform_state.tar.gz pages.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 end
def backup_directories def backup_directories
...@@ -137,6 +137,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -137,6 +137,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive(:invoke) expect(Rake::Task['gitlab:backup:lfs:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive(:invoke) expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:backup:registry:restore']).to receive(:invoke) expect(Rake::Task['gitlab:backup:registry:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:backup:packages:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke) expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke)
end end
...@@ -213,7 +214,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -213,7 +214,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... ") expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping lfs objects ... ")
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... ") expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping terraform states ... ")
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... ") expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping container registry images ... ")
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(8).times expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping packages ... ")
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(9).times
backup_types.each do |task| backup_types.each do |task|
run_rake_task("gitlab:backup:#{task}:create") run_rake_task("gitlab:backup:#{task}:create")
...@@ -279,9 +281,11 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -279,9 +281,11 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, exit_status = Gitlab::Popen.popen( 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} %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(exit_status).to eq(0)
expect(tar_contents).to match('db') expect(tar_contents).to match('db')
expect(tar_contents).to match('uploads.tar.gz') expect(tar_contents).to match('uploads.tar.gz')
...@@ -292,6 +296,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -292,6 +296,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(tar_contents).to match('lfs.tar.gz') expect(tar_contents).to match('lfs.tar.gz')
expect(tar_contents).to match('terraform_state.tar.gz') expect(tar_contents).to match('terraform_state.tar.gz')
expect(tar_contents).to match('registry.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 end
...@@ -299,7 +304,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -299,7 +304,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
temp_dirs = Dir.glob( temp_dirs = Dir.glob(
File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry}') File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry,packages}')
) )
expect(temp_dirs).to be_empty expect(temp_dirs).to be_empty
...@@ -461,7 +466,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -461,7 +466,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
tar_contents, _exit_status = Gitlab::Popen.popen( 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} %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/') expect(tar_contents).to match('db/')
...@@ -472,6 +477,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -472,6 +477,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(tar_contents).to match('terraform_state.tar.gz') expect(tar_contents).to match('terraform_state.tar.gz')
expect(tar_contents).to match('pages.tar.gz') expect(tar_contents).to match('pages.tar.gz')
expect(tar_contents).to match('registry.tar.gz') expect(tar_contents).to match('registry.tar.gz')
expect(tar_contents).to match('packages.tar.gz')
expect(tar_contents).not_to match('repositories/') expect(tar_contents).not_to match('repositories/')
expect(tar_contents).to match('repositories: Not found in archive') expect(tar_contents).to match('repositories: Not found in archive')
end end
...@@ -492,6 +498,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -492,6 +498,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive :invoke expect(Rake::Task['gitlab:backup:lfs:restore']).to receive :invoke
expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive :invoke expect(Rake::Task['gitlab:backup:terraform_state:restore']).to receive :invoke
expect(Rake::Task['gitlab:backup:registry:restore']).to receive :invoke expect(Rake::Task['gitlab:backup:registry:restore']).to receive :invoke
expect(Rake::Task['gitlab:backup:packages:restore']).to receive :invoke
expect(Rake::Task['gitlab:shell:setup']).to receive :invoke expect(Rake::Task['gitlab:shell:setup']).to receive :invoke
expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout_from_any_process expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout_from_any_process
end end
...@@ -519,6 +526,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do ...@@ -519,6 +526,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
'terraform_state.tar.gz', 'terraform_state.tar.gz',
'pages.tar.gz', 'pages.tar.gz',
'registry.tar.gz', 'registry.tar.gz',
'packages.tar.gz',
'repositories' 'repositories'
) )
end 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