fix(podman): resolve macOS Podman socket dynamically (#3135)

* docs(podman): document macOS socket path mismatch and dynamic lookup

On macOS, Homebrew-installed Podman does not create the default socket
path that the Podman driver probes. Document the OPENSHELL_PODMAN_SOCKET
override and the podman machine inspect lookup in both the compute
drivers reference and the debug-openshell-cluster skill.

Fixes #1690

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* fix(podman): resolve macOS Podman socket dynamically

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* chore: restore debug skill file

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* chore: drop legacy debug skill path

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* fix(podman): trim unrelated e2e changes

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* fix(e2e): harden shell array expansion

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

* chore: remove unrelated skill note

* ci: retrigger checks

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>

---------

Signed-off-by: Gaizka Menendez Hernandez <gmenende@redhat.com>
This commit is contained in:
Gaizka Menendez
2026-09-09 14:10:59 +00:00
committed by GitHub
parent 3693b32841
commit 8af79a7f4b
5 changed files with 42 additions and 40 deletions
@@ -255,6 +255,26 @@ For maintainer-level implementation details, refer to the [Podman driver README]
Select Podman with `compute_drivers = ["podman"]` in `[openshell.gateway]`. Configure Podman driver values such as `socket_path`, `network_name`, `supervisor_image`, `stop_timeout_secs`, `image_pull_policy`, `grpc_endpoint`, `host_gateway_ip`, `sandbox_ssh_socket_path`, `sandbox_pids_limit`, and `guest_tls_*` in `[openshell.drivers.podman]`.
### macOS Podman Socket Path
On macOS, Homebrew-installed Podman does not create the default socket path
that the driver probes (`~/.local/share/containers/podman/machine/podman.sock`).
The actual API socket lives under `/var/folders/` in a path that macOS can
rotate after a reboot.
If the gateway fails with `Podman socket not found; is podman machine running?`
while `podman machine list` shows a running machine, set the
`OPENSHELL_PODMAN_SOCKET` environment variable to the dynamic socket path:
```shell
export OPENSHELL_PODMAN_SOCKET="$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')"
```
Add this to your shell profile or gateway launch environment so it resolves
correctly after each reboot. Alternatively, set `socket_path` in
`[openshell.drivers.podman]` to the current path, but note that the path may
change when macOS rotates `/var/folders/`.
Podman sandboxes default to a 45-second graceful stop window before Podman escalates from `SIGTERM` to `SIGKILL`. Set `stop_timeout_secs` in gateway config, or `OPENSHELL_STOP_TIMEOUT` for the standalone driver, when a local runtime needs a different teardown window.
Stop stops the existing Podman container while retaining its named workspace
+6 -31
View File
@@ -458,7 +458,7 @@ async fn connect_container_api(driver: &str) -> Result<Docker, String> {
"docker" => Docker::connect_with_local_defaults()
.map_err(|err| format!("connect to Docker API: {err}"))?,
"podman" => {
let socket = podman_socket_path();
let socket = podman_socket_path()?;
let socket_display = socket.display().to_string();
Docker::connect_with_unix(
socket
@@ -478,36 +478,11 @@ async fn connect_container_api(driver: &str) -> Result<Docker, String> {
Ok(docker)
}
fn podman_socket_path() -> PathBuf {
if let Some(path) = std::env::var_os("OPENSHELL_PODMAN_SOCKET") {
return PathBuf::from(path);
}
#[cfg(target_os = "macos")]
{
let home = std::env::var_os("HOME").unwrap_or_default();
PathBuf::from(home).join(".local/share/containers/podman/machine/podman.sock")
}
#[cfg(target_os = "linux")]
{
std::env::var_os("XDG_RUNTIME_DIR").map_or_else(
|| {
let uid = std::process::Command::new("id")
.arg("-u")
.output()
.ok()
.and_then(|output| {
String::from_utf8(output.stdout)
.ok()
.map(|value| value.trim().to_string())
})
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "1000".to_string());
PathBuf::from(format!("/run/user/{uid}/podman/podman.sock"))
},
|xdg| PathBuf::from(xdg).join("podman/podman.sock"),
)
}
fn podman_socket_path() -> Result<PathBuf, String> {
let path = std::env::var_os("OPENSHELL_PODMAN_SOCKET").ok_or_else(|| {
"OPENSHELL_PODMAN_SOCKET must be set by e2e/with-podman-gateway.sh".to_string()
})?;
Ok(PathBuf::from(path))
}
fn unique_volume_name(driver: &str) -> String {
+4 -4
View File
@@ -218,11 +218,11 @@ e2e_build_gateway_binaries() {
if [ -z "${OPENSHELL_GATEWAY_BIN:-}" ]; then
echo "Building openshell-gateway..."
if [ "${OPENSHELL_E2E_EXTERNAL_COMPUTE_DRIVER:-0}" = "1" ]; then
cargo build "${jobs[@]}" \
cargo build ${jobs[@]+"${jobs[@]}"} \
-p openshell-gateway --bin openshell-gateway \
--no-default-features --features telemetry
else
cargo build "${jobs[@]}" \
cargo build ${jobs[@]+"${jobs[@]}"} \
-p openshell-gateway --bin openshell-gateway
fi
else
@@ -231,7 +231,7 @@ e2e_build_gateway_binaries() {
if [ -z "${OPENSHELL_BIN:-}" ]; then
echo "Building openshell-cli..."
cargo build "${jobs[@]}" \
cargo build ${jobs[@]+"${jobs[@]}"} \
-p openshell-cli
else
echo "Using prebuilt openshell CLI at ${OPENSHELL_BIN}"
@@ -265,7 +265,7 @@ e2e_build_external_driver() {
else
printf -v "${output_var}" '%s' "${target_dir}/debug/${binary}"
echo "Building external ${binary}..."
cargo build "${jobs[@]}" -p "${package}" --bin "${binary}"
cargo build ${jobs[@]+"${jobs[@]}"} -p "${package}" --bin "${binary}"
fi
if [ ! -x "${!output_var}" ]; then
echo "ERROR: expected external driver binary at ${!output_var}" >&2
+11 -4
View File
@@ -80,7 +80,11 @@ with_podman_config() {
}
podman_cmd() {
with_podman_config podman "$@"
if [ -n "${OPENSHELL_PODMAN_SOCKET:-}" ]; then
with_podman_config podman --url "unix://${OPENSHELL_PODMAN_SOCKET}" "$@"
else
with_podman_config podman "$@"
fi
}
WORKDIR_PARENT="${TMPDIR:-/tmp}"
@@ -234,6 +238,7 @@ default_podman_socket_path() {
ensure_podman_api_socket() {
if [ -n "${OPENSHELL_PODMAN_SOCKET:-}" ]; then
export CONTAINER_HOST="${CONTAINER_HOST:-unix://${OPENSHELL_PODMAN_SOCKET}}"
return 0
fi
@@ -241,8 +246,9 @@ ensure_podman_api_socket() {
default_socket="$(default_podman_socket_path || true)"
if [ -n "${default_socket}" ] \
&& [ -S "${default_socket}" ] \
&& podman_cmd --url "unix://${default_socket}" info >/dev/null 2>&1; then
&& with_podman_config podman --url "unix://${default_socket}" info >/dev/null 2>&1; then
export OPENSHELL_PODMAN_SOCKET="${default_socket}"
export CONTAINER_HOST="${CONTAINER_HOST:-unix://${OPENSHELL_PODMAN_SOCKET}}"
return 0
fi
@@ -266,12 +272,13 @@ ensure_podman_api_socket() {
>"${PODMAN_SERVICE_LOG}" 2>&1 &
PODMAN_SERVICE_PID=$!
export OPENSHELL_PODMAN_SOCKET="${PODMAN_SOCKET}"
export CONTAINER_HOST="${CONTAINER_HOST:-unix://${OPENSHELL_PODMAN_SOCKET}}"
local elapsed=0
local timeout=30
while [ "${elapsed}" -lt "${timeout}" ]; do
if [ -S "${PODMAN_SOCKET}" ] \
&& podman_cmd --url "unix://${PODMAN_SOCKET}" info >/dev/null 2>&1; then
&& podman_cmd info >/dev/null 2>&1; then
return 0
fi
@@ -375,12 +382,12 @@ if ! command -v podman >/dev/null 2>&1; then
echo "ERROR: podman CLI is required to run Podman-backed e2e tests" >&2
exit 2
fi
ensure_podman_api_socket
if ! podman_cmd info >/dev/null 2>&1; then
echo "ERROR: podman service is not reachable (podman info failed)" >&2
echo " Start it with 'podman machine start' on macOS, or the user service on Linux." >&2
exit 2
fi
ensure_podman_api_socket
e2e_build_gateway_binaries "${ROOT}" TARGET_DIR GATEWAY_BIN CLI_BIN
export OPENSHELL_BIN="${CLI_BIN}"
+1 -1
View File
@@ -254,7 +254,7 @@ build_component_for_arch() {
if [[ -n "$build_rustflags" ]]; then
export RUSTFLAGS="$build_rustflags"
fi
CARGO_INCREMENTAL=0 mise x -- "${cargo_env[@]}" "${cargo_subcommand[@]}" "${args[@]}"
CARGO_INCREMENTAL=0 mise x -- ${cargo_env[@]+"${cargo_env[@]}"} "${cargo_subcommand[@]}" "${args[@]}"
)
binary_path="${ROOT}/target/${target}/release/${binary}"