Skip to content

Commit e5bbf8d

Browse files
committed
feat: Default to Podman Socket
Update s2i's defaults to inspect the host system for Podman sockets. Podman socket provides support for the Docker v1.40 API, which meets s2i's needs. The logic looks for the podman socket in the following order: 1. Rootless podman socket 2. Root podman socket 3. Docker socket If none are found, the default falls back to the docker socket. As before, the `--url` and `DOCKER_HOST` environment variables can override the container engine socket location. Signed-off-by: Adam Kaplan <[email protected]>
1 parent c301811 commit e5bbf8d

File tree

2 files changed

+112
-2
lines changed

2 files changed

+112
-2
lines changed

pkg/docker/util.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ var (
3030
log = utillog.StderrLog
3131

3232
// DefaultEntrypoint is the default entry point used when starting containers
33-
DefaultEntrypoint = []string{"/usr/bin/env"}
33+
DefaultEntrypoint = []string{"/usr/bin/env"}
34+
DefaultPodmanSocket = filepath.Join("/run", "podman", "podman.sock")
3435
)
3536

3637
// AuthConfigurations maps a registry name to an AuthConfig, as used for
@@ -434,7 +435,7 @@ func GetDefaultDockerConfig() *api.DockerConfig {
434435
cfg := &api.DockerConfig{}
435436

436437
if cfg.Endpoint = os.Getenv("DOCKER_HOST"); cfg.Endpoint == "" {
437-
cfg.Endpoint = client.DefaultDockerHost
438+
cfg.Endpoint = GetDefaultContainerEngineHost()
438439
}
439440

440441
certPath := os.Getenv("DOCKER_CERT_PATH")
@@ -457,6 +458,36 @@ func GetDefaultDockerConfig() *api.DockerConfig {
457458
return cfg
458459
}
459460

461+
// GetDefaultContainerEngineHost returns a default container engine socket address. It checks the
462+
// following locations for a container engine socket:
463+
//
464+
// 1. Rootless podman socket: unix://$XDG_RUNTIME_DIR/podman/podman.sock
465+
// 2. "Rootful" podman socket: unix:///run/podman/podman.sock
466+
// 3. Docker socket: unix:///var/run/docker.sock
467+
func GetDefaultContainerEngineHost() string {
468+
podmanSockets := []string{}
469+
470+
// Podman socket provides a unix socket that is directly compatible with Docker
471+
// There are two modes the socket can be provided:
472+
//
473+
// 1) "rootless" - runs as nonroot, with socket at $XDG_RUNTIME_DIR/podman/podman.sock
474+
// 2) "rootful" - runs as root, with socket at /run/podman/podman.sock
475+
476+
if runtimeDir, ok := os.LookupEnv("XDG_RUNTIME_DIR"); ok {
477+
podmanSockets = append(podmanSockets, filepath.Join(runtimeDir, "podman", "podman.sock"))
478+
}
479+
podmanSockets = append(podmanSockets, DefaultPodmanSocket)
480+
481+
for _, socket := range podmanSockets {
482+
if _, err := os.Stat(socket); err == nil {
483+
return fmt.Sprintf("unix://%s", socket)
484+
}
485+
}
486+
487+
// Fall back to default docker socket.
488+
return client.DefaultDockerHost
489+
}
490+
460491
// GetAssembleUser finds an assemble user on the given image.
461492
// This functions receives the config to check if the AssembleUser was defined in command line
462493
// If the cmd is blank, it tries to fetch the value from the Builder Image defined Label (assemble-user)

pkg/docker/util_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package docker
22

33
import (
4+
"fmt"
45
"os"
6+
"path/filepath"
57
"testing"
68

9+
"github.com/docker/docker/client"
710
"github.com/openshift/source-to-image/pkg/api"
811
"github.com/openshift/source-to-image/pkg/api/constants"
912
"github.com/openshift/source-to-image/pkg/util/user"
@@ -233,14 +236,17 @@ func TestGetDefaultDockerConfig(t *testing.T) {
233236
},
234237
}
235238
for _, tc := range tests {
239+
oldXdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
236240
oldHost := os.Getenv("DOCKER_HOST")
237241
oldCertPath := os.Getenv("DOCKER_CERT_PATH")
238242
oldTLSVerify := os.Getenv("DOCKER_TLS_VERIFY")
239243
oldTLS := os.Getenv("DOCKER_TLS")
244+
os.Setenv("XDG_RUNTIME_DIR", "")
240245
os.Setenv("DOCKER_HOST", tc.envHost)
241246
os.Setenv("DOCKER_CERT_PATH", tc.envCertPath)
242247
os.Setenv("DOCKER_TLS_VERIFY", tc.envTLSVerify)
243248
os.Setenv("DOCKER_TLS", tc.envTLS)
249+
defer os.Setenv("XDG_RUNTIME_DIR", oldXdgRuntimeDir)
244250
defer os.Setenv("DOCKER_HOST", oldHost)
245251
defer os.Setenv("DOCKER_CERT_PATH", oldCertPath)
246252
defer os.Setenv("DOCKER_TLS_VERIFY", oldTLSVerify)
@@ -262,6 +268,79 @@ func TestGetDefaultDockerConfig(t *testing.T) {
262268
}
263269
}
264270

271+
func TestGetDefaultContainerEngineHost(t *testing.T) {
272+
273+
tmpDir, err := os.MkdirTemp("", "s2i-container-engine-host-*")
274+
if err != nil {
275+
t.Fatalf("failed to create xdg temp dir: %v", err)
276+
}
277+
278+
testCases := []struct {
279+
name string
280+
xdgRuntimeDir string
281+
createPodmanSocket bool
282+
expectedHost string
283+
}{
284+
{
285+
name: "rootless podman - socket exists",
286+
xdgRuntimeDir: tmpDir,
287+
createPodmanSocket: true,
288+
expectedHost: fmt.Sprintf("unix://%s", filepath.Join(tmpDir, "podman", "podman.sock")),
289+
},
290+
{
291+
name: "rootless podman - socket does not exist",
292+
xdgRuntimeDir: tmpDir,
293+
createPodmanSocket: false,
294+
expectedHost: client.DefaultDockerHost,
295+
},
296+
{
297+
name: "docker default",
298+
expectedHost: client.DefaultDockerHost,
299+
},
300+
}
301+
302+
for _, tc := range testCases {
303+
t.Run(tc.name, func(t *testing.T) {
304+
oldXdgDir := os.Getenv("XDG_RUNTIME_DIR")
305+
os.Setenv("XDG_RUNTIME_DIR", tc.xdgRuntimeDir)
306+
defer os.Setenv("XDG_RUNTIME_DIR", oldXdgDir)
307+
308+
socketCreated := false
309+
socketPath := filepath.Join(tc.xdgRuntimeDir, "podman", "podman.sock")
310+
if tc.createPodmanSocket {
311+
312+
if _, err := os.Stat(socketPath); err != nil {
313+
if err := os.MkdirAll(filepath.Dir(socketPath), 0750); err != nil {
314+
t.Fatalf("failed to create socket directory: %v", err)
315+
}
316+
file, err := os.Create(socketPath)
317+
if err != nil {
318+
t.Fatalf("failed to create default podman socket: %v", err)
319+
}
320+
defer func() {
321+
if closeErr := file.Close(); closeErr != nil {
322+
t.Errorf("failed to close file: %v", closeErr)
323+
}
324+
}()
325+
socketCreated = true
326+
}
327+
}
328+
329+
engineHost := GetDefaultContainerEngineHost()
330+
if tc.expectedHost != engineHost {
331+
t.Errorf("expected container host %s; got %s", tc.expectedHost, engineHost)
332+
}
333+
334+
if socketCreated {
335+
if err := os.RemoveAll(filepath.Dir(socketPath)); err != nil {
336+
t.Errorf("failed to clean up podman socket: %v", err)
337+
}
338+
}
339+
340+
})
341+
}
342+
}
343+
265344
func TestGetAssembleUser(t *testing.T) {
266345
testCases := []struct {
267346
name string

0 commit comments

Comments
 (0)