Skip to content

Commit

Permalink
Try rootless Docker socket paths before defaulting to the root docker…
Browse files Browse the repository at this point in the history
… socket path in unix platforms
  • Loading branch information
mominul committed Aug 30, 2024
1 parent 06ab5bc commit 4e1b8ca
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
60 changes: 53 additions & 7 deletions testcontainers/src/core/env/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::{
borrow::Cow,
env::var,
path::{Path, PathBuf},
str::FromStr,
process::Command as StdCommand,
str::{from_utf8, FromStr},
};

use crate::core::env::GetEnvValue;
Expand Down Expand Up @@ -127,18 +128,54 @@ impl Config {
/// 1. Docker host from the `tc.host` property in the `~/.testcontainers.properties` file.
/// 2. `DOCKER_HOST` environment variable.
/// 3. Docker host from the `docker.host` property in the `~/.testcontainers.properties` file.
/// 4. Else, the default Docker socket will be returned.
/// 4. Read the default Docker socket path, without the unix schema. E.g. `/var/run/docker.sock`.
/// 5. Read the rootless Docker socket path, checking in the following alternative locations:
/// 1. `${XDG_RUNTIME_DIR}/.docker/run/docker.sock`.
/// 2. `${HOME}/.docker/run/docker.sock`.
/// 3. `${HOME}/.docker/desktop/docker.sock`.
/// 4. `/run/user/${UID}/docker.sock`, where `${UID}` is the user ID of the current user.
/// 6. The default Docker socket including schema will be returned if none of the above are set.
pub(crate) fn docker_host(&self) -> Cow<'_, str> {
self.tc_host
.as_deref()
.or(self.host.as_deref())
.map(Cow::Borrowed)
.unwrap_or_else(|| {
// Docker Desktop on macOS creates the socket in the user's home directory
// from version 4.13.0.
// https://github.com/docker/for-mac/issues/6529
if cfg!(target_os = "macos") {
format!("unix://{}/.docker/run/docker.sock", var("HOME").unwrap()).into()
if cfg!(unix) {
check_path_exists("/var/run/docker.sock".into())
.or_else(|| {
var("XDG_RUNTIME_DIR").ok().and_then(|dir| {
check_path_exists(format!("{dir}/.docker/run/docker.sock",))
})
})
.or_else(|| {
check_path_exists(format!(
"{}/.docker/run/docker.sock",
var("HOME").unwrap()
))
})
.or_else(|| {
check_path_exists(format!(
"{}/.docker/desktop/docker.sock",
var("HOME").unwrap()
))
})
.or_else(|| {
// Get the user ID of the current user by running `id -u`
StdCommand::new("id")
.arg("-u")
.output()
.ok()
.and_then(|output| {
from_utf8(&output.stdout).map(|s| s.trim().to_string()).ok()
})
.and_then(|uid| {
check_path_exists(format!("/run/user/${uid}/docker.sock"))
})
})
.map(|p| format!("unix://{p}"))
.map(Cow::Owned)
.unwrap_or(DEFAULT_DOCKER_HOST.into())
} else {
DEFAULT_DOCKER_HOST.into()
}
Expand All @@ -162,6 +199,15 @@ impl Config {
}
}

/// Checks if the path exists and returns it if it does.
fn check_path_exists(path: String) -> Option<String> {
if Path::new(&path).exists() {
Some(path)
} else {
None
}
}

/// Read the Docker authentication configuration in the following order:
///
/// 1. `DOCKER_AUTH_CONFIG` environment variable, unmarshalling the string value from its JSON representation and using it as the Docker config.
Expand Down
8 changes: 7 additions & 1 deletion testcontainers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@
//! 1. Docker host from the `tc.host` property in the `~/.testcontainers.properties` file.
//! 2. `DOCKER_HOST` environment variable.
//! 3. Docker host from the "docker.host" property in the `~/.testcontainers.properties` file.
//! 4. Else, the default Docker socket will be returned.
//! 4. Read the default Docker socket path, without the unix schema. E.g. `/var/run/docker.sock`.
//! 5. Read the rootless Docker socket path, checking in the following alternative locations:
//! 1. `${XDG_RUNTIME_DIR}/.docker/run/docker.sock`.
//! 2. `${HOME}/.docker/run/docker.sock`.
//! 3. `${HOME}/.docker/desktop/docker.sock`.
//! 4. `/run/user/${UID}/docker.sock`, where `${UID}` is the user ID of the current user.
//! 6. The default Docker socket including schema will be returned if none of the above are set.
//!
//! ### Docker authentication
//!
Expand Down

0 comments on commit 4e1b8ca

Please sign in to comment.