Files
moby/daemon/image_store_choice.go
Paweł Gronowski 391247ce96 daemon: Fix image store choice priority for prior graphdriver state
The priority order for determining image store choice was incorrect when
a prior graphdriver existed.

The issue occurred because the prior graphdriver check happened after
processing explicit driver configuration, effectively ignoring user
intent when prior state existed.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2025-11-13 10:05:49 +01:00

154 lines
4.4 KiB
Go

package daemon
import (
"context"
"fmt"
"os"
"runtime"
"github.com/containerd/log"
"github.com/moby/moby/v2/daemon/config"
"github.com/moby/moby/v2/daemon/graphdriver"
)
type imageStoreChoice string
const (
// containerd by default
imageStoreChoiceContainerd imageStoreChoice = "containerd-by-default"
// containerd explicitly chosen by user
imageStoreChoiceContainerdExplicit imageStoreChoice = "containerd-explicit"
// graphdriver by default
imageStoreChoiceGraphdriver imageStoreChoice = "graphdriver-by-default"
// graphdrivers explicitly chosen by user
imageStoreChoiceGraphdriverExplicit imageStoreChoice = "graphdriver-explicit"
// would be containerd, but the system has already been running with a graphdriver
imageStoreChoiceGraphdriverPrior imageStoreChoice = "graphdriver-prior"
)
func (c imageStoreChoice) IsGraphDriver() bool {
switch c {
case imageStoreChoiceContainerd, imageStoreChoiceContainerdExplicit:
return false
default:
return true
}
}
func (c imageStoreChoice) IsExplicit() bool {
switch c {
case imageStoreChoiceGraphdriverExplicit, imageStoreChoiceContainerdExplicit:
return true
default:
return false
}
}
// getDriverOverride determines the storage driver name based on environment variables,
// configuration, and platform-specific logic.
// On Windows we don't support the environment variable, or a user supplied graphdriver,
// but it is allowed when using snapshotters.
// Unix platforms however run a single graphdriver for all containers, and it can
// be set through an environment variable, a daemon start parameter, or chosen through
// initialization of the layerstore through driver priority order for example.
func getDriverOverride(ctx context.Context, cfgGraphDriver string, imgStoreChoice imageStoreChoice) string {
driverName := os.Getenv("DOCKER_DRIVER")
if driverName == "" {
driverName = cfgGraphDriver
} else {
log.G(ctx).Infof("Setting the storage driver from the $DOCKER_DRIVER environment variable (%s)", driverName)
}
if runtime.GOOS == "windows" {
if driverName == "" {
driverName = cfgGraphDriver
}
switch driverName {
case "windows":
// Docker WCOW snapshotters
case "windowsfilter":
// Docker WCOW graphdriver
case "":
if imgStoreChoice.IsGraphDriver() {
driverName = "windowsfilter"
} else {
driverName = "windows"
}
default:
log.G(ctx).Infof("Using non-default snapshotter %s", driverName)
}
}
return driverName
}
type determineImageStoreChoiceOptions struct {
hasPriorDriver func(root string) bool
isRegisteredGraphdriver func(driverName string) bool
runtimeOS string
}
func determineImageStoreChoice(cfgStore *config.Config, opts determineImageStoreChoiceOptions) (imageStoreChoice, error) {
if opts.hasPriorDriver == nil {
opts.hasPriorDriver = graphdriver.HasPriorDriver
}
if opts.isRegisteredGraphdriver == nil {
opts.isRegisteredGraphdriver = graphdriver.IsRegistered
}
if opts.runtimeOS == "" {
opts.runtimeOS = runtime.GOOS
}
out := imageStoreChoiceContainerd
if opts.runtimeOS == "windows" {
out = imageStoreChoiceGraphdriver
}
driverName := os.Getenv("DOCKER_DRIVER")
if driverName == "" {
driverName = cfgStore.GraphDriver
}
if enabled, ok := cfgStore.Features["containerd-snapshotter"]; ok {
if enabled {
if out == imageStoreChoiceContainerd {
log.G(context.TODO()).Warn(`"containerd-snapshotter" is now the default and no longer needed to be set`)
}
out = imageStoreChoiceContainerdExplicit
} else {
out = imageStoreChoiceGraphdriverExplicit
}
}
if os.Getenv("TEST_INTEGRATION_USE_GRAPHDRIVER") != "" {
out = imageStoreChoiceGraphdriverExplicit
}
if out == imageStoreChoiceContainerd {
if opts.hasPriorDriver(cfgStore.Root) {
return imageStoreChoiceGraphdriverPrior, nil
}
}
if driverName != "" {
if !out.IsExplicit() && opts.isRegisteredGraphdriver(driverName) {
return imageStoreChoiceGraphdriverExplicit, nil
}
if out.IsGraphDriver() {
if opts.isRegisteredGraphdriver(driverName) {
return imageStoreChoiceGraphdriverExplicit, nil
} else if out.IsExplicit() {
return imageStoreChoiceGraphdriverExplicit, fmt.Errorf("graphdriver is explicitly enabled but %q is not registered, %v %v", driverName, cfgStore.Features, os.Getenv("TEST_INTEGRATION_USE_GRAPHDRIVER"))
}
}
// Assume snapshotter is chosen
return imageStoreChoiceContainerdExplicit, nil
}
return out, nil
}