github.com/rumpl/bof@v23.0.0-rc.2+incompatible/daemon/images/service.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 8 "github.com/containerd/containerd/content" 9 "github.com/containerd/containerd/leases" 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/api/types/filters" 12 "github.com/docker/docker/container" 13 daemonevents "github.com/docker/docker/daemon/events" 14 "github.com/docker/docker/distribution/metadata" 15 "github.com/docker/docker/distribution/xfer" 16 "github.com/docker/docker/image" 17 "github.com/docker/docker/layer" 18 dockerreference "github.com/docker/docker/reference" 19 "github.com/docker/docker/registry" 20 "github.com/opencontainers/go-digest" 21 "github.com/pkg/errors" 22 "golang.org/x/sync/singleflight" 23 ) 24 25 type containerStore interface { 26 // used by image delete 27 First(container.StoreFilter) *container.Container 28 // used by image prune, and image list 29 List() []*container.Container 30 // TODO: remove, only used for CommitBuildStep 31 Get(string) *container.Container 32 } 33 34 // ImageServiceConfig is the configuration used to create a new ImageService 35 type ImageServiceConfig struct { 36 ContainerStore containerStore 37 DistributionMetadataStore metadata.Store 38 EventsService *daemonevents.Events 39 ImageStore image.Store 40 LayerStore layer.Store 41 MaxConcurrentDownloads int 42 MaxConcurrentUploads int 43 MaxDownloadAttempts int 44 ReferenceStore dockerreference.Store 45 RegistryService registry.Service 46 ContentStore content.Store 47 Leases leases.Manager 48 ContentNamespace string 49 } 50 51 // NewImageService returns a new ImageService from a configuration 52 func NewImageService(config ImageServiceConfig) *ImageService { 53 return &ImageService{ 54 containers: config.ContainerStore, 55 distributionMetadataStore: config.DistributionMetadataStore, 56 downloadManager: xfer.NewLayerDownloadManager(config.LayerStore, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)), 57 eventsService: config.EventsService, 58 imageStore: &imageStoreWithLease{Store: config.ImageStore, leases: config.Leases, ns: config.ContentNamespace}, 59 layerStore: config.LayerStore, 60 referenceStore: config.ReferenceStore, 61 registryService: config.RegistryService, 62 uploadManager: xfer.NewLayerUploadManager(config.MaxConcurrentUploads), 63 leases: config.Leases, 64 content: config.ContentStore, 65 contentNamespace: config.ContentNamespace, 66 } 67 } 68 69 // ImageService provides a backend for image management 70 type ImageService struct { 71 containers containerStore 72 distributionMetadataStore metadata.Store 73 downloadManager *xfer.LayerDownloadManager 74 eventsService *daemonevents.Events 75 imageStore image.Store 76 layerStore layer.Store 77 pruneRunning int32 78 referenceStore dockerreference.Store 79 registryService registry.Service 80 uploadManager *xfer.LayerUploadManager 81 leases leases.Manager 82 content content.Store 83 contentNamespace string 84 usage singleflight.Group 85 } 86 87 // DistributionServices provides daemon image storage services 88 type DistributionServices struct { 89 DownloadManager *xfer.LayerDownloadManager 90 V2MetadataService metadata.V2MetadataService 91 LayerStore layer.Store 92 ImageStore image.Store 93 ReferenceStore dockerreference.Store 94 } 95 96 // DistributionServices return services controlling daemon image storage 97 func (i *ImageService) DistributionServices() DistributionServices { 98 return DistributionServices{ 99 DownloadManager: i.downloadManager, 100 V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore), 101 LayerStore: i.layerStore, 102 ImageStore: i.imageStore, 103 ReferenceStore: i.referenceStore, 104 } 105 } 106 107 // CountImages returns the number of images stored by ImageService 108 // called from info.go 109 func (i *ImageService) CountImages() int { 110 return i.imageStore.Len() 111 } 112 113 // Children returns the children image.IDs for a parent image. 114 // called from list.go to filter containers 115 // TODO: refactor to expose an ancestry for image.ID? 116 func (i *ImageService) Children(id image.ID) []image.ID { 117 return i.imageStore.Children(id) 118 } 119 120 // CreateLayer creates a filesystem layer for a container. 121 // called from create.go 122 // TODO: accept an opt struct instead of container? 123 func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) { 124 var layerID layer.ChainID 125 if container.ImageID != "" { 126 img, err := i.imageStore.Get(container.ImageID) 127 if err != nil { 128 return nil, err 129 } 130 layerID = img.RootFS.ChainID() 131 } 132 133 rwLayerOpts := &layer.CreateRWLayerOpts{ 134 MountLabel: container.MountLabel, 135 InitFunc: initFunc, 136 StorageOpt: container.HostConfig.StorageOpt, 137 } 138 139 return i.layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts) 140 } 141 142 // GetLayerByID returns a layer by ID 143 // called from daemon.go Daemon.restore(), and Daemon.containerExport() 144 func (i *ImageService) GetLayerByID(cid string) (layer.RWLayer, error) { 145 return i.layerStore.GetRWLayer(cid) 146 } 147 148 // LayerStoreStatus returns the status for each layer store 149 // called from info.go 150 func (i *ImageService) LayerStoreStatus() [][2]string { 151 return i.layerStore.DriverStatus() 152 } 153 154 // GetLayerMountID returns the mount ID for a layer 155 // called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup) 156 // TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID 157 func (i *ImageService) GetLayerMountID(cid string) (string, error) { 158 return i.layerStore.GetMountID(cid) 159 } 160 161 // Cleanup resources before the process is shutdown. 162 // called from daemon.go Daemon.Shutdown() 163 func (i *ImageService) Cleanup() error { 164 if err := i.layerStore.Cleanup(); err != nil { 165 return errors.Wrap(err, "error during layerStore.Cleanup()") 166 } 167 return nil 168 } 169 170 // GraphDriverName returns the name of the graph drvier 171 // moved from Daemon.GraphDriverName, used by: 172 // - newContainer 173 // - to report an error in Daemon.Mount(container) 174 func (i *ImageService) GraphDriverName() string { 175 return i.layerStore.DriverName() 176 } 177 178 // ReleaseLayer releases a layer allowing it to be removed 179 // called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport() 180 func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error { 181 metadata, err := i.layerStore.ReleaseRWLayer(rwlayer) 182 layer.LogReleaseMetadata(metadata) 183 if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) { 184 return errors.Wrapf(err, "driver %q failed to remove root filesystem", 185 i.layerStore.DriverName()) 186 } 187 return nil 188 } 189 190 // LayerDiskUsage returns the number of bytes used by layer stores 191 // called from disk_usage.go 192 func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) { 193 ch := i.usage.DoChan("LayerDiskUsage", func() (interface{}, error) { 194 var allLayersSize int64 195 layerRefs := i.getLayerRefs() 196 allLayers := i.layerStore.Map() 197 for _, l := range allLayers { 198 select { 199 case <-ctx.Done(): 200 return allLayersSize, ctx.Err() 201 default: 202 size := l.DiffSize() 203 if _, ok := layerRefs[l.ChainID()]; ok { 204 allLayersSize += size 205 } 206 } 207 } 208 return allLayersSize, nil 209 }) 210 select { 211 case <-ctx.Done(): 212 return 0, ctx.Err() 213 case res := <-ch: 214 if res.Err != nil { 215 return 0, res.Err 216 } 217 return res.Val.(int64), nil 218 } 219 } 220 221 func (i *ImageService) getLayerRefs() map[layer.ChainID]int { 222 tmpImages := i.imageStore.Map() 223 layerRefs := map[layer.ChainID]int{} 224 for id, img := range tmpImages { 225 dgst := digest.Digest(id) 226 if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 { 227 continue 228 } 229 230 rootFS := *img.RootFS 231 rootFS.DiffIDs = nil 232 for _, id := range img.RootFS.DiffIDs { 233 rootFS.Append(id) 234 chid := rootFS.ChainID() 235 layerRefs[chid]++ 236 } 237 } 238 239 return layerRefs 240 } 241 242 // ImageDiskUsage returns information about image data disk usage. 243 func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) { 244 ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) { 245 // Get all top images with extra attributes 246 images, err := i.Images(ctx, types.ImageListOptions{ 247 Filters: filters.NewArgs(), 248 SharedSize: true, 249 ContainerCount: true, 250 }) 251 if err != nil { 252 return nil, fmt.Errorf("failed to retrieve image list: %v", err) 253 } 254 return images, nil 255 }) 256 select { 257 case <-ctx.Done(): 258 return nil, ctx.Err() 259 case res := <-ch: 260 if res.Err != nil { 261 return nil, res.Err 262 } 263 return res.Val.([]*types.ImageSummary), nil 264 } 265 } 266 267 // UpdateConfig values 268 // 269 // called from reload.go 270 func (i *ImageService) UpdateConfig(maxDownloads, maxUploads int) { 271 if i.downloadManager != nil && maxDownloads != 0 { 272 i.downloadManager.SetConcurrency(maxDownloads) 273 } 274 if i.uploadManager != nil && maxUploads != 0 { 275 i.uploadManager.SetConcurrency(maxUploads) 276 } 277 }