github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/images/image_import.go (about)

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