Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4314202d9d
commit
dc93436903
31 changed files with 325 additions and 105 deletions
|
@ -463,7 +463,7 @@ db:backup_and_restore:
|
|||
script:
|
||||
- . scripts/prepare_build.sh
|
||||
- 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,registry}
|
||||
- mkdir -p tmp/tests/public/uploads tmp/tests/{artifacts,pages,lfs-objects,terraform_state,registry}
|
||||
- bundle exec rake gitlab:backup:create
|
||||
- date
|
||||
- bundle exec rake gitlab:backup:restore
|
||||
|
|
|
@ -44,6 +44,11 @@ module Types
|
|||
null: true,
|
||||
description: 'Name given to the token.'
|
||||
|
||||
field :status,
|
||||
GraphQL::Types::String,
|
||||
null: true,
|
||||
description: 'Current status of the token.'
|
||||
|
||||
def cluster_agent
|
||||
Gitlab::Graphql::Loaders::BatchModelLoader.new(::Clusters::Agent, object.agent_id).find
|
||||
end
|
||||
|
|
|
@ -36,8 +36,8 @@ module Clusters
|
|||
requested_project == project
|
||||
end
|
||||
|
||||
def active?
|
||||
agent_tokens.where("last_used_at > ?", INACTIVE_AFTER.ago).exists?
|
||||
def connected?
|
||||
agent_tokens.active.where("last_used_at > ?", INACTIVE_AFTER.ago).exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,13 +23,18 @@ module Clusters
|
|||
|
||||
scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
|
||||
|
||||
enum status: {
|
||||
active: 0,
|
||||
revoked: 1
|
||||
}
|
||||
|
||||
def track_usage
|
||||
track_values = { last_used_at: Time.current.utc }
|
||||
|
||||
cache_attributes(track_values)
|
||||
|
||||
if can_update_track_values?
|
||||
log_activity_event!(track_values[:last_used_at]) unless agent.active?
|
||||
log_activity_event!(track_values[:last_used_at]) unless agent.connected?
|
||||
|
||||
# Use update_column so updated_at is skipped
|
||||
update_columns(track_values)
|
||||
|
|
26
db/fixtures/development/31_terraform_state.rb
Normal file
26
db/fixtures/development/31_terraform_state.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
TERRAFORM_FILE_VERSION = 1
|
||||
|
||||
# Create sample terraform states in existing projects
|
||||
Gitlab::Seeder.quiet do
|
||||
tfdata = {terraform_version: '0.14.1'}.to_json
|
||||
|
||||
Project.not_mass_generated.find_each do |project|
|
||||
# Create as the project's creator
|
||||
user = project.creator
|
||||
# Set a build job source, if one exists for the project
|
||||
build = project.builds.last
|
||||
|
||||
remote_state_handler = ::Terraform::RemoteStateHandler.new(project, user, name: project.path, lock_id: nil)
|
||||
|
||||
remote_state_handler.handle_with_lock do |state|
|
||||
# Upload a file if a version does not already exist
|
||||
state.update_file!(CarrierWaveStringFile.new(tfdata), version: TERRAFORM_FILE_VERSION, build: build) if state.latest_version.nil?
|
||||
end
|
||||
|
||||
# rubocop:disable Rails/Output
|
||||
print '.'
|
||||
# rubocop:enable Rails/Output
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddStatusToClusterAgentTokens < Gitlab::Database::Migration[1.0]
|
||||
def change
|
||||
add_column :cluster_agent_tokens, :status, :smallint, null: false, default: 0
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CleanupAfterDropInvalidSecurityFindings < Gitlab::Database::Migration[1.0]
|
||||
MIGRATION = "DropInvalidSecurityFindings"
|
||||
INDEX_NAME = "tmp_index_uuid_is_null"
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# Make sure all jobs scheduled by
|
||||
# db/post_migrate/20211110151350_schedule_drop_invalid_security_findings.rb
|
||||
# are finished
|
||||
finalize_background_migration(MIGRATION)
|
||||
# Created by db/post_migrate/20211110151320_add_temporary_index_on_security_findings_uuid.rb
|
||||
remove_concurrent_index_by_name :security_findings, INDEX_NAME
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index(
|
||||
:security_findings,
|
||||
:id,
|
||||
where: "uuid IS NULL",
|
||||
name: INDEX_NAME
|
||||
)
|
||||
end
|
||||
end
|
1
db/schema_migrations/20211123161906
Normal file
1
db/schema_migrations/20211123161906
Normal file
|
@ -0,0 +1 @@
|
|||
46767d804bde08ad4a076f20436652f980eb935a79b2ad30b4735b956be69a7a
|
1
db/schema_migrations/20211209230042
Normal file
1
db/schema_migrations/20211209230042
Normal file
|
@ -0,0 +1 @@
|
|||
907fafc18fa515fff8f716f6464263ccc8a9b6e5ead36f30b05089100fd71b6b
|
|
@ -12384,6 +12384,7 @@ CREATE TABLE cluster_agent_tokens (
|
|||
description text,
|
||||
name text,
|
||||
last_used_at timestamp with time zone,
|
||||
status smallint DEFAULT 0 NOT NULL,
|
||||
CONSTRAINT check_0fb634d04d CHECK ((name IS NOT NULL)),
|
||||
CONSTRAINT check_2b79dbb315 CHECK ((char_length(name) <= 255)),
|
||||
CONSTRAINT check_4e4ec5070a CHECK ((char_length(description) <= 1024)),
|
||||
|
@ -27982,8 +27983,6 @@ CREATE UNIQUE INDEX tmp_index_on_tmp_project_id_on_namespaces ON namespaces USIN
|
|||
|
||||
CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING btree (id) WHERE (state <> 2);
|
||||
|
||||
CREATE INDEX tmp_index_uuid_is_null ON security_findings USING btree (id) WHERE (uuid IS NULL);
|
||||
|
||||
CREATE UNIQUE INDEX uniq_pkgs_deb_grp_architectures_on_distribution_id_and_name ON packages_debian_group_architectures USING btree (distribution_id, name);
|
||||
|
||||
CREATE UNIQUE INDEX uniq_pkgs_deb_grp_components_on_distribution_id_and_name ON packages_debian_group_components USING btree (distribution_id, name);
|
||||
|
|
|
@ -8960,6 +8960,7 @@ GitLab CI/CD configuration template.
|
|||
| <a id="clusteragenttokenid"></a>`id` | [`ClustersAgentTokenID!`](#clustersagenttokenid) | Global ID of the token. |
|
||||
| <a id="clusteragenttokenlastusedat"></a>`lastUsedAt` | [`Time`](#time) | Timestamp the token was last used. |
|
||||
| <a id="clusteragenttokenname"></a>`name` | [`String`](#string) | Name given to the token. |
|
||||
| <a id="clusteragenttokenstatus"></a>`status` | [`String`](#string) | Current status of the token. |
|
||||
|
||||
### `CodeCoverageActivity`
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ including:
|
|||
- CI/CD job output logs
|
||||
- CI/CD job artifacts
|
||||
- LFS objects
|
||||
- Terraform states
|
||||
- Container Registry images
|
||||
- GitLab Pages content
|
||||
- Snippets
|
||||
|
@ -65,7 +66,6 @@ including:
|
|||
|
||||
Backups do not include:
|
||||
|
||||
- [Terraform state files](../administration/terraform_state.md)
|
||||
- [Package registry files](../administration/packages/index.md)
|
||||
- [Mattermost data](https://docs.mattermost.com/administration/config-settings.html#file-storage)
|
||||
|
||||
|
@ -276,6 +276,7 @@ You can exclude specific directories from the backup by adding the environment v
|
|||
- `builds` (CI job output logs)
|
||||
- `artifacts` (CI job artifacts)
|
||||
- `lfs` (LFS objects)
|
||||
- `terraform_state` (Terraform states)
|
||||
- `registry` (Container Registry images)
|
||||
- `pages` (Pages content)
|
||||
- `repositories` (Git repositories data)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Backup
|
||||
class Manager
|
||||
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs registry].freeze
|
||||
ARCHIVES_TO_BACKUP = %w[uploads builds artifacts pages lfs terraform_state registry].freeze
|
||||
FOLDERS_TO_BACKUP = %w[repositories db].freeze
|
||||
FILE_NAME_SUFFIX = '_gitlab_backup.tar'
|
||||
|
||||
|
|
13
lib/backup/terraform_state.rb
Normal file
13
lib/backup/terraform_state.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Backup
|
||||
class TerraformState < Backup::Files
|
||||
attr_reader :progress
|
||||
|
||||
def initialize(progress)
|
||||
@progress = progress
|
||||
|
||||
super('terraform_state', Settings.terraform_state.storage_path, excludes: ['tmp'])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -165,7 +165,7 @@ module Gitlab
|
|||
|
||||
authorization_token, _options = token_and_options(current_request)
|
||||
|
||||
::Clusters::AgentToken.find_by_token(authorization_token)
|
||||
::Clusters::AgentToken.active.find_by_token(authorization_token)
|
||||
end
|
||||
|
||||
def find_runner_from_token
|
||||
|
|
|
@ -76,20 +76,7 @@ module Gitlab
|
|||
|
||||
def self.cleanup_leftovers!
|
||||
PostgresIndex.reindexing_leftovers.each do |index|
|
||||
Gitlab::AppLogger.info("Removing index #{index.identifier} which is a leftover, temporary index from previous reindexing activity")
|
||||
|
||||
retries = Gitlab::Database::WithLockRetriesOutsideTransaction.new(
|
||||
connection: index.connection,
|
||||
timing_configuration: REMOVE_INDEX_RETRY_CONFIG,
|
||||
klass: self.class,
|
||||
logger: Gitlab::AppLogger
|
||||
)
|
||||
|
||||
retries.run(raise_on_exhaustion: false) do
|
||||
index.connection.tap do |conn|
|
||||
conn.execute("DROP INDEX CONCURRENTLY IF EXISTS #{conn.quote_table_name(index.schema)}.#{conn.quote_table_name(index.name)}")
|
||||
end
|
||||
end
|
||||
Coordinator.new(index).drop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,6 +31,25 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def drop
|
||||
try_obtain_lease do
|
||||
Gitlab::AppLogger.info("Removing index #{index.identifier} which is a leftover, temporary index from previous reindexing activity")
|
||||
|
||||
retries = Gitlab::Database::WithLockRetriesOutsideTransaction.new(
|
||||
connection: index.connection,
|
||||
timing_configuration: REMOVE_INDEX_RETRY_CONFIG,
|
||||
klass: self.class,
|
||||
logger: Gitlab::AppLogger
|
||||
)
|
||||
|
||||
retries.run(raise_on_exhaustion: false) do
|
||||
index.connection.tap do |conn|
|
||||
conn.execute("DROP INDEX CONCURRENTLY IF EXISTS #{conn.quote_table_name(index.schema)}.#{conn.quote_table_name(index.name)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_notifications(action)
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace :gitlab do
|
|||
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)
|
||||
|
@ -83,6 +84,7 @@ namespace :gitlab do
|
|||
Rake::Task['gitlab:backup:artifacts:restore'].invoke unless backup.skipped?('artifacts')
|
||||
Rake::Task['gitlab:backup:pages:restore'].invoke unless backup.skipped?('pages')
|
||||
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:registry:restore'].invoke unless backup.skipped?('registry')
|
||||
Rake::Task['gitlab:shell:setup'].invoke
|
||||
Rake::Task['cache:clear'].invoke
|
||||
|
@ -254,6 +256,25 @@ namespace :gitlab do
|
|||
end
|
||||
end
|
||||
|
||||
namespace :terraform_state do
|
||||
task create: :gitlab_environment do
|
||||
puts_time "Dumping terraform states ... ".color(:blue)
|
||||
|
||||
if ENV["SKIP"] && ENV["SKIP"].include?("terraform_state")
|
||||
puts_time "[SKIPPED]".color(:cyan)
|
||||
else
|
||||
Backup::TerraformState.new(progress).dump
|
||||
puts_time "done".color(:green)
|
||||
end
|
||||
end
|
||||
|
||||
task restore: :gitlab_environment do
|
||||
puts_time "Restoring terraform states ... ".color(:blue)
|
||||
Backup::TerraformState.new(progress).restore
|
||||
puts_time "done".color(:green)
|
||||
end
|
||||
end
|
||||
|
||||
namespace :registry do
|
||||
task create: :gitlab_environment do
|
||||
puts_time "Dumping container registry images ... ".color(:blue)
|
||||
|
|
0
shared/terraform_state/.gitkeep
Normal file
0
shared/terraform_state/.gitkeep
Normal file
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe GitlabSchema.types['ClusterAgentToken'] do
|
||||
let(:fields) { %i[cluster_agent created_at created_by_user description id last_used_at name] }
|
||||
let(:fields) { %i[cluster_agent created_at created_by_user description id last_used_at name status] }
|
||||
|
||||
it { expect(described_class.graphql_name).to eq('ClusterAgentToken') }
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ RSpec.describe Backup::Artifacts do
|
|||
Dir.mktmpdir do |tmpdir|
|
||||
allow(JobArtifactUploader).to receive(:root) { "#{tmpdir}" }
|
||||
|
||||
expect(backup.app_files_dir).to eq("#{tmpdir}")
|
||||
expect(backup.app_files_dir).to eq("#{File.realpath(tmpdir)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
27
spec/lib/backup/lfs_spec.rb
Normal file
27
spec/lib/backup/lfs_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Backup::Lfs do
|
||||
let(:progress) { StringIO.new }
|
||||
|
||||
subject(:backup) { described_class.new(progress) }
|
||||
|
||||
describe '#dump' do
|
||||
before do
|
||||
allow(File).to receive(:realpath).and_call_original
|
||||
allow(File).to receive(:realpath).with('/var/lfs-objects').and_return('/var/lfs-objects')
|
||||
allow(File).to receive(:realpath).with('/var/lfs-objects/..').and_return('/var')
|
||||
allow(Settings.lfs).to receive(:storage_path).and_return('/var/lfs-objects')
|
||||
end
|
||||
|
||||
it 'uses the correct lfs dir in tar command', :aggregate_failures do
|
||||
expect(backup.app_files_dir).to eq('/var/lfs-objects')
|
||||
expect(backup).to receive(:tar).and_return('blabla-tar')
|
||||
expect(backup).to receive(:run_pipeline!).with([%w(blabla-tar --exclude=lost+found -C /var/lfs-objects -cf - .), 'gzip -c -1'], any_args).and_return([[true, true], ''])
|
||||
expect(backup).to receive(:pipeline_succeeded?).and_return(true)
|
||||
|
||||
backup.dump
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,7 +15,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
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 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 backup_information.yml) }
|
||||
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_cmdline) { ['tar', '-cf', '-', *expected_backup_contents, tar_system_options] }
|
||||
|
@ -57,7 +57,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
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 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 backup_information.yml} }
|
||||
let(:backup_information) do
|
||||
{
|
||||
backup_created_at: Time.zone.parse('2019-01-01'),
|
||||
|
@ -74,7 +74,7 @@ RSpec.describe Backup::Manager do
|
|||
end
|
||||
|
||||
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 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 backup_information.yml} }
|
||||
|
||||
before do
|
||||
expect(Dir).to receive(:exist?).with(File.join(Gitlab.config.backup.path, 'repositories')).and_return(false)
|
||||
|
|
27
spec/lib/backup/terraform_state_spec.rb
Normal file
27
spec/lib/backup/terraform_state_spec.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Backup::TerraformState do
|
||||
let(:progress) { StringIO.new }
|
||||
|
||||
subject(:backup) { described_class.new(progress) }
|
||||
|
||||
describe '#dump' do
|
||||
before do
|
||||
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('/var/terraform_state/..').and_return('/var')
|
||||
allow(Settings.terraform_state).to receive(:storage_path).and_return('/var/terraform_state')
|
||||
end
|
||||
|
||||
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).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(:pipeline_succeeded?).and_return(true)
|
||||
|
||||
backup.dump
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,13 +14,14 @@ RSpec.describe Backup::Uploads do
|
|||
|
||||
allow(Gitlab.config.uploads).to receive(:storage_path) { tmpdir }
|
||||
|
||||
expect(backup.app_files_dir).to eq("#{tmpdir}/uploads")
|
||||
expect(backup.app_files_dir).to eq("#{File.realpath(tmpdir)}/uploads")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#dump' do
|
||||
before do
|
||||
allow(File).to receive(:realpath).and_call_original
|
||||
allow(File).to receive(:realpath).with('/var/uploads').and_return('/var/uploads')
|
||||
allow(File).to receive(:realpath).with('/var/uploads/..').and_return('/var')
|
||||
allow(Gitlab.config.uploads).to receive(:storage_path) { '/var' }
|
||||
|
|
|
@ -939,21 +939,19 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
end
|
||||
|
||||
describe '#cluster_agent_token_from_authorization_token' do
|
||||
let_it_be(:agent_token, freeze: true) { create(:cluster_agent_token) }
|
||||
let_it_be(:agent_token) { create(:cluster_agent_token) }
|
||||
|
||||
subject { cluster_agent_token_from_authorization_token }
|
||||
|
||||
context 'when route_setting is empty' do
|
||||
it 'returns nil' do
|
||||
expect(cluster_agent_token_from_authorization_token).to be_nil
|
||||
end
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'when route_setting allows cluster agent token' do
|
||||
let(:route_authentication_setting) { { cluster_agent_token_allowed: true } }
|
||||
|
||||
context 'Authorization header is empty' do
|
||||
it 'returns nil' do
|
||||
expect(cluster_agent_token_from_authorization_token).to be_nil
|
||||
end
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'Authorization header is incorrect' do
|
||||
|
@ -961,9 +959,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
request.headers['Authorization'] = 'Bearer ABCD'
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(cluster_agent_token_from_authorization_token).to be_nil
|
||||
end
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'Authorization header is malformed' do
|
||||
|
@ -971,9 +967,7 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
request.headers['Authorization'] = 'Bearer'
|
||||
end
|
||||
|
||||
it 'returns nil' do
|
||||
expect(cluster_agent_token_from_authorization_token).to be_nil
|
||||
end
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
|
||||
context 'Authorization header matches agent token' do
|
||||
|
@ -981,8 +975,14 @@ RSpec.describe Gitlab::Auth::AuthFinders do
|
|||
request.headers['Authorization'] = "Bearer #{agent_token.token}"
|
||||
end
|
||||
|
||||
it 'returns the agent token' do
|
||||
expect(cluster_agent_token_from_authorization_token).to eq(agent_token)
|
||||
it { is_expected.to eq(agent_token) }
|
||||
|
||||
context 'agent token has been revoked' do
|
||||
before do
|
||||
agent_token.revoked!
|
||||
end
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,30 +6,34 @@ RSpec.describe Gitlab::Database::Reindexing::Coordinator do
|
|||
include Database::DatabaseHelpers
|
||||
include ExclusiveLeaseHelpers
|
||||
|
||||
describe '.perform' do
|
||||
let(:notifier) { instance_double(Gitlab::Database::Reindexing::GrafanaNotifier, notify_start: nil, notify_end: nil) }
|
||||
let(:index) { create(:postgres_index) }
|
||||
let(:connection) { index.connection }
|
||||
|
||||
let!(:lease) { stub_exclusive_lease(lease_key, uuid, timeout: lease_timeout) }
|
||||
let(:lease_key) { "gitlab/database/reindexing/coordinator/#{Gitlab::Database::PRIMARY_DATABASE_NAME}" }
|
||||
let(:lease_timeout) { 1.day }
|
||||
let(:uuid) { 'uuid' }
|
||||
|
||||
around do |example|
|
||||
model = Gitlab::Database.database_base_models[Gitlab::Database::PRIMARY_DATABASE_NAME]
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(model.connection) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
swapout_view_for_table(:postgres_indexes)
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
subject { described_class.new(index, notifier).perform }
|
||||
|
||||
let(:index) { create(:postgres_index) }
|
||||
let(:notifier) { instance_double(Gitlab::Database::Reindexing::GrafanaNotifier, notify_start: nil, notify_end: nil) }
|
||||
let(:reindexer) { instance_double(Gitlab::Database::Reindexing::ReindexConcurrently, perform: nil) }
|
||||
let(:action) { create(:reindex_action, index: index) }
|
||||
|
||||
let!(:lease) { stub_exclusive_lease(lease_key, uuid, timeout: lease_timeout) }
|
||||
let(:lease_key) { "gitlab/database/reindexing/coordinator/#{Gitlab::Database::PRIMARY_DATABASE_NAME}" }
|
||||
let(:lease_timeout) { 1.day }
|
||||
let(:uuid) { 'uuid' }
|
||||
|
||||
around do |example|
|
||||
model = Gitlab::Database.database_base_models[Gitlab::Database::PRIMARY_DATABASE_NAME]
|
||||
|
||||
Gitlab::Database::SharedModel.using_connection(model.connection) do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
swapout_view_for_table(:postgres_indexes)
|
||||
|
||||
allow(Gitlab::Database::Reindexing::ReindexConcurrently).to receive(:new).with(index).and_return(reindexer)
|
||||
allow(Gitlab::Database::Reindexing::ReindexAction).to receive(:create_for).with(index).and_return(action)
|
||||
end
|
||||
|
@ -87,4 +91,40 @@ RSpec.describe Gitlab::Database::Reindexing::Coordinator do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#drop' do
|
||||
let(:connection) { index.connection }
|
||||
|
||||
subject(:drop) { described_class.new(index, notifier).drop }
|
||||
|
||||
context 'when exclusive lease is granted' do
|
||||
it 'drops the index with lock retries' do
|
||||
expect(lease).to receive(:try_obtain).ordered.and_return(uuid)
|
||||
|
||||
expect_query("SET lock_timeout TO '60000ms'")
|
||||
expect_query("DROP INDEX CONCURRENTLY IF EXISTS \"public\".\"#{index.name}\"")
|
||||
expect_query("RESET idle_in_transaction_session_timeout; RESET lock_timeout")
|
||||
|
||||
expect(Gitlab::ExclusiveLease).to receive(:cancel).ordered.with(lease_key, uuid)
|
||||
|
||||
drop
|
||||
end
|
||||
|
||||
def expect_query(sql)
|
||||
expect(connection).to receive(:execute).ordered.with(sql).and_wrap_original do |method, sql|
|
||||
method.call(sql.sub(/CONCURRENTLY/, ''))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exclusive lease is not granted' do
|
||||
it 'does not drop the index' do
|
||||
expect(lease).to receive(:try_obtain).ordered.and_return(false)
|
||||
expect(Gitlab::Database::WithLockRetriesOutsideTransaction).not_to receive(:new)
|
||||
expect(connection).not_to receive(:execute)
|
||||
|
||||
drop
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,12 +76,12 @@ RSpec.describe Clusters::Agent do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
describe '#connected?' do
|
||||
let_it_be(:agent) { create(:cluster_agent) }
|
||||
|
||||
let!(:token) { create(:cluster_agent_token, agent: agent, last_used_at: last_used_at) }
|
||||
|
||||
subject { agent.active? }
|
||||
subject { agent.connected? }
|
||||
|
||||
context 'agent has never connected' do
|
||||
let(:last_used_at) { nil }
|
||||
|
@ -99,6 +99,14 @@ RSpec.describe Clusters::Agent do
|
|||
let(:last_used_at) { 2.minutes.ago }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
|
||||
context 'agent token has been revoked' do
|
||||
before do
|
||||
token.revoked!
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
|
||||
context 'agent has multiple tokens' do
|
||||
|
|
|
@ -9,6 +9,8 @@ RSpec.describe Clusters::AgentToken do
|
|||
it { is_expected.to validate_length_of(:name).is_at_most(255) }
|
||||
it { is_expected.to validate_presence_of(:name) }
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
describe 'scopes' do
|
||||
describe '.order_last_used_at_desc' do
|
||||
let_it_be(:token_1) { create(:cluster_agent_token, last_used_at: 7.days.ago) }
|
||||
|
@ -76,9 +78,9 @@ RSpec.describe Clusters::AgentToken do
|
|||
end
|
||||
end
|
||||
|
||||
context 'agent is inactive' do
|
||||
context 'agent is not connected' do
|
||||
before do
|
||||
allow(agent).to receive(:active?).and_return(false)
|
||||
allow(agent).to receive(:connected?).and_return(false)
|
||||
end
|
||||
|
||||
it 'creates an activity event' do
|
||||
|
@ -94,9 +96,9 @@ RSpec.describe Clusters::AgentToken do
|
|||
end
|
||||
end
|
||||
|
||||
context 'agent is active' do
|
||||
context 'agent is connected' do
|
||||
before do
|
||||
allow(agent).to receive(:active?).and_return(true)
|
||||
allow(agent).to receive(:connected?).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not create an activity event' do
|
||||
|
|
|
@ -148,6 +148,8 @@ module TestEnv
|
|||
FileUtils.mkdir_p(backup_path)
|
||||
FileUtils.mkdir_p(pages_path)
|
||||
FileUtils.mkdir_p(artifacts_path)
|
||||
FileUtils.mkdir_p(lfs_path)
|
||||
FileUtils.mkdir_p(terraform_state_path)
|
||||
end
|
||||
|
||||
def setup_gitlab_shell
|
||||
|
@ -414,6 +416,14 @@ module TestEnv
|
|||
Gitlab.config.artifacts.storage_path
|
||||
end
|
||||
|
||||
def lfs_path
|
||||
Gitlab.config.lfs.storage_path
|
||||
end
|
||||
|
||||
def terraform_state_path
|
||||
Gitlab.config.terraform_state.storage_path
|
||||
end
|
||||
|
||||
# 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
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'rake_helper'
|
|||
|
||||
RSpec.describe 'gitlab:app namespace rake task', :delete do
|
||||
let(:enable_registry) { true }
|
||||
let(:backup_types) { %w{db repo uploads builds artifacts pages lfs terraform_state registry} }
|
||||
|
||||
def tars_glob
|
||||
Dir.glob(File.join(Gitlab.config.backup.path, '*_gitlab_backup.tar'))
|
||||
|
@ -14,7 +15,7 @@ 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 pages.tar.gz)
|
||||
%w(backup_information.yml artifacts.tar.gz builds.tar.gz lfs.tar.gz terraform_state.tar.gz pages.tar.gz)
|
||||
end
|
||||
|
||||
def backup_directories
|
||||
|
@ -47,7 +48,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
end
|
||||
|
||||
def reenable_backup_sub_tasks
|
||||
%w{db repo uploads builds artifacts pages lfs registry}.each do |subtask|
|
||||
backup_types.each do |subtask|
|
||||
Rake::Task["gitlab:backup:#{subtask}:create"].reenable
|
||||
end
|
||||
end
|
||||
|
@ -71,14 +72,9 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
allow(YAML).to receive(:load_file)
|
||||
.and_return({ gitlab_version: gitlab_version })
|
||||
expect(Rake::Task['gitlab:db:drop_tables']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:db:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:repo:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:builds:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:uploads:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:pages:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:registry:restore']).to receive(:invoke)
|
||||
backup_types.each do |subtask|
|
||||
expect(Rake::Task["gitlab:backup:#{subtask}:restore"]).to receive(:invoke)
|
||||
end
|
||||
expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke)
|
||||
end
|
||||
|
||||
|
@ -95,7 +91,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
context 'when the restore directory is not empty' do
|
||||
before do
|
||||
# We only need a backup of the repositories for this test
|
||||
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,registry')
|
||||
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
|
||||
|
||||
create(:project, :repository)
|
||||
end
|
||||
|
@ -139,11 +135,9 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:backup:pages: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:registry:restore']).to receive(:invoke)
|
||||
expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke)
|
||||
|
||||
# We only need a backup of the repositories for this test
|
||||
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,registry')
|
||||
end
|
||||
|
||||
it 'restores the data' do
|
||||
|
@ -202,10 +196,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
end
|
||||
|
||||
context 'specific backup tasks' do
|
||||
let(:task_list) { %w(db repo uploads builds artifacts pages lfs registry) }
|
||||
|
||||
it 'prints a progress message to stdout' do
|
||||
task_list.each do |task|
|
||||
backup_types.each do |task|
|
||||
expect { run_rake_task("gitlab:backup:#{task}:create") }.to output(/Dumping /).to_stdout_from_any_process
|
||||
end
|
||||
end
|
||||
|
@ -219,10 +211,11 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping artifacts ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "Dumping pages ... ")
|
||||
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 container registry images ... ")
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(7).times
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: "done").exactly(8).times
|
||||
|
||||
task_list.each do |task|
|
||||
backup_types.each do |task|
|
||||
run_rake_task("gitlab:backup:#{task}:create")
|
||||
end
|
||||
end
|
||||
|
@ -255,7 +248,7 @@ 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 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}
|
||||
)
|
||||
|
||||
expect(exit_status).to eq(0)
|
||||
|
@ -266,6 +259,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(tar_contents).to match('artifacts.tar.gz')
|
||||
expect(tar_contents).to match('pages.tar.gz')
|
||||
expect(tar_contents).to match('lfs.tar.gz')
|
||||
expect(tar_contents).to match('terraform_state.tar.gz')
|
||||
expect(tar_contents).to match('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
|
||||
|
@ -274,7 +268,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete 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,registry}')
|
||||
File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,pages,lfs,terraform_state,registry}')
|
||||
)
|
||||
|
||||
expect(temp_dirs).to be_empty
|
||||
|
@ -304,7 +298,7 @@ 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,registry')
|
||||
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
|
||||
|
@ -378,7 +372,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
context 'concurrency settings' do
|
||||
before do
|
||||
# We only need a backup of the repositories for this test
|
||||
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,registry')
|
||||
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,terraform_state,registry')
|
||||
|
||||
create(:project, :repository)
|
||||
end
|
||||
|
@ -425,31 +419,33 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
end
|
||||
# backup_create task
|
||||
|
||||
describe "Skipping items" do
|
||||
describe "Skipping items in a backup" do
|
||||
before do
|
||||
stub_env('SKIP', 'repositories,uploads')
|
||||
stub_env('SKIP', 'an-unknown-type,repositories,uploads,anotherunknowntype')
|
||||
|
||||
create(:project, :repository)
|
||||
end
|
||||
|
||||
it "does not contain skipped item" do
|
||||
it "does not contain repositories and uploads" 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 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}
|
||||
)
|
||||
|
||||
expect(tar_contents).to match('db/')
|
||||
expect(tar_contents).to match('uploads.tar.gz')
|
||||
expect(tar_contents).to match('uploads.tar.gz: Not found in archive')
|
||||
expect(tar_contents).to match('builds.tar.gz')
|
||||
expect(tar_contents).to match('artifacts.tar.gz')
|
||||
expect(tar_contents).to match('lfs.tar.gz')
|
||||
expect(tar_contents).to match('terraform_state.tar.gz')
|
||||
expect(tar_contents).to match('pages.tar.gz')
|
||||
expect(tar_contents).to match('registry.tar.gz')
|
||||
expect(tar_contents).not_to match('repositories/')
|
||||
expect(tar_contents).to match('repositories: Not found in archive')
|
||||
end
|
||||
|
||||
it 'does not invoke repositories restore' do
|
||||
it 'does not invoke restore of repositories and uploads' do
|
||||
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout_from_any_process
|
||||
|
||||
allow(Rake::Task['gitlab:shell:setup'])
|
||||
|
@ -463,6 +459,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:pages: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:registry:restore']).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
|
||||
|
@ -488,6 +485,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
'builds.tar.gz',
|
||||
'artifacts.tar.gz',
|
||||
'lfs.tar.gz',
|
||||
'terraform_state.tar.gz',
|
||||
'pages.tar.gz',
|
||||
'registry.tar.gz',
|
||||
'repositories'
|
||||
|
@ -501,14 +499,9 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
|
|||
.to receive(:invoke).and_return(true)
|
||||
|
||||
expect(Rake::Task['gitlab:db:drop_tables']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:db:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:repo:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:uploads:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:builds:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:pages:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive :invoke
|
||||
expect(Rake::Task['gitlab:backup:registry:restore']).to receive :invoke
|
||||
backup_types.each do |subtask|
|
||||
expect(Rake::Task["gitlab:backup:#{subtask}:restore"]).to receive :invoke
|
||||
end
|
||||
expect(Rake::Task['gitlab:shell:setup']).to receive :invoke
|
||||
expect { run_rake_task("gitlab:backup:restore") }.to output.to_stdout_from_any_process
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue