Skip to content

Commit 4e78548

Browse files
committed
Adding colima support to existing docker runtime searches
- Respects the default colima socket location - TOOLHIVE_COLIMA_SOCKET=.colima/default/docker.sock - This is documented here: https://github.com/abiosoft/colima/blob/main/docs/FAQ.md#v040-or-newer - Adds test coverage for new colima functionality
1 parent c704a07 commit 4e78548

File tree

7 files changed

+248
-0
lines changed

7 files changed

+248
-0
lines changed

pkg/container/docker/sdk/client_unix.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ func findPlatformContainerSocket(rt runtime.Type) (string, runtime.Type, error)
5353
return customSocketPath, runtime.TypePodman, nil
5454
}
5555

56+
if customSocketPath := os.Getenv(ColimaSocketEnv); customSocketPath != "" {
57+
logger.Debugf("Using Colima socket from env: %s", customSocketPath)
58+
// validate the socket path
59+
if _, err := os.Stat(customSocketPath); err != nil {
60+
return "", runtime.TypeColima, fmt.Errorf("invalid Colima socket path: %w", err)
61+
}
62+
return customSocketPath, runtime.TypeColima, nil
63+
}
64+
5665
if customSocketPath := os.Getenv(DockerSocketEnv); customSocketPath != "" {
5766
logger.Debugf("Using Docker socket from env: %s", customSocketPath)
5867
// validate the socket path
@@ -78,6 +87,13 @@ func findPlatformContainerSocket(rt runtime.Type) (string, runtime.Type, error)
7887
}
7988
}
8089

90+
if rt == runtime.TypeColima {
91+
socketPath, err := findColimaSocket()
92+
if err == nil {
93+
return socketPath, runtime.TypeColima, nil
94+
}
95+
}
96+
8197
if rt == runtime.TypeDocker {
8298
socketPath, err := findDockerSocket()
8399
if err == nil {
@@ -135,6 +151,24 @@ func findPodmanSocket() (string, error) {
135151
return "", fmt.Errorf("podman socket not found in standard locations")
136152
}
137153

154+
// findColimaSocket attempts to locate a Colima socket
155+
func findColimaSocket() (string, error) {
156+
// Check user-specific location for Colima
157+
if home := os.Getenv("HOME"); home != "" {
158+
colimaSocketPath := filepath.Join(home, ColimaSocketPath)
159+
_, err := os.Stat(colimaSocketPath)
160+
161+
if err == nil {
162+
logger.Debugf("Found Colima socket at %s", colimaSocketPath)
163+
return colimaSocketPath, nil
164+
}
165+
166+
logger.Debugf("Failed to check Colima socket at %s: %v", colimaSocketPath, err)
167+
}
168+
169+
return "", fmt.Errorf("colima socket not found in standard locations")
170+
}
171+
138172
// findDockerSocket attempts to locate a Docker socket
139173
func findDockerSocket() (string, error) {
140174
// Try Docker socket as fallback
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
package sdk
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
13+
"github.com/stacklok/toolhive/pkg/container/runtime"
14+
"github.com/stacklok/toolhive/pkg/logger"
15+
)
16+
17+
func init() {
18+
// Initialize the logger for tests
19+
logger.Initialize()
20+
}
21+
22+
func TestColimaRuntimeTypeSupport(t *testing.T) {
23+
t.Parallel()
24+
25+
// Test that Colima is included in supported socket paths
26+
found := false
27+
for _, rt := range supportedSocketPaths {
28+
if rt == runtime.TypeColima {
29+
found = true
30+
break
31+
}
32+
}
33+
34+
require.True(t, found, "TypeColima should be included in supportedSocketPaths")
35+
}
36+
37+
func TestColimaConstants(t *testing.T) {
38+
t.Parallel()
39+
40+
// Test that Colima constants are properly defined
41+
assert.Equal(t, "TOOLHIVE_COLIMA_SOCKET", ColimaSocketEnv)
42+
assert.Equal(t, ".colima/default/docker.sock", ColimaSocketPath)
43+
assert.Equal(t, runtime.Type("colima"), runtime.TypeColima)
44+
}
45+
46+
func TestNewDockerClientWithColima(t *testing.T) {
47+
t.Parallel()
48+
49+
// This test verifies that the NewDockerClient function can handle
50+
// the Colima runtime type in the supportedSocketPaths without errors
51+
// Note: This test won't actually connect since no container runtime is available
52+
// but it verifies the code paths don't panic and handle the new runtime type
53+
54+
ctx := context.Background()
55+
_, _, _, err := NewDockerClient(ctx)
56+
57+
// We expect an error since no container runtime is available in the test environment
58+
// but we're testing that the function doesn't panic or have compile errors
59+
// with the new Colima support
60+
assert.Error(t, err)
61+
assert.Contains(t, err.Error(), "no supported container runtime")
62+
}

pkg/container/docker/sdk/client_windows.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ func findPlatformContainerSocket(rt runtime.Type) (string, runtime.Type, error)
7171
return customPipePath, runtime.TypePodman, nil
7272
}
7373

74+
if customPipePath := os.Getenv(ColimaSocketEnv); customPipePath != "" {
75+
logger.Debugf("Using Colima pipe from env: %s", customPipePath)
76+
// Validate the pipe path exists with timeout
77+
ctx, cancel := context.WithTimeout(context.Background(), pipeConnectionTimeout)
78+
defer cancel()
79+
conn, err := winio.DialPipeContext(ctx, customPipePath)
80+
if err != nil {
81+
return "", runtime.TypeColima, fmt.Errorf("invalid Colima pipe path: %w", err)
82+
}
83+
conn.Close()
84+
return customPipePath, runtime.TypeColima, nil
85+
}
86+
7487
if customPipePath := os.Getenv(DockerSocketEnv); customPipePath != "" {
7588
logger.Debugf("Using Docker pipe from env: %s", customPipePath)
7689
// Validate the pipe path exists with timeout
@@ -97,6 +110,20 @@ func findPlatformContainerSocket(rt runtime.Type) (string, runtime.Type, error)
97110
logger.Debugf("Failed to connect to Podman pipe at %s: %v", PodmanDesktopWindowsPipePath, err)
98111
}
99112

113+
if rt == runtime.TypeColima {
114+
// On Windows, Colima would typically use Docker Desktop's socket if available
115+
// Try Docker named pipe as fallback for Colima
116+
ctx, cancel := context.WithTimeout(context.Background(), pipeConnectionTimeout)
117+
defer cancel()
118+
conn, err := winio.DialPipeContext(ctx, DockerDesktopWindowsPipePath)
119+
if err == nil {
120+
logger.Debugf("Found Colima (Docker) pipe at %s", DockerDesktopWindowsPipePath)
121+
conn.Close()
122+
return DockerDesktopWindowsPipePath, runtime.TypeColima, nil
123+
}
124+
logger.Debugf("Failed to connect to Colima (Docker) pipe at %s: %v", DockerDesktopWindowsPipePath, err)
125+
}
126+
100127
if rt == runtime.TypeDocker {
101128
// Try Docker named pipe with timeout
102129
ctx, cancel := context.WithTimeout(context.Background(), pipeConnectionTimeout)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package sdk
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
13+
"github.com/stacklok/toolhive/pkg/container/runtime"
14+
"github.com/stacklok/toolhive/pkg/logger"
15+
)
16+
17+
func init() {
18+
// Initialize the logger for tests
19+
logger.Initialize()
20+
}
21+
22+
func TestColimaRuntimeTypeSupportWindows(t *testing.T) {
23+
t.Parallel()
24+
25+
// Test that Colima is included in supported socket paths
26+
found := false
27+
for _, rt := range supportedSocketPaths {
28+
if rt == runtime.TypeColima {
29+
found = true
30+
break
31+
}
32+
}
33+
34+
require.True(t, found, "TypeColima should be included in supportedSocketPaths")
35+
}
36+
37+
func TestColimaConstantsWindows(t *testing.T) {
38+
t.Parallel()
39+
40+
// Test that Colima constants are properly defined
41+
assert.Equal(t, "TOOLHIVE_COLIMA_SOCKET", ColimaSocketEnv)
42+
assert.Equal(t, ".colima/default/docker.sock", ColimaSocketPath)
43+
assert.Equal(t, runtime.Type("colima"), runtime.TypeColima)
44+
}
45+
46+
func TestNewDockerClientWithColimaWindows(t *testing.T) {
47+
t.Parallel()
48+
49+
// This test verifies that the NewDockerClient function can handle
50+
// the Colima runtime type in the supportedSocketPaths without errors on Windows
51+
// Note: This test won't actually connect since no container runtime is available
52+
// but it verifies the code paths don't panic and handle the new runtime type
53+
54+
ctx := context.Background()
55+
_, _, _, err := NewDockerClient(ctx)
56+
57+
// We expect an error since no container runtime is available in the test environment
58+
// but we're testing that the function doesn't panic or have compile errors
59+
// with the new Colima support
60+
assert.Error(t, err)
61+
assert.Contains(t, err.Error(), "no supported container runtime")
62+
}

pkg/container/docker/sdk/factory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const (
3434
PodmanXDGRuntimeSocketPath = "podman/podman.sock"
3535
// DockerSocketPath is the default Docker socket path
3636
DockerSocketPath = "/var/run/docker.sock"
37+
// ColimaSocketPath is the default Colima socket path
38+
ColimaSocketPath = ".colima/default/docker.sock"
3739
// DockerDesktopMacSocketPath is the Docker Desktop socket path on macOS
3840
DockerDesktopMacSocketPath = ".docker/run/docker.sock"
3941
// RancherDesktopMacSocketPath is the Docker socket path for Rancher Desktop on macOS

pkg/container/runtime/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ const (
185185
TypePodman Type = "podman"
186186
// TypeDocker represents the Docker runtime
187187
TypeDocker Type = "docker"
188+
// TypeColima represents the Colima runtime
189+
TypeColima Type = "colima"
188190
// TypeKubernetes represents the Kubernetes runtime
189191
TypeKubernetes Type = "kubernetes"
190192
// TypeColima represents the Colima runtime
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package runtime
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestRuntimeTypes(t *testing.T) {
10+
t.Parallel()
11+
12+
// Test that all runtime types are properly defined
13+
tests := []struct {
14+
name string
15+
runtimeType Type
16+
expectedValue string
17+
}{
18+
{
19+
name: "TypePodman",
20+
runtimeType: TypePodman,
21+
expectedValue: "podman",
22+
},
23+
{
24+
name: "TypeDocker",
25+
runtimeType: TypeDocker,
26+
expectedValue: "docker",
27+
},
28+
{
29+
name: "TypeColima",
30+
runtimeType: TypeColima,
31+
expectedValue: "colima",
32+
},
33+
{
34+
name: "TypeKubernetes",
35+
runtimeType: TypeKubernetes,
36+
expectedValue: "kubernetes",
37+
},
38+
}
39+
40+
for _, tt := range tests {
41+
tt := tt
42+
t.Run(tt.name, func(t *testing.T) {
43+
t.Parallel()
44+
assert.Equal(t, tt.expectedValue, string(tt.runtimeType))
45+
})
46+
}
47+
}
48+
49+
func TestColimaRuntimeTypeExists(t *testing.T) {
50+
t.Parallel()
51+
52+
// Ensure TypeColima constant exists and has the correct value
53+
assert.Equal(t, Type("colima"), TypeColima)
54+
55+
// Verify it's different from other runtime types
56+
assert.NotEqual(t, TypeColima, TypeDocker)
57+
assert.NotEqual(t, TypeColima, TypePodman)
58+
assert.NotEqual(t, TypeColima, TypeKubernetes)
59+
}

0 commit comments

Comments
 (0)