diff options
Diffstat (limited to 'app/services/dependency_proxy')
6 files changed, 127 insertions, 13 deletions
diff --git a/app/services/dependency_proxy/auth_token_service.rb b/app/services/dependency_proxy/auth_token_service.rb new file mode 100644 index 00000000000..16279ed12b0 --- /dev/null +++ b/app/services/dependency_proxy/auth_token_service.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module DependencyProxy + class AuthTokenService < DependencyProxy::BaseService + attr_reader :token + + def initialize(token) + @token = token + end + + def execute + JSONWebToken::HMACToken.decode(token, ::Auth::DependencyProxyAuthenticationService.secret).first + end + + class << self + def decoded_token_payload(token) + self.new(token).execute + end + end + end +end diff --git a/app/services/dependency_proxy/base_service.rb b/app/services/dependency_proxy/base_service.rb index 1b2d4b14a27..944877fd5f9 100644 --- a/app/services/dependency_proxy/base_service.rb +++ b/app/services/dependency_proxy/base_service.rb @@ -2,6 +2,16 @@ module DependencyProxy class BaseService < ::BaseService + class DownloadError < StandardError + attr_reader :http_status + + def initialize(message, http_status) + @http_status = http_status + + super(message) + end + end + private def registry diff --git a/app/services/dependency_proxy/download_blob_service.rb b/app/services/dependency_proxy/download_blob_service.rb index 3c690683bf6..b3548c8a126 100644 --- a/app/services/dependency_proxy/download_blob_service.rb +++ b/app/services/dependency_proxy/download_blob_service.rb @@ -2,16 +2,6 @@ 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 diff --git a/app/services/dependency_proxy/find_or_create_manifest_service.rb b/app/services/dependency_proxy/find_or_create_manifest_service.rb new file mode 100644 index 00000000000..6b46f5e4c59 --- /dev/null +++ b/app/services/dependency_proxy/find_or_create_manifest_service.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module DependencyProxy + class FindOrCreateManifestService < DependencyProxy::BaseService + def initialize(group, image, tag, token) + @group = group + @image = image + @tag = tag + @token = token + @file_name = "#{@image}:#{@tag}.json" + @manifest = nil + end + + def execute + @manifest = @group.dependency_proxy_manifests + .find_or_initialize_by_file_name(@file_name) + + head_result = DependencyProxy::HeadManifestService.new(@image, @tag, @token).execute + + return success(manifest: @manifest) if cached_manifest_matches?(head_result) + + pull_new_manifest + respond + rescue Timeout::Error, *Gitlab::HTTP::HTTP_ERRORS + respond + end + + private + + def pull_new_manifest + DependencyProxy::PullManifestService.new(@image, @tag, @token).execute_with_manifest do |new_manifest| + @manifest.update!( + digest: new_manifest[:digest], + file: new_manifest[:file], + size: new_manifest[:file].size + ) + end + end + + def cached_manifest_matches?(head_result) + @manifest && @manifest.digest == head_result[:digest] + end + + def respond + if @manifest.persisted? + success(manifest: @manifest) + else + error('Failed to download the manifest from the external registry', 503) + end + end + end +end diff --git a/app/services/dependency_proxy/head_manifest_service.rb b/app/services/dependency_proxy/head_manifest_service.rb new file mode 100644 index 00000000000..87d9c417c98 --- /dev/null +++ b/app/services/dependency_proxy/head_manifest_service.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module DependencyProxy + class HeadManifestService < DependencyProxy::BaseService + def initialize(image, tag, token) + @image = image + @tag = tag + @token = token + end + + def execute + response = Gitlab::HTTP.head(manifest_url, headers: auth_headers) + + if response.success? + success(digest: response.headers['docker-content-digest']) + 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/pull_manifest_service.rb b/app/services/dependency_proxy/pull_manifest_service.rb index fc54ef85c96..5c804489fd1 100644 --- a/app/services/dependency_proxy/pull_manifest_service.rb +++ b/app/services/dependency_proxy/pull_manifest_service.rb @@ -8,13 +8,25 @@ module DependencyProxy @token = token end - def execute + def execute_with_manifest + raise ArgumentError, 'Block must be provided' unless block_given? + response = Gitlab::HTTP.get(manifest_url, headers: auth_headers) if response.success? - success(manifest: response.body) + file = Tempfile.new + + begin + file.write(response) + file.flush + + yield(success(file: file, digest: response.headers['docker-content-digest'])) + ensure + file.close + file.unlink + end else - error(response.body, response.code) + yield(error(response.body, response.code)) end rescue Timeout::Error => exception error(exception.message, 599) |