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