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