github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/import.go (about) 1 package daemon 2 3 import ( 4 "encoding/json" 5 "io" 6 "net/http" 7 "net/url" 8 "runtime" 9 "strings" 10 "time" 11 12 "github.com/docker/distribution/reference" 13 "github.com/docker/docker/api/types/container" 14 "github.com/docker/docker/builder/dockerfile" 15 "github.com/docker/docker/builder/remotecontext" 16 "github.com/docker/docker/dockerversion" 17 "github.com/docker/docker/image" 18 "github.com/docker/docker/layer" 19 "github.com/docker/docker/pkg/archive" 20 "github.com/docker/docker/pkg/progress" 21 "github.com/docker/docker/pkg/streamformatter" 22 "github.com/pkg/errors" 23 ) 24 25 // ImportImage imports an image, getting the archived layer data either from 26 // inConfig (if src is "-"), or from a URI specified in src. Progress output is 27 // written to outStream. Repository and tag names can optionally be given in 28 // the repo and tag arguments, respectively. 29 func (daemon *Daemon) ImportImage(src string, repository, os string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error { 30 var ( 31 rc io.ReadCloser 32 resp *http.Response 33 newRef reference.Named 34 ) 35 36 // Default the operating system if not supplied. 37 if os == "" { 38 os = runtime.GOOS 39 } 40 41 if repository != "" { 42 var err error 43 newRef, err = reference.ParseNormalizedNamed(repository) 44 if err != nil { 45 return validationError{err} 46 } 47 if _, isCanonical := newRef.(reference.Canonical); isCanonical { 48 return validationError{errors.New("cannot import digest reference")} 49 } 50 51 if tag != "" { 52 newRef, err = reference.WithTag(newRef, tag) 53 if err != nil { 54 return validationError{err} 55 } 56 } 57 } 58 59 config, err := dockerfile.BuildFromConfig(&container.Config{}, changes) 60 if err != nil { 61 return err 62 } 63 if src == "-" { 64 rc = inConfig 65 } else { 66 inConfig.Close() 67 if len(strings.Split(src, "://")) == 1 { 68 src = "http://" + src 69 } 70 u, err := url.Parse(src) 71 if err != nil { 72 return validationError{err} 73 } 74 75 resp, err = remotecontext.GetWithStatusError(u.String()) 76 if err != nil { 77 return err 78 } 79 outStream.Write(streamformatter.FormatStatus("", "Downloading from %s", u)) 80 progressOutput := streamformatter.NewJSONProgressOutput(outStream, true) 81 rc = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing") 82 } 83 84 defer rc.Close() 85 if len(msg) == 0 { 86 msg = "Imported from " + src 87 } 88 89 inflatedLayerData, err := archive.DecompressStream(rc) 90 if err != nil { 91 return err 92 } 93 l, err := daemon.stores[os].layerStore.Register(inflatedLayerData, "", layer.OS(os)) 94 if err != nil { 95 return err 96 } 97 defer layer.ReleaseAndLog(daemon.stores[os].layerStore, l) 98 99 created := time.Now().UTC() 100 imgConfig, err := json.Marshal(&image.Image{ 101 V1Image: image.V1Image{ 102 DockerVersion: dockerversion.Version, 103 Config: config, 104 Architecture: runtime.GOARCH, 105 OS: os, 106 Created: created, 107 Comment: msg, 108 }, 109 RootFS: &image.RootFS{ 110 Type: "layers", 111 DiffIDs: []layer.DiffID{l.DiffID()}, 112 }, 113 History: []image.History{{ 114 Created: created, 115 Comment: msg, 116 }}, 117 }) 118 if err != nil { 119 return err 120 } 121 122 id, err := daemon.stores[os].imageStore.Create(imgConfig) 123 if err != nil { 124 return err 125 } 126 127 // FIXME: connect with commit code and call refstore directly 128 if newRef != nil { 129 if err := daemon.TagImageWithReference(id, os, newRef); err != nil { 130 return err 131 } 132 } 133 134 daemon.LogImageEvent(id.String(), id.String(), "import") 135 outStream.Write(streamformatter.FormatStatus("", id.String())) 136 return nil 137 }