99cd23cefd
This reverts commit98fc09128b
in order to keep registry v2 schema1 handling and libtrust-key-based engine ID. Because registry v2 schema1 was not officially deprecated and registries are still relying on it, this patch puts its logic back. However, registry v1 relics are not added back since v1 logic has been removed a while ago. This also fixes an engine upgrade issue in a swarm cluster. It was relying on the Engine ID to be the same upon upgrade, but the mentioned commit modified the logic to use UUID and from a different file. Since the libtrust key is always needed to support v2 schema1 pushes, that the old engine ID is based on the libtrust key, and that the engine ID needs to be conserved across upgrades, adding a UUID-based engine ID logic seems to add more complexity than it solves the problems. Hence reverting the engine ID changes as well. Signed-off-by: Tibor Vass <tibor@docker.com> (cherry picked from commitf695e98cb7
) Signed-off-by: Tibor Vass <tibor@docker.com>
249 lines
8.3 KiB
Go
249 lines
8.3 KiB
Go
package images // import "github.com/docker/docker/daemon/images"
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/docker/docker/container"
|
|
daemonevents "github.com/docker/docker/daemon/events"
|
|
"github.com/docker/docker/distribution"
|
|
"github.com/docker/docker/distribution/metadata"
|
|
"github.com/docker/docker/distribution/xfer"
|
|
"github.com/docker/docker/image"
|
|
"github.com/docker/docker/layer"
|
|
dockerreference "github.com/docker/docker/reference"
|
|
"github.com/docker/docker/registry"
|
|
"github.com/docker/libtrust"
|
|
"github.com/opencontainers/go-digest"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type containerStore interface {
|
|
// used by image delete
|
|
First(container.StoreFilter) *container.Container
|
|
// used by image prune, and image list
|
|
List() []*container.Container
|
|
// TODO: remove, only used for CommitBuildStep
|
|
Get(string) *container.Container
|
|
}
|
|
|
|
// ImageServiceConfig is the configuration used to create a new ImageService
|
|
type ImageServiceConfig struct {
|
|
ContainerStore containerStore
|
|
DistributionMetadataStore metadata.Store
|
|
EventsService *daemonevents.Events
|
|
ImageStore image.Store
|
|
LayerStores map[string]layer.Store
|
|
MaxConcurrentDownloads int
|
|
MaxConcurrentUploads int
|
|
ReferenceStore dockerreference.Store
|
|
RegistryService registry.Service
|
|
TrustKey libtrust.PrivateKey
|
|
}
|
|
|
|
// NewImageService returns a new ImageService from a configuration
|
|
func NewImageService(config ImageServiceConfig) *ImageService {
|
|
logrus.Debugf("Max Concurrent Downloads: %d", config.MaxConcurrentDownloads)
|
|
logrus.Debugf("Max Concurrent Uploads: %d", config.MaxConcurrentUploads)
|
|
return &ImageService{
|
|
containers: config.ContainerStore,
|
|
distributionMetadataStore: config.DistributionMetadataStore,
|
|
downloadManager: xfer.NewLayerDownloadManager(config.LayerStores, config.MaxConcurrentDownloads),
|
|
eventsService: config.EventsService,
|
|
imageStore: config.ImageStore,
|
|
layerStores: config.LayerStores,
|
|
referenceStore: config.ReferenceStore,
|
|
registryService: config.RegistryService,
|
|
trustKey: config.TrustKey,
|
|
uploadManager: xfer.NewLayerUploadManager(config.MaxConcurrentUploads),
|
|
}
|
|
}
|
|
|
|
// ImageService provides a backend for image management
|
|
type ImageService struct {
|
|
containers containerStore
|
|
distributionMetadataStore metadata.Store
|
|
downloadManager *xfer.LayerDownloadManager
|
|
eventsService *daemonevents.Events
|
|
imageStore image.Store
|
|
layerStores map[string]layer.Store // By operating system
|
|
pruneRunning int32
|
|
referenceStore dockerreference.Store
|
|
registryService registry.Service
|
|
trustKey libtrust.PrivateKey
|
|
uploadManager *xfer.LayerUploadManager
|
|
}
|
|
|
|
// DistributionServices provides daemon image storage services
|
|
type DistributionServices struct {
|
|
DownloadManager distribution.RootFSDownloadManager
|
|
V2MetadataService metadata.V2MetadataService
|
|
LayerStore layer.Store // TODO: lcow
|
|
ImageStore image.Store
|
|
ReferenceStore dockerreference.Store
|
|
}
|
|
|
|
// DistributionServices return services controlling daemon image storage
|
|
func (i *ImageService) DistributionServices() DistributionServices {
|
|
return DistributionServices{
|
|
DownloadManager: i.downloadManager,
|
|
V2MetadataService: metadata.NewV2MetadataService(i.distributionMetadataStore),
|
|
LayerStore: i.layerStores[runtime.GOOS],
|
|
ImageStore: i.imageStore,
|
|
ReferenceStore: i.referenceStore,
|
|
}
|
|
}
|
|
|
|
// CountImages returns the number of images stored by ImageService
|
|
// called from info.go
|
|
func (i *ImageService) CountImages() int {
|
|
return i.imageStore.Len()
|
|
}
|
|
|
|
// Children returns the children image.IDs for a parent image.
|
|
// called from list.go to filter containers
|
|
// TODO: refactor to expose an ancestry for image.ID?
|
|
func (i *ImageService) Children(id image.ID) []image.ID {
|
|
return i.imageStore.Children(id)
|
|
}
|
|
|
|
// 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) {
|
|
var layerID layer.ChainID
|
|
if container.ImageID != "" {
|
|
img, err := i.imageStore.Get(container.ImageID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
layerID = img.RootFS.ChainID()
|
|
}
|
|
|
|
rwLayerOpts := &layer.CreateRWLayerOpts{
|
|
MountLabel: container.MountLabel,
|
|
InitFunc: initFunc,
|
|
StorageOpt: container.HostConfig.StorageOpt,
|
|
}
|
|
|
|
// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
|
|
// caller), and guaranteed non-nil
|
|
return i.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts)
|
|
}
|
|
|
|
// GetLayerByID returns a layer by ID and operating system
|
|
// called from daemon.go Daemon.restore(), and Daemon.containerExport()
|
|
func (i *ImageService) GetLayerByID(cid string, os string) (layer.RWLayer, error) {
|
|
return i.layerStores[os].GetRWLayer(cid)
|
|
}
|
|
|
|
// LayerStoreStatus returns the status for each layer store
|
|
// called from info.go
|
|
func (i *ImageService) LayerStoreStatus() map[string][][2]string {
|
|
result := make(map[string][][2]string)
|
|
for os, store := range i.layerStores {
|
|
result[os] = store.DriverStatus()
|
|
}
|
|
return result
|
|
}
|
|
|
|
// 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
|
|
func (i *ImageService) GetLayerMountID(cid string, os string) (string, error) {
|
|
return i.layerStores[os].GetMountID(cid)
|
|
}
|
|
|
|
// Cleanup resources before the process is shutdown.
|
|
// called from daemon.go Daemon.Shutdown()
|
|
func (i *ImageService) Cleanup() {
|
|
for os, ls := range i.layerStores {
|
|
if ls != nil {
|
|
if err := ls.Cleanup(); err != nil {
|
|
logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, os)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// GraphDriverForOS returns the name of the graph drvier
|
|
// moved from Daemon.GraphDriverName, used by:
|
|
// - newContainer
|
|
// - to report an error in Daemon.Mount(container)
|
|
func (i *ImageService) GraphDriverForOS(os string) string {
|
|
return i.layerStores[os].DriverName()
|
|
}
|
|
|
|
// 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, containerOS string) error {
|
|
metadata, err := i.layerStores[containerOS].ReleaseRWLayer(rwlayer)
|
|
layer.LogReleaseMetadata(metadata)
|
|
if err != nil && err != layer.ErrMountDoesNotExist && !os.IsNotExist(errors.Cause(err)) {
|
|
return errors.Wrapf(err, "driver %q failed to remove root filesystem",
|
|
i.layerStores[containerOS].DriverName())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LayerDiskUsage returns the number of bytes used by layer stores
|
|
// called from disk_usage.go
|
|
func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) {
|
|
var allLayersSize int64
|
|
layerRefs := i.getLayerRefs()
|
|
for _, ls := range i.layerStores {
|
|
allLayers := ls.Map()
|
|
for _, l := range allLayers {
|
|
select {
|
|
case <-ctx.Done():
|
|
return allLayersSize, ctx.Err()
|
|
default:
|
|
size, err := l.DiffSize()
|
|
if err == nil {
|
|
if _, ok := layerRefs[l.ChainID()]; ok {
|
|
allLayersSize += size
|
|
}
|
|
} else {
|
|
logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return allLayersSize, nil
|
|
}
|
|
|
|
func (i *ImageService) getLayerRefs() map[layer.ChainID]int {
|
|
tmpImages := i.imageStore.Map()
|
|
layerRefs := map[layer.ChainID]int{}
|
|
for id, img := range tmpImages {
|
|
dgst := digest.Digest(id)
|
|
if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
|
|
continue
|
|
}
|
|
|
|
rootFS := *img.RootFS
|
|
rootFS.DiffIDs = nil
|
|
for _, id := range img.RootFS.DiffIDs {
|
|
rootFS.Append(id)
|
|
chid := rootFS.ChainID()
|
|
layerRefs[chid]++
|
|
}
|
|
}
|
|
|
|
return layerRefs
|
|
}
|
|
|
|
// UpdateConfig values
|
|
//
|
|
// called from reload.go
|
|
func (i *ImageService) UpdateConfig(maxDownloads, maxUploads *int) {
|
|
if i.downloadManager != nil && maxDownloads != nil {
|
|
i.downloadManager.SetConcurrency(*maxDownloads)
|
|
}
|
|
if i.uploadManager != nil && maxUploads != nil {
|
|
i.uploadManager.SetConcurrency(*maxUploads)
|
|
}
|
|
}
|