blob: 9f8f9af7d7050f8b22756186f358d877976cbed4 [file] [log] [blame]
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)
}