summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-28 03:08:39 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-28 03:08:39 +0000
commit5cef625594aedbac12011d870719fe81a1587a98 (patch)
tree147d465fb4275ab2d14be99ed58888ca23e10111 /app
parentee7de3a24d62376916d78649d7e477a184b2e203 (diff)
downloadgitlab-ce-5cef625594aedbac12011d870719fe81a1587a98.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/services/projects/destroy_rollback_service.rb31
-rw-r--r--app/services/projects/destroy_service.rb98
-rw-r--r--app/services/projects/overwrite_project_service.rb2
-rw-r--r--app/services/repositories/base_service.rb52
-rw-r--r--app/services/repositories/destroy_rollback_service.rb19
-rw-r--r--app/services/repositories/destroy_service.rb28
-rw-r--r--app/services/repositories/shell_destroy_service.rb15
7 files changed, 158 insertions, 87 deletions
diff --git a/app/services/projects/destroy_rollback_service.rb b/app/services/projects/destroy_rollback_service.rb
new file mode 100644
index 00000000000..7f0ca63a406
--- /dev/null
+++ b/app/services/projects/destroy_rollback_service.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Projects
+ class DestroyRollbackService < BaseService
+ include Gitlab::ShellAdapter
+
+ def execute
+ return unless project
+
+ Projects::ForksCountService.new(project).delete_cache
+
+ unless rollback_repository(project.repository)
+ raise_error(s_('DeleteProject|Failed to restore project repository. Please contact the administrator.'))
+ end
+
+ unless rollback_repository(project.wiki.repository)
+ raise_error(s_('DeleteProject|Failed to restore wiki repository. Please contact the administrator.'))
+ end
+ end
+
+ private
+
+ def rollback_repository(repository)
+ return true unless repository
+
+ result = Repositories::DestroyRollbackService.new(repository).execute
+
+ result[:status] == :success
+ end
+ end
+end
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index cbed794f92e..066d1f1ca72 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -6,9 +6,6 @@ module Projects
DestroyError = Class.new(StandardError)
- DELETED_FLAG = '+deleted'
- REPO_REMOVAL_DELAY = 5.minutes.to_i
-
def async_execute
project.update_attribute(:pending_delete, true)
@@ -18,7 +15,7 @@ module Projects
schedule_stale_repos_removal
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}") # rubocop:disable Gitlab/RailsLogger
+ log_info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}")
end
def execute
@@ -48,82 +45,34 @@ module Projects
raise
end
- def attempt_repositories_rollback
- return unless @project
-
- flush_caches(@project)
-
- unless rollback_repository(removal_path(repo_path), repo_path)
- raise_error(s_('DeleteProject|Failed to restore project repository. Please contact the administrator.'))
- end
-
- unless rollback_repository(removal_path(wiki_path), wiki_path)
- raise_error(s_('DeleteProject|Failed to restore wiki repository. Please contact the administrator.'))
- end
- end
-
private
- def repo_path
- project.disk_path
- end
-
- def wiki_path
- project.wiki.disk_path
- end
-
def trash_repositories!
- unless remove_repository(repo_path)
+ unless remove_repository(project.repository)
raise_error(s_('DeleteProject|Failed to remove project repository. Please try again or contact administrator.'))
end
- unless remove_repository(wiki_path)
+ unless remove_repository(project.wiki.repository)
raise_error(s_('DeleteProject|Failed to remove wiki repository. Please try again or contact administrator.'))
end
end
- def remove_repository(path)
- # There is a possibility project does not have repository or wiki
- return true unless repo_exists?(path)
+ def remove_repository(repository)
+ return true unless repository
- new_path = removal_path(path)
+ result = Repositories::DestroyService.new(repository).execute
- if mv_repository(path, new_path)
- log_info(%Q{Repository "#{path}" moved to "#{new_path}" for project "#{project.full_path}"})
-
- project.run_after_commit do
- GitlabShellWorker.perform_in(REPO_REMOVAL_DELAY, :remove_repository, self.repository_storage, new_path)
- end
- else
- false
- end
+ result[:status] == :success
end
def schedule_stale_repos_removal
- repo_paths = [removal_path(repo_path), removal_path(wiki_path)]
+ repos = [project.repository, project.wiki.repository]
- # 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
+ repos.each do |repository|
+ next unless repository
- def rollback_repository(old_path, new_path)
- # There is a possibility project does not have repository or wiki
- return true unless repo_exists?(old_path)
-
- mv_repository(old_path, new_path)
- end
-
- def repo_exists?(path)
- gitlab_shell.repository_exists?(project.repository_storage, path + '.git')
- end
-
- def mv_repository(from_path, to_path)
- return true unless repo_exists?(from_path)
-
- gitlab_shell.mv_repository(project.repository_storage, from_path, to_path)
+ Repositories::ShellDestroyService.new(repository).execute(Repositories::ShellDestroyService::STALE_REMOVAL_DELAY)
+ end
end
def attempt_rollback(project, message)
@@ -191,32 +140,9 @@ module Projects
raise DestroyError.new(message)
end
- # Build a path for removing repositories
- # We use `+` because its not allowed by GitLab so user can not create
- # project with name cookies+119+deleted and capture someone stalled repository
- #
- # gitlab/cookies.git -> gitlab/cookies+119+deleted.git
- #
- def removal_path(path)
- "#{path}+#{project.id}#{DELETED_FLAG}"
- end
-
def flush_caches(project)
- ignore_git_errors(repo_path) { project.repository.before_delete }
-
- ignore_git_errors(wiki_path) { Repository.new(wiki_path, project, disk_path: repo_path).before_delete }
-
Projects::ForksCountService.new(project).delete_cache
end
-
- # If we get a Gitaly error, the repository may be corrupted. We can
- # ignore these errors since we're going to trash the repositories
- # anyway.
- def ignore_git_errors(disk_path, &block)
- yield
- rescue Gitlab::Git::CommandError => e
- Gitlab::GitLogger.warn(class: self.class.name, project_id: project.id, disk_path: disk_path, message: e.to_s)
- end
end
end
diff --git a/app/services/projects/overwrite_project_service.rb b/app/services/projects/overwrite_project_service.rb
index c5e38f166da..64cc1c3aee3 100644
--- a/app/services/projects/overwrite_project_service.rb
+++ b/app/services/projects/overwrite_project_service.rb
@@ -55,7 +55,7 @@ module Projects
end
def attempt_restore_repositories(project)
- ::Projects::DestroyService.new(project, @current_user).attempt_repositories_rollback
+ ::Projects::DestroyRollbackService.new(project, @current_user).execute
end
def add_source_project_to_fork_network(source_project)
diff --git a/app/services/repositories/base_service.rb b/app/services/repositories/base_service.rb
new file mode 100644
index 00000000000..6a39399c791
--- /dev/null
+++ b/app/services/repositories/base_service.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+class Repositories::BaseService < BaseService
+ include Gitlab::ShellAdapter
+
+ DELETED_FLAG = '+deleted'
+
+ attr_reader :repository
+
+ delegate :project, :disk_path, :full_path, to: :repository
+ delegate :repository_storage, to: :project
+
+ def initialize(repository)
+ @repository = repository
+ end
+
+ def repo_exists?(path)
+ gitlab_shell.repository_exists?(repository_storage, path + '.git')
+ end
+
+ def mv_repository(from_path, to_path)
+ return true unless repo_exists?(from_path)
+
+ gitlab_shell.mv_repository(repository_storage, from_path, to_path)
+ end
+
+ # Build a path for removing repositories
+ # We use `+` because its not allowed by GitLab so user can not create
+ # project with name cookies+119+deleted and capture someone stalled repository
+ #
+ # gitlab/cookies.git -> gitlab/cookies+119+deleted.git
+ #
+ def removal_path
+ "#{disk_path}+#{project.id}#{DELETED_FLAG}"
+ end
+
+ # If we get a Gitaly error, the repository may be corrupted. We can
+ # ignore these errors since we're going to trash the repositories
+ # anyway.
+ def ignore_git_errors(&block)
+ yield
+ rescue Gitlab::Git::CommandError => e
+ Gitlab::GitLogger.warn(class: self.class.name, project_id: project.id, disk_path: disk_path, message: e.to_s)
+ end
+
+ def move_error(path)
+ error = %Q{Repository "#{path}" could not be moved}
+
+ log_error(error)
+ error(error)
+ end
+end
diff --git a/app/services/repositories/destroy_rollback_service.rb b/app/services/repositories/destroy_rollback_service.rb
new file mode 100644
index 00000000000..5ef4e11bf55
--- /dev/null
+++ b/app/services/repositories/destroy_rollback_service.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class Repositories::DestroyRollbackService < Repositories::BaseService
+ def execute
+ # There is a possibility project does not have repository or wiki
+ return success unless repo_exists?(removal_path)
+
+ # Flush the cache for both repositories.
+ ignore_git_errors { repository.before_delete }
+
+ if mv_repository(removal_path, disk_path)
+ log_info(%Q{Repository "#{removal_path}" moved to "#{disk_path}" for repository "#{full_path}"})
+
+ success
+ else
+ move_error(removal_path)
+ end
+ end
+end
diff --git a/app/services/repositories/destroy_service.rb b/app/services/repositories/destroy_service.rb
new file mode 100644
index 00000000000..374968f610e
--- /dev/null
+++ b/app/services/repositories/destroy_service.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class Repositories::DestroyService < Repositories::BaseService
+ def execute
+ return success unless repository
+ return success unless repo_exists?(disk_path)
+
+ # Flush the cache for both repositories. This has to be done _before_
+ # removing the physical repositories as some expiration code depends on
+ # Git data (e.g. a list of branch names).
+ ignore_git_errors { repository.before_delete }
+
+ if mv_repository(disk_path, removal_path)
+ log_info(%Q{Repository "#{disk_path}" moved to "#{removal_path}" for repository "#{full_path}"})
+
+ current_repository = repository
+ project.run_after_commit do
+ Repositories::ShellDestroyService.new(current_repository).execute
+ end
+
+ log_info("Project \"#{project.full_path}\" was removed")
+
+ success
+ else
+ move_error(disk_path)
+ end
+ end
+end
diff --git a/app/services/repositories/shell_destroy_service.rb b/app/services/repositories/shell_destroy_service.rb
new file mode 100644
index 00000000000..2f5af10e24c
--- /dev/null
+++ b/app/services/repositories/shell_destroy_service.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class Repositories::ShellDestroyService < Repositories::BaseService
+ REPO_REMOVAL_DELAY = 5.minutes.to_i
+ STALE_REMOVAL_DELAY = REPO_REMOVAL_DELAY * 2
+
+ def execute(delay = REPO_REMOVAL_DELAY)
+ return success unless repository
+
+ GitlabShellWorker.perform_in(delay,
+ :remove_repository,
+ repository_storage,
+ removal_path)
+ end
+end