Commit a6c0e0c9 authored by Markus Koller's avatar Markus Koller

Merge branch '349741-registry-client-changes' into 'master'

Add support for the gitlab container registry API

See merge request gitlab-org/gitlab!78452
parents 6e7d0fe0 f4504543
...@@ -23,7 +23,7 @@ class ContainerRepository < ApplicationRecord ...@@ -23,7 +23,7 @@ class ContainerRepository < ApplicationRecord
enum expiration_policy_cleanup_status: { cleanup_unscheduled: 0, cleanup_scheduled: 1, cleanup_unfinished: 2, cleanup_ongoing: 3 } enum expiration_policy_cleanup_status: { cleanup_unscheduled: 0, cleanup_scheduled: 1, cleanup_unfinished: 2, cleanup_ongoing: 3 }
enum migration_skipped_reason: { not_in_plan: 0, too_many_retries: 1, too_many_tags: 2, root_namespace_in_deny_list: 3 } enum migration_skipped_reason: { not_in_plan: 0, too_many_retries: 1, too_many_tags: 2, root_namespace_in_deny_list: 3 }
delegate :client, to: :registry delegate :client, :gitlab_api_client, to: :registry
scope :ordered, -> { order(:name) } scope :ordered, -> { order(:name) }
scope :with_api_entity_associations, -> { preload(project: [:route, { namespace: :route }]) } scope :with_api_entity_associations, -> { preload(project: [:route, { namespace: :route }]) }
...@@ -150,6 +150,18 @@ class ContainerRepository < ApplicationRecord ...@@ -150,6 +150,18 @@ class ContainerRepository < ApplicationRecord
migration_state == 'importing' migration_state == 'importing'
end end
def migration_pre_import
return :error unless gitlab_api_client.supports_gitlab_api?
gitlab_api_client.pre_import_repository(self.path)
end
def migration_import
return :error unless gitlab_api_client.supports_gitlab_api?
gitlab_api_client.import_repository(self.path)
end
def self.build_from_path(path) def self.build_from_path(path)
self.new(project: path.repository_project, self.new(project: path.repository_project,
name: path.repository_name) name: path.repository_name)
......
...@@ -15,6 +15,12 @@ class UpdateContainerRegistryInfoService ...@@ -15,6 +15,12 @@ class UpdateContainerRegistryInfoService
client = ContainerRegistry::Client.new(registry_config.api_url, token: token) client = ContainerRegistry::Client.new(registry_config.api_url, token: token)
info = client.registry_info info = client.registry_info
gitlab_api_client = ContainerRegistry::GitlabApiClient.new(registry_config.api_url, token: token)
if gitlab_api_client.supports_gitlab_api?
info[:features] ||= []
info[:features] << ContainerRegistry::GitlabApiClient::REGISTRY_GITLAB_V1_API_FEATURE
end
Gitlab::CurrentSettings.update!( Gitlab::CurrentSettings.update!(
container_registry_vendor: info[:vendor] || '', container_registry_vendor: info[:vendor] || '',
container_registry_version: info[:version] || '', container_registry_version: info[:version] || '',
......
# frozen_string_literal: true
require 'faraday'
require 'faraday_middleware'
require 'digest'
module ContainerRegistry
class BaseClient
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json'
DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE = 'application/vnd.docker.distribution.manifest.list.v2+json'
OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json'
CONTAINER_IMAGE_V1_TYPE = 'application/vnd.docker.container.image.v1+json'
ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze
ACCEPTED_TYPES_RAW = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE, DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE].freeze
RETRY_EXCEPTIONS = [Faraday::Request::Retry::DEFAULT_EXCEPTIONS, Faraday::ConnectionFailed].flatten.freeze
RETRY_OPTIONS = {
max: 1,
interval: 5,
exceptions: RETRY_EXCEPTIONS
}.freeze
ERROR_CALLBACK_OPTIONS = {
callback: -> (env, exception) do
Gitlab::ErrorTracking.log_exception(
exception,
class: name,
url: env[:url]
)
end
}.freeze
# Taken from: FaradayMiddleware::FollowRedirects
REDIRECT_CODES = Set.new [301, 302, 303, 307]
class << self
private
def with_dummy_client(return_value_if_disabled: nil)
registry_config = Gitlab.config.registry
unless registry_config.enabled && registry_config.api_url.present?
return return_value_if_disabled
end
token = Auth::ContainerRegistryAuthenticationService.access_token([], [])
yield new(registry_config.api_url, token: token)
end
end
def initialize(base_uri, options = {})
@base_uri = base_uri
@options = options
end
private
def faraday(timeout_enabled: true)
@faraday ||= faraday_base(timeout_enabled: timeout_enabled) do |conn|
initialize_connection(conn, @options, &method(:accept_manifest))
end
end
def faraday_base(timeout_enabled: true, &block)
request_options = timeout_enabled ? Gitlab::HTTP::DEFAULT_TIMEOUT_OPTIONS : nil
Faraday.new(
@base_uri,
headers: { user_agent: "GitLab/#{Gitlab::VERSION}" },
request: request_options,
&block
)
end
def initialize_connection(conn, options)
conn.request :json
if options[:user] && options[:password]
conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)
elsif options[:token]
conn.request(:authorization, :bearer, options[:token].to_s)
end
yield(conn) if block_given?
conn.request(:retry, RETRY_OPTIONS)
conn.request(:gitlab_error_callback, ERROR_CALLBACK_OPTIONS)
conn.adapter :net_http
end
def response_body(response, allow_redirect: false)
if allow_redirect && REDIRECT_CODES.include?(response.status)
response = redirect_response(response.headers['location'])
end
response.body if response && response.success?
end
def redirect_response(location)
return unless location
uri = URI(@base_uri).merge(location)
raise ArgumentError, "Invalid scheme for #{location}" unless %w[http https].include?(uri.scheme)
faraday_redirect.get(uri)
end
def accept_manifest(conn)
conn.headers['Accept'] = ACCEPTED_TYPES
conn.response :json, content_type: 'application/json'
conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+prettyjws'
conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+json'
conn.response :json, content_type: DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
conn.response :json, content_type: OCI_MANIFEST_V1_TYPE
end
# Create a new request to make sure the Authorization header is not inserted
# via the Faraday middleware
def faraday_redirect
@faraday_redirect ||= faraday_base do |conn|
conn.request :json
conn.request(:retry, RETRY_OPTIONS)
conn.request(:gitlab_error_callback, ERROR_CALLBACK_OPTIONS)
conn.adapter :net_http
end
end
def delete_if_exists(path)
result = faraday.delete(path)
result.success? || result.status == 404
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
require 'faraday'
require 'faraday_middleware'
require 'digest'
module ContainerRegistry module ContainerRegistry
class Client class Client < BaseClient
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
attr_accessor :uri attr_accessor :uri
DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json'
DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE = 'application/vnd.docker.distribution.manifest.list.v2+json'
OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json'
CONTAINER_IMAGE_V1_TYPE = 'application/vnd.docker.container.image.v1+json'
REGISTRY_VERSION_HEADER = 'gitlab-container-registry-version' REGISTRY_VERSION_HEADER = 'gitlab-container-registry-version'
REGISTRY_FEATURES_HEADER = 'gitlab-container-registry-features' REGISTRY_FEATURES_HEADER = 'gitlab-container-registry-features'
REGISTRY_TAG_DELETE_FEATURE = 'tag_delete' REGISTRY_TAG_DELETE_FEATURE = 'tag_delete'
ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze
ACCEPTED_TYPES_RAW = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE, DOCKER_DISTRIBUTION_MANIFEST_LIST_V2_TYPE].freeze
# Taken from: FaradayMiddleware::FollowRedirects
REDIRECT_CODES = Set.new [301, 302, 303, 307]
RETRY_EXCEPTIONS = [Faraday::Request::Retry::DEFAULT_EXCEPTIONS, Faraday::ConnectionFailed].flatten.freeze
RETRY_OPTIONS = {
max: 1,
interval: 5,
exceptions: RETRY_EXCEPTIONS
}.freeze
ERROR_CALLBACK_OPTIONS = {
callback: -> (env, exception) do
Gitlab::ErrorTracking.log_exception(
exception,
class: name,
url: env[:url]
)
end
}.freeze
def self.supports_tag_delete? def self.supports_tag_delete?
registry_config = Gitlab.config.registry with_dummy_client(return_value_if_disabled: false) do |client|
return false unless registry_config.enabled && registry_config.api_url.present? client.supports_tag_delete?
end
token = Auth::ContainerRegistryAuthenticationService.access_token([], [])
client = new(registry_config.api_url, token: token)
client.supports_tag_delete?
end end
def self.registry_info def self.registry_info
registry_config = Gitlab.config.registry with_dummy_client do |client|
return unless registry_config.enabled && registry_config.api_url.present? client.registry_info
end
token = Auth::ContainerRegistryAuthenticationService.access_token([], [])
client = new(registry_config.api_url, token: token)
client.registry_info
end
def initialize(base_uri, options = {})
@base_uri = base_uri
@options = options
end end
def registry_info def registry_info
...@@ -176,89 +133,11 @@ module ContainerRegistry ...@@ -176,89 +133,11 @@ module ContainerRegistry
private private
def initialize_connection(conn, options)
conn.request :json
if options[:user] && options[:password]
conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)
elsif options[:token]
conn.request(:authorization, :bearer, options[:token].to_s)
end
yield(conn) if block_given?
conn.request(:retry, RETRY_OPTIONS)
conn.request(:gitlab_error_callback, ERROR_CALLBACK_OPTIONS)
conn.adapter :net_http
end
def accept_manifest(conn)
conn.headers['Accept'] = ACCEPTED_TYPES
conn.response :json, content_type: 'application/json'
conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+prettyjws'
conn.response :json, content_type: 'application/vnd.docker.distribution.manifest.v1+json'
conn.response :json, content_type: DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
conn.response :json, content_type: OCI_MANIFEST_V1_TYPE
end
def response_body(response, allow_redirect: false)
if allow_redirect && REDIRECT_CODES.include?(response.status)
response = redirect_response(response.headers['location'])
end
response.body if response && response.success?
end
def redirect_response(location)
return unless location
uri = URI(@base_uri).merge(location)
raise ArgumentError, "Invalid scheme for #{location}" unless %w[http https].include?(uri.scheme)
faraday_redirect.get(uri)
end
def faraday(timeout_enabled: true)
@faraday ||= faraday_base(timeout_enabled: timeout_enabled) do |conn|
initialize_connection(conn, @options, &method(:accept_manifest))
end
end
def faraday_blob def faraday_blob
@faraday_blob ||= faraday_base do |conn| @faraday_blob ||= faraday_base do |conn|
initialize_connection(conn, @options) initialize_connection(conn, @options)
end end
end end
# Create a new request to make sure the Authorization header is not inserted
# via the Faraday middleware
def faraday_redirect
@faraday_redirect ||= faraday_base do |conn|
conn.request :json
conn.request(:retry, RETRY_OPTIONS)
conn.request(:gitlab_error_callback, ERROR_CALLBACK_OPTIONS)
conn.adapter :net_http
end
end
def faraday_base(timeout_enabled: true, &block)
request_options = timeout_enabled ? Gitlab::HTTP::DEFAULT_TIMEOUT_OPTIONS : nil
Faraday.new(
@base_uri,
headers: { user_agent: "GitLab/#{Gitlab::VERSION}" },
request: request_options,
&block
)
end
def delete_if_exists(path)
result = faraday.delete(path)
result.success? || result.status == 404
end
end end
end end
......
# frozen_string_literal: true
module ContainerRegistry
class GitlabApiClient < BaseClient
include Gitlab::Utils::StrongMemoize
IMPORT_RESPONSES = {
200 => :already_imported,
202 => :ok,
401 => :unauthorized,
404 => :not_found,
409 => :already_being_imported,
424 => :pre_import_failed,
425 => :already_being_imported,
429 => :too_many_imports
}.freeze
REGISTRY_GITLAB_V1_API_FEATURE = 'gitlab_v1_api'
def self.supports_gitlab_api?
with_dummy_client(return_value_if_disabled: false) do |client|
client.supports_gitlab_api?
end
end
def supports_gitlab_api?
strong_memoize(:supports_gitlab_api) do
registry_features = Gitlab::CurrentSettings.container_registry_features || []
next true if ::Gitlab.com? && registry_features.include?(REGISTRY_GITLAB_V1_API_FEATURE)
response = faraday.get('/gitlab/v1/')
response.success? || response.status == 401
end
end
def pre_import_repository(path)
response = start_import_for(path, pre: true)
IMPORT_RESPONSES.fetch(response.status, :error)
end
def import_repository(path)
response = start_import_for(path, pre: false)
IMPORT_RESPONSES.fetch(response.status, :error)
end
private
def start_import_for(path, pre:)
faraday.put("/gitlab/v1/import/#{path}") do |req|
req.params['pre'] = pre.to_s
end
end
end
end
...@@ -2,12 +2,21 @@ ...@@ -2,12 +2,21 @@
module ContainerRegistry module ContainerRegistry
class Registry class Registry
include Gitlab::Utils::StrongMemoize
attr_reader :uri, :client, :path attr_reader :uri, :client, :path
def initialize(uri, options = {}) def initialize(uri, options = {})
@uri = uri @uri = uri
@path = options[:path] || default_path @options = options
@client = ContainerRegistry::Client.new(uri, options) @path = @options[:path] || default_path
@client = ContainerRegistry::Client.new(@uri, @options)
end
def gitlab_api_client
strong_memoize(:gitlab_api_client) do
ContainerRegistry::GitlabApiClient.new(@uri, @options)
end
end end
private private
......
This diff is collapsed.
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ContainerRegistry::GitlabApiClient do
using RSpec::Parameterized::TableSyntax
include_context 'container registry client'
describe '#supports_gitlab_api?' do
subject { client.supports_gitlab_api? }
where(:registry_gitlab_api_enabled, :is_on_dot_com, :container_registry_features, :expect_registry_to_be_pinged, :expected_result) do
false | true | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | false | true
true | false | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | true | true
true | true | [] | true | true
true | false | [] | true | true
false | true | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | false | true
false | false | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | true | false
false | true | [] | true | false
false | false | [] | true | false
end
with_them do
before do
allow(::Gitlab).to receive(:com?).and_return(is_on_dot_com)
stub_registry_gitlab_api_support(registry_gitlab_api_enabled)
stub_application_setting(container_registry_features: container_registry_features)
end
it 'returns the expected result' do
if expect_registry_to_be_pinged
expect_next_instance_of(Faraday::Connection) do |connection|
expect(connection).to receive(:run_request).and_call_original
end
else
expect(Faraday::Connection).not_to receive(:new)
end
expect(subject).to be expected_result
end
end
context 'with 401 response' do
before do
allow(::Gitlab).to receive(:com?).and_return(false)
stub_application_setting(container_registry_features: [])
stub_request(:get, "#{registry_api_url}/gitlab/v1/")
.to_return(status: 401, body: '')
end
it { is_expected.to be_truthy }
end
end
describe '#pre_import_repository' do
let(:path) { 'namespace/path/to/repository' }
subject { client.pre_import_repository('namespace/path/to/repository') }
where(:status_code, :expected_result) do
200 | :already_imported
202 | :ok
401 | :unauthorized
404 | :not_found
409 | :already_being_imported
418 | :error
424 | :pre_import_failed
425 | :already_being_imported
429 | :too_many_imports
end
with_them do
before do
stub_pre_import(path, status_code, pre: true)
end
it { is_expected.to eq(expected_result) }
end
end
describe '#pre_import_repository' do
let(:path) { 'namespace/path/to/repository' }
subject { client.import_repository('namespace/path/to/repository') }
where(:status_code, :expected_result) do
200 | :already_imported
202 | :ok
401 | :unauthorized
404 | :not_found
409 | :already_being_imported
418 | :error
424 | :pre_import_failed
425 | :already_being_imported
429 | :too_many_imports
end
with_them do
before do
stub_pre_import(path, status_code, pre: false)
end
it { is_expected.to eq(expected_result) }
end
end
describe '.supports_gitlab_api?' do
subject { described_class.supports_gitlab_api? }
where(:registry_gitlab_api_enabled, :is_on_dot_com, :container_registry_features, :expect_registry_to_be_pinged, :expected_result) do
true | true | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | false | true
true | false | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | true | true
false | true | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | false | true
false | false | [described_class::REGISTRY_GITLAB_V1_API_FEATURE] | true | false
true | true | [] | true | true
true | false | [] | true | true
false | true | [] | true | false
false | false | [] | true | false
end
with_them do
before do
allow(::Gitlab).to receive(:com?).and_return(is_on_dot_com)
stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key')
stub_registry_gitlab_api_support(registry_gitlab_api_enabled)
stub_application_setting(container_registry_features: container_registry_features)
end
it 'returns the expected result' do
if expect_registry_to_be_pinged
expect_next_instance_of(Faraday::Connection) do |connection|
expect(connection).to receive(:run_request).and_call_original
end
else
expect(Faraday::Connection).not_to receive(:new)
end
expect(subject).to be expected_result
end
end
context 'with the registry disabled' do
before do
stub_container_registry_config(enabled: false, api_url: 'http://sandbox.local', key: 'spec/fixtures/x509_certificate_pk.key')
end
it 'returns false' do
expect(Faraday::Connection).not_to receive(:new)
expect(subject).to be_falsey
end
end
context 'with a blank registry url' do
before do
stub_container_registry_config(enabled: true, api_url: '', key: 'spec/fixtures/x509_certificate_pk.key')
end
it 'returns false' do
expect(Faraday::Connection).not_to receive(:new)
expect(subject).to be_falsey
end
end
end
def stub_pre_import(path, status_code, pre:)
stub_request(:put, "#{registry_api_url}/gitlab/v1/import/#{path}?pre=#{pre}")
.to_return(status: status_code, body: '')
end
def stub_registry_gitlab_api_support(supported = true)
status_code = supported ? 200 : 404
stub_request(:get, "#{registry_api_url}/gitlab/v1/")
.to_return(status: status_code, body: '')
end
end
...@@ -27,4 +27,10 @@ RSpec.describe ContainerRegistry::Registry do ...@@ -27,4 +27,10 @@ RSpec.describe ContainerRegistry::Registry do
it { is_expected.to eq(path) } it { is_expected.to eq(path) }
end end
end end
describe '#gitlab_api_client' do
subject { registry.gitlab_api_client }
it { is_expected.to be_instance_of(ContainerRegistry::GitlabApiClient) }
end
end end
...@@ -209,6 +209,46 @@ RSpec.describe ContainerRepository do ...@@ -209,6 +209,46 @@ RSpec.describe ContainerRepository do
end end
end end
context 'registry migration' do
shared_examples 'handling the migration step' do |step|
let(:client_response) { :foobar }
before do
allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
end
it 'returns the same response as the client' do
expect(repository.gitlab_api_client)
.to receive(step).with(repository.path).and_return(client_response)
expect(subject).to eq(client_response)
end
context 'when the gitlab_api feature is not supported' do
before do
allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(false)
end
it 'returns :error' do
expect(repository.gitlab_api_client).not_to receive(step)
expect(subject).to eq(:error)
end
end
end
describe '#migration_pre_import' do
subject { repository.migration_pre_import }
it_behaves_like 'handling the migration step', :pre_import_repository
end
describe '#migration_import' do
subject { repository.migration_import }
it_behaves_like 'handling the migration step', :import_repository
end
end
describe '.build_from_path' do describe '.build_from_path' do
let(:registry_path) do let(:registry_path) do
ContainerRegistry::Path.new(project.full_path + '/some/image') ContainerRegistry::Path.new(project.full_path + '/some/image')
......
...@@ -48,6 +48,7 @@ RSpec.describe UpdateContainerRegistryInfoService do ...@@ -48,6 +48,7 @@ RSpec.describe UpdateContainerRegistryInfoService do
before do before do
stub_registry_info({}) stub_registry_info({})
stub_supports_gitlab_api(false)
end end
it 'uses a token with no access permissions' do it 'uses a token with no access permissions' do
...@@ -63,6 +64,7 @@ RSpec.describe UpdateContainerRegistryInfoService do ...@@ -63,6 +64,7 @@ RSpec.describe UpdateContainerRegistryInfoService do
context 'when unabled to detect the container registry type' do context 'when unabled to detect the container registry type' do
it 'sets the application settings to their defaults' do it 'sets the application settings to their defaults' do
stub_registry_info({}) stub_registry_info({})
stub_supports_gitlab_api(false)
subject subject
...@@ -76,20 +78,23 @@ RSpec.describe UpdateContainerRegistryInfoService do ...@@ -76,20 +78,23 @@ RSpec.describe UpdateContainerRegistryInfoService do
context 'when able to detect the container registry type' do context 'when able to detect the container registry type' do
context 'when using the GitLab container registry' do context 'when using the GitLab container registry' do
it 'updates application settings accordingly' do it 'updates application settings accordingly' do
stub_registry_info(vendor: 'gitlab', version: '2.9.1-gitlab', features: %w[a,b,c]) stub_registry_info(vendor: 'gitlab', version: '2.9.1-gitlab', features: %w[a b c])
stub_supports_gitlab_api(true)
subject subject
application_settings.reload application_settings.reload
expect(application_settings.container_registry_vendor).to eq('gitlab') expect(application_settings.container_registry_vendor).to eq('gitlab')
expect(application_settings.container_registry_version).to eq('2.9.1-gitlab') expect(application_settings.container_registry_version).to eq('2.9.1-gitlab')
expect(application_settings.container_registry_features).to eq(%w[a,b,c]) expect(application_settings.container_registry_features)
.to match_array(%W[a b c #{ContainerRegistry::GitlabApiClient::REGISTRY_GITLAB_V1_API_FEATURE}])
end end
end end
context 'when using a third-party container registry' do context 'when using a third-party container registry' do
it 'updates application settings accordingly' do it 'updates application settings accordingly' do
stub_registry_info(vendor: 'other', version: nil, features: nil) stub_registry_info(vendor: 'other', version: nil, features: nil)
stub_supports_gitlab_api(false)
subject subject
...@@ -112,4 +117,10 @@ RSpec.describe UpdateContainerRegistryInfoService do ...@@ -112,4 +117,10 @@ RSpec.describe UpdateContainerRegistryInfoService do
allow(client).to receive(:registry_info).and_return(output) allow(client).to receive(:registry_info).and_return(output)
end end
end end
def stub_supports_gitlab_api(output)
allow_next_instance_of(ContainerRegistry::GitlabApiClient) do |client|
allow(client).to receive(:supports_gitlab_api?).and_return(output)
end
end
end end
# frozen_string_literal: true
RSpec.shared_context 'container registry client' do
let(:token) { '12345' }
let(:options) { { token: token } }
let(:registry_api_url) { 'http://container-registry' }
let(:client) { described_class.new(registry_api_url, options) }
let(:push_blob_headers) do
{
'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
'Authorization' => "bearer #{token}",
'Content-Type' => 'application/octet-stream',
'User-Agent' => "GitLab/#{Gitlab::VERSION}"
}
end
let(:headers_with_accept_types) do
{
'Accept' => 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json',
'Authorization' => "bearer #{token}",
'User-Agent' => "GitLab/#{Gitlab::VERSION}"
}
end
let(:expected_faraday_headers) { { user_agent: "GitLab/#{Gitlab::VERSION}" } }
let(:expected_faraday_request_options) { Gitlab::HTTP::DEFAULT_TIMEOUT_OPTIONS }
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment