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 }