github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/images/service.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "context" 5 "os" 6 "runtime" 7 8 "github.com/docker/docker/container" 9 daemonevents "github.com/docker/docker/daemon/events" 10 "github.com/docker/docker/distribution" 11 "github.com/docker/docker/distribution/metadata" 12 "github.com/docker/docker/distribution/xfer" 13 "github.com/docker/docker/image" 14 "github.com/docker/docker/layer" 15 dockerreference "github.com/docker/docker/reference" 16 "github.com/docker/docker/registry" 17 "github.com/docker/libtrust" 18 digest "github.com/opencontainers/go-digest" 19 "github.com/pkg/errors" 20 "github.com/sirupsen/logrus" 21 ) 22 23 type containerStore interface { 24 // used by image delete 25 First(container.StoreFilter) *container.Container 26 // used by image prune, and image list 27 List() []*container.Container 28 // TODO: remove, only used for CommitBuildStep 29 Get(string) *container.Container 30 } 31 32 // ImageServiceConfig is the configuration used to create a new ImageService 33 type ImageServiceConfig struct { 34 ContainerStore containerStore 35 DistributionMetadataStore metadata.Store 36 EventsService *daemonevents.Events 37 ImageStore image.Store 38 LayerStores map[string]layer.Store 39 MaxConcurrentDownloads int 40 MaxConcurrentUploads int 41 MaxDownloadAttempts int 42 ReferenceStore dockerreference.Store 43 RegistryService registry.Service 44 TrustKey libtrust.PrivateKey 45 } 46 47 // NewImageService returns a new ImageService from a configuration 48 func NewImageService(config ImageServiceConfig) *ImageService { 49 logrus.Debugf("Max Concurrent Downloads: %d", config.MaxConcurrentDownloads) 50 logrus.Debugf("Max Concurrent Uploads: %d", config.MaxConcurrentUploads) 51 logrus.Debugf("Max Download Attempts: %d", config.MaxDownloadAttempts) 52 return &ImageService{ 53 containers: config.ContainerStore, 54 distributionMetadataStore: config.DistributionMetadataStore, 55 downloadManager: xfer.NewLayerDownloadManager(config.LayerStores, config.MaxConcurrentDownloads, xfer.WithMaxDownloadAttempts(config.MaxDownloadAttempts)), 56 eventsService: config.EventsService, 57 imageStore: config.ImageStore, 58 layerStores: config.LayerStores, 59 referenceStore: config.ReferenceStore, 60 registryService: config.RegistryService, 61 trustKey: config.TrustKey, 62 uploadManager: xfer.NewLayerUploadManager(config.MaxConcurrentUploads), 63 } 64 } 65 66 // ImageService provides a backend for image management 67 type ImageService struct { 68 containers containerStore 69 distributionMetadataStore metadata.Store 70 downloadManager *xfer.LayerDownloadManager 71 eventsService *daemonevents.Events 72 imageStore image.Store 73 layerStores map[string]layer.Store // By operating system 74 pruneRunning int32 75 referenceStore dockerreference.Store 76 registryService registry.Service 77 trustKey libtrust.PrivateKey 78 uploadManager *xfer.LayerUploadManager 79 } 80 81 // DistributionServices provides daemon image storage services 82 type DistributionServices struct { 83 DownloadManager distribution.RootFSDownloadManager 84 V2MetadataService metadata.V2MetadataService 85 LayerStore layer.Store // TODO: lcow 86 ImageStore image.Store 87 ReferenceStore dockerreference.Store 88 } 89 90 // DistributionServices return services controlling daemon image storage 91 func (i *ImageService) DistributionServices() DistributionServices { 92 return DistributionServices{ 93 DownloadManager: i.downloadManager, 94 V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore), 95 LayerStore: i.layerStores[runtime.GOOS], 96 ImageStore: i.imageStore, 97 ReferenceStore: i.referenceStore, 98 } 99 } 100 101 // CountImages returns the number of images stored by ImageService 102 // called from info.go 103 func (i *ImageService) CountImages() int { 104 return i.imageStore.Len() 105 } 106 107 // Children returns the children image.IDs for a parent image. 108 // called from list.go to filter containers 109 // TODO: refactor to expose an ancestry for image.ID? 110 func (i *ImageService) Children(id image.ID) []image.ID { 111 return i.imageStore.Children(id) 112 } 113 114 // CreateLayer creates a filesystem layer for a container. 115 // called from create.go 116 // TODO: accept an opt struct instead of container? 117 func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) { 118 var layerID layer.ChainID 119 if container.ImageID != "" { 120 img, err := i.imageStore.Get(container.ImageID) 121 if err != nil { 122 return nil, err 123 } 124 layerID = img.RootFS.ChainID() 125 } 126 127 rwLayerOpts := &layer.CreateRWLayerOpts{ 128 MountLabel: container.MountLabel, 129 InitFunc: initFunc, 130 StorageOpt: container.HostConfig.StorageOpt, 131 } 132 133 // Indexing by OS is safe here as validation of OS has already been performed in create() (the only 134 // caller), and guaranteed non-nil 135 return i.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts) 136 } 137 138 // GetLayerByID returns a layer by ID and operating system 139 // called from daemon.go Daemon.restore(), and Daemon.containerExport() 140 func (i *ImageService) GetLayerByID(cid string, os string) (layer.RWLayer, error) { 141 return i.layerStores[os].GetRWLayer(cid) 142 } 143 144 // LayerStoreStatus returns the status for each layer store 145 // called from info.go 146 func (i *ImageService) LayerStoreStatus() map[string][][2]string { 147 result := make(map[string][][2]string) 148 for os, store := range i.layerStores { 149 result[os] = store.DriverStatus() 150 } 151 return result 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 157 // with GetLayerByID 158 func (i *ImageService) GetLayerMountID(cid string, os string) (string, error) { 159 return i.layerStores[os].GetMountID(cid) 160 } 161 162 // Cleanup resources before the process is shutdown. 163 // called from daemon.go Daemon.Shutdown() 164 func (i *ImageService) Cleanup() { 165 for os, ls := range i.layerStores { 166 if ls != nil { 167 if err := ls.Cleanup(); err != nil { 168 logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, os) 169 } 170 } 171 } 172 } 173 174 // GraphDriverForOS returns the name of the graph drvier 175 // moved from Daemon.GraphDriverName, used by: 176 // - newContainer 177 // - to report an error in Daemon.Mount(container) 178 func (i *ImageService) GraphDriverForOS(os string) string { 179 return i.layerStores[os].DriverName() 180 } 181 182 // ReleaseLayer releases a layer allowing it to be removed 183 // called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport() 184 func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer, containerOS string) error { 185 metadata, err := i.layerStores[containerOS].ReleaseRWLayer(rwlayer) 186 layer.LogReleaseMetadata(metadata) 187 if err != nil && !errors.Is(err, layer.ErrMountDoesNotExist) && !errors.Is(err, os.ErrNotExist) { 188 return errors.Wrapf(err, "driver %q failed to remove root filesystem", 189 i.layerStores[containerOS].DriverName()) 190 } 191 return nil 192 } 193 194 // LayerDiskUsage returns the number of bytes used by layer stores 195 // called from disk_usage.go 196 func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) { 197 var allLayersSize int64 198 layerRefs := i.getLayerRefs() 199 for _, ls := range i.layerStores { 200 allLayers := ls.Map() 201 for _, l := range allLayers { 202 select { 203 case <-ctx.Done(): 204 return allLayersSize, ctx.Err() 205 default: 206 size, err := l.DiffSize() 207 if err == nil { 208 if _, ok := layerRefs[l.ChainID()]; ok { 209 allLayersSize += size 210 } 211 } else { 212 logrus.Warnf("failed to get diff size for layer %v", l.ChainID()) 213 } 214 } 215 } 216 } 217 return allLayersSize, nil 218 } 219 220 func (i *ImageService) getLayerRefs() map[layer.ChainID]int { 221 tmpImages := i.imageStore.Map() 222 layerRefs := map[layer.ChainID]int{} 223 for id, img := range tmpImages { 224 dgst := digest.Digest(id) 225 if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 { 226 continue 227 } 228 229 rootFS := *img.RootFS 230 rootFS.DiffIDs = nil 231 for _, id := range img.RootFS.DiffIDs { 232 rootFS.Append(id) 233 chid := rootFS.ChainID() 234 layerRefs[chid]++ 235 } 236 } 237 238 return layerRefs 239 } 240 241 // UpdateConfig values 242 // 243 // called from reload.go 244 func (i *ImageService) UpdateConfig(maxDownloads, maxUploads *int) { 245 if i.downloadManager != nil && maxDownloads != nil { 246 i.downloadManager.SetConcurrency(*maxDownloads) 247 } 248 if i.uploadManager != nil && maxUploads != nil { 249 i.uploadManager.SetConcurrency(*maxUploads) 250 } 251 }