Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.

Commit 1974e28

Browse files
committed
support loading oci image
Signed-off-by: Gao feng <[email protected]>
1 parent 07982b8 commit 1974e28

File tree

4 files changed

+118
-5
lines changed

4 files changed

+118
-5
lines changed

daemon/images.go

+8
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,11 @@ func (daemon *Daemon) ExportImage(names []string, format string, refs map[string
1515
imageExporter := tarexport.NewTarExporter(daemon.ImageStore(), daemon.LayerStore(), daemon.ReferenceStore())
1616
return imageExporter.Save(names, format, refs, outStream)
1717
}
18+
19+
// LoadImage uploads a set of images into the repository. This is the
20+
// complement of ImageExport. The input stream is an uncompressed tar
21+
// ball containing images and metadata.
22+
func (daemon *Daemon) LoadImage(inTar io.ReadCloser, name string, refs map[string]string, outStream io.Writer) error {
23+
imageExporter := tarexport.NewTarExporter(daemon.ImageStore(), daemon.LayerStore(), daemon.ReferenceStore())
24+
return imageExporter.Load(inTar, name, refs, outStream)
25+
}

image/image.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66

77
// Exporter provides interface for exporting and importing images
88
type Exporter interface {
9-
Load(io.ReadCloser, io.Writer) error
9+
Load(io.ReadCloser, string, map[string]string, io.Writer) error
1010
// TODO: Load(net.Context, io.ReadCloser, <- chan StatusMessage) error
1111
Save([]string, string, map[string]string, io.Writer) error
1212
}

image/tarexport/load.go

+98-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import (
1616
"github.com/docker/docker/pkg/chrootarchive"
1717
"github.com/docker/docker/pkg/symlink"
1818
"github.com/docker/docker/reference"
19+
digest "github.com/opencontainers/go-digest"
20+
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
1921
)
2022

21-
func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
23+
func (l *tarexporter) Load(inTar io.ReadCloser, name string, refs map[string]string, outStream io.Writer) error {
2224
tmpDir, err := ioutil.TempDir("", "docker-import-")
2325
if err != nil {
2426
return err
@@ -28,6 +30,18 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
2830
if err := chrootarchive.Untar(inTar, tmpDir, nil); err != nil {
2931
return err
3032
}
33+
34+
// check and try to load an OCI image layout
35+
ociLayoutPath, err := safePath(tmpDir, "oci-layout")
36+
if err != nil {
37+
return err
38+
}
39+
ociLayoutFile, err := os.Open(ociLayoutPath)
40+
if err == nil {
41+
ociLayoutFile.Close()
42+
return l.ociLoad(tmpDir, name, refs, outStream)
43+
}
44+
3145
// read manifest, if no file then load in legacy mode
3246
manifestPath, err := safePath(tmpDir, manifestFileName)
3347
if err != nil {
@@ -47,7 +61,11 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
4761
return err
4862
}
4963

50-
for _, m := range manifest {
64+
return l.loadHelper(tmpDir, manifest, outStream)
65+
}
66+
67+
func (l *tarexporter) loadHelper(tmpDir string, manifests []manifestItem, outStream io.Writer) error {
68+
for _, m := range manifests {
5169
configPath, err := safePath(tmpDir, m.Config)
5270
if err != nil {
5371
return err
@@ -105,7 +123,6 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
105123
}
106124
l.setLoadedTag(ref, imgID, outStream)
107125
}
108-
109126
}
110127

111128
return nil
@@ -139,6 +156,84 @@ func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, ou
139156
return nil
140157
}
141158

159+
func (l *tarexporter) ociLoad(tmpDir, name string, refs map[string]string, outStream io.Writer) error {
160+
if name != "" && len(refs) != 0 {
161+
return fmt.Errorf("cannot load with either name and refs")
162+
}
163+
164+
if name == "" && len(refs) == 0 {
165+
return fmt.Errorf("no OCI image name mapping provided")
166+
}
167+
168+
var manifests []manifestItem
169+
indexJSON, err := os.Open(filepath.Join(tmpDir, "index.json"))
170+
if err != nil {
171+
return err
172+
}
173+
defer indexJSON.Close()
174+
index := ociv1.ImageIndex{}
175+
if err := json.NewDecoder(indexJSON).Decode(&index); err != nil {
176+
return err
177+
}
178+
for _, md := range index.Manifests {
179+
if md.MediaType != ociv1.MediaTypeImageManifest {
180+
continue
181+
}
182+
d := digest.Digest(md.Digest)
183+
manifestPath := filepath.Join(tmpDir, "blobs", d.Algorithm().String(), d.Hex())
184+
f, err := os.Open(manifestPath)
185+
if err != nil {
186+
return err
187+
}
188+
defer f.Close()
189+
man := ociv1.Manifest{}
190+
if err := json.NewDecoder(f).Decode(&man); err != nil {
191+
return err
192+
}
193+
layers := make([]string, len(man.Layers))
194+
for i, l := range man.Layers {
195+
layerDigest := digest.Digest(l.Digest)
196+
layers[i] = filepath.Join("blobs", layerDigest.Algorithm().String(), layerDigest.Hex())
197+
}
198+
tag := ""
199+
refName, ok := md.Annotations["org.opencontainers.ref.name"]
200+
if !ok {
201+
return fmt.Errorf("no ref name annotation")
202+
}
203+
if name != "" {
204+
named, err := reference.ParseNamed(name)
205+
if err != nil {
206+
return err
207+
}
208+
withTag, err := reference.WithTag(named, refName)
209+
if err != nil {
210+
return err
211+
}
212+
tag = withTag.String()
213+
} else {
214+
_, rs, err := getRefs(refs)
215+
if err != nil {
216+
return err
217+
}
218+
r, ok := rs[refName]
219+
if !ok {
220+
return fmt.Errorf("no naming provided for %q", refName)
221+
}
222+
tag = r.String()
223+
}
224+
configDigest := digest.Digest(man.Config.Digest)
225+
manifests = append(manifests, manifestItem{
226+
Config: filepath.Join("blobs", configDigest.Algorithm().String(), configDigest.Hex()),
227+
RepoTags: []string{tag},
228+
Layers: layers,
229+
// TODO(runcom): foreign srcs?
230+
// See https://github.com/docker/docker/pull/22866/files#r96125181
231+
})
232+
}
233+
234+
return l.loadHelper(tmpDir, manifests, outStream)
235+
}
236+
142237
func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer) error {
143238
legacyLoadedMap := make(map[string]image.ID)
144239

server/router/local/image.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,17 @@ func (s *router) postImagesLoad(ctx context.Context, w http.ResponseWriter, r *h
108108
w.Header().Set("Content-Type", "application/json")
109109
output := ioutils.NewWriteFlusher(w)
110110
defer output.Close()
111-
err := s.daemon.LoadImage(r.Body, output)
111+
112+
name := r.FormValue("name")
113+
var refs = map[string]string{}
114+
refsJSON := r.FormValue("refs")
115+
if refsJSON != "" {
116+
if err := json.NewDecoder(strings.NewReader(refsJSON)).Decode(&refs); err != nil {
117+
return err
118+
}
119+
}
120+
121+
err := s.daemon.LoadImage(r.Body, name, refs, output)
112122
if err != nil {
113123
if !output.Flushed() {
114124
return err

0 commit comments

Comments
 (0)