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 }