Add Podman fallback when Docker socket is missing.
Release rolling / release (push) Successful in 7m51s
Release rolling / release (push) Successful in 7m51s
Auto-detect rootless/rootful Podman sockets after Docker candidates, honor PEARDOCK_ENGINE and CONTAINER_HOST, and use podman compose for stacks when the engine is Podman.
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
import test from 'brittle'
|
||||
import {
|
||||
classifySocketPath,
|
||||
listDockerSocketCandidates,
|
||||
listPodmanSocketCandidates,
|
||||
parseUnixHostEnv,
|
||||
resolveContainerSocket,
|
||||
engineDisplayName,
|
||||
} from '../server/services/docker.js'
|
||||
import { resolveComposeCli } from '../server/utils/composeManager.js'
|
||||
|
||||
test('classifySocketPath detects docker vs podman', (t) => {
|
||||
t.is(classifySocketPath('/var/run/docker.sock'), 'docker')
|
||||
t.is(classifySocketPath('/run/user/1000/podman/podman.sock'), 'podman')
|
||||
t.is(classifySocketPath('//./pipe/dockerDesktopLinuxEngine'), 'docker')
|
||||
t.is(classifySocketPath('//./pipe/podman-machine-default'), 'podman')
|
||||
t.is(classifySocketPath('/tmp/custom.sock'), 'unknown')
|
||||
})
|
||||
|
||||
test('parseUnixHostEnv accepts unix and bare paths', (t) => {
|
||||
t.is(parseUnixHostEnv('unix:///run/podman/podman.sock'), '/run/podman/podman.sock')
|
||||
t.is(parseUnixHostEnv('unix://'), '/var/run/docker.sock')
|
||||
t.is(parseUnixHostEnv('/var/run/docker.sock'), '/var/run/docker.sock')
|
||||
t.is(parseUnixHostEnv('tcp://1.2.3.4:2375'), null)
|
||||
})
|
||||
|
||||
test('listPodmanSocketCandidates includes rootless and rootful paths', (t) => {
|
||||
const list = listPodmanSocketCandidates(
|
||||
{ XDG_RUNTIME_DIR: '/run/user/42', PODMAN_SOCK: '/custom/podman.sock' },
|
||||
'/home/alice'
|
||||
)
|
||||
t.ok(list.includes('/custom/podman.sock'))
|
||||
t.ok(list.includes('/run/user/42/podman/podman.sock'))
|
||||
t.ok(list.includes('/run/podman/podman.sock'))
|
||||
t.ok(list.includes('/home/alice/.local/share/containers/podman/machine/podman.sock'))
|
||||
})
|
||||
|
||||
test('listDockerSocketCandidates includes env and colima', (t) => {
|
||||
const list = listDockerSocketCandidates(
|
||||
{ DOCKER_SOCK: '/tmp/my-docker.sock' },
|
||||
'/home/alice'
|
||||
)
|
||||
t.ok(list.includes('/tmp/my-docker.sock'))
|
||||
t.ok(list.includes('/var/run/docker.sock'))
|
||||
t.ok(list.includes('/home/alice/.colima/default/docker.sock'))
|
||||
})
|
||||
|
||||
test('resolveContainerSocket prefers Docker when present', (t) => {
|
||||
const accessible = new Set(['/var/run/docker.sock', '/run/podman/podman.sock'])
|
||||
const r = resolveContainerSocket({
|
||||
env: {},
|
||||
platform: 'linux',
|
||||
homedir: '/home/alice',
|
||||
access: (p) => accessible.has(p),
|
||||
})
|
||||
t.is(r.path, '/var/run/docker.sock')
|
||||
t.is(r.kind, 'docker')
|
||||
t.ok(r.exists)
|
||||
})
|
||||
|
||||
test('resolveContainerSocket falls back to Podman when Docker missing', (t) => {
|
||||
const accessible = new Set(['/run/user/1000/podman/podman.sock'])
|
||||
const r = resolveContainerSocket({
|
||||
env: { XDG_RUNTIME_DIR: '/run/user/1000' },
|
||||
platform: 'linux',
|
||||
homedir: '/home/alice',
|
||||
access: (p) => accessible.has(p),
|
||||
})
|
||||
t.is(r.path, '/run/user/1000/podman/podman.sock')
|
||||
t.is(r.kind, 'podman')
|
||||
t.ok(r.exists)
|
||||
})
|
||||
|
||||
test('resolveContainerSocket PEARDOCK_ENGINE=podman prefers podman', (t) => {
|
||||
const accessible = new Set(['/var/run/docker.sock', '/run/podman/podman.sock'])
|
||||
const r = resolveContainerSocket({
|
||||
env: { PEARDOCK_ENGINE: 'podman' },
|
||||
platform: 'linux',
|
||||
homedir: '/home/alice',
|
||||
access: (p) => accessible.has(p),
|
||||
})
|
||||
t.is(r.path, '/run/podman/podman.sock')
|
||||
t.is(r.kind, 'podman')
|
||||
})
|
||||
|
||||
test('resolveContainerSocket DOCKER_HOST wins', (t) => {
|
||||
const r = resolveContainerSocket({
|
||||
env: { DOCKER_HOST: 'unix:///custom/engine.sock' },
|
||||
platform: 'linux',
|
||||
homedir: '/home/alice',
|
||||
access: () => true,
|
||||
})
|
||||
t.is(r.path, '/custom/engine.sock')
|
||||
t.is(r.source, 'DOCKER_HOST')
|
||||
})
|
||||
|
||||
test('resolveContainerSocket CONTAINER_HOST wins when no DOCKER_HOST', (t) => {
|
||||
const r = resolveContainerSocket({
|
||||
env: { CONTAINER_HOST: 'unix:///run/user/1/podman/podman.sock' },
|
||||
platform: 'linux',
|
||||
homedir: '/home/alice',
|
||||
access: () => false,
|
||||
})
|
||||
t.is(r.path, '/run/user/1/podman/podman.sock')
|
||||
t.is(r.kind, 'podman')
|
||||
t.is(r.source, 'CONTAINER_HOST')
|
||||
t.is(r.exists, false)
|
||||
})
|
||||
|
||||
test('resolveComposeCli picks podman for podman engine', (t) => {
|
||||
t.alike(resolveComposeCli('podman'), { cmd: 'podman', prefix: ['compose'] })
|
||||
t.alike(resolveComposeCli('docker'), { cmd: 'docker', prefix: ['compose'] })
|
||||
t.is(engineDisplayName('podman'), 'Podman')
|
||||
t.is(engineDisplayName('docker'), 'Docker')
|
||||
})
|
||||
Reference in New Issue
Block a user