service.go 6.5 KB

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