github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/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/docker/docker/pkg/system" 12 "github.com/pkg/errors" 13 ) 14 15 // CommitImage creates a new image from a commit config 16 func (i *ImageService) CommitImage(c backend.CommitConfig) (image.ID, error) { 17 layerStore, ok := i.layerStores[c.ContainerOS] 18 if !ok { 19 return "", system.ErrNotSupportedOperatingSystem 20 } 21 rwTar, err := exportContainerRw(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 := layerStore.Register(rwTar, parent.RootFS.ChainID()) 43 if err != nil { 44 return "", err 45 } 46 defer layer.ReleaseAndLog(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(c backend.CommitConfig) (image.ID, error) { 118 container := i.containers.Get(c.ContainerID) 119 if container == nil { 120 // TODO: use typed error 121 return "", errors.Errorf("container not found: %s", c.ContainerID) 122 } 123 c.ContainerMountLabel = container.MountLabel 124 c.ContainerOS = container.OS 125 c.ParentImageID = string(container.ImageID) 126 return i.CommitImage(c) 127 }