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  }