adding some support for annotations at the manifest level

Signed-off-by: Mike Brown <brownwm@us.ibm.com>
pull/2614/head
Mike Brown 2017-07-31 18:34:11 -05:00
parent ec2aa05cdf
commit f186e1da1c
3 changed files with 28 additions and 10 deletions

View File

@ -18,15 +18,19 @@ type builder struct {
// layers is a list of layer descriptors that gets built by successive // layers is a list of layer descriptors that gets built by successive
// calls to AppendReference. // calls to AppendReference.
layers []distribution.Descriptor layers []distribution.Descriptor
// Annotations contains arbitrary metadata relating to the targeted content.
annotations map[string]string
} }
// NewManifestBuilder is used to build new manifests for the current schema // NewManifestBuilder is used to build new manifests for the current schema
// version. It takes a BlobService so it can publish the configuration blob // version. It takes a BlobService so it can publish the configuration blob
// as part of the Build process. // as part of the Build process, and annotations.
func NewManifestBuilder(bs distribution.BlobService, configJSON []byte) distribution.ManifestBuilder { func NewManifestBuilder(bs distribution.BlobService, configJSON []byte, annotations map[string]string) distribution.ManifestBuilder {
mb := &builder{ mb := &builder{
bs: bs, bs: bs,
configJSON: make([]byte, len(configJSON)), configJSON: make([]byte, len(configJSON)),
annotations: annotations,
} }
copy(mb.configJSON, configJSON) copy(mb.configJSON, configJSON)
@ -36,8 +40,9 @@ func NewManifestBuilder(bs distribution.BlobService, configJSON []byte) distribu
// Build produces a final manifest from the given references. // Build produces a final manifest from the given references.
func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) { func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
m := Manifest{ m := Manifest{
Versioned: SchemaVersion, Versioned: SchemaVersion,
Layers: make([]distribution.Descriptor, len(mb.layers)), Layers: make([]distribution.Descriptor, len(mb.layers)),
Annotations: mb.annotations,
} }
copy(m.Layers, mb.layers) copy(m.Layers, mb.layers)

View File

@ -88,6 +88,9 @@ func TestBuilder(t *testing.T) {
], ],
"type": "layers" "type": "layers"
}, },
"annotations": {
"hot": "potato"
}
"history": [ "history": [
{ {
"created": "2015-10-31T22:22:54.690851953Z", "created": "2015-10-31T22:22:54.690851953Z",
@ -120,9 +123,10 @@ func TestBuilder(t *testing.T) {
MediaType: v1.MediaTypeImageLayerGzip, MediaType: v1.MediaTypeImageLayerGzip,
}, },
} }
annotations := map[string]string{"hot": "potato"}
bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)} bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
builder := NewManifestBuilder(bs, imgJSON) builder := NewManifestBuilder(bs, imgJSON, annotations)
for _, d := range descriptors { for _, d := range descriptors {
if err := builder.AppendReference(d); err != nil { if err := builder.AppendReference(d); err != nil {
@ -142,6 +146,9 @@ func TestBuilder(t *testing.T) {
} }
manifest := built.(*DeserializedManifest).Manifest manifest := built.(*DeserializedManifest).Manifest
if manifest.Annotations["hot"] != "potato" {
t.Fatalf("unexpected annotation in manifest: %s", manifest.Annotations["hot"])
}
if manifest.Versioned.SchemaVersion != 2 { if manifest.Versioned.SchemaVersion != 2 {
t.Fatal("SchemaVersion != 2") t.Fatal("SchemaVersion != 2")
@ -154,7 +161,7 @@ func TestBuilder(t *testing.T) {
if target.MediaType != v1.MediaTypeImageConfig { if target.MediaType != v1.MediaTypeImageConfig {
t.Fatalf("unexpected media type in target: %s", target.MediaType) t.Fatalf("unexpected media type in target: %s", target.MediaType)
} }
if target.Size != 1582 { if target.Size != 1632 {
t.Fatalf("unexpected size in target: %d", target.Size) t.Fatalf("unexpected size in target: %d", target.Size)
} }

View File

@ -10,7 +10,6 @@ import (
"github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/image-spec/specs-go/v1"
) )
// TODO (mikebrow): add annotations to the test
var expectedManifestSerialization = []byte(`{ var expectedManifestSerialization = []byte(`{
"schemaVersion": 2, "schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json", "mediaType": "application/vnd.oci.image.manifest.v1+json",
@ -31,7 +30,10 @@ var expectedManifestSerialization = []byte(`{
"lettuce": "wrap" "lettuce": "wrap"
} }
} }
] ],
"annotations": {
"hot": "potato"
}
}`) }`)
func TestManifest(t *testing.T) { func TestManifest(t *testing.T) {
@ -51,6 +53,7 @@ func TestManifest(t *testing.T) {
Annotations: map[string]string{"lettuce": "wrap"}, Annotations: map[string]string{"lettuce": "wrap"},
}, },
}, },
Annotations: map[string]string{"hot": "potato"},
} }
deserialized, err := FromStruct(manifest) deserialized, err := FromStruct(manifest)
@ -87,6 +90,9 @@ func TestManifest(t *testing.T) {
if !reflect.DeepEqual(&unmarshalled, deserialized) { if !reflect.DeepEqual(&unmarshalled, deserialized) {
t.Fatalf("manifests are different after unmarshaling: %v != %v", unmarshalled, *deserialized) t.Fatalf("manifests are different after unmarshaling: %v != %v", unmarshalled, *deserialized)
} }
if deserialized.Annotations["hot"] != "potato" {
t.Fatalf("unexpected annotation in manifest: %s", deserialized.Annotations["hot"])
}
target := deserialized.Target() target := deserialized.Target()
if target.Digest != "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b" { if target.Digest != "sha256:1a9ec845ee94c202b2d5da74a24f0ed2058318bfa9879fa541efaecba272e86b" {