diff --git a/docs/reference/sandbox-compute-drivers.mdx b/docs/reference/sandbox-compute-drivers.mdx index 987e66b0d9..1aead424b3 100644 --- a/docs/reference/sandbox-compute-drivers.mdx +++ b/docs/reference/sandbox-compute-drivers.mdx @@ -241,6 +241,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 diff --git a/e2e/rust/tests/driver_config_volume.rs b/e2e/rust/tests/driver_config_volume.rs index 2d8789edce..7a2b24f015 100644 --- a/e2e/rust/tests/driver_config_volume.rs +++ b/e2e/rust/tests/driver_config_volume.rs @@ -505,7 +505,7 @@ async fn connect_container_api(driver: &str) -> Result { "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 @@ -525,36 +525,11 @@ async fn connect_container_api(driver: &str) -> Result { 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 { + 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 { diff --git a/e2e/support/gateway-common.sh b/e2e/support/gateway-common.sh index b1f62e380b..8a777c6e0e 100644 --- a/e2e/support/gateway-common.sh +++ b/e2e/support/gateway-common.sh @@ -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 diff --git a/e2e/with-podman-gateway.sh b/e2e/with-podman-gateway.sh index fc3419e182..fb14be747b 100755 --- a/e2e/with-podman-gateway.sh +++ b/e2e/with-podman-gateway.sh @@ -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}" diff --git a/tasks/scripts/stage-prebuilt-binaries.sh b/tasks/scripts/stage-prebuilt-binaries.sh index fe4913439a..b3f75bbaba 100755 --- a/tasks/scripts/stage-prebuilt-binaries.sh +++ b/tasks/scripts/stage-prebuilt-binaries.sh @@ -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}"