registry: remove deprecated SetCertsDir and unify CertsDir code

This was deprecated in b633c4cc33, which was
in v28, and no longer has any consumer, so we can remove it.

Now that we no longer have to synchronise `CertsDir` with `SetCertsDir`
we can also remove the synchronization (`homedir.GetConfigHome()` does
some additional lookups, but those usually are just looking up env-vars,
and `user.Current()` already has a `sync.Once` or equivalent). Also
unifying the platform-specific code to remove some abstraction and put
the logic in plain sight.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-07-10 22:29:09 +02:00
parent 924cd22d1d
commit 5862b926f5
4 changed files with 31 additions and 77 deletions

View File

@@ -6,9 +6,9 @@ import (
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"github.com/containerd/log"
"github.com/distribution/reference"
@@ -59,51 +59,33 @@ var (
}
validHostPortRegex = lazyregexp.New(`^` + reference.DomainRegexp.String() + `$`)
// certsDir is used to override defaultCertsDir when running with rootlessKit.
//
// TODO(thaJeztah): change to a sync.OnceValue once we remove [SetCertsDir]
// TODO(thaJeztah): certsDir should not be a package variable, but stored in our config, and passed when needed.
setCertsDirOnce sync.Once
certsDir string
)
func setCertsDir(dir string) string {
setCertsDirOnce.Do(func() {
if dir != "" {
certsDir = dir
return
}
if os.Getenv("ROOTLESSKIT_STATE_DIR") != "" {
// Configure registry.CertsDir() when running in rootless-mode
// This is the equivalent of [rootless.RunningWithRootlessKit],
// but inlining it to prevent adding that as a dependency
// for docker/cli.
//
// [rootless.RunningWithRootlessKit]: https://github.com/moby/moby/blob/b4bdf12daec84caaf809a639f923f7370d4926ad/pkg/rootless/rootless.go#L5-L8
if configHome, _ := homedir.GetConfigHome(); configHome != "" {
certsDir = filepath.Join(configHome, "docker/certs.d")
return
}
}
certsDir = defaultCertsDir
})
return certsDir
}
// SetCertsDir allows the default certs directory to be changed. This function
// is used at daemon startup to set the correct location when running in
// rootless mode.
// runningWithRootlessKit is a fork of [rootless.RunningWithRootlessKit],
// but inlining it to prevent adding that as a dependency for docker/cli.
//
// Deprecated: the cert-directory is now automatically selected when running with rootlessKit, and should no longer be set manually.
func SetCertsDir(path string) {
setCertsDir(path)
// [rootless.RunningWithRootlessKit]: https://github.com/moby/moby/blob/b4bdf12daec84caaf809a639f923f7370d4926ad/pkg/rootless/rootless.go#L5-L8
func runningWithRootlessKit() bool {
return os.Getenv("ROOTLESSKIT_STATE_DIR") != ""
}
// CertsDir is the directory where certificates are stored.
//
// - Linux: "/etc/docker/certs.d/"
// - Linux (with rootlessKit): $XDG_CONFIG_HOME/docker/certs.d/" or "$HOME/.config/docker/certs.d/"
// - Windows: "%PROGRAMDATA%/docker/certs.d/"
//
// TODO(thaJeztah): certsDir but stored in our config, and passed when needed. For the CLI, we should also default to same path as rootless.
func CertsDir() string {
// call setCertsDir with an empty path to synchronise with [SetCertsDir]
return setCertsDir("")
certsDir := "/etc/docker/certs.d"
if runningWithRootlessKit() {
if configHome, _ := homedir.GetConfigHome(); configHome != "" {
certsDir = filepath.Join(configHome, "docker", "certs.d")
}
} else if runtime.GOOS == "windows" {
certsDir = filepath.Join(os.Getenv("programdata"), "docker", "certs.d")
}
return certsDir
}
// newServiceConfig returns a new instance of ServiceConfig

View File

@@ -1,16 +0,0 @@
//go:build !windows
package registry
// defaultCertsDir is the platform-specific default directory where certificates
// are stored. On Linux, it may be overridden through certsDir, for example, when
// running in rootless mode.
const defaultCertsDir = "/etc/docker/certs.d"
// cleanPath is used to ensure that a directory name is valid on the target
// platform. It will be passed in something *similar* to a URL such as
// https:/index.docker.io/v1. Not all platforms support directory names
// which contain those characters (such as : on Windows)
func cleanPath(s string) string {
return s
}

View File

@@ -1,20 +0,0 @@
package registry
import (
"os"
"path/filepath"
"strings"
)
// defaultCertsDir is the platform-specific default directory where certificates
// are stored. On Linux, it may be overridden through certsDir, for example, when
// running in rootless mode.
var defaultCertsDir = os.Getenv("programdata") + `\docker\certs.d`
// cleanPath is used to ensure that a directory name is valid on the target
// platform. It will be passed in something *similar* to a URL such as
// https:\index.docker.io\v1. Not all platforms support directory names
// which contain those characters (such as : on Windows)
func cleanPath(s string) string {
return filepath.FromSlash(strings.ReplaceAll(s, ":", ""))
}

View File

@@ -8,6 +8,8 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/containerd/log"
@@ -17,8 +19,14 @@ import (
)
// hostCertsDir returns the config directory for a specific host.
func hostCertsDir(hostname string) string {
return filepath.Join(CertsDir(), cleanPath(hostname))
func hostCertsDir(hostnameAndPort string) string {
if runtime.GOOS == "windows" {
// Ensure that a directory name is valid; hostnameAndPort may contain
// a colon (:) if a port is included, and Windows does not allow colons
// in directory names.
hostnameAndPort = filepath.FromSlash(strings.ReplaceAll(hostnameAndPort, ":", ""))
}
return filepath.Join(CertsDir(), hostnameAndPort)
}
// newTLSConfig constructs a client TLS configuration based on server defaults