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