2018-11-20 20:47:30 +05:30
# frozen_string_literal: true
2017-09-10 17:25:29 +05:30
module Storage
module LegacyNamespace
extend ActiveSupport :: Concern
2019-02-15 15:39:39 +05:30
include Gitlab :: ShellAdapter
2017-09-10 17:25:29 +05:30
def move_dir
2018-12-05 23:21:45 +05:30
proj_with_tags = first_project_with_container_registry_tags
if proj_with_tags
raise Gitlab :: UpdatePathError . new ( " Namespace #{ name } ( #{ id } ) cannot be moved because at least one project (e.g. #{ proj_with_tags . name } ( #{ proj_with_tags . id } )) has tags in container registry " )
2017-09-10 17:25:29 +05:30
end
2019-07-31 22:56:46 +05:30
parent_was = if saved_change_to_parent? && parent_id_before_last_save . present?
Namespace . find ( parent_id_before_last_save ) # raise NotFound early if needed
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
move_repositories
2017-09-10 17:25:29 +05:30
2019-07-31 22:56:46 +05:30
if saved_change_to_parent?
2018-03-17 18:26:18 +05:30
former_parent_full_path = parent_was & . full_path
parent_full_path = parent & . full_path
Gitlab :: UploadsTransfer . new . move_namespace ( path , former_parent_full_path , parent_full_path )
2020-11-24 15:15:51 +05:30
if any_project_with_pages_deployed?
run_after_commit do
Gitlab :: PagesTransfer . new . async . move_namespace ( path , former_parent_full_path , parent_full_path )
end
end
2018-03-17 18:26:18 +05:30
else
2019-07-31 22:56:46 +05:30
Gitlab :: UploadsTransfer . new . rename_namespace ( full_path_before_last_save , full_path )
2020-11-24 15:15:51 +05:30
if any_project_with_pages_deployed?
full_path_was = full_path_before_last_save
run_after_commit do
Gitlab :: PagesTransfer . new . async . rename_namespace ( full_path_was , full_path )
end
end
2018-03-17 18:26:18 +05:30
end
2017-09-10 17:25:29 +05:30
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
send_update_instructions
2018-03-17 18:26:18 +05:30
write_projects_repository_config
2018-11-18 11:00:15 +05:30
rescue = > e
2020-01-01 13:55:28 +05:30
Gitlab :: ErrorTracking . track_and_raise_for_dev_exception ( e ,
full_path_before_last_save : full_path_before_last_save ,
full_path : full_path ,
action : 'move_dir' )
2017-09-10 17:25:29 +05:30
end
2018-11-18 11:00:15 +05:30
true # false would cancel later callbacks but not rollback
2017-09-10 17:25:29 +05:30
end
# Hooks
2018-10-15 14:42:47 +05:30
# Save the storages before the projects are destroyed to use them on after destroy
2017-09-10 17:25:29 +05:30
def prepare_for_destroy
2018-10-15 14:42:47 +05:30
old_repository_storages
2017-09-10 17:25:29 +05:30
end
private
2018-03-17 18:26:18 +05:30
def move_repositories
2018-10-15 14:42:47 +05:30
# Move the namespace directory in all storages used by member projects
2019-12-26 22:10:19 +05:30
repository_storages ( legacy_only : true ) . each do | repository_storage |
2018-03-17 18:26:18 +05:30
# Ensure old directory exists before moving it
2019-12-26 22:10:19 +05:30
Gitlab :: GitalyClient :: NamespaceService . allow do
gitlab_shell . add_namespace ( repository_storage , full_path_before_last_save )
2018-03-17 18:26:18 +05:30
2019-12-26 22:10:19 +05:30
# Ensure new directory exists before moving it (if there's a parent)
gitlab_shell . add_namespace ( repository_storage , parent . full_path ) if parent
2018-03-17 18:26:18 +05:30
2019-12-26 22:10:19 +05:30
unless gitlab_shell . mv_namespace ( repository_storage , full_path_before_last_save , full_path )
2018-03-17 18:26:18 +05:30
2020-06-23 00:09:42 +05:30
Gitlab :: AppLogger . error ( " Exception moving path #{ repository_storage } from #{ full_path_before_last_save } to #{ full_path } " )
2018-03-17 18:26:18 +05:30
2019-12-26 22:10:19 +05:30
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Gitlab :: UpdatePathError . new ( 'namespace directory cannot be moved' )
end
2018-03-17 18:26:18 +05:30
end
end
end
2018-10-15 14:42:47 +05:30
def old_repository_storages
@old_repository_storage_paths || = repository_storages
2017-09-10 17:25:29 +05:30
end
2019-12-26 22:10:19 +05:30
def repository_storages ( legacy_only : false )
2017-09-10 17:25:29 +05:30
# We need to get the storage paths for all the projects, even the ones that are
# pending delete. Unscoping also get rids of the default order, which causes
# problems with SELECT DISTINCT.
Project . unscoped do
2019-12-26 22:10:19 +05:30
namespace_projects = all_projects
namespace_projects = namespace_projects . without_storage_feature ( :repository ) if legacy_only
namespace_projects . pluck ( Arel . sql ( 'distinct(repository_storage)' ) )
2017-09-10 17:25:29 +05:30
end
end
def rm_dir
# Remove the namespace directory in all storages paths used by member projects
2018-10-15 14:42:47 +05:30
old_repository_storages . each do | repository_storage |
2017-09-10 17:25:29 +05:30
# Move namespace directory into trash.
# We will remove it later async
new_path = " #{ full_path } + #{ id } +deleted "
2019-12-26 22:10:19 +05:30
Gitlab :: GitalyClient :: NamespaceService . allow do
if gitlab_shell . mv_namespace ( repository_storage , full_path , new_path )
Gitlab :: AppLogger . info %Q( Namespace directory " #{ full_path } " moved to " #{ new_path } " )
2017-09-10 17:25:29 +05:30
2019-12-26 22:10:19 +05:30
# Remove namespace directory async with delay so
# GitLab has time to remove all projects first
run_after_commit do
GitlabShellWorker . perform_in ( 5 . minutes , :rm_namespace , repository_storage , new_path )
end
2017-09-10 17:25:29 +05:30
end
end
end
end
end
end