Commit ecc6b25a authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre Committed by Nick Thomas

Refactor Geo::MoveRepositoryService

parent a6356bf3
...@@ -19,11 +19,10 @@ module Geo ...@@ -19,11 +19,10 @@ module Geo
end end
def execute def execute
project = Project.find(project_id)
project.expire_caches_before_rename(old_disk_path) project.expire_caches_before_rename(old_disk_path)
if migrating_from_legacy_storage?(project) if migrating_from_legacy_storage? && !move_repository
Geo::MoveRepositoryService.new(project, old_disk_path, new_disk_path).execute raise RepositoryCannotBeRenamed, "Repository #{old_disk_path} could not be renamed to #{new_disk_path}"
end end
true true
...@@ -31,12 +30,20 @@ module Geo ...@@ -31,12 +30,20 @@ module Geo
private private
def migrating_from_legacy_storage?(project) def project
@project ||= Project.find(project_id)
end
def migrating_from_legacy_storage?
from_legacy_storage? && project.hashed_storage?(:repository) from_legacy_storage? && project.hashed_storage?(:repository)
end end
def from_legacy_storage? def from_legacy_storage?
old_storage_version.nil? || old_storage_version.zero? old_storage_version.nil? || old_storage_version.zero?
end end
def move_repository
Geo::MoveRepositoryService.new(project, old_disk_path, new_disk_path).execute
end
end end
end end
module Geo module Geo
RepositoryCannotBeRenamed = Class.new(StandardError)
class MoveRepositoryService class MoveRepositoryService
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Gitlab::Geo::ProjectLogHelpers
attr_reader :project, :old_disk_path, :new_disk_path attr_reader :project, :old_disk_path, :new_disk_path
...@@ -11,29 +14,21 @@ module Geo ...@@ -11,29 +14,21 @@ module Geo
end end
def execute def execute
# Make sure target directory exists (used when transfering repositories)
project.ensure_storage_path_exists project.ensure_storage_path_exists
move_project_repository && move_wiki_repository
if gitlab_shell.mv_repository(project.repository_storage_path,
old_disk_path, new_disk_path)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository(project.repository_storage_path,
"#{old_disk_path}.wiki", "#{new_disk_path}.wiki")
rescue rescue
# Returning false does not rollback after_* transaction but gives log_error('Repository cannot be renamed')
# us information about failing some of tasks
false false
end end
else
# if we cannot move namespace directory we should rollback private
# db changes in order to prevent out of sync between db and fs
raise StandardError.new('Repository cannot be renamed') def move_project_repository
gitlab_shell.mv_repository(project.repository_storage_path, old_disk_path, new_disk_path)
end end
true def move_wiki_repository
gitlab_shell.mv_repository(project.repository_storage_path, "#{old_disk_path}.wiki", "#{new_disk_path}.wiki")
end end
end end
end end
...@@ -13,11 +13,22 @@ module Geo ...@@ -13,11 +13,22 @@ module Geo
end end
def execute def execute
project = Project.find(project_id)
project.expire_caches_before_rename(old_disk_path) project.expire_caches_before_rename(old_disk_path)
return true if project.hashed_storage?(:repository) if project.legacy_storage? && !move_repository
raise RepositoryCannotBeRenamed, "Repository #{old_disk_path} could not be renamed to #{new_disk_path}"
end
true
end
private
def project
@project ||= Project.find(project_id)
end
def move_repository
Geo::MoveRepositoryService.new(project, old_disk_path, new_disk_path).execute Geo::MoveRepositoryService.new(project, old_disk_path, new_disk_path).execute
end end
end end
......
---
title: Geo - Allow Sidekiq to retry failed jobs to rename project repositories
merge_request:
author:
type: fixed
...@@ -2,22 +2,41 @@ require 'spec_helper' ...@@ -2,22 +2,41 @@ require 'spec_helper'
describe Geo::HashedStorageMigrationService do describe Geo::HashedStorageMigrationService do
let(:project) { create(:project, :repository, :hashed) } let(:project) { create(:project, :repository, :hashed) }
let(:new_path) { "#{project.full_path}+renamed" } let(:old_path) { project.full_path }
let(:new_path) { "#{old_path}+renamed" }
describe '#execute' do subject(:service) { described_class.new(project.id, old_disk_path: old_path, new_disk_path: new_path, old_storage_version: nil) }
it 'moves project backed by legacy storage' do
service = described_class.new(
project.id,
old_disk_path: project.full_path,
new_disk_path: new_path,
old_storage_version: nil
)
expect_any_instance_of(Geo::MoveRepositoryService).to receive(:execute).once describe '#execute' do
context 'project backed by legacy storage' do
it 'moves the project repositories' do
expect_any_instance_of(Geo::MoveRepositoryService).to receive(:execute)
.once.and_return(true)
service.execute service.execute
end end
it 'raises an error when project repository can not be moved' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(false)
expect { service.execute }.to raise_error(Geo::RepositoryCannotBeRenamed, "Repository #{old_path} could not be renamed to #{new_path}")
end
it 'raises an error when wiki repository can not be moved' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(true)
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki")
.and_return(false)
expect { service.execute }.to raise_error(Geo::RepositoryCannotBeRenamed, "Repository #{old_path} could not be renamed to #{new_path}")
end
end
it 'does not move project backed by hashed storage' do it 'does not move project backed by hashed storage' do
service = described_class.new( service = described_class.new(
project.id, project.id,
...@@ -33,8 +52,6 @@ describe Geo::HashedStorageMigrationService do ...@@ -33,8 +52,6 @@ describe Geo::HashedStorageMigrationService do
end end
describe '#async_execute' do describe '#async_execute' do
subject(:service) { described_class.new(project.id, old_disk_path: project.full_path, new_disk_path: new_path, old_storage_version: nil) }
it 'starts the worker' do it 'starts the worker' do
expect(Geo::HashedStorageMigrationWorker).to receive(:perform_async) expect(Geo::HashedStorageMigrationWorker).to receive(:perform_async)
......
require 'spec_helper' require 'spec_helper'
describe Geo::MoveRepositoryService do describe Geo::MoveRepositoryService do
let(:project) { create(:project, :repository) } describe '#execute' do
let(:project) { create(:project, :repository, :wiki_repo) }
let(:old_path) { project.full_path }
let(:new_path) { "#{project.full_path}+renamed" } let(:new_path) { "#{project.full_path}+renamed" }
describe '#execute' do subject(:service) { described_class.new(project, old_path, new_path) }
it 'renames the path' do
old_path = project.repository.path_to_repo
full_new_path = File.join(project.repository_storage_path, new_path)
service = described_class.new(project, project.full_path, new_path) it 'renames the project repositories' do
old_disk_path = project.repository.path_to_repo
old_wiki_disk_path = project.wiki.repository.path_to_repo
full_new_path = File.join(project.repository_storage_path, new_path)
expect(File.directory?(old_path)).to be_truthy expect(File.directory?(old_disk_path)).to be_truthy
expect(File.directory?(old_wiki_disk_path)).to be_truthy
expect(service.execute).to eq(true) expect(service.execute).to eq(true)
expect(File.directory?(old_path)).to be_falsey expect(File.directory?(old_disk_path)).to be_falsey
expect(File.directory?(old_wiki_disk_path)).to be_falsey
expect(File.directory?("#{full_new_path}.git")).to be_truthy expect(File.directory?("#{full_new_path}.git")).to be_truthy
expect(File.directory?("#{full_new_path}.wiki.git")).to be_truthy
end
it 'returns false when project repository can not be renamed' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(false)
expect(service.execute).to eq false
end
it 'returns false when wiki repository can not be renamed' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(true)
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki")
.and_return(false)
expect(service.execute).to eq false
end end
end end
end end
...@@ -2,17 +2,41 @@ require 'spec_helper' ...@@ -2,17 +2,41 @@ require 'spec_helper'
describe Geo::RenameRepositoryService do describe Geo::RenameRepositoryService do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:new_path) { "#{project.full_path}+renamed" } let(:old_path) { project.full_path }
let(:new_path) { "#{old_path}+renamed" }
describe '#execute' do subject(:service) { described_class.new(project.id, old_path, new_path) }
it 'moves project backed by legacy storage' do
service = described_class.new(project.id, project.full_path, new_path)
expect_any_instance_of(Geo::MoveRepositoryService).to receive(:execute).once describe '#execute' do
context 'project backed by legacy storage' do
it 'moves the project repositories' do
expect_any_instance_of(Geo::MoveRepositoryService).to receive(:execute)
.once.and_return(true)
service.execute service.execute
end end
it 'raises an error when project repository can not be moved' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(false)
expect { service.execute }.to raise_error(Geo::RepositoryCannotBeRenamed, "Repository #{old_path} could not be renamed to #{new_path}")
end
it 'raises an error when wiki repository can not be moved' do
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, old_path, new_path)
.and_return(true)
allow_any_instance_of(Gitlab::Shell).to receive(:mv_repository)
.with(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki")
.and_return(false)
expect { service.execute }.to raise_error(Geo::RepositoryCannotBeRenamed, "Repository #{old_path} could not be renamed to #{new_path}")
end
end
it 'does not move project backed by hashed storage' do it 'does not move project backed by hashed storage' do
project_hashed_storage = create(:project, :hashed) project_hashed_storage = create(:project, :hashed)
service = described_class.new(project_hashed_storage.id, project_hashed_storage.full_path, new_path) service = described_class.new(project_hashed_storage.id, project_hashed_storage.full_path, new_path)
...@@ -24,8 +48,6 @@ describe Geo::RenameRepositoryService do ...@@ -24,8 +48,6 @@ describe Geo::RenameRepositoryService do
end end
describe '#async_execute' do describe '#async_execute' do
subject(:service) { described_class.new(project.id, project.full_path, new_path) }
it 'starts the worker' do it 'starts the worker' do
expect(Geo::RenameRepositoryWorker).to receive(:perform_async) expect(Geo::RenameRepositoryWorker).to receive(:perform_async)
......
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