mirror of
https://github.com/containers/skopeo.git
synced 2025-08-21 16:03:35 +00:00
Work around Docker Desktop's macOS socket location change
Docker Desktop 4.13.0+ moved the socket from /var/run/docker.sock to ~/.docker/run/docker.sock on macOS, but the Docker client library still defaults to the old location for all Unix systems. Add platform-specific logic to use the correct default on macOS when --daemon-host is not specified. This makes skopeo work more reliable out of the box for new users. Signed-off-by: Jacques Nadeau <jacques@apache.org>
This commit is contained in:
parent
729a053464
commit
8ec3080e14
@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -32,7 +34,20 @@ import (
|
|||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
// errorShouldDisplayUsage is a subtype of error used by command handlers to indicate that the command’s help should be included.
|
// getDefaultDockerSocket returns the platform-specific default Docker socket path
|
||||||
|
func getDefaultDockerSocket() string {
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
// On macOS, use the user-specific Docker socket location
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
return "unix://" + filepath.Join(home, ".docker/run/docker.sock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For all other platforms or if HOME is not set, return empty string
|
||||||
|
// to use the default from the Docker client library
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorShouldDisplayUsage is a subtype of error used by command handlers to indicate that the command's help should be included.
|
||||||
type errorShouldDisplayUsage struct {
|
type errorShouldDisplayUsage struct {
|
||||||
error
|
error
|
||||||
}
|
}
|
||||||
@ -204,6 +219,12 @@ func (opts *imageOptions) newSystemContext() (*types.SystemContext, error) {
|
|||||||
ctx.OCISharedBlobDirPath = opts.sharedBlobDir
|
ctx.OCISharedBlobDirPath = opts.sharedBlobDir
|
||||||
ctx.AuthFilePath = opts.shared.authFilePath
|
ctx.AuthFilePath = opts.shared.authFilePath
|
||||||
ctx.DockerDaemonHost = opts.dockerDaemonHost
|
ctx.DockerDaemonHost = opts.dockerDaemonHost
|
||||||
|
// Set platform-specific default for Docker daemon host if not explicitly set
|
||||||
|
if ctx.DockerDaemonHost == "" {
|
||||||
|
if defaultSocket := getDefaultDockerSocket(); defaultSocket != "" {
|
||||||
|
ctx.DockerDaemonHost = defaultSocket
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.DockerDaemonCertPath = opts.dockerCertPath
|
ctx.DockerDaemonCertPath = opts.dockerCertPath
|
||||||
if opts.authFilePath.Present() {
|
if opts.authFilePath.Present() {
|
||||||
ctx.AuthFilePath = opts.authFilePath.Value()
|
ctx.AuthFilePath = opts.authFilePath.Value()
|
||||||
|
33
cmd/skopeo/utils_darwin_test.go
Normal file
33
cmd/skopeo/utils_darwin_test.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetDefaultDockerSocketDarwin(t *testing.T) {
|
||||||
|
// Save original HOME
|
||||||
|
originalHome := os.Getenv("HOME")
|
||||||
|
defer func() {
|
||||||
|
os.Setenv("HOME", originalHome)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Test with HOME set
|
||||||
|
testHome := "/Users/test"
|
||||||
|
os.Setenv("HOME", testHome)
|
||||||
|
expected := "unix://" + filepath.Join(testHome, ".docker/run/docker.sock")
|
||||||
|
result := getDefaultDockerSocket()
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected %s, got %s", expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with HOME unset
|
||||||
|
os.Unsetenv("HOME")
|
||||||
|
result = getDefaultDockerSocket()
|
||||||
|
if result != "" {
|
||||||
|
t.Errorf("Expected empty string when HOME is unset, got %s", result)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containers/image/v5/copy"
|
"github.com/containers/image/v5/copy"
|
||||||
@ -16,6 +18,21 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// newExpectedSystemContext creates a SystemContext with expected defaults for tests,
|
||||||
|
// accounting for platform-specific behavior like macOS Docker socket location
|
||||||
|
func newExpectedSystemContext() *types.SystemContext {
|
||||||
|
ctx := &types.SystemContext{
|
||||||
|
DockerRegistryUserAgent: defaultUserAgent,
|
||||||
|
}
|
||||||
|
// On macOS, DockerDaemonHost gets set to the platform-specific default
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
ctx.DockerDaemonHost = "unix://" + filepath.Join(home, ".docker/run/docker.sock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
func TestNoteCloseFailure(t *testing.T) {
|
func TestNoteCloseFailure(t *testing.T) {
|
||||||
const description = "description"
|
const description = "description"
|
||||||
|
|
||||||
@ -73,9 +90,7 @@ func TestImageOptionsNewSystemContext(t *testing.T) {
|
|||||||
opts := fakeImageOptions(t, "dest-", true, []string{}, []string{})
|
opts := fakeImageOptions(t, "dest-", true, []string{}, []string{})
|
||||||
res, err := opts.newSystemContext()
|
res, err := opts.newSystemContext()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &types.SystemContext{
|
assert.Equal(t, newExpectedSystemContext(), res)
|
||||||
DockerRegistryUserAgent: defaultUserAgent,
|
|
||||||
}, res)
|
|
||||||
|
|
||||||
// Set everything to non-default values.
|
// Set everything to non-default values.
|
||||||
opts = fakeImageOptions(t, "dest-", true, []string{
|
opts = fakeImageOptions(t, "dest-", true, []string{
|
||||||
@ -148,9 +163,7 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
|
|||||||
opts := fakeImageDestOptions(t, "dest-", true, []string{}, []string{})
|
opts := fakeImageDestOptions(t, "dest-", true, []string{}, []string{})
|
||||||
res, err := opts.newSystemContext()
|
res, err := opts.newSystemContext()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &types.SystemContext{
|
assert.Equal(t, newExpectedSystemContext(), res)
|
||||||
DockerRegistryUserAgent: defaultUserAgent,
|
|
||||||
}, res)
|
|
||||||
|
|
||||||
authFile := "/tmp/auth.json"
|
authFile := "/tmp/auth.json"
|
||||||
// Make sure when REGISTRY_AUTH_FILE is set the auth file is used
|
// Make sure when REGISTRY_AUTH_FILE is set the auth file is used
|
||||||
@ -162,10 +175,9 @@ func TestImageDestOptionsNewSystemContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
res, err = opts.newSystemContext()
|
res, err = opts.newSystemContext()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &types.SystemContext{
|
expected := newExpectedSystemContext()
|
||||||
AuthFilePath: authFile,
|
expected.AuthFilePath = authFile
|
||||||
DockerRegistryUserAgent: defaultUserAgent,
|
assert.Equal(t, expected, res)
|
||||||
}, res)
|
|
||||||
|
|
||||||
// Set everything to non-default values.
|
// Set everything to non-default values.
|
||||||
opts = fakeImageDestOptions(t, "dest-", true, []string{
|
opts = fakeImageDestOptions(t, "dest-", true, []string{
|
||||||
@ -255,10 +267,9 @@ func TestImageOptionsUsernamePassword(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &types.SystemContext{
|
expected := newExpectedSystemContext()
|
||||||
DockerRegistryUserAgent: defaultUserAgent,
|
expected.DockerAuthConfig = command.expectedAuthConfig
|
||||||
DockerAuthConfig: command.expectedAuthConfig,
|
assert.Equal(t, expected, res)
|
||||||
}, res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,9 +519,16 @@ func TestImageOptionsAuthfileOverride(t *testing.T) {
|
|||||||
res, err := opts.newSystemContext()
|
res, err := opts.newSystemContext()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, &types.SystemContext{
|
expected := &types.SystemContext{
|
||||||
AuthFilePath: testCase.expectedAuthfilePath,
|
AuthFilePath: testCase.expectedAuthfilePath,
|
||||||
DockerRegistryUserAgent: defaultUserAgent,
|
DockerRegistryUserAgent: defaultUserAgent,
|
||||||
}, res)
|
}
|
||||||
|
// On macOS, DockerDaemonHost gets set to the platform-specific default
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
expected.DockerDaemonHost = "unix://" + filepath.Join(home, ".docker/run/docker.sock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.Equal(t, expected, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user