@@ -19,114 +19,89 @@ package oci
1919
2020import (
2121 "archive/tar"
22+ "bytes"
2223 "context"
23- "encoding/json"
24- "fmt"
2524 "io"
2625 "io/ioutil"
2726 "path"
2827 "strings"
2928
3029 "github.com/containerd/containerd/content"
31- "github.com/containerd/containerd/errdefs"
3230 "github.com/containerd/containerd/images"
31+ "github.com/containerd/containerd/log"
3332 digest "github.com/opencontainers/go-digest"
3433 ocispec "github.com/opencontainers/image-spec/specs-go/v1"
3534 "github.com/pkg/errors"
3635)
3736
3837// V1Importer implements OCI Image Spec v1.
39- type V1Importer struct {
40- // ImageName is preprended to either `:` + OCI ref name or `@` + digest (for anonymous refs).
41- // This field is mandatory atm, but may change in the future. maybe ref map[string]string as in moby/moby#33355
42- ImageName string
43- }
38+ type V1Importer struct {}
4439
4540var _ images.Importer = & V1Importer {}
4641
4742// Import implements Importer.
48- func (oi * V1Importer ) Import (ctx context.Context , store content.Store , reader io.Reader ) ([]images.Image , error ) {
49- if oi .ImageName == "" {
50- return nil , errors .New ("ImageName not set" )
51- }
52- tr := tar .NewReader (reader )
53- var imgrecs []images.Image
54- foundIndexJSON := false
43+ func (oi * V1Importer ) Import (ctx context.Context , store content.Store , reader io.Reader ) (ocispec.Descriptor , error ) {
44+ var (
45+ desc ocispec.Descriptor
46+ tr = tar .NewReader (reader )
47+ )
5548 for {
5649 hdr , err := tr .Next ()
5750 if err == io .EOF {
5851 break
5952 }
6053 if err != nil {
61- return nil , err
54+ return ocispec. Descriptor {} , err
6255 }
6356 if hdr .Typeflag != tar .TypeReg && hdr .Typeflag != tar .TypeRegA {
57+ log .G (ctx ).WithField ("file" , hdr .Name ).Debug ("file type ignored" )
6458 continue
6559 }
6660 hdrName := path .Clean (hdr .Name )
6761 if hdrName == "index.json" {
68- if foundIndexJSON {
69- return nil , errors .New ("duplicated index.json" )
62+ if desc . Digest != "" {
63+ return ocispec. Descriptor {} , errors .New ("duplicated index.json" )
7064 }
71- foundIndexJSON = true
72- imgrecs , err = onUntarIndexJSON (tr , oi .ImageName )
65+ desc , err = onUntarIndexJSON (ctx , tr , store , hdr .Size )
7366 if err != nil {
74- return nil , err
67+ return ocispec. Descriptor {} , err
7568 }
76- continue
77- }
78- if strings .HasPrefix (hdrName , "blobs/" ) {
69+ } else if strings .HasPrefix (hdrName , "blobs/" ) {
7970 if err := onUntarBlob (ctx , tr , store , hdrName , hdr .Size ); err != nil {
80- return nil , err
71+ return ocispec. Descriptor {} , err
8172 }
73+ } else if hdrName == ocispec .ImageLayoutFile {
74+ // TODO Validate
75+ } else {
76+ log .G (ctx ).WithField ("file" , hdr .Name ).Debug ("unknown file ignored" )
8277 }
8378 }
84- if ! foundIndexJSON {
85- return nil , errors .New ("no index.json found" )
86- }
87- for _ , img := range imgrecs {
88- err := setGCRefContentLabels (ctx , store , img .Target )
89- if err != nil {
90- return imgrecs , err
91- }
79+ if desc .Digest == "" {
80+ return ocispec.Descriptor {}, errors .New ("no index.json found" )
9281 }
93- // FIXME(AkihiroSuda): set GC labels for unreferrenced blobs (i.e. with unknown media types)?
94- return imgrecs , nil
82+
83+ return desc , nil
9584}
9685
97- func onUntarIndexJSON (r io.Reader , imageName string ) ([]images. Image , error ) {
86+ func onUntarIndexJSON (ctx context. Context , r io.Reader , store content. Ingester , size int64 ) (ocispec. Descriptor , error ) {
9887 b , err := ioutil .ReadAll (r )
9988 if err != nil {
100- return nil , err
89+ return ocispec. Descriptor {} , err
10190 }
102- var idx ocispec.Index
103- if err := json .Unmarshal (b , & idx ); err != nil {
104- return nil , err
91+ desc := ocispec.Descriptor {
92+ MediaType : ocispec .MediaTypeImageIndex ,
93+ Digest : digest .FromBytes (b ),
94+ Size : size ,
10595 }
106- var imgrecs []images.Image
107- for _ , m := range idx .Manifests {
108- ref , err := normalizeImageRef (imageName , m )
109- if err != nil {
110- return nil , err
111- }
112- imgrecs = append (imgrecs , images.Image {
113- Name : ref ,
114- Target : m ,
115- })
96+ if int64 (len (b )) != size {
97+ return ocispec.Descriptor {}, errors .Errorf ("size mismatch %d v %d" , len (b ), size )
11698 }
117- return imgrecs , nil
118- }
11999
120- func normalizeImageRef (imageName string , manifest ocispec.Descriptor ) (string , error ) {
121- digest := manifest .Digest
122- if digest == "" {
123- return "" , errors .Errorf ("manifest with empty digest: %v" , manifest )
124- }
125- ociRef := manifest .Annotations [ocispec .AnnotationRefName ]
126- if ociRef == "" {
127- return imageName + "@" + digest .String (), nil
100+ if err := content .WriteBlob (ctx , store , "index-" + desc .Digest .String (), bytes .NewReader (b ), desc ); err != nil {
101+ return ocispec.Descriptor {}, err
128102 }
129- return imageName + ":" + ociRef , nil
103+
104+ return desc , err
130105}
131106
132107func onUntarBlob (ctx context.Context , r io.Reader , store content.Ingester , name string , size int64 ) error {
@@ -140,65 +115,22 @@ func onUntarBlob(ctx context.Context, r io.Reader, store content.Ingester, name
140115 return errors .Errorf ("unsupported algorithm: %s" , algo )
141116 }
142117 dgst := digest .NewDigestFromHex (algo .String (), split [2 ])
143- return content .WriteBlob (ctx , store , "unknown -" + dgst .String (), r , ocispec.Descriptor {Size : size , Digest : dgst })
118+ return content .WriteBlob (ctx , store , "blob -" + dgst .String (), r , ocispec.Descriptor {Size : size , Digest : dgst })
144119}
145120
146- // GetChildrenDescriptors returns children blob descriptors for the following supported types:
147- // - images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest
148- // - images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex
149- func GetChildrenDescriptors (r io.Reader , desc ocispec.Descriptor ) ([]ocispec.Descriptor , error ) {
150- switch desc .MediaType {
151- case images .MediaTypeDockerSchema2Manifest , ocispec .MediaTypeImageManifest :
152- var manifest ocispec.Manifest
153- if err := json .NewDecoder (r ).Decode (& manifest ); err != nil {
154- return nil , err
155- }
156- return append ([]ocispec.Descriptor {manifest .Config }, manifest .Layers ... ), nil
157- case images .MediaTypeDockerSchema2ManifestList , ocispec .MediaTypeImageIndex :
158- var index ocispec.Index
159- if err := json .NewDecoder (r ).Decode (& index ); err != nil {
160- return nil , err
161- }
162- return index .Manifests , nil
121+ // RefTranslator creates a reference using an OCI ref annotation,
122+ // which is mentioned in the spec as only a tag compontent,
123+ // concatenated with an image name
124+ func RefTranslator (prefix string ) func (string ) string {
125+ return func (ref string ) string {
126+ return prefix + ":" + ref
163127 }
164- return nil , nil
165128}
166129
167- func setGCRefContentLabels (ctx context.Context , store content.Store , desc ocispec.Descriptor ) error {
168- info , err := store .Info (ctx , desc .Digest )
169- if err != nil {
170- if errdefs .IsNotFound (err ) {
171- // when the archive is created from multi-arch image,
172- // it may contain only blobs for a certain platform.
173- // So ErrNotFound (on manifest list) is expected here.
174- return nil
175- }
176- return err
177- }
178- ra , err := store .ReaderAt (ctx , desc )
179- if err != nil {
180- return err
181- }
182- defer ra .Close ()
183- r := content .NewReader (ra )
184- children , err := GetChildrenDescriptors (r , desc )
185- if err != nil {
186- return err
187- }
188- if info .Labels == nil {
189- info .Labels = map [string ]string {}
190- }
191- for i , child := range children {
192- // Note: child blob is not guaranteed to be written to the content store. (multi-arch)
193- info .Labels [fmt .Sprintf ("containerd.io/gc.ref.content.%d" , i )] = child .Digest .String ()
194- }
195- if _ , err := store .Update (ctx , info , "labels" ); err != nil {
196- return err
197- }
198- for _ , child := range children {
199- if err := setGCRefContentLabels (ctx , store , child ); err != nil {
200- return err
201- }
130+ // DigestTranslator creates a digest reference by adding the
131+ // digest to an image name
132+ func DigestTranslator (prefix string ) func (digest.Digest ) string {
133+ return func (dgst digest.Digest ) string {
134+ return prefix + "@" + dgst .String ()
202135 }
203- return nil
204136}
0 commit comments