121 lines
2.9 KiB
Go
121 lines
2.9 KiB
Go
package containerd
|
|
|
|
import (
|
|
"archive/tar"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
"github.com/containerd/containerd/content"
|
|
"github.com/containerd/containerd/errdefs"
|
|
"github.com/containerd/containerd/images"
|
|
"github.com/containerd/containerd/reference"
|
|
digest "github.com/opencontainers/go-digest"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func resolveOCIIndex(idx ocispec.Index, refObject string) (*ocispec.Descriptor, error) {
|
|
tag, dgst := reference.SplitObject(refObject)
|
|
if tag == "" && dgst == "" {
|
|
return nil, errors.Errorf("unexpected object: %q", refObject)
|
|
}
|
|
for _, m := range idx.Manifests {
|
|
if m.Digest == dgst {
|
|
return &m, nil
|
|
}
|
|
annot, ok := m.Annotations[ocispec.AnnotationRefName]
|
|
if ok && annot == tag && tag != "" {
|
|
return &m, nil
|
|
}
|
|
}
|
|
return nil, errors.Errorf("not found: %q", refObject)
|
|
}
|
|
|
|
func (c *Client) importFromOCITar(ctx context.Context, ref string, reader io.Reader, iopts importOpts) (Image, error) {
|
|
tr := tar.NewReader(reader)
|
|
store := c.ContentStore()
|
|
var desc *ocispec.Descriptor
|
|
for {
|
|
hdr, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA {
|
|
continue
|
|
}
|
|
if hdr.Name == "index.json" {
|
|
desc, err = onUntarIndexJSON(tr, iopts.refObject)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(hdr.Name, "blobs/") {
|
|
if err := onUntarBlob(ctx, tr, store, hdr.Name, hdr.Size); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
if desc == nil {
|
|
return nil, errors.Errorf("no descriptor found for reference object %q", iopts.refObject)
|
|
}
|
|
imgrec := images.Image{
|
|
Name: ref,
|
|
Target: *desc,
|
|
Labels: iopts.labels,
|
|
}
|
|
is := c.ImageService()
|
|
if updated, err := is.Update(ctx, imgrec, "target"); err != nil {
|
|
if !errdefs.IsNotFound(err) {
|
|
return nil, err
|
|
}
|
|
|
|
created, err := is.Create(ctx, imgrec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
imgrec = created
|
|
} else {
|
|
imgrec = updated
|
|
}
|
|
|
|
img := &image{
|
|
client: c,
|
|
i: imgrec,
|
|
}
|
|
return img, nil
|
|
}
|
|
|
|
func onUntarIndexJSON(r io.Reader, refObject string) (*ocispec.Descriptor, error) {
|
|
b, err := ioutil.ReadAll(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var idx ocispec.Index
|
|
if err := json.Unmarshal(b, &idx); err != nil {
|
|
return nil, err
|
|
}
|
|
return resolveOCIIndex(idx, refObject)
|
|
}
|
|
|
|
func onUntarBlob(ctx context.Context, r io.Reader, store content.Store, name string, size int64) error {
|
|
// name is like "blobs/sha256/deadbeef"
|
|
split := strings.Split(name, "/")
|
|
if len(split) != 3 {
|
|
return errors.Errorf("unexpected name: %q", name)
|
|
}
|
|
algo := digest.Algorithm(split[1])
|
|
if !algo.Available() {
|
|
return errors.Errorf("unsupported algorithm: %s", algo)
|
|
}
|
|
dgst := digest.NewDigestFromHex(algo.String(), split[2])
|
|
return content.WriteBlob(ctx, store, "unknown-"+dgst.String(), r, size, dgst)
|
|
}
|