2022-07-05 14:33:39 +00:00
|
|
|
package containerd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-07-26 10:09:27 +00:00
|
|
|
"fmt"
|
2023-04-04 14:10:25 +00:00
|
|
|
"sync/atomic"
|
2022-07-05 14:33:39 +00:00
|
|
|
|
|
|
|
"github.com/containerd/containerd"
|
2023-11-17 05:55:54 +00:00
|
|
|
"github.com/containerd/containerd/content"
|
2023-07-26 10:09:27 +00:00
|
|
|
cerrdefs "github.com/containerd/containerd/errdefs"
|
2023-11-17 05:33:11 +00:00
|
|
|
"github.com/containerd/containerd/images"
|
2022-08-22 16:36:03 +00:00
|
|
|
"github.com/containerd/containerd/plugin"
|
2022-09-12 08:40:45 +00:00
|
|
|
"github.com/containerd/containerd/remotes/docker"
|
2022-09-01 08:30:34 +00:00
|
|
|
"github.com/containerd/containerd/snapshots"
|
2023-09-13 15:41:45 +00:00
|
|
|
"github.com/containerd/log"
|
2023-08-30 16:31:46 +00:00
|
|
|
"github.com/distribution/reference"
|
2022-07-05 14:33:39 +00:00
|
|
|
"github.com/docker/docker/container"
|
2023-03-30 14:11:02 +00:00
|
|
|
daemonevents "github.com/docker/docker/daemon/events"
|
2023-11-17 05:55:54 +00:00
|
|
|
dimages "github.com/docker/docker/daemon/images"
|
2023-05-15 15:42:37 +00:00
|
|
|
"github.com/docker/docker/daemon/snapshotter"
|
2022-08-10 13:22:32 +00:00
|
|
|
"github.com/docker/docker/errdefs"
|
2022-07-05 14:33:39 +00:00
|
|
|
"github.com/docker/docker/layer"
|
2023-08-30 13:47:00 +00:00
|
|
|
"github.com/docker/docker/pkg/idtools"
|
2023-04-13 12:19:51 +00:00
|
|
|
"github.com/docker/docker/registry"
|
2022-09-01 08:30:34 +00:00
|
|
|
"github.com/pkg/errors"
|
2022-07-05 14:33:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ImageService implements daemon.ImageService
|
|
|
|
type ImageService struct {
|
2024-02-26 16:36:20 +00:00
|
|
|
client *containerd.Client
|
|
|
|
images images.Store
|
|
|
|
content content.Store
|
|
|
|
containers container.Store
|
|
|
|
snapshotterServices map[string]snapshots.Snapshotter
|
|
|
|
snapshotter string
|
|
|
|
registryHosts docker.RegistryHosts
|
|
|
|
registryService registryResolver
|
|
|
|
eventsService *daemonevents.Events
|
|
|
|
pruneRunning atomic.Bool
|
|
|
|
refCountMounter snapshotter.Mounter
|
|
|
|
idMapping idtools.IdentityMapping
|
2022-09-12 08:40:45 +00:00
|
|
|
}
|
|
|
|
|
2023-09-20 12:28:01 +00:00
|
|
|
type registryResolver interface {
|
2023-03-01 00:25:15 +00:00
|
|
|
IsInsecureRegistry(host string) bool
|
2023-04-13 12:19:51 +00:00
|
|
|
ResolveRepository(name reference.Named) (*registry.RepositoryInfo, error)
|
2023-09-20 12:28:01 +00:00
|
|
|
LookupPullEndpoints(hostname string) ([]registry.APIEndpoint, error)
|
|
|
|
LookupPushEndpoints(hostname string) ([]registry.APIEndpoint, error)
|
2023-03-01 00:25:15 +00:00
|
|
|
}
|
|
|
|
|
2023-03-30 14:11:02 +00:00
|
|
|
type ImageServiceConfig struct {
|
2023-05-15 15:42:37 +00:00
|
|
|
Client *containerd.Client
|
|
|
|
Containers container.Store
|
|
|
|
Snapshotter string
|
|
|
|
RegistryHosts docker.RegistryHosts
|
2023-09-20 12:28:01 +00:00
|
|
|
Registry registryResolver
|
2023-05-15 15:42:37 +00:00
|
|
|
EventsService *daemonevents.Events
|
|
|
|
RefCountMounter snapshotter.Mounter
|
2023-08-30 13:47:00 +00:00
|
|
|
IDMapping idtools.IdentityMapping
|
2023-03-30 14:11:02 +00:00
|
|
|
}
|
|
|
|
|
2022-07-05 14:33:39 +00:00
|
|
|
// NewService creates a new ImageService.
|
2023-03-30 14:11:02 +00:00
|
|
|
func NewService(config ImageServiceConfig) *ImageService {
|
2022-07-05 14:33:39 +00:00
|
|
|
return &ImageService{
|
2024-02-26 16:36:20 +00:00
|
|
|
client: config.Client,
|
|
|
|
images: config.Client.ImageService(),
|
|
|
|
content: config.Client.ContentStore(),
|
|
|
|
snapshotterServices: map[string]snapshots.Snapshotter{
|
|
|
|
config.Snapshotter: config.Client.SnapshotService(config.Snapshotter),
|
|
|
|
},
|
2023-03-30 14:11:02 +00:00
|
|
|
containers: config.Containers,
|
|
|
|
snapshotter: config.Snapshotter,
|
2023-05-25 20:51:37 +00:00
|
|
|
registryHosts: config.RegistryHosts,
|
2023-03-30 14:11:02 +00:00
|
|
|
registryService: config.Registry,
|
|
|
|
eventsService: config.EventsService,
|
2023-05-15 15:42:37 +00:00
|
|
|
refCountMounter: config.RefCountMounter,
|
2023-08-30 13:47:00 +00:00
|
|
|
idMapping: config.IDMapping,
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 16:36:20 +00:00
|
|
|
func (i *ImageService) snapshotterService(snapshotter string) snapshots.Snapshotter {
|
|
|
|
s, ok := i.snapshotterServices[snapshotter]
|
|
|
|
if !ok {
|
|
|
|
s = i.client.SnapshotService(snapshotter)
|
|
|
|
i.snapshotterServices[snapshotter] = s
|
|
|
|
}
|
|
|
|
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// DistributionServices return services controlling daemon image storage.
|
2023-11-17 05:55:54 +00:00
|
|
|
func (i *ImageService) DistributionServices() dimages.DistributionServices {
|
|
|
|
return dimages.DistributionServices{}
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// CountImages returns the number of images stored by ImageService
|
|
|
|
// called from info.go
|
2023-09-10 00:05:05 +00:00
|
|
|
func (i *ImageService) CountImages(ctx context.Context) int {
|
|
|
|
imgs, err := i.client.ListImages(ctx)
|
2022-07-05 14:33:39 +00:00
|
|
|
if err != nil {
|
2022-07-18 10:51:49 +00:00
|
|
|
return 0
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
return len(imgs)
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// CreateLayer creates a filesystem layer for a container.
|
|
|
|
// called from create.go
|
|
|
|
// TODO: accept an opt struct instead of container?
|
|
|
|
func (i *ImageService) CreateLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
|
2022-08-10 13:22:32 +00:00
|
|
|
return nil, errdefs.NotImplemented(errdefs.NotImplemented(errors.New("not implemented")))
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// LayerStoreStatus returns the status for each layer store
|
|
|
|
// called from info.go
|
|
|
|
func (i *ImageService) LayerStoreStatus() [][2]string {
|
2022-08-22 16:36:03 +00:00
|
|
|
// TODO(thaJeztah) do we want to add more details about the driver here?
|
|
|
|
return [][2]string{
|
|
|
|
{"driver-type", string(plugin.SnapshotPlugin)},
|
|
|
|
}
|
2022-07-18 10:51:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-05 14:33:39 +00:00
|
|
|
// GetLayerMountID returns the mount ID for a layer
|
|
|
|
// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
|
|
|
|
// TODO: needs to be refactored to Unmount (see callers), or removed and replaced with GetLayerByID
|
2022-07-18 10:51:49 +00:00
|
|
|
func (i *ImageService) GetLayerMountID(cid string) (string, error) {
|
2022-08-10 13:22:32 +00:00
|
|
|
return "", errdefs.NotImplemented(errors.New("not implemented"))
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup resources before the process is shutdown.
|
|
|
|
// called from daemon.go Daemon.Shutdown()
|
2022-07-18 08:57:11 +00:00
|
|
|
func (i *ImageService) Cleanup() error {
|
2022-07-05 14:33:39 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-09 15:03:50 +00:00
|
|
|
// StorageDriver returns the name of the default storage-driver (snapshotter)
|
|
|
|
// used by the ImageService.
|
|
|
|
func (i *ImageService) StorageDriver() string {
|
2022-08-03 09:20:54 +00:00
|
|
|
return i.snapshotter
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// ReleaseLayer releases a layer allowing it to be removed
|
|
|
|
// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
|
|
|
|
func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error {
|
2022-08-10 13:22:32 +00:00
|
|
|
return errdefs.NotImplemented(errors.New("not implemented"))
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LayerDiskUsage returns the number of bytes used by layer stores
|
|
|
|
// called from disk_usage.go
|
2022-07-18 08:57:11 +00:00
|
|
|
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
|
2022-11-29 15:46:19 +00:00
|
|
|
var allLayersSize int64
|
2023-04-05 12:09:21 +00:00
|
|
|
// TODO(thaJeztah): do we need to take multiple snapshotters into account? See https://github.com/moby/moby/issues/45273
|
2022-11-29 15:46:19 +00:00
|
|
|
snapshotter := i.client.SnapshotService(i.snapshotter)
|
|
|
|
snapshotter.Walk(ctx, func(ctx context.Context, info snapshots.Info) error {
|
|
|
|
usage, err := snapshotter.Usage(ctx, info.Name)
|
2022-09-01 08:30:34 +00:00
|
|
|
if err != nil {
|
2022-11-29 15:46:19 +00:00
|
|
|
return err
|
2022-09-01 08:30:34 +00:00
|
|
|
}
|
2022-11-29 15:46:19 +00:00
|
|
|
allLayersSize += usage.Size
|
|
|
|
return nil
|
2022-09-01 08:30:34 +00:00
|
|
|
})
|
2022-11-29 15:46:19 +00:00
|
|
|
return allLayersSize, nil
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 10:51:49 +00:00
|
|
|
// UpdateConfig values
|
|
|
|
//
|
|
|
|
// called from reload.go
|
|
|
|
func (i *ImageService) UpdateConfig(maxDownloads, maxUploads int) {
|
2023-09-08 10:21:16 +00:00
|
|
|
log.G(context.TODO()).Warn("max downloads and uploads is not yet implemented with the containerd store")
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetContainerLayerSize returns the real size & virtual size of the container.
|
2023-03-06 15:02:37 +00:00
|
|
|
func (i *ImageService) GetContainerLayerSize(ctx context.Context, containerID string) (int64, int64, error) {
|
|
|
|
ctr := i.containers.Get(containerID)
|
|
|
|
if ctr == nil {
|
|
|
|
return 0, 0, nil
|
|
|
|
}
|
2023-04-25 13:10:55 +00:00
|
|
|
|
|
|
|
snapshotter := i.client.SnapshotService(ctr.Driver)
|
2023-07-26 10:09:27 +00:00
|
|
|
rwLayerUsage, err := snapshotter.Usage(ctx, containerID)
|
2023-04-25 13:10:55 +00:00
|
|
|
if err != nil {
|
2023-07-26 10:09:27 +00:00
|
|
|
if cerrdefs.IsNotFound(err) {
|
|
|
|
return 0, 0, errdefs.NotFound(fmt.Errorf("rw layer snapshot not found for container %s", containerID))
|
2023-04-25 13:10:55 +00:00
|
|
|
}
|
2023-07-26 10:09:27 +00:00
|
|
|
return 0, 0, errdefs.System(errors.Wrapf(err, "snapshotter.Usage failed for %s", containerID))
|
2023-03-06 15:02:37 +00:00
|
|
|
}
|
|
|
|
|
2023-07-26 10:09:27 +00:00
|
|
|
unpackedUsage, err := calculateSnapshotParentUsage(ctx, snapshotter, containerID)
|
2023-03-06 15:02:37 +00:00
|
|
|
if err != nil {
|
2023-07-26 10:09:27 +00:00
|
|
|
if cerrdefs.IsNotFound(err) {
|
|
|
|
log.G(ctx).WithField("ctr", containerID).Warn("parent of container snapshot no longer present")
|
|
|
|
} else {
|
|
|
|
log.G(ctx).WithError(err).WithField("ctr", containerID).Warn("unexpected error when calculating usage of the parent snapshots")
|
2023-03-06 15:02:37 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-30 15:18:56 +00:00
|
|
|
log.G(ctx).WithFields(log.Fields{
|
2023-07-26 10:09:27 +00:00
|
|
|
"rwLayerUsage": rwLayerUsage.Size,
|
|
|
|
"unpacked": unpackedUsage.Size,
|
|
|
|
}).Debug("GetContainerLayerSize")
|
2023-03-06 15:02:37 +00:00
|
|
|
|
2023-04-17 11:53:21 +00:00
|
|
|
// TODO(thaJeztah): include content-store size for the image (similar to "GET /images/json")
|
2023-07-26 10:09:27 +00:00
|
|
|
return rwLayerUsage.Size, rwLayerUsage.Size + unpackedUsage.Size, nil
|
2022-07-05 14:33:39 +00:00
|
|
|
}
|