Commit 2a04eff3 authored by James Fargher's avatar James Fargher

Update the database when moving repos between identical storages

When any two storages are configured identically it was previously
impossible to move projects from one to the other. This is because
before trying to move the repository we check if the storages are
identical to prevent dataloss. Instead of bailing out with an exception,
now we simply update the database. This allows admins to update all
projects before fixing the configuration error.
parent 2a62b9da
# frozen_string_literal: true # frozen_string_literal: true
module UpdateRepositoryStorageMethods module UpdateRepositoryStorageMethods
include Gitlab::Utils::StrongMemoize
Error = Class.new(StandardError) Error = Class.new(StandardError)
SameFilesystemError = Class.new(Error)
attr_reader :repository_storage_move attr_reader :repository_storage_move
delegate :container, :source_storage_name, :destination_storage_name, to: :repository_storage_move delegate :container, :source_storage_name, :destination_storage_name, to: :repository_storage_move
...@@ -18,9 +19,7 @@ module UpdateRepositoryStorageMethods ...@@ -18,9 +19,7 @@ module UpdateRepositoryStorageMethods
repository_storage_move.start! repository_storage_move.start!
end end
raise SameFilesystemError if same_filesystem?(source_storage_name, destination_storage_name) mirror_repositories unless same_filesystem?
mirror_repositories
repository_storage_move.transaction do repository_storage_move.transaction do
repository_storage_move.finish_replication! repository_storage_move.finish_replication!
...@@ -28,8 +27,10 @@ module UpdateRepositoryStorageMethods ...@@ -28,8 +27,10 @@ module UpdateRepositoryStorageMethods
track_repository(destination_storage_name) track_repository(destination_storage_name)
end end
remove_old_paths unless same_filesystem?
enqueue_housekeeping remove_old_paths
enqueue_housekeeping
end
repository_storage_move.finish_cleanup! repository_storage_move.finish_cleanup!
...@@ -80,8 +81,10 @@ module UpdateRepositoryStorageMethods ...@@ -80,8 +81,10 @@ module UpdateRepositoryStorageMethods
end end
end end
def same_filesystem?(old_storage, new_storage) def same_filesystem?
Gitlab::GitalyClient.filesystem_id(old_storage) == Gitlab::GitalyClient.filesystem_id(new_storage) strong_memoize(:same_filesystem) do
Gitlab::GitalyClient.filesystem_id(source_storage_name) == Gitlab::GitalyClient.filesystem_id(destination_storage_name)
end
end end
def remove_old_paths def remove_old_paths
......
---
title: Update the database when moving repos between identical storages
merge_request: 52743
author:
type: fixed
...@@ -55,13 +55,18 @@ RSpec.describe Groups::UpdateRepositoryStorageService do ...@@ -55,13 +55,18 @@ RSpec.describe Groups::UpdateRepositoryStorageService do
end end
context 'when the filesystems are the same' do context 'when the filesystems are the same' do
let(:destination) { wiki.repository_storage } before do
expect(Gitlab::GitalyClient).to receive(:filesystem_id).twice.and_return(SecureRandom.uuid)
end
it 'bails out and does nothing' do it 'updates the database without trying to move the repostory', :aggregate_failures do
result = subject.execute result = subject.execute
group.reload
expect(result).to be_error expect(result).to be_success
expect(result.message).to match(/SameFilesystemError/) expect(group).not_to be_repository_read_only
expect(wiki.repository_storage).to eq(destination)
expect(group.group_wiki_repository.shard_name).to eq(destination)
end end
end end
......
...@@ -59,13 +59,18 @@ RSpec.describe Projects::UpdateRepositoryStorageService do ...@@ -59,13 +59,18 @@ RSpec.describe Projects::UpdateRepositoryStorageService do
end end
context 'when the filesystems are the same' do context 'when the filesystems are the same' do
let(:destination) { project.repository_storage } before do
expect(Gitlab::GitalyClient).to receive(:filesystem_id).twice.and_return(SecureRandom.uuid)
end
it 'bails out and does nothing' do it 'updates the database without trying to move the repostory', :aggregate_failures do
result = subject.execute result = subject.execute
project.reload
expect(result).to be_error expect(result).to be_success
expect(result.message).to match(/SameFilesystemError/) expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('test_second_storage')
expect(project.project_repository.shard_name).to eq('test_second_storage')
end end
end end
......
...@@ -54,13 +54,18 @@ RSpec.describe Snippets::UpdateRepositoryStorageService do ...@@ -54,13 +54,18 @@ RSpec.describe Snippets::UpdateRepositoryStorageService do
end end
context 'when the filesystems are the same' do context 'when the filesystems are the same' do
let(:destination) { snippet.repository_storage } before do
expect(Gitlab::GitalyClient).to receive(:filesystem_id).twice.and_return(SecureRandom.uuid)
end
it 'bails out and does nothing' do it 'updates the database without trying to move the repostory', :aggregate_failures do
result = subject.execute result = subject.execute
snippet.reload
expect(result).to be_error expect(result).to be_success
expect(result.message).to match(/SameFilesystemError/) expect(snippet).not_to be_repository_read_only
expect(snippet.repository_storage).to eq(destination)
expect(snippet.snippet_repository.shard_name).to eq(destination)
end end
end end
......
...@@ -95,13 +95,18 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type| ...@@ -95,13 +95,18 @@ RSpec.shared_examples 'moves repository to another storage' do |repository_type|
end end
context 'when the filesystems are the same' do context 'when the filesystems are the same' do
let(:destination) { project.repository_storage } before do
expect(Gitlab::GitalyClient).to receive(:filesystem_id).twice.and_return(SecureRandom.uuid)
end
it 'bails out and does nothing' do it 'updates the database without trying to move the repostory', :aggregate_failures do
result = subject.execute result = subject.execute
project.reload
expect(result).to be_error expect(result).to be_success
expect(result.message).to match(/SameFilesystemError/) expect(project).not_to be_repository_read_only
expect(project.repository_storage).to eq('test_second_storage')
expect(project.project_repository.shard_name).to eq('test_second_storage')
end end
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