github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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 61 if c.ParentImageID != "" { 62 if err := i.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil { 63 return "", err 64 } 65 } 66 return id, nil 67 } 68 69 func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.ReadCloser, err error) { 70 rwlayer, err := layerStore.GetRWLayer(id) 71 if err != nil { 72 return nil, err 73 } 74 defer func() { 75 if err != nil { 76 layerStore.ReleaseRWLayer(rwlayer) 77 } 78 }() 79 80 // TODO: this mount call is not necessary as we assume that TarStream() should 81 // mount the layer if needed. But the Diff() function for windows requests that 82 // the layer should be mounted when calling it. So we reserve this mount call 83 // until windows driver can implement Diff() interface correctly. 84 _, err = rwlayer.Mount(mountLabel) 85 if err != nil { 86 return nil, err 87 } 88 89 archive, err := rwlayer.TarStream() 90 if err != nil { 91 rwlayer.Unmount() 92 return nil, err 93 } 94 return ioutils.NewReadCloserWrapper(archive, func() error { 95 archive.Close() 96 err = rwlayer.Unmount() 97 layerStore.ReleaseRWLayer(rwlayer) 98 return err 99 }), 100 nil 101 } 102 103 // CommitBuildStep is used by the builder to create an image for each step in 104 // the build. 105 // 106 // This method is different from CreateImageFromContainer: 107 // - it doesn't attempt to validate container state 108 // - it doesn't send a commit action to metrics 109 // - it doesn't log a container commit event 110 // 111 // This is a temporary shim. Should be removed when builder stops using commit. 112 func (i *ImageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) { 113 ctr := i.containers.Get(c.ContainerID) 114 if ctr == nil { 115 // TODO: use typed error 116 return "", errors.Errorf("container not found: %s", c.ContainerID) 117 } 118 c.ContainerMountLabel = ctr.MountLabel 119 c.ContainerOS = ctr.OS 120 c.ParentImageID = string(ctr.ImageID) 121 return i.CommitImage(c) 122 }