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