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