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:
commit
c5a74a9e15
3 changed files with 58 additions and 5 deletions
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Cleanup stale +deleted repo paths on project removal (adjusts project removal bug)
|
||||||
|
merge_request: 24269
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -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' }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue