diff options
Diffstat (limited to 'app/services/pages')
-rw-r--r-- | app/services/pages/migrate_legacy_storage_to_deployment_service.rb | 58 | ||||
-rw-r--r-- | app/services/pages/zip_directory_service.rb | 49 |
2 files changed, 91 insertions, 16 deletions
diff --git a/app/services/pages/migrate_legacy_storage_to_deployment_service.rb b/app/services/pages/migrate_legacy_storage_to_deployment_service.rb new file mode 100644 index 00000000000..dac994b2ccc --- /dev/null +++ b/app/services/pages/migrate_legacy_storage_to_deployment_service.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Pages + class MigrateLegacyStorageToDeploymentService + ExclusiveLeaseTakenError = Class.new(StandardError) + + include BaseServiceUtility + include ::Pages::LegacyStorageLease + + attr_reader :project + + def initialize(project) + @project = project + end + + def execute + result = try_obtain_lease do + execute_unsafe + end + + raise ExclusiveLeaseTakenError, "Can't migrate pages for project #{project.id}: exclusive lease taken" if result.nil? + + result + end + + private + + def execute_unsafe + zip_result = ::Pages::ZipDirectoryService.new(project.pages_path).execute + + if zip_result[:status] == :error + if !project.pages_metadatum&.reload&.pages_deployment && + Feature.enabled?(:pages_migration_mark_as_not_deployed, project) + project.mark_pages_as_not_deployed + end + + return error("Can't create zip archive: #{zip_result[:message]}") + end + + archive_path = zip_result[:archive_path] + + deployment = nil + File.open(archive_path) do |file| + deployment = project.pages_deployments.create!( + file: file, + file_count: zip_result[:entries_count], + file_sha256: Digest::SHA256.file(archive_path).hexdigest + ) + end + + project.set_first_pages_deployment!(deployment) + + success + ensure + FileUtils.rm_f(archive_path) if archive_path + end + end +end diff --git a/app/services/pages/zip_directory_service.rb b/app/services/pages/zip_directory_service.rb index a27ad5fda46..ba7a8571e88 100644 --- a/app/services/pages/zip_directory_service.rb +++ b/app/services/pages/zip_directory_service.rb @@ -2,37 +2,43 @@ module Pages class ZipDirectoryService - InvalidArchiveError = Class.new(RuntimeError) - InvalidEntryError = Class.new(RuntimeError) + include BaseServiceUtility + include Gitlab::Utils::StrongMemoize + + # used only to track exceptions in Sentry + InvalidEntryError = Class.new(StandardError) PUBLIC_DIR = 'public' def initialize(input_dir) - @input_dir = File.realpath(input_dir) - @output_file = File.join(@input_dir, "@migrated.zip") # '@' to avoid any name collision with groups or projects + @input_dir = input_dir end def execute - FileUtils.rm_f(@output_file) + return error("Can not find valid public dir in #{@input_dir}") unless valid_path?(public_dir) + + output_file = File.join(real_dir, "@migrated.zip") # '@' to avoid any name collision with groups or projects + + FileUtils.rm_f(output_file) - count = 0 - ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile| + entries_count = 0 + ::Zip::File.open(output_file, ::Zip::File::CREATE) do |zipfile| write_entry(zipfile, PUBLIC_DIR) - count = zipfile.entries.count + entries_count = zipfile.entries.count end - [@output_file, count] + success(archive_path: output_file, entries_count: entries_count) + rescue => e + FileUtils.rm_f(output_file) if output_file + raise e end private def write_entry(zipfile, zipfile_path) - disk_file_path = File.join(@input_dir, zipfile_path) + disk_file_path = File.join(real_dir, zipfile_path) unless valid_path?(disk_file_path) - # archive without public directory is completelly unusable - raise InvalidArchiveError if zipfile_path == PUBLIC_DIR - # archive with invalid entry will just have this entry missing raise InvalidEntryError end @@ -71,13 +77,24 @@ module Pages def valid_path?(disk_file_path) realpath = File.realpath(disk_file_path) - realpath == File.join(@input_dir, PUBLIC_DIR) || - realpath.start_with?(File.join(@input_dir, PUBLIC_DIR + "/")) + realpath == public_dir || realpath.start_with?(public_dir + "/") # happens if target of symlink isn't there rescue => e - Gitlab::ErrorTracking.track_exception(e, input_dir: @input_dir, disk_file_path: disk_file_path) + Gitlab::ErrorTracking.track_exception(e, input_dir: real_dir, disk_file_path: disk_file_path) false end + + def real_dir + strong_memoize(:real_dir) do + File.realpath(@input_dir) rescue nil + end + end + + def public_dir + strong_memoize(:public_dir) do + File.join(real_dir, PUBLIC_DIR) rescue nil + end + end end end |