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-07-26 10:09:27 +00:00
cerrdefs "github.com/containerd/containerd/errdefs"
2023-06-23 00:33:17 +00:00
"github.com/containerd/containerd/log"
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-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"
2022-07-05 14:33:39 +00:00
"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/image"
"github.com/docker/docker/layer"
2023-04-13 12:19:51 +00:00
"github.com/docker/docker/registry"
2023-03-06 15:02:37 +00:00
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
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 {
2022-09-01 15:03:10 +00:00
client * containerd . Client
2022-08-04 08:37:04 +00:00
containers container . Store
2022-09-01 15:03:10 +00:00
snapshotter string
2023-05-25 20:51:37 +00:00
registryHosts docker . RegistryHosts
2023-03-01 00:25:15 +00:00
registryService RegistryConfigProvider
2023-03-30 14:11:02 +00:00
eventsService * daemonevents . Events
2023-04-04 14:10:25 +00:00
pruneRunning atomic . Bool
2023-05-15 15:42:37 +00:00
refCountMounter snapshotter . Mounter
2022-09-12 08:40:45 +00:00
}
2023-03-01 00:25:15 +00:00
type RegistryConfigProvider interface {
IsInsecureRegistry ( host string ) bool
2023-04-13 12:19:51 +00:00
ResolveRepository ( name reference . Named ) ( * registry . RepositoryInfo , 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
Registry RegistryConfigProvider
EventsService * daemonevents . Events
RefCountMounter snapshotter . Mounter
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 {
2023-03-30 14:11:02 +00:00
client : config . Client ,
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 ,
2022-07-05 14:33:39 +00:00
}
}
2022-07-18 10:51:49 +00:00
// DistributionServices return services controlling daemon image storage.
func ( i * ImageService ) DistributionServices ( ) images . DistributionServices {
return images . 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
func ( i * ImageService ) CountImages ( ) int {
imgs , err := i . client . ListImages ( context . TODO ( ) )
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 ) {
2022-07-05 14:33:39 +00:00
panic ( "not implemented" )
}
2022-07-18 10:51:49 +00:00
// GetLayerFolders returns the layer folders from an image RootFS.
func ( i * ImageService ) GetLayerFolders ( img * image . Image , rwLayer layer . RWLayer ) ( [ ] string , error ) {
2022-08-10 13:22:32 +00:00
return nil , errdefs . NotImplemented ( errors . New ( "not implemented" ) )
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
}
2023-04-25 13:10:55 +00:00
// getContainerImageManifest safely dereferences ImageManifest.
// ImageManifest can be nil for containers created with Docker Desktop with old
// containerd image store integration enabled which didn't set this field.
func getContainerImageManifest ( ctr * container . Container ) ( ocispec . Descriptor , error ) {
if ctr . ImageManifest == nil {
return ocispec . Descriptor { } , errdefs . InvalidParameter ( errors . New ( "container is missing ImageManifest (probably created on old version), please recreate it" ) )
}
return * ctr . ImageManifest , nil
}