Merge branch 'osw-enforces-project-removal-with-past-failed-attempts' into 'master'

Cleanup stale +deleted repo paths on project removal (adjusts project removal bug)

Closes #46146

See merge request gitlab-org/gitlab-ce!24269
This commit is contained in:
Nick Thomas 2019-01-18 16:32:44 +00:00
commit c5a74a9e15
3 changed files with 58 additions and 5 deletions

View file

@ -7,9 +7,16 @@ module Projects
DestroyError = Class.new(StandardError) DestroyError = Class.new(StandardError)
DELETED_FLAG = '+deleted'.freeze DELETED_FLAG = '+deleted'.freeze
REPO_REMOVAL_DELAY = 5.minutes.to_i
def async_execute def async_execute
project.update_attribute(:pending_delete, true) project.update_attribute(:pending_delete, true)
# Ensure no repository +deleted paths are kept,
# regardless of any issue with the ProjectDestroyWorker
# job process.
schedule_stale_repos_removal
job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params) job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params)
Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}") Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}")
end end
@ -92,14 +99,23 @@ module Projects
log_info(%Q{Repository "#{path}" moved to "#{new_path}" for project "#{project.full_path}"}) log_info(%Q{Repository "#{path}" moved to "#{new_path}" for project "#{project.full_path}"})
project.run_after_commit do project.run_after_commit do
# self is now project GitlabShellWorker.perform_in(REPO_REMOVAL_DELAY, :remove_repository, self.repository_storage, new_path)
GitlabShellWorker.perform_in(5.minutes, :remove_repository, self.repository_storage, new_path)
end end
else else
false false
end end
end end
def schedule_stale_repos_removal
repo_paths = [removal_path(repo_path), removal_path(wiki_path)]
# Ideally it should wait until the regular removal phase finishes,
# so let's delay it a bit further.
repo_paths.each do |path|
GitlabShellWorker.perform_in(REPO_REMOVAL_DELAY * 2, :remove_repository, project.repository_storage, path)
end
end
def rollback_repository(old_path, new_path) def rollback_repository(old_path, new_path)
# There is a possibility project does not have repository or wiki # There is a possibility project does not have repository or wiki
return true unless repo_exists?(old_path) return true unless repo_exists?(old_path)
@ -113,13 +129,11 @@ module Projects
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def mv_repository(from_path, to_path) def mv_repository(from_path, to_path)
return true unless gitlab_shell.exists?(project.repository_storage, from_path + '.git') return true unless repo_exists?(from_path)
gitlab_shell.mv_repository(project.repository_storage, from_path, to_path) gitlab_shell.mv_repository(project.repository_storage, from_path, to_path)
end end
# rubocop: enable CodeReuse/ActiveRecord
def attempt_rollback(project, message) def attempt_rollback(project, message)
return unless project return unless project

View file

@ -0,0 +1,5 @@
---
title: Cleanup stale +deleted repo paths on project removal (adjusts project removal bug)
merge_request: 24269
author:
type: fixed

View file

@ -281,6 +281,40 @@ describe Projects::DestroyService do
end end
end end
context 'repository +deleted path removal' do
def removal_path(path)
"#{path}+#{project.id}#{described_class::DELETED_FLAG}"
end
context 'regular phase' do
it 'schedules +deleted removal of existing repos' do
service = described_class.new(project, user, {})
allow(service).to receive(:schedule_stale_repos_removal)
expect(GitlabShellWorker).to receive(:perform_in)
.with(5.minutes, :remove_repository, project.repository_storage, removal_path(project.disk_path))
service.execute
end
end
context 'stale cleanup' do
let!(:async) { true }
it 'schedules +deleted wiki and repo removal' do
allow(ProjectDestroyWorker).to receive(:perform_async)
expect(GitlabShellWorker).to receive(:perform_in)
.with(10.minutes, :remove_repository, project.repository_storage, removal_path(project.disk_path))
expect(GitlabShellWorker).to receive(:perform_in)
.with(10.minutes, :remove_repository, project.repository_storage, removal_path(project.wiki.disk_path))
destroy_project(project, user, {})
end
end
end
context '#attempt_restore_repositories' do context '#attempt_restore_repositories' do
let(:path) { project.disk_path + '.git' } let(:path) { project.disk_path + '.git' }