diff --git a/registry/config.go b/registry/config.go index 3468c6b8c8..6a9e153d28 100644 --- a/registry/config.go +++ b/registry/config.go @@ -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 diff --git a/registry/config_unix.go b/registry/config_unix.go deleted file mode 100644 index 6aa6cdcca3..0000000000 --- a/registry/config_unix.go +++ /dev/null @@ -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 -} diff --git a/registry/config_windows.go b/registry/config_windows.go deleted file mode 100644 index fd13bffde0..0000000000 --- a/registry/config_windows.go +++ /dev/null @@ -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, ":", "")) -} diff --git a/registry/registry.go b/registry/registry.go index d3b3fbc9ba..d69c1d9ec7 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -8,6 +8,8 @@ import ( "net/http" "os" "path/filepath" + "runtime" + "strings" "time" "github.com/containerd/log" @@ -16,16 +18,15 @@ import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) -// HostCertsDir returns the config directory for a specific host. -// -// Deprecated: this function was only used internally, and will be removed in a future release. -func HostCertsDir(hostname string) string { - return hostCertsDir(hostname) -} - // 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