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  }