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 }