github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/daemon/commit.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"runtime"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/container"
    12  	"github.com/docker/docker/dockerversion"
    13  	"github.com/docker/docker/image"
    14  	"github.com/docker/docker/layer"
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/ioutils"
    17  	"github.com/docker/docker/reference"
    18  	"github.com/docker/docker/runconfig"
    19  )
    20  
    21  // Commit creates a new filesystem image from the current state of a container.
    22  // The image can optionally be tagged into a repository.
    23  func (daemon *Daemon) Commit(name string, c *types.ContainerCommitConfig) (string, error) {
    24  	container, err := daemon.GetContainer(name)
    25  	if err != nil {
    26  		return "", err
    27  	}
    28  
    29  	// It is not possible to commit a running container on Windows
    30  	if runtime.GOOS == "windows" && container.IsRunning() {
    31  		return "", fmt.Errorf("Windows does not support commit of a running container")
    32  	}
    33  
    34  	if c.Pause && !container.IsPaused() {
    35  		daemon.containerPause(container)
    36  		defer daemon.containerUnpause(container)
    37  	}
    38  
    39  	if c.MergeConfigs {
    40  		if err := runconfig.Merge(c.Config, container.Config); err != nil {
    41  			return "", err
    42  		}
    43  	}
    44  
    45  	rwTar, err := daemon.exportContainerRw(container)
    46  	if err != nil {
    47  		return "", err
    48  	}
    49  	defer func() {
    50  		if rwTar != nil {
    51  			rwTar.Close()
    52  		}
    53  	}()
    54  
    55  	var history []image.History
    56  	rootFS := image.NewRootFS()
    57  
    58  	if container.ImageID != "" {
    59  		img, err := daemon.imageStore.Get(container.ImageID)
    60  		if err != nil {
    61  			return "", err
    62  		}
    63  		history = img.History
    64  		rootFS = img.RootFS
    65  	}
    66  
    67  	l, err := daemon.layerStore.Register(rwTar, rootFS.ChainID())
    68  	if err != nil {
    69  		return "", err
    70  	}
    71  	defer layer.ReleaseAndLog(daemon.layerStore, l)
    72  
    73  	h := image.History{
    74  		Author:     c.Author,
    75  		Created:    time.Now().UTC(),
    76  		CreatedBy:  strings.Join(container.Config.Cmd.Slice(), " "),
    77  		Comment:    c.Comment,
    78  		EmptyLayer: true,
    79  	}
    80  
    81  	if diffID := l.DiffID(); layer.DigestSHA256EmptyTar != diffID {
    82  		h.EmptyLayer = false
    83  		rootFS.Append(diffID)
    84  	}
    85  
    86  	history = append(history, h)
    87  
    88  	config, err := json.Marshal(&image.Image{
    89  		V1Image: image.V1Image{
    90  			DockerVersion:   dockerversion.Version,
    91  			Config:          c.Config,
    92  			Architecture:    runtime.GOARCH,
    93  			OS:              runtime.GOOS,
    94  			Container:       container.ID,
    95  			ContainerConfig: *container.Config,
    96  			Author:          c.Author,
    97  			Created:         h.Created,
    98  		},
    99  		RootFS:  rootFS,
   100  		History: history,
   101  	})
   102  
   103  	if err != nil {
   104  		return "", err
   105  	}
   106  
   107  	id, err := daemon.imageStore.Create(config)
   108  	if err != nil {
   109  		return "", err
   110  	}
   111  
   112  	if container.ImageID != "" {
   113  		if err := daemon.imageStore.SetParent(id, container.ImageID); err != nil {
   114  			return "", err
   115  		}
   116  	}
   117  
   118  	if c.Repo != "" {
   119  		newTag, err := reference.WithName(c.Repo) // todo: should move this to API layer
   120  		if err != nil {
   121  			return "", err
   122  		}
   123  		if c.Tag != "" {
   124  			if newTag, err = reference.WithTag(newTag, c.Tag); err != nil {
   125  				return "", err
   126  			}
   127  		}
   128  		if err := daemon.TagImage(newTag, id.String()); err != nil {
   129  			return "", err
   130  		}
   131  	}
   132  
   133  	daemon.LogContainerEvent(container, "commit")
   134  	return id.String(), nil
   135  }
   136  
   137  func (daemon *Daemon) exportContainerRw(container *container.Container) (archive.Archive, error) {
   138  	if err := daemon.Mount(container); err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	archive, err := container.RWLayer.TarStream()
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	return ioutils.NewReadCloserWrapper(archive, func() error {
   147  			archive.Close()
   148  			return daemon.layerStore.Unmount(container.ID)
   149  		}),
   150  		nil
   151  }