github.com/moby/docker@v26.1.3+incompatible/daemon/containerd/service.go (about)

     1  package containerd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync/atomic"
     7  
     8  	"github.com/containerd/containerd"
     9  	"github.com/containerd/containerd/content"
    10  	cerrdefs "github.com/containerd/containerd/errdefs"
    11  	"github.com/containerd/containerd/images"
    12  	"github.com/containerd/containerd/plugin"
    13  	"github.com/containerd/containerd/remotes/docker"
    14  	"github.com/containerd/containerd/snapshots"
    15  	"github.com/containerd/log"
    16  	"github.com/distribution/reference"
    17  	"github.com/docker/docker/container"
    18  	daemonevents "github.com/docker/docker/daemon/events"
    19  	dimages "github.com/docker/docker/daemon/images"
    20  	"github.com/docker/docker/daemon/snapshotter"
    21  	"github.com/docker/docker/errdefs"
    22  	"github.com/docker/docker/layer"
    23  	"github.com/docker/docker/pkg/idtools"
    24  	"github.com/docker/docker/registry"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  // ImageService implements daemon.ImageService
    29  type ImageService struct {
    30  	client              *containerd.Client
    31  	images              images.Store
    32  	content             content.Store
    33  	containers          container.Store
    34  	snapshotterServices map[string]snapshots.Snapshotter
    35  	snapshotter         string
    36  	registryHosts       docker.RegistryHosts
    37  	registryService     registryResolver
    38  	eventsService       *daemonevents.Events
    39  	pruneRunning        atomic.Bool
    40  	refCountMounter     snapshotter.Mounter
    41  	idMapping           idtools.IdentityMapping
    42  }
    43  
    44  type registryResolver interface {
    45  	IsInsecureRegistry(host string) bool
    46  	ResolveRepository(name reference.Named) (*registry.RepositoryInfo, error)
    47  	LookupPullEndpoints(hostname string) ([]registry.APIEndpoint, error)
    48  	LookupPushEndpoints(hostname string) ([]registry.APIEndpoint, error)
    49  }
    50  
    51  type ImageServiceConfig struct {
    52  	Client          *containerd.Client
    53  	Containers      container.Store
    54  	Snapshotter     string
    55  	RegistryHosts   docker.RegistryHosts
    56  	Registry        registryResolver
    57  	EventsService   *daemonevents.Events
    58  	RefCountMounter snapshotter.Mounter
    59  	IDMapping       idtools.IdentityMapping
    60  }
    61  
    62  // NewService creates a new ImageService.
    63  func NewService(config ImageServiceConfig) *ImageService {
    64  	return &ImageService{
    65  		client:  config.Client,
    66  		images:  config.Client.ImageService(),
    67  		content: config.Client.ContentStore(),
    68  		snapshotterServices: map[string]snapshots.Snapshotter{
    69  			config.Snapshotter: config.Client.SnapshotService(config.Snapshotter),
    70  		},
    71  		containers:      config.Containers,
    72  		snapshotter:     config.Snapshotter,
    73  		registryHosts:   config.RegistryHosts,
    74  		registryService: config.Registry,
    75  		eventsService:   config.EventsService,
    76  		refCountMounter: config.RefCountMounter,
    77  		idMapping:       config.IDMapping,
    78  	}
    79  }
    80  
    81  func (i *ImageService) snapshotterService(snapshotter string) snapshots.Snapshotter {
    82  	s, ok := i.snapshotterServices[snapshotter]
    83  	if !ok {
    84  		s = i.client.SnapshotService(snapshotter)
    85  		i.snapshotterServices[snapshotter] = s
    86  	}
    87  
    88  	return s
    89  }
    90  
    91  // DistributionServices return services controlling daemon image storage.
    92  func (i *ImageService) DistributionServices() dimages.DistributionServices {
    93  	return dimages.DistributionServices{}
    94  }
    95  
    96  // CountImages returns the number of images stored by ImageService
    97  // called from info.go
    98  func (i *ImageService) CountImages(ctx context.Context) int {
    99  	imgs, err := i.client.ListImages(ctx)
   100  	if err != nil {
   101  		return 0
   102  	}
   103  
   104  	return len(imgs)
   105  }
   106  
   107  // CreateLayer creates a filesystem layer for a container.
   108  // called from create.go
   109  // TODO: accept an opt struct instead of container?
   110  func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
   111  	return nil, errdefs.NotImplemented(errdefs.NotImplemented(errors.New("not implemented")))
   112  }
   113  
   114  // LayerStoreStatus returns the status for each layer store
   115  // called from info.go
   116  func (i *ImageService) LayerStoreStatus() [][2]string {
   117  	// TODO(thaJeztah) do we want to add more details about the driver here?
   118  	return [][2]string{
   119  		{"driver-type", string(plugin.SnapshotPlugin)},
   120  	}
   121  }
   122  
   123  // GetLayerMountID returns the mount ID for a layer
   124  // called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
   125  // TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
   126  func (i *ImageService) GetLayerMountID(cid string) (string, error) {
   127  	return "", errdefs.NotImplemented(errors.New("not implemented"))
   128  }
   129  
   130  // Cleanup resources before the process is shutdown.
   131  // called from daemon.go Daemon.Shutdown()
   132  func (i *ImageService) Cleanup() error {
   133  	return nil
   134  }
   135  
   136  // StorageDriver returns the name of the default storage-driver (snapshotter)
   137  // used by the ImageService.
   138  func (i *ImageService) StorageDriver() string {
   139  	return i.snapshotter
   140  }
   141  
   142  // ReleaseLayer releases a layer allowing it to be removed
   143  // called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
   144  func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
   145  	return errdefs.NotImplemented(errors.New("not implemented"))
   146  }
   147  
   148  // LayerDiskUsage returns the number of bytes used by layer stores
   149  // called from disk_usage.go
   150  func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
   151  	var allLayersSize int64
   152  	// TODO(thaJeztah): do we need to take multiple snapshotters into account? See https://github.com/moby/moby/issues/45273
   153  	snapshotter := i.client.SnapshotService(i.snapshotter)
   154  	snapshotter.Walk(ctx, func(ctx context.Context, info snapshots.Info) error {
   155  		usage, err := snapshotter.Usage(ctx, info.Name)
   156  		if err != nil {
   157  			return err
   158  		}
   159  		allLayersSize += usage.Size
   160  		return nil
   161  	})
   162  	return allLayersSize, nil
   163  }
   164  
   165  // UpdateConfig values
   166  //
   167  // called from reload.go
   168  func (i *ImageService) UpdateConfig(maxDownloads, maxUploads int) {
   169  	log.G(context.TODO()).Warn("max downloads and uploads is not yet implemented with the containerd store")
   170  }
   171  
   172  // GetContainerLayerSize returns the real size & virtual size of the container.
   173  func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error) {
   174  	ctr := i.containers.Get(containerID)
   175  	if ctr == nil {
   176  		return 0, 0, nil
   177  	}
   178  
   179  	snapshotter := i.client.SnapshotService(ctr.Driver)
   180  	rwLayerUsage, err := snapshotter.Usage(ctx, containerID)
   181  	if err != nil {
   182  		if cerrdefs.IsNotFound(err) {
   183  			return 0, 0, errdefs.NotFound(fmt.Errorf("rw layer snapshot not found for container %s", containerID))
   184  		}
   185  		return 0, 0, errdefs.System(errors.Wrapf(err, "snapshotter.Usage failed for %s", containerID))
   186  	}
   187  
   188  	unpackedUsage, err := calculateSnapshotParentUsage(ctx, snapshotter, containerID)
   189  	if err != nil {
   190  		if cerrdefs.IsNotFound(err) {
   191  			log.G(ctx).WithField("ctr", containerID).Warn("parent of container snapshot no longer present")
   192  		} else {
   193  			log.G(ctx).WithError(err).WithField("ctr", containerID).Warn("unexpected error when calculating usage of the parent snapshots")
   194  		}
   195  	}
   196  	log.G(ctx).WithFields(log.Fields{
   197  		"rwLayerUsage": rwLayerUsage.Size,
   198  		"unpacked":     unpackedUsage.Size,
   199  	}).Debug("GetContainerLayerSize")
   200  
   201  	// TODO(thaJeztah): include content-store size for the image (similar to "GET /images/json")
   202  	return rwLayerUsage.Size, rwLayerUsage.Size + unpackedUsage.Size, nil
   203  }