diff options
Diffstat (limited to 'app/services/dependency_proxy')
5 files changed, 168 insertions, 0 deletions
diff --git a/app/services/dependency_proxy/base_service.rb b/app/services/dependency_proxy/base_service.rb new file mode 100644 index 00000000000..1b2d4b14a27 --- /dev/null +++ b/app/services/dependency_proxy/base_service.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module DependencyProxy + class BaseService < ::BaseService + private + + def registry + DependencyProxy::Registry + end + + def auth_headers + { + Authorization: "Bearer #{@token}" + } + end + end +end diff --git a/app/services/dependency_proxy/download_blob_service.rb b/app/services/dependency_proxy/download_blob_service.rb new file mode 100644 index 00000000000..3c690683bf6 --- /dev/null +++ b/app/services/dependency_proxy/download_blob_service.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module DependencyProxy + class DownloadBlobService < DependencyProxy::BaseService + class DownloadError < StandardError + attr_reader :http_status + + def initialize(message, http_status) + @http_status = http_status + + super(message) + end + end + + def initialize(image, blob_sha, token) + @image = image + @blob_sha = blob_sha + @token = token + @temp_file = Tempfile.new + end + + def execute + File.open(@temp_file.path, "wb") do |file| + Gitlab::HTTP.get(blob_url, headers: auth_headers, stream_body: true) do |fragment| + if [301, 302, 307].include?(fragment.code) + # do nothing + elsif fragment.code == 200 + file.write(fragment) + else + raise DownloadError.new('Non-success response code on downloading blob fragment', fragment.code) + end + end + end + + success(file: @temp_file) + rescue DownloadError => exception + error(exception.message, exception.http_status) + rescue Timeout::Error => exception + error(exception.message, 599) + end + + private + + def blob_url + registry.blob_url(@image, @blob_sha) + end + end +end diff --git a/app/services/dependency_proxy/find_or_create_blob_service.rb b/app/services/dependency_proxy/find_or_create_blob_service.rb new file mode 100644 index 00000000000..bd06f9d7628 --- /dev/null +++ b/app/services/dependency_proxy/find_or_create_blob_service.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module DependencyProxy + class FindOrCreateBlobService < DependencyProxy::BaseService + def initialize(group, image, token, blob_sha) + @group = group + @image = image + @token = token + @blob_sha = blob_sha + end + + def execute + file_name = @blob_sha.sub('sha256:', '') + '.gz' + blob = @group.dependency_proxy_blobs.find_or_build(file_name) + + unless blob.persisted? + result = DependencyProxy::DownloadBlobService + .new(@image, @blob_sha, @token).execute + + if result[:status] == :error + log_failure(result) + + return error('Failed to download the blob', result[:http_status]) + end + + blob.file = result[:file] + blob.size = result[:file].size + blob.save! + end + + success(blob: blob) + end + + private + + def log_failure(result) + log_error( + "Dependency proxy: Failed to download the blob." \ + "Blob sha: #{@blob_sha}." \ + "Error message: #{result[:message][0, 100]}" \ + "HTTP status: #{result[:http_status]}" + ) + end + end +end diff --git a/app/services/dependency_proxy/pull_manifest_service.rb b/app/services/dependency_proxy/pull_manifest_service.rb new file mode 100644 index 00000000000..fc54ef85c96 --- /dev/null +++ b/app/services/dependency_proxy/pull_manifest_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module DependencyProxy + class PullManifestService < DependencyProxy::BaseService + def initialize(image, tag, token) + @image = image + @tag = tag + @token = token + end + + def execute + response = Gitlab::HTTP.get(manifest_url, headers: auth_headers) + + if response.success? + success(manifest: response.body) + else + error(response.body, response.code) + end + rescue Timeout::Error => exception + error(exception.message, 599) + end + + private + + def manifest_url + registry.manifest_url(@image, @tag) + end + end +end diff --git a/app/services/dependency_proxy/request_token_service.rb b/app/services/dependency_proxy/request_token_service.rb new file mode 100644 index 00000000000..4ca7239b9f6 --- /dev/null +++ b/app/services/dependency_proxy/request_token_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module DependencyProxy + class RequestTokenService < DependencyProxy::BaseService + def initialize(image) + @image = image + end + + def execute + response = Gitlab::HTTP.get(auth_url) + + if response.success? + success(token: Gitlab::Json.parse(response.body)['token']) + else + error('Expected 200 response code for an access token', response.code) + end + rescue Timeout::Error => exception + error(exception.message, 599) + rescue JSON::ParserError + error('Failed to parse a response body for an access token', 500) + end + + private + + def auth_url + registry.auth_url(@image) + end + end +end |