Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/backup/remote_storage.rb')
-rw-r--r--lib/backup/remote_storage.rb156
1 files changed, 156 insertions, 0 deletions
diff --git a/lib/backup/remote_storage.rb b/lib/backup/remote_storage.rb
new file mode 100644
index 00000000000..bf62d5d9a7b
--- /dev/null
+++ b/lib/backup/remote_storage.rb
@@ -0,0 +1,156 @@
+# frozen_string_literal: true
+
+module Backup
+ class RemoteStorage
+ attr_reader :progress, :options, :backup_information
+
+ def initialize(progress:, options:)
+ @progress = progress
+ @options = options
+ end
+
+ def upload(backup_information:)
+ @backup_information = backup_information
+ connection_settings = Gitlab.config.backup.upload.connection
+
+ if connection_settings.blank? ||
+ options.skippable_operations.remote_storage ||
+ options.skippable_operations.archive
+ puts_time "Uploading backup archive to remote storage #{remote_directory} ... ".color(:blue) +
+ "[SKIPPED]".color(:cyan)
+ return
+ end
+
+ puts_time "Uploading backup archive to remote storage #{remote_directory} ... ".color(:blue)
+
+ directory = connect_to_remote_directory
+ upload = directory.files.create(create_attributes)
+
+ if upload
+ if upload.respond_to?(:encryption) && upload.encryption
+ puts_time "Uploading backup archive to remote storage #{remote_directory} ... ".color(:blue) +
+ "done (encrypted with #{upload.encryption})".color(:green)
+ else
+ puts_time "Uploading backup archive to remote storage #{remote_directory} ... ".color(:blue) +
+ "done".color(:green)
+ end
+ else
+ puts_time "Uploading backup to #{remote_directory} failed".color(:red)
+ raise Backup::Error, 'Backup failed'
+ end
+ end
+
+ def remote_target
+ if options.remote_directory
+ File.join(options.remote_directory, tar_file)
+ else
+ tar_file
+ end
+ end
+
+ def create_attributes
+ attrs = {
+ key: remote_target,
+ body: File.open(File.join(backup_path, tar_file)),
+ multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size,
+ storage_class: Gitlab.config.backup.upload.storage_class
+ }.merge(encryption_attributes)
+
+ # Google bucket-only policies prevent setting an ACL. In any case, by default,
+ # all objects are set to the default ACL, which is project-private:
+ # https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls
+ attrs[:public] = false unless google_provider?
+
+ attrs
+ end
+
+ def encryption_attributes
+ return object_storage_config.fog_attributes if object_storage_config.aws_server_side_encryption_enabled?
+
+ # Use customer-managed keys. Also, this preserves backward-compatibility
+ # for existing use of Amazon S3-Managed Keys (SSE-S3) that don't set
+ # `backup.upload.storage_options.server_side_encryption` to `'AES256'`.
+ #
+ # AWS supports three different modes for encrypting S3 data:
+ #
+ # 1. Server-Side Encryption with Amazon S3-Managed Keys (SSE-S3)
+ # 2. Server-Side Encryption with Customer Master Keys (CMKs) Stored in AWS
+ # Key Management Service (SSE-KMS)
+ # 3. Server-Side Encryption with Customer-Provided Keys (SSE-C)
+ #
+ # Previously, SSE-S3 and SSE-C were supported via the
+ # `backup.upload.encryption` and `backup.upload.encryption_key`
+ # configuration options.
+ #
+ # SSE-KMS was previously not supported in backups because there was no way
+ # to specify which customer-managed key to use. However, we did support
+ # SSE-KMS with consolidated object storage enabled for other CI artifacts,
+ # attachments, LFS, etc. Note that SSE-C is NOT supported here.
+ #
+ # In consolidated object storage, the `storage_options` Hash provides the
+ # `server_side_encryption` and `server_side_encryption_kms_key_id`
+ # parameters that allow admins to configure SSE-KMS. We reuse this
+ # configuration in backups to support SSE-KMS.
+ {
+ encryption_key: Gitlab.config.backup.upload.encryption_key,
+ encryption: Gitlab.config.backup.upload.encryption
+ }
+ end
+
+ def google_provider?
+ Gitlab.config.backup.upload.connection&.provider&.downcase == 'google'
+ end
+
+ private
+
+ def connect_to_remote_directory
+ connection = ::Fog::Storage.new(object_storage_config.credentials)
+
+ # We only attempt to create the directory for local backups. For AWS
+ # and other cloud providers, we cannot guarantee the user will have
+ # permission to create the bucket.
+ if connection.service == ::Fog::Storage::Local
+ connection.directories.create(key: remote_directory)
+ else
+ connection.directories.new(key: remote_directory)
+ end
+ end
+
+ # The remote 'directory' to store your backups. For S3, this would be the bucket name.
+ # @example Configuration setting the S3 bucket name
+ # remote_directory: 'my.s3.bucket'
+ def remote_directory
+ Gitlab.config.backup.upload.remote_directory
+ end
+
+ def object_storage_config
+ @object_storage_config ||= ObjectStorage::Config.new(Gitlab.config.backup.upload)
+ end
+
+ # TODO: This is a temporary workaround for bad design in Backup::Manager
+ # Output related code would be moved to a new location
+ def puts_time(msg)
+ progress.puts "#{Time.current} -- #{msg}"
+ Gitlab::BackupLogger.info(message: Rainbow.uncolor(msg))
+ end
+
+ # TODO: This is a temporary workaround for bad design in Backup::Manager
+ def tar_file
+ @tar_file ||= "#{backup_id}#{Backup::Manager::FILE_NAME_SUFFIX}"
+ end
+
+ # TODO: This is a temporary workaround for bad design in Backup::Manager
+ def backup_id
+ if options.backup_id.present?
+ File.basename(options.backup_id)
+ else
+ "#{backup_information[:backup_created_at].strftime('%s_%Y_%m_%d_')}#{backup_information[:gitlab_version]}"
+ end
+ end
+
+ # TODO: This is a temporary workaround for bad design in Backup::Manager
+ def backup_path
+ Gitlab.config.backup.path
+ end
+ end
+end