Skip to content

Commit 694df3f

Browse files
committed
Add distribution package
Signed-off-by: Aaron Lehmann <[email protected]>
1 parent 01ba0a9 commit 694df3f

23 files changed

+3350
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"schemaVersion": 2,
3+
"name": "library/hello-world",
4+
"tag": "latest",
5+
"architecture": "amd64",
6+
"fsLayers": [
7+
{
8+
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
9+
},
10+
{
11+
"blobSum": "sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb"
12+
}
13+
],
14+
"history": [
15+
{
16+
"v1Compatibility": "{\"id\":\"af340544ed62de0680f441c71fa1a80cb084678fed42bae393e543faea3a572c\",\"parent\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.608577814Z\",\"container\":\"c2b715156f640c7ac7d98472ea24335aba5432a1323a3bb722697e6d37ef794f\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"/hello\\\"]\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/hello\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
17+
},
18+
{
19+
"v1Compatibility": "{\"id\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.241352727Z\",\"container\":\"9aeb0006ffa72a8287564caaea87625896853701459261d3b569e320c0c9d5dc\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) COPY file:4abd3bff60458ca3b079d7b131ce26b2719055a030dfa96ff827da2b7c7038a7 in /\"],\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":960}\n"
20+
}
21+
],
22+
"signatures": [
23+
{
24+
"header": {
25+
"jwk": {
26+
"crv": "P-256",
27+
"kid": "OIH7:HQFS:44FK:45VB:3B53:OIAG:TPL4:ATF5:6PNE:MGHN:NHQX:2GE4",
28+
"kty": "EC",
29+
"x": "Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ",
30+
"y": "zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8"
31+
},
32+
"alg": "ES256"
33+
},
34+
"signature": "Y6xaFz9Sy-OtcnKQS1Ilq3Dh8cu4h3nBTJCpOTF1XF7vKtcxxA_xMP8-SgDo869SJ3VsvgPL9-Xn-OoYG2rb1A",
35+
"protected": "eyJmb3JtYXRMZW5ndGgiOjMxOTcsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wOS0xMVQwNDoxMzo0OFoifQ"
36+
}
37+
]
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"schemaVersion": 1,
3+
"name": "library/hello-world",
4+
"tag": "latest",
5+
"architecture": "amd64",
6+
"fsLayers": [
7+
{
8+
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
9+
},
10+
{
11+
"blobSum": "sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb"
12+
}
13+
],
14+
"history": [
15+
{
16+
"v1Compatibility": "{\"id\":\"af340544ed62de0680f441c71fa1a80cb084678fed42bae393e543faea3a572c\",\"parent\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.608577814Z\",\"container\":\"c2b715156f640c7ac7d98472ea24335aba5432a1323a3bb722697e6d37ef794f\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"/hello\\\"]\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/hello\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
17+
},
18+
{
19+
"v1Compatibility": "{\"id\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.241352727Z\",\"container\":\"9aeb0006ffa72a8287564caaea87625896853701459261d3b569e320c0c9d5dc\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) COPY file:4abd3bff60458ca3b079d7b131ce26b2719055a030dfa96ff827da2b7c7038a7 in /\"],\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":960}\n"
20+
}
21+
],
22+
"fsLayers": [
23+
{
24+
"blobSum": "sha256:ffff95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
25+
},
26+
{
27+
"blobSum": "sha256:ffff658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb"
28+
}
29+
],
30+
"signatures": [
31+
{
32+
"header": {
33+
"jwk": {
34+
"crv": "P-256",
35+
"kid": "OIH7:HQFS:44FK:45VB:3B53:OIAG:TPL4:ATF5:6PNE:MGHN:NHQX:2GE4",
36+
"kty": "EC",
37+
"x": "Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ",
38+
"y": "zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8"
39+
},
40+
"alg": "ES256"
41+
},
42+
"signature": "Y6xaFz9Sy-OtcnKQS1Ilq3Dh8cu4h3nBTJCpOTF1XF7vKtcxxA_xMP8-SgDo869SJ3VsvgPL9-Xn-OoYG2rb1A",
43+
"protected": "eyJmb3JtYXRMZW5ndGgiOjMxOTcsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wOS0xMVQwNDoxMzo0OFoifQ"
44+
}
45+
]
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"schemaVersion": 1,
3+
"name": "library/hello-world",
4+
"tag": "latest",
5+
"architecture": "amd64",
6+
"fsLayers": [
7+
{
8+
"blobSum": "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"
9+
},
10+
{
11+
"blobSum": "sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb"
12+
}
13+
],
14+
"history": [
15+
{
16+
"v1Compatibility": "{\"id\":\"af340544ed62de0680f441c71fa1a80cb084678fed42bae393e543faea3a572c\",\"parent\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.608577814Z\",\"container\":\"c2b715156f640c7ac7d98472ea24335aba5432a1323a3bb722697e6d37ef794f\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) CMD [\\\"/hello\\\"]\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/hello\"],\"Image\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":{}},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":0}\n"
17+
},
18+
{
19+
"v1Compatibility": "{\"id\":\"535020c3e8add9d6bb06e5ac15a261e73d9b213d62fb2c14d752b8e189b2b912\",\"created\":\"2015-08-06T23:53:22.241352727Z\",\"container\":\"9aeb0006ffa72a8287564caaea87625896853701459261d3b569e320c0c9d5dc\",\"container_config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":[\"/bin/sh\",\"-c\",\"#(nop) COPY file:4abd3bff60458ca3b079d7b131ce26b2719055a030dfa96ff827da2b7c7038a7 in /\"],\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"docker_version\":\"1.7.1\",\"config\":{\"Hostname\":\"9aeb0006ffa7\",\"Domainname\":\"\",\"User\":\"\",\"AttachStdin\":false,\"AttachStdout\":false,\"AttachStderr\":false,\"PortSpecs\":null,\"ExposedPorts\":null,\"Tty\":false,\"OpenStdin\":false,\"StdinOnce\":false,\"Env\":null,\"Cmd\":null,\"Image\":\"\",\"Volumes\":null,\"VolumeDriver\":\"\",\"WorkingDir\":\"\",\"Entrypoint\":null,\"NetworkDisabled\":false,\"MacAddress\":\"\",\"OnBuild\":null,\"Labels\":null},\"architecture\":\"amd64\",\"os\":\"linux\",\"Size\":960}\n"
20+
}
21+
],
22+
"signatures": [
23+
{
24+
"header": {
25+
"jwk": {
26+
"crv": "P-256",
27+
"kid": "OIH7:HQFS:44FK:45VB:3B53:OIAG:TPL4:ATF5:6PNE:MGHN:NHQX:2GE4",
28+
"kty": "EC",
29+
"x": "Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ",
30+
"y": "zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8"
31+
},
32+
"alg": "ES256"
33+
},
34+
"signature": "Y6xaFz9Sy-OtcnKQS1Ilq3Dh8cu4h3nBTJCpOTF1XF7vKtcxxA_xMP8-SgDo869SJ3VsvgPL9-Xn-OoYG2rb1A",
35+
"protected": "eyJmb3JtYXRMZW5ndGgiOjMxOTcsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wOS0xMVQwNDoxMzo0OFoifQ"
36+
}
37+
]
38+
}
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package metadata
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/docker/distribution/digest"
7+
"github.com/docker/docker/layer"
8+
)
9+
10+
// BlobSumService maps layer IDs to a set of known blobsums for
11+
// the layer.
12+
type BlobSumService struct {
13+
store Store
14+
}
15+
16+
// maxBlobSums is the number of blobsums to keep per layer DiffID.
17+
const maxBlobSums = 5
18+
19+
// NewBlobSumService creates a new blobsum mapping service.
20+
func NewBlobSumService(store Store) *BlobSumService {
21+
return &BlobSumService{
22+
store: store,
23+
}
24+
}
25+
26+
func (blobserv *BlobSumService) diffIDNamespace() string {
27+
return "blobsum-storage"
28+
}
29+
30+
func (blobserv *BlobSumService) blobSumNamespace() string {
31+
return "blobsum-lookup"
32+
}
33+
34+
func (blobserv *BlobSumService) diffIDKey(diffID layer.DiffID) string {
35+
return string(digest.Digest(diffID).Algorithm()) + "/" + digest.Digest(diffID).Hex()
36+
}
37+
38+
func (blobserv *BlobSumService) blobSumKey(blobsum digest.Digest) string {
39+
return string(blobsum.Algorithm()) + "/" + blobsum.Hex()
40+
}
41+
42+
// GetBlobSums finds the blobsums associated with a layer DiffID.
43+
func (blobserv *BlobSumService) GetBlobSums(diffID layer.DiffID) ([]digest.Digest, error) {
44+
jsonBytes, err := blobserv.store.Get(blobserv.diffIDNamespace(), blobserv.diffIDKey(diffID))
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
var blobsums []digest.Digest
50+
if err := json.Unmarshal(jsonBytes, &blobsums); err != nil {
51+
return nil, err
52+
}
53+
54+
return blobsums, nil
55+
}
56+
57+
// GetDiffID finds a layer DiffID from a blobsum hash.
58+
func (blobserv *BlobSumService) GetDiffID(blobsum digest.Digest) (layer.DiffID, error) {
59+
diffIDBytes, err := blobserv.store.Get(blobserv.blobSumNamespace(), blobserv.blobSumKey(blobsum))
60+
if err != nil {
61+
return layer.DiffID(""), err
62+
}
63+
64+
return layer.DiffID(diffIDBytes), nil
65+
}
66+
67+
// Add associates a blobsum with a layer DiffID. If too many blobsums are
68+
// present, the oldest one is dropped.
69+
func (blobserv *BlobSumService) Add(diffID layer.DiffID, blobsum digest.Digest) error {
70+
oldBlobSums, err := blobserv.GetBlobSums(diffID)
71+
if err != nil {
72+
oldBlobSums = nil
73+
}
74+
newBlobSums := make([]digest.Digest, 0, len(oldBlobSums)+1)
75+
76+
// Copy all other blobsums to new slice
77+
for _, oldSum := range oldBlobSums {
78+
if oldSum != blobsum {
79+
newBlobSums = append(newBlobSums, oldSum)
80+
}
81+
}
82+
83+
newBlobSums = append(newBlobSums, blobsum)
84+
85+
if len(newBlobSums) > maxBlobSums {
86+
newBlobSums = newBlobSums[len(newBlobSums)-maxBlobSums:]
87+
}
88+
89+
jsonBytes, err := json.Marshal(newBlobSums)
90+
if err != nil {
91+
return err
92+
}
93+
94+
err = blobserv.store.Set(blobserv.diffIDNamespace(), blobserv.diffIDKey(diffID), jsonBytes)
95+
if err != nil {
96+
return err
97+
}
98+
99+
return blobserv.store.Set(blobserv.blobSumNamespace(), blobserv.blobSumKey(blobsum), []byte(diffID))
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package metadata
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"reflect"
7+
"testing"
8+
9+
"github.com/docker/distribution/digest"
10+
"github.com/docker/docker/layer"
11+
)
12+
13+
func TestBlobSumService(t *testing.T) {
14+
tmpDir, err := ioutil.TempDir("", "blobsum-storage-service-test")
15+
if err != nil {
16+
t.Fatalf("could not create temp dir: %v", err)
17+
}
18+
defer os.RemoveAll(tmpDir)
19+
20+
metadataStore, err := NewFSMetadataStore(tmpDir)
21+
if err != nil {
22+
t.Fatalf("could not create metadata store: %v", err)
23+
}
24+
blobSumService := NewBlobSumService(metadataStore)
25+
26+
testVectors := []struct {
27+
diffID layer.DiffID
28+
blobsums []digest.Digest
29+
}{
30+
{
31+
diffID: layer.DiffID("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"),
32+
blobsums: []digest.Digest{
33+
digest.Digest("sha256:f0cd5ca10b07f35512fc2f1cbf9a6cefbdb5cba70ac6b0c9e5988f4497f71937"),
34+
},
35+
},
36+
{
37+
diffID: layer.DiffID("sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"),
38+
blobsums: []digest.Digest{
39+
digest.Digest("sha256:f0cd5ca10b07f35512fc2f1cbf9a6cefbdb5cba70ac6b0c9e5988f4497f71937"),
40+
digest.Digest("sha256:9e3447ca24cb96d86ebd5960cb34d1299b07e0a0e03801d90b9969a2c187dd6e"),
41+
},
42+
},
43+
{
44+
diffID: layer.DiffID("sha256:03f4658f8b782e12230c1783426bd3bacce651ce582a4ffb6fbbfa2079428ecb"),
45+
blobsums: []digest.Digest{
46+
digest.Digest("sha256:f0cd5ca10b07f35512fc2f1cbf9a6cefbdb5cba70ac6b0c9e5988f4497f71937"),
47+
digest.Digest("sha256:9e3447ca24cb96d86ebd5960cb34d1299b07e0a0e03801d90b9969a2c187dd6e"),
48+
digest.Digest("sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"),
49+
digest.Digest("sha256:8902a7ca89aabbb868835260912159026637634090dd8899eee969523252236e"),
50+
digest.Digest("sha256:c84364306344ccc48532c52ff5209236273525231dddaaab53262322352883aa"),
51+
digest.Digest("sha256:aa7583bbc87532a8352bbb72520a821b3623523523a8352523a52352aaa888fe"),
52+
},
53+
},
54+
}
55+
56+
// Set some associations
57+
for _, vec := range testVectors {
58+
for _, blobsum := range vec.blobsums {
59+
err := blobSumService.Add(vec.diffID, blobsum)
60+
if err != nil {
61+
t.Fatalf("error calling Set: %v", err)
62+
}
63+
}
64+
}
65+
66+
// Check the correct values are read back
67+
for _, vec := range testVectors {
68+
blobsums, err := blobSumService.GetBlobSums(vec.diffID)
69+
if err != nil {
70+
t.Fatalf("error calling Get: %v", err)
71+
}
72+
expectedBlobsums := len(vec.blobsums)
73+
if expectedBlobsums > 5 {
74+
expectedBlobsums = 5
75+
}
76+
if !reflect.DeepEqual(blobsums, vec.blobsums[len(vec.blobsums)-expectedBlobsums:len(vec.blobsums)]) {
77+
t.Fatal("Get returned incorrect layer ID")
78+
}
79+
}
80+
81+
// Test GetBlobSums on a nonexistent entry
82+
_, err = blobSumService.GetBlobSums(layer.DiffID("sha256:82379823067823853223359023576437723560923756b03560378f4497753917"))
83+
if err == nil {
84+
t.Fatal("expected error looking up nonexistent entry")
85+
}
86+
87+
// Test GetDiffID on a nonexistent entry
88+
_, err = blobSumService.GetDiffID(digest.Digest("sha256:82379823067823853223359023576437723560923756b03560378f4497753917"))
89+
if err == nil {
90+
t.Fatal("expected error looking up nonexistent entry")
91+
}
92+
93+
// Overwrite one of the entries and read it back
94+
err = blobSumService.Add(testVectors[1].diffID, testVectors[0].blobsums[0])
95+
if err != nil {
96+
t.Fatalf("error calling Add: %v", err)
97+
}
98+
diffID, err := blobSumService.GetDiffID(testVectors[0].blobsums[0])
99+
if err != nil {
100+
t.Fatalf("error calling GetDiffID: %v", err)
101+
}
102+
if diffID != testVectors[1].diffID {
103+
t.Fatal("GetDiffID returned incorrect diffID")
104+
}
105+
}

distribution/metadata/metadata.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package metadata
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
"sync"
8+
)
9+
10+
// Store implements a K/V store for mapping distribution-related IDs
11+
// to on-disk layer IDs and image IDs. The namespace identifies the type of
12+
// mapping (i.e. "v1ids" or "artifacts"). MetadataStore is goroutine-safe.
13+
type Store interface {
14+
// Get retrieves data by namespace and key.
15+
Get(namespace string, key string) ([]byte, error)
16+
// Set writes data indexed by namespace and key.
17+
Set(namespace, key string, value []byte) error
18+
}
19+
20+
// FSMetadataStore uses the filesystem to associate metadata with layer and
21+
// image IDs.
22+
type FSMetadataStore struct {
23+
sync.RWMutex
24+
basePath string
25+
}
26+
27+
// NewFSMetadataStore creates a new filesystem-based metadata store.
28+
func NewFSMetadataStore(basePath string) (*FSMetadataStore, error) {
29+
if err := os.MkdirAll(basePath, 0700); err != nil {
30+
return nil, err
31+
}
32+
return &FSMetadataStore{
33+
basePath: basePath,
34+
}, nil
35+
}
36+
37+
func (store *FSMetadataStore) path(namespace, key string) string {
38+
return filepath.Join(store.basePath, namespace, key)
39+
}
40+
41+
// Get retrieves data by namespace and key. The data is read from a file named
42+
// after the key, stored in the namespace's directory.
43+
func (store *FSMetadataStore) Get(namespace string, key string) ([]byte, error) {
44+
store.RLock()
45+
defer store.RUnlock()
46+
47+
return ioutil.ReadFile(store.path(namespace, key))
48+
}
49+
50+
// Set writes data indexed by namespace and key. The data is written to a file
51+
// named after the key, stored in the namespace's directory.
52+
func (store *FSMetadataStore) Set(namespace, key string, value []byte) error {
53+
store.Lock()
54+
defer store.Unlock()
55+
56+
path := store.path(namespace, key)
57+
tempFilePath := path + ".tmp"
58+
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
59+
return err
60+
}
61+
if err := ioutil.WriteFile(tempFilePath, value, 0644); err != nil {
62+
return err
63+
}
64+
return os.Rename(tempFilePath, path)
65+
}

0 commit comments

Comments
 (0)