github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/images/image_import.go (about)

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