summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2019-07-24 21:44:07 -0700
committerStan Hu <stanhu@gmail.com>2019-07-25 04:11:38 -0700
commita40116065e2a761f6fa8dc7d569cb3e39025f6d3 (patch)
tree64d0d2ba3cfdc8f1cbc57c4fa7bc21ae7044a01b
parenta5eaefc9027696fc65b7d51251902e013c14d161 (diff)
downloadgitlab-ce-a40116065e2a761f6fa8dc7d569cb3e39025f6d3.tar.gz
Support Docker OCI imagessh-support-docker-oci-images
Docker Distribution v2.7.0 shipped with OCI support, but our container registry client was not updated to handle the manifest format in the HTTP `Accept` header. As a result, API calls to retrieve a manifest would return with an error, "OCI manifest found, but accept header does not support OCI manifests". This would result in blank fields in the container registry page and prevent tags from being deleted. To fix this, we just need to add `application/vnd.oci.image.manifest.v1+json` to the `Accept` header and configure Faraday to parse the response as JSON. The response structure is the same as the standard Docker Distribution V2 manifest. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/58685 Closes https://gitlab.com/gitlab-org/gitlab-ee/issues/12877
-rw-r--r--changelogs/unreleased/sh-support-docker-oci-images.yml5
-rw-r--r--lib/container_registry/client.rb9
-rw-r--r--spec/lib/container_registry/client_spec.rb36
-rw-r--r--spec/lib/container_registry/tag_spec.rb2
-rw-r--r--spec/models/container_repository_spec.rb2
5 files changed, 49 insertions, 5 deletions
diff --git a/changelogs/unreleased/sh-support-docker-oci-images.yml b/changelogs/unreleased/sh-support-docker-oci-images.yml
new file mode 100644
index 00000000000..2dcf980fa50
--- /dev/null
+++ b/changelogs/unreleased/sh-support-docker-oci-images.yml
@@ -0,0 +1,5 @@
+---
+title: Support Docker OCI images
+merge_request: 31127
+author:
+type: fixed
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
index c80f49f5ae0..c3a19af7a94 100644
--- a/lib/container_registry/client.rb
+++ b/lib/container_registry/client.rb
@@ -7,7 +7,9 @@ module ContainerRegistry
class Client
attr_accessor :uri
- MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json'.freeze
+ DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json'
+ OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json'
+ ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze
# Taken from: FaradayMiddleware::FollowRedirects
REDIRECT_CODES = Set.new [301, 302, 303, 307]
@@ -60,12 +62,13 @@ module ContainerRegistry
end
def accept_manifest(conn)
- conn.headers['Accept'] = MANIFEST_VERSION
+ 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: 'application/vnd.docker.distribution.manifest.v2+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)
diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb
index 3df33f48adb..ce06377bbbf 100644
--- a/spec/lib/container_registry/client_spec.rb
+++ b/spec/lib/container_registry/client_spec.rb
@@ -6,6 +6,42 @@ describe ContainerRegistry::Client do
let(:options) { { token: token } }
let(:client) { described_class.new("http://container-registry", options) }
+ shared_examples '#repository_manifest' do |manifest_type|
+ let(:manifest) do
+ {
+ "schemaVersion" => 2,
+ "config" => {
+ "mediaType" => manifest_type,
+ "digest" =>
+ "sha256:4a3ef0786dd241be6000311e1503869b320be433b9cba84cfafeb512d1720c95",
+ "size" => 6608
+ },
+ "layers" => [
+ {
+ "mediaType" => manifest_type,
+ "digest" =>
+ "sha256:83ef92b73cf4595aa7fe214ec6747228283d585f373d8f6bc08d66bebab531b7",
+ "size" => 2828661
+ }
+ ]
+ }
+ end
+
+ it 'GET /v2/:name/manifests/mytag' do
+ stub_request(:get, "http://container-registry/v2/group/test/manifests/mytag")
+ .with(headers: {
+ 'Accept' => described_class::ACCEPTED_TYPES.join(', '),
+ 'Authorization' => "bearer #{token}"
+ })
+ .to_return(status: 200, body: manifest.to_json, headers: { content_type: manifest_type })
+
+ expect(client.repository_manifest('group/test', 'mytag')).to eq(manifest)
+ end
+ end
+
+ it_behaves_like '#repository_manifest', described_class::DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE
+ it_behaves_like '#repository_manifest', described_class::OCI_MANIFEST_V1_TYPE
+
describe '#blob' do
it 'GET /v2/:name/blobs/:digest' do
stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345")
diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb
index cb4ae3be525..65090f32f66 100644
--- a/spec/lib/container_registry/tag_spec.rb
+++ b/spec/lib/container_registry/tag_spec.rb
@@ -9,7 +9,7 @@ describe ContainerRegistry::Tag do
end
let(:headers) do
- { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' }
+ { 'Accept' => ContainerRegistry::Client::ACCEPTED_TYPES.join(', ') }
end
let(:tag) { described_class.new(repository, 'tag') }
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 013112d1d51..935838ce294 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -16,7 +16,7 @@ describe ContainerRepository do
host_port: 'registry.gitlab')
stub_request(:get, 'http://registry.gitlab/v2/group/test/my_image/tags/list')
- .with(headers: { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' })
+ .with(headers: { 'Accept' => ContainerRegistry::Client::ACCEPTED_TYPES.join(', ') })
.to_return(
status: 200,
body: JSON.dump(tags: ['test_tag']),