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

     1  package images // import "github.com/docker/docker/daemon/images"
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  
     7  	"github.com/docker/docker/api/types/backend"
     8  	"github.com/docker/docker/image"
     9  	"github.com/docker/docker/layer"
    10  	"github.com/docker/docker/pkg/ioutils"
    11  	"github.com/docker/docker/pkg/system"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  // CommitImage creates a new image from a commit config
    16  func (i *ImageService) CommitImage(c backend.CommitConfig) (image.ID, error) {
    17  	layerStore, ok := i.layerStores[c.ContainerOS]
    18  	if !ok {
    19  		return "", system.ErrNotSupportedOperatingSystem
    20  	}
    21  	rwTar, err := exportContainerRw(layerStore, c.ContainerID, c.ContainerMountLabel)
    22  	if err != nil {
    23  		return "", err
    24  	}
    25  	defer func() {
    26  		if rwTar != nil {
    27  			rwTar.Close()
    28  		}
    29  	}()
    30  
    31  	var parent *image.Image
    32  	if c.ParentImageID == "" {
    33  		parent = new(image.Image)
    34  		parent.RootFS = image.NewRootFS()
    35  	} else {
    36  		parent, err = i.imageStore.Get(image.ID(c.ParentImageID))
    37  		if err != nil {
    38  			return "", err
    39  		}
    40  	}
    41  
    42  	l, err := layerStore.Register(rwTar, parent.RootFS.ChainID())
    43  	if err != nil {
    44  		return "", err
    45  	}
    46  	defer layer.ReleaseAndLog(layerStore, l)
    47  
    48  	cc := image.ChildConfig{
    49  		ContainerID:     c.ContainerID,
    50  		Author:          c.Author,
    51  		Comment:         c.Comment,
    52  		ContainerConfig: c.ContainerConfig,
    53  		Config:          c.Config,
    54  		DiffID:          l.DiffID(),
    55  	}
    56  	config, err := json.Marshal(image.NewChildImage(parent, cc, c.ContainerOS))
    57  	if err != nil {
    58  		return "", err
    59  	}
    60  
    61  	id, err := i.imageStore.Create(config)
    62  	if err != nil {
    63  		return "", err
    64  	}
    65  
    66  	if c.ParentImageID != "" {
    67  		if err := i.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil {
    68  			return "", err
    69  		}
    70  	}
    71  	return id, nil
    72  }
    73  
    74  func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.ReadCloser, err error) {
    75  	rwlayer, err := layerStore.GetRWLayer(id)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	defer func() {
    80  		if err != nil {
    81  			layerStore.ReleaseRWLayer(rwlayer)
    82  		}
    83  	}()
    84  
    85  	// TODO: this mount call is not necessary as we assume that TarStream() should
    86  	// mount the layer if needed. But the Diff() function for windows requests that
    87  	// the layer should be mounted when calling it. So we reserve this mount call
    88  	// until windows driver can implement Diff() interface correctly.
    89  	_, err = rwlayer.Mount(mountLabel)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	archive, err := rwlayer.TarStream()
    95  	if err != nil {
    96  		rwlayer.Unmount()
    97  		return nil, err
    98  	}
    99  	return ioutils.NewReadCloserWrapper(archive, func() error {
   100  			archive.Close()
   101  			err = rwlayer.Unmount()
   102  			layerStore.ReleaseRWLayer(rwlayer)
   103  			return err
   104  		}),
   105  		nil
   106  }
   107  
   108  // CommitBuildStep is used by the builder to create an image for each step in
   109  // the build.
   110  //
   111  // This method is different from CreateImageFromContainer:
   112  //   * it doesn't attempt to validate container state
   113  //   * it doesn't send a commit action to metrics
   114  //   * it doesn't log a container commit event
   115  //
   116  // This is a temporary shim. Should be removed when builder stops using commit.
   117  func (i *ImageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
   118  	container := i.containers.Get(c.ContainerID)
   119  	if container == nil {
   120  		// TODO: use typed error
   121  		return "", errors.Errorf("container not found: %s", c.ContainerID)
   122  	}
   123  	c.ContainerMountLabel = container.MountLabel
   124  	c.ContainerOS = container.OS
   125  	c.ParentImageID = string(container.ImageID)
   126  	return i.CommitImage(c)
   127  }