Skip to content

Commit

Permalink
listupdate,oci: instance show read-only annotations and CompressionAl…
Browse files Browse the repository at this point in the history
…gorithmNames

There is a need to read annotations of a particular instance to get its
compression. Expose `Annotations` as a read-only field.

Needed By: containers#1987

Signed-off-by: Aditya R <[email protected]>
  • Loading branch information
flouthoc committed Aug 4, 2023
1 parent 45c50cf commit 668ff9b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 15 deletions.
21 changes: 12 additions & 9 deletions internal/manifest/docker_schema2_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

platform "github.com/containers/image/v5/internal/pkg/platform"
compression "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -57,18 +58,20 @@ func (list *Schema2ListPublic) Instances() []digest.Digest {
func (list *Schema2ListPublic) Instance(instanceDigest digest.Digest) (ListUpdate, error) {
for _, manifest := range list.Manifests {
if manifest.Digest == instanceDigest {
return ListUpdate{
ret := ListUpdate{
Digest: manifest.Digest,
Size: manifest.Size,
MediaType: manifest.MediaType,
Platform: &imgspecv1.Platform{
OS: manifest.Platform.OS,
Architecture: manifest.Platform.Architecture,
OSVersion: manifest.Platform.OSVersion,
OSFeatures: manifest.Platform.OSFeatures,
Variant: manifest.Platform.Variant,
},
}, nil
}
ret.ReadOnly.CompressionAlgorithmNames = []string{compression.GzipAlgorithmName}
ret.ReadOnly.Platform = &imgspecv1.Platform{
OS: manifest.Platform.OS,
Architecture: manifest.Platform.Architecture,
OSVersion: manifest.Platform.OSVersion,
OSFeatures: manifest.Platform.OSFeatures,
Variant: manifest.Platform.Variant,
}
return ret, nil
}
}
return ListUpdate{}, fmt.Errorf("unable to find instance %s passed to Schema2List.Instances", instanceDigest)
Expand Down
4 changes: 3 additions & 1 deletion internal/manifest/docker_schema2_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"path/filepath"
"testing"

compressionTypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -56,7 +57,8 @@ func TestSchema2ListEditInstances(t *testing.T) {
assert.Equal(t, "something", instance.MediaType)
assert.Equal(t, int64(32), instance.Size)
// platform must match with instance platform set in `v2list.manifest.json` for the first instance
assert.Equal(t, &imgspecv1.Platform{Architecture: "ppc64le", OS: "linux", OSVersion: "", OSFeatures: []string(nil), Variant: ""}, instance.Platform)
assert.Equal(t, &imgspecv1.Platform{Architecture: "ppc64le", OS: "linux", OSVersion: "", OSFeatures: []string(nil), Variant: ""}, instance.ReadOnly.Platform)
assert.Equal(t, []string{compressionTypes.GzipAlgorithmName}, instance.ReadOnly.CompressionAlgorithmNames)

// Create a fresh list
list, err = ListFromBlob(validManifest, GuessMIMEType(validManifest))
Expand Down
7 changes: 6 additions & 1 deletion internal/manifest/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,12 @@ type ListUpdate struct {
Digest digest.Digest
Size int64
MediaType string
Platform *imgspecv1.Platform // read-only field: may be set by Instance(), ignored by UpdateInstance()
// ReadOnly fields: may be set by Instance(), ignored by UpdateInstance()
ReadOnly struct {
Platform *imgspecv1.Platform
Annotations map[string]string
CompressionAlgorithmNames []string
}
}

type ListOp int
Expand Down
21 changes: 18 additions & 3 deletions internal/manifest/oci_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,15 @@ func (index *OCI1IndexPublic) Instances() []digest.Digest {
func (index *OCI1IndexPublic) Instance(instanceDigest digest.Digest) (ListUpdate, error) {
for _, manifest := range index.Manifests {
if manifest.Digest == instanceDigest {
return ListUpdate{
ret := ListUpdate{
Digest: manifest.Digest,
Size: manifest.Size,
MediaType: manifest.MediaType,
Platform: manifest.Platform,
}, nil
}
ret.ReadOnly.Platform = manifest.Platform
ret.ReadOnly.Annotations = manifest.Annotations
ret.ReadOnly.CompressionAlgorithmNames = annotationsToCompressionAlgorithmNames(manifest.Annotations)
return ret, nil
}
}
return ListUpdate{}, fmt.Errorf("unable to find instance %s in OCI1Index", instanceDigest)
Expand All @@ -79,6 +82,18 @@ func (index *OCI1IndexPublic) UpdateInstances(updates []ListUpdate) error {
return index.editInstances(editInstances)
}

func annotationsToCompressionAlgorithmNames(annotations map[string]string) []string {
result := make([]string, 0, 1)
if annotations[OCI1InstanceAnnotationCompressionZSTD] == OCI1InstanceAnnotationCompressionZSTDValue {
result = append(result, compression.ZstdAlgorithmName)
}
// No compression was detected, hence assume instance has default compression `Gzip`
if len(result) == 0 {
result = append(result, compression.GzipAlgorithmName)
}
return result
}

func addCompressionAnnotations(compressionAlgorithms []compression.Algorithm, annotationsMap map[string]string) {
// TODO: This should also delete the algorithm if map already contains an algorithm and compressionAlgorithm
// list has a different algorithm. To do that, we would need to modify the callers to always provide a reliable
Expand Down
12 changes: 11 additions & 1 deletion internal/manifest/oci_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/containers/image/v5/pkg/compression"
compressionTypes "github.com/containers/image/v5/pkg/compression/types"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -78,7 +79,8 @@ func TestOCI1EditInstances(t *testing.T) {
assert.Equal(t, "something", instance.MediaType)
assert.Equal(t, int64(32), instance.Size)
// platform must match with what was set in `ociv1.image.index.json` for the first instance
assert.Equal(t, &imgspecv1.Platform{Architecture: "ppc64le", OS: "linux", OSVersion: "", OSFeatures: []string(nil), Variant: ""}, instance.Platform)
assert.Equal(t, &imgspecv1.Platform{Architecture: "ppc64le", OS: "linux", OSVersion: "", OSFeatures: []string(nil), Variant: ""}, instance.ReadOnly.Platform)
assert.Equal(t, []string{compressionTypes.GzipAlgorithmName}, instance.ReadOnly.CompressionAlgorithmNames)

// Create a fresh list
list, err = ListFromBlob(validManifest, GuessMIMEType(validManifest))
Expand Down Expand Up @@ -132,6 +134,14 @@ func TestOCI1EditInstances(t *testing.T) {
// Zstd should be kept on lowest priority as compared to the default gzip ones and order of prior elements must be preserved.
assert.Equal(t, list.Instances(), []digest.Digest{digest.Digest("sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"), digest.Digest("sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"), digest.Digest("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), digest.Digest("sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"), digest.Digest("sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"), digest.Digest("sha256:hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"), digest.Digest("sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")})

instance, err = list.Instance(digest.Digest("sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"))
require.NoError(t, err)
// Verify if annotations are preserved and correctly set in ReadOnly field.
assert.Equal(t, annotations, instance.ReadOnly.Annotations)
// Verify compression of an instance is added to the ReadOnly CompressionAlgorithmNames where compression name
// is internally derived from the appropriate annotations.
assert.Equal(t, []string{compressionTypes.ZstdAlgorithmName}, instance.ReadOnly.CompressionAlgorithmNames)

// Update list and remove zstd annotation from existing instance, and verify if resorting works
editInstances = []ListEdit{}
editInstances = append(editInstances, ListEdit{
Expand Down

0 comments on commit 668ff9b

Please sign in to comment.