Add support for Docker Registry manifest v1
This commit is contained in:
parent
3a857e0e6c
commit
f30d1fdf94
7 changed files with 130 additions and 38 deletions
|
@ -29,6 +29,7 @@ v 8.9.0 (unreleased)
|
||||||
- Fix groups API to list only user's accessible projects
|
- Fix groups API to list only user's accessible projects
|
||||||
- Redesign account and email confirmation emails
|
- Redesign account and email confirmation emails
|
||||||
- Don't fail builds for projects that are deleted
|
- Don't fail builds for projects that are deleted
|
||||||
|
- Support Docker Registry manifest v1
|
||||||
- `git clone https://host/namespace/project` now works, in addition to using the `.git` suffix
|
- `git clone https://host/namespace/project` now works, in addition to using the `.git` suffix
|
||||||
- Bump nokogiri to 1.6.8
|
- Bump nokogiri to 1.6.8
|
||||||
- Use gitlab-shell v3.0.0
|
- Use gitlab-shell v3.0.0
|
||||||
|
|
|
@ -9,11 +9,19 @@
|
||||||
- else
|
- else
|
||||||
\-
|
\-
|
||||||
%td
|
%td
|
||||||
= number_to_human_size(tag.total_size)
|
- if tag.total_size
|
||||||
·
|
= number_to_human_size(tag.total_size)
|
||||||
= pluralize(tag.layers.size, "layer")
|
·
|
||||||
|
= pluralize(tag.layers.size, "layer")
|
||||||
|
- else
|
||||||
|
.light
|
||||||
|
\-
|
||||||
%td
|
%td
|
||||||
|
- if tag.created_at
|
||||||
= time_ago_in_words(tag.created_at)
|
= time_ago_in_words(tag.created_at)
|
||||||
|
- else
|
||||||
|
.light
|
||||||
|
\-
|
||||||
- if can?(current_user, :update_container_image, @project)
|
- if can?(current_user, :update_container_image, @project)
|
||||||
%td.content
|
%td.content
|
||||||
.controls.hidden-xs.pull-right
|
.controls.hidden-xs.pull-right
|
||||||
|
|
|
@ -18,7 +18,7 @@ module ContainerRegistry
|
||||||
end
|
end
|
||||||
|
|
||||||
def digest
|
def digest
|
||||||
config['digest']
|
config['digest'] || config['blobSum']
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
|
|
|
@ -47,7 +47,9 @@ module ContainerRegistry
|
||||||
conn.request :json
|
conn.request :json
|
||||||
conn.headers['Accept'] = MANIFEST_VERSION
|
conn.headers['Accept'] = MANIFEST_VERSION
|
||||||
|
|
||||||
conn.response :json, content_type: /\bjson$/
|
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'
|
||||||
|
|
||||||
if options[:user] && options[:password]
|
if options[:user] && options[:password]
|
||||||
conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)
|
conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)
|
||||||
|
|
|
@ -12,6 +12,14 @@ module ContainerRegistry
|
||||||
manifest.present?
|
manifest.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def v1?
|
||||||
|
manifest && manifest['schemaVersion'] == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def v2?
|
||||||
|
manifest && manifest['schemaVersion'] == 2
|
||||||
|
end
|
||||||
|
|
||||||
def manifest
|
def manifest
|
||||||
return @manifest if defined?(@manifest)
|
return @manifest if defined?(@manifest)
|
||||||
|
|
||||||
|
@ -57,7 +65,9 @@ module ContainerRegistry
|
||||||
return @layers if defined?(@layers)
|
return @layers if defined?(@layers)
|
||||||
return unless manifest
|
return unless manifest
|
||||||
|
|
||||||
@layers = manifest['layers'].map do |layer|
|
layers = manifest['layers'] || manifest['fsLayers']
|
||||||
|
|
||||||
|
@layers = layers.map do |layer|
|
||||||
repository.blob(layer)
|
repository.blob(layer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -65,7 +75,7 @@ module ContainerRegistry
|
||||||
def total_size
|
def total_size
|
||||||
return unless layers
|
return unless layers
|
||||||
|
|
||||||
layers.map(&:size).sum
|
layers.map(&:size).sum if v2?
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
|
|
32
spec/fixtures/container_registry/tag_manifest_1.json
vendored
Normal file
32
spec/fixtures/container_registry/tag_manifest_1.json
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"name": "library/alpine",
|
||||||
|
"tag": "2.6",
|
||||||
|
"architecture": "amd64",
|
||||||
|
"fsLayers": [
|
||||||
|
{
|
||||||
|
"blobSum": "sha256:2a3ebcb7fbcc29bf40c4f62863008bb573acdea963454834d9483b3e5300c45d"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"history": [
|
||||||
|
{
|
||||||
|
"v1Compatibility": "{\"id\":\"dd807873c9a21bcc82e30317c283e6601d7e19f5cf7867eec34cdd1aeb3f099e\",\"created\":\"2016-01-18T18:32:39.162138276Z\",\"container\":\"556a728876db7b0e621adc029c87c649d32520804f8f15defd67bb070dc1a88d\",\"container_config\":{\"Hostname\":\"556a728876db\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) ADD file:7dee8a455bcc39013aa168d27ece9227aad155adbaacbd153d94ca60113f59fc in /\"],\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.8.3\",\"config\":{\"Hostname\":\"556a728876db\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"WorkingDir\":\"\",\"Entrypoint\":null,\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":4501436}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"header": {
|
||||||
|
"jwk": {
|
||||||
|
"crv": "P-256",
|
||||||
|
"kid": "4MZL:Z5ZP:2RPA:Q3TD:QOHA:743L:EM2G:QY6Q:ZJCX:BSD7:CRYC:LQ6T",
|
||||||
|
"kty": "EC",
|
||||||
|
"x": "qmWOaxPUk7QsE5iTPdeG1e9yNE-wranvQEnWzz9FhWM",
|
||||||
|
"y": "WeeBpjTOYnTNrfCIxtFY5qMrJNNk9C1vc5ryxbbMD_M"
|
||||||
|
},
|
||||||
|
"alg": "ES256"
|
||||||
|
},
|
||||||
|
"signature": "0zmjTJ4m21yVwAeteLc3SsQ0miScViCDktFPR67W-ozGjjI3iBjlDjwOl6o2sds5ZI9U6bSIKOeLDinGOhHoOQ",
|
||||||
|
"protected": "eyJmb3JtYXRMZW5ndGgiOjEzNzIsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNi0wNi0xNVQxMDo0NDoxNFoifQ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -17,46 +17,85 @@ describe ContainerRegistry::Tag do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'manifest processing' do
|
context 'manifest processing' do
|
||||||
before do
|
context 'schema v1' do
|
||||||
stub_request(:get, 'http://example.com/v2/group/test/manifests/tag').
|
|
||||||
with(headers: headers).
|
|
||||||
to_return(
|
|
||||||
status: 200,
|
|
||||||
body: File.read(Rails.root + 'spec/fixtures/container_registry/tag_manifest.json'),
|
|
||||||
headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json' })
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#layers' do
|
|
||||||
subject { tag.layers }
|
|
||||||
|
|
||||||
it { expect(subject.length).to eq(1) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#total_size' do
|
|
||||||
subject { tag.total_size }
|
|
||||||
|
|
||||||
it { is_expected.to eq(2319870) }
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'config processing' do
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac').
|
stub_request(:get, 'http://example.com/v2/group/test/manifests/tag').
|
||||||
with(headers: { 'Accept' => 'application/octet-stream' }).
|
with(headers: headers).
|
||||||
to_return(
|
to_return(
|
||||||
status: 200,
|
status: 200,
|
||||||
body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json'))
|
body: File.read(Rails.root + 'spec/fixtures/container_registry/tag_manifest_1.json'),
|
||||||
|
headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v1+prettyjws' })
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#config' do
|
context '#layers' do
|
||||||
subject { tag.config }
|
subject { tag.layers }
|
||||||
|
|
||||||
it { is_expected.not_to be_nil }
|
it { expect(subject.length).to eq(1) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#created_at' do
|
context '#total_size' do
|
||||||
subject { tag.created_at }
|
subject { tag.total_size }
|
||||||
|
|
||||||
it { is_expected.not_to be_nil }
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'config processing' do
|
||||||
|
context '#config' do
|
||||||
|
subject { tag.config }
|
||||||
|
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#created_at' do
|
||||||
|
subject { tag.created_at }
|
||||||
|
|
||||||
|
it { is_expected.to be_nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'schema v2' do
|
||||||
|
before do
|
||||||
|
stub_request(:get, 'http://example.com/v2/group/test/manifests/tag').
|
||||||
|
with(headers: headers).
|
||||||
|
to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read(Rails.root + 'spec/fixtures/container_registry/tag_manifest.json'),
|
||||||
|
headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json' })
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#layers' do
|
||||||
|
subject { tag.layers }
|
||||||
|
|
||||||
|
it { expect(subject.length).to eq(1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#total_size' do
|
||||||
|
subject { tag.total_size }
|
||||||
|
|
||||||
|
it { is_expected.to eq(2319870) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'config processing' do
|
||||||
|
before do
|
||||||
|
stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac').
|
||||||
|
with(headers: { 'Accept' => 'application/octet-stream' }).
|
||||||
|
to_return(
|
||||||
|
status: 200,
|
||||||
|
body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json'))
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#config' do
|
||||||
|
subject { tag.config }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#created_at' do
|
||||||
|
subject { tag.created_at }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_nil }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue