1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
//go:build nydus
// +build nydus
package compression
import (
"context"
"io"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/labels"
digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
nydusify "github.com/containerd/nydus-snapshotter/pkg/converter"
)
type nydusType struct{}
var Nydus = nydusType{}
func init() {
toDockerLayerType[nydusify.MediaTypeNydusBlob] = nydusify.MediaTypeNydusBlob
toOCILayerType[nydusify.MediaTypeNydusBlob] = nydusify.MediaTypeNydusBlob
}
func Parse(t string) (Type, error) {
ct, err := parse(t)
if err != nil && t == Nydus.String() {
return Nydus, nil
}
return ct, err
}
func FromMediaType(mediaType string) (Type, error) {
ct, err := fromMediaType(mediaType)
if err != nil && mediaType == nydusify.MediaTypeNydusBlob {
return Nydus, nil
}
return ct, err
}
func (c nydusType) Compress(ctx context.Context, comp Config) (compressorFunc Compressor, finalize Finalizer) {
digester := digest.Canonical.Digester()
return func(dest io.Writer, requiredMediaType string) (io.WriteCloser, error) {
writer := io.MultiWriter(dest, digester.Hash())
return nydusify.Pack(ctx, writer, nydusify.PackOption{})
}, func(ctx context.Context, cs content.Store) (map[string]string, error) {
// Fill necessary labels
uncompressedDgst := digester.Digest().String()
info, err := cs.Info(ctx, digester.Digest())
if err != nil {
return nil, errors.Wrap(err, "get info from content store")
}
if info.Labels == nil {
info.Labels = make(map[string]string)
}
info.Labels[labels.LabelUncompressed] = uncompressedDgst
if _, err := cs.Update(ctx, info, "labels."+labels.LabelUncompressed); err != nil {
return nil, errors.Wrap(err, "update info to content store")
}
// Fill annotations
annotations := map[string]string{
labels.LabelUncompressed: uncompressedDgst,
// Use this annotation to identify nydus blob layer.
nydusify.LayerAnnotationNydusBlob: "true",
}
return annotations, nil
}
}
func (c nydusType) Decompress(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (io.ReadCloser, error) {
ra, err := cs.ReaderAt(ctx, desc)
if err != nil {
return nil, err
}
pr, pw := io.Pipe()
go func() {
defer pw.Close()
if err := nydusify.Unpack(ctx, ra, pw, nydusify.UnpackOption{}); err != nil {
pw.CloseWithError(errors.Wrap(err, "unpack nydus blob"))
}
}()
return pr, nil
}
func (c nydusType) NeedsConversion(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (bool, error) {
if !images.IsLayerType(desc.MediaType) {
return false, nil
}
if isNydusBlob, err := c.Is(ctx, cs, desc); err != nil {
return true, nil
} else if isNydusBlob {
return false, nil
}
return true, nil
}
func (c nydusType) NeedsComputeDiffBySelf(comp Config) bool {
return true
}
func (c nydusType) OnlySupportOCITypes() bool {
return true
}
func (c nydusType) MediaType() string {
return nydusify.MediaTypeNydusBlob
}
func (c nydusType) String() string {
return "nydus"
}
// Is returns true when the specified digest of content exists in
// the content store and it's nydus format.
func (c nydusType) Is(ctx context.Context, cs content.Store, desc ocispecs.Descriptor) (bool, error) {
if desc.Annotations == nil {
return false, nil
}
hasMediaType := desc.MediaType == nydusify.MediaTypeNydusBlob
_, hasAnno := desc.Annotations[nydusify.LayerAnnotationNydusBlob]
_, err := cs.Info(ctx, desc.Digest)
if err != nil {
return false, err
}
return hasMediaType && hasAnno, nil
}
|