Add support for Docker Registry manifest v1

This commit is contained in:
Kamil Trzcinski 2016-06-15 12:53:10 +02:00
parent 3a857e0e6c
commit f30d1fdf94
7 changed files with 130 additions and 38 deletions

View file

@ -29,6 +29,7 @@ v 8.9.0 (unreleased)
- Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails
- 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
- Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0

View file

@ -9,11 +9,19 @@
- else
\-
%td
= number_to_human_size(tag.total_size)
·
= pluralize(tag.layers.size, "layer")
- if tag.total_size
= number_to_human_size(tag.total_size)
·
= pluralize(tag.layers.size, "layer")
- else
.light
\-
%td
- if tag.created_at
= time_ago_in_words(tag.created_at)
- else
.light
\-
- if can?(current_user, :update_container_image, @project)
%td.content
.controls.hidden-xs.pull-right

View file

@ -18,7 +18,7 @@ module ContainerRegistry
end
def digest
config['digest']
config['digest'] || config['blobSum']
end
def type

View file

@ -47,7 +47,9 @@ module ContainerRegistry
conn.request :json
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]
conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)

View file

@ -12,6 +12,14 @@ module ContainerRegistry
manifest.present?
end
def v1?
manifest && manifest['schemaVersion'] == 1
end
def v2?
manifest && manifest['schemaVersion'] == 2
end
def manifest
return @manifest if defined?(@manifest)
@ -57,7 +65,9 @@ module ContainerRegistry
return @layers if defined?(@layers)
return unless manifest
@layers = manifest['layers'].map do |layer|
layers = manifest['layers'] || manifest['fsLayers']
@layers = layers.map do |layer|
repository.blob(layer)
end
end
@ -65,7 +75,7 @@ module ContainerRegistry
def total_size
return unless layers
layers.map(&:size).sum
layers.map(&:size).sum if v2?
end
def delete

View 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"
}
]
}

View file

@ -17,46 +17,85 @@ describe ContainerRegistry::Tag do
end
context 'manifest processing' 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
context 'schema v1' do
before do
stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac').
with(headers: { 'Accept' => 'application/octet-stream' }).
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/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
context '#config' do
subject { tag.config }
context '#layers' do
subject { tag.layers }
it { is_expected.not_to be_nil }
it { expect(subject.length).to eq(1) }
end
context '#created_at' do
subject { tag.created_at }
context '#total_size' do
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