Skip to content

Commit

Permalink
[CLI] Support Docker socket in home directory for local testnet
Browse files Browse the repository at this point in the history
  • Loading branch information
banool committed Oct 24, 2023
1 parent 67cd757 commit f4887f2
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 35 deletions.
80 changes: 53 additions & 27 deletions crates/aptos/src/node/local_testnet/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,60 @@ use bollard::{
container::{RemoveContainerOptions, StopContainerOptions},
image::CreateImageOptions,
volume::{CreateVolumeOptions, RemoveVolumeOptions},
Docker,
Docker, API_DEFAULT_VERSION,
};
use futures::TryStreamExt;
use std::{fs::create_dir_all, path::Path};
use tracing::{info, warn};
use version_compare::Version;

pub fn get_docker() -> Result<Docker> {
let docker = Docker::connect_with_local_defaults()
.context("Docker is not available, confirm it is installed and running. On Linux you may need to use sudo.")?;
Ok(docker)
}

pub async fn confirm_docker_available() -> Result<()> {
let docker = get_docker()?;
let info = docker
.info()
.await
.context("Docker is not available, confirm it is installed and running. On Linux you may need to use sudo.")?;

info!("Docker Info: {:?}", info);

let version = docker
.version()
.await
.context("Failed to get Docker version")?;
const ERROR_MESSAGE: &str = "Docker is not available, confirm it is installed and running. See https://aptos.dev/guides/local-development-network#faq for assistance.";

info!("Docker Version: {:?}", version);
/// This function returns a Docker client. Before returning, it confirms that it can
/// actually query the API and checks that the API version is sufficient. It first
/// tries to connect at the default socket location and if that fails, it tries to find
/// a socket in the user's home directory. On Windows NT it doesn't try that since
/// there no second location, there is just the one named pipe.
pub async fn get_docker() -> Result<Docker> {
let docker = Docker::connect_with_local_defaults()
.context(format!("{} (init_default)", ERROR_MESSAGE))?;

// We have to specify the type because the compiler can't figure out the error
// in the case where the system is Unix.
let out: Result<(Docker, bollard::system::Version), bollard::errors::Error> =
match docker.version().await {
Ok(version) => Ok((docker, version)),
Err(err) => {
warn!(
"Got this error trying to use default Docker socket location: {:#}",
err
);
// Look for the socket in ~/.docker/run
// We don't have to do this if this issue gets addressed:
// https://github.com/fussybeaver/bollard/issues/345
#[cfg(unix)]
{
let path = dirs::home_dir()
.context(format!("{} (home_dir)", ERROR_MESSAGE))?
.join(".docker")
.join("run")
.join("docker.sock");
info!("Looking for Docker socket at {}", path.display());
let path = path.to_str().context(format!("{} (path)", ERROR_MESSAGE))?;
let docker = Docker::connect_with_socket(path, 120, API_DEFAULT_VERSION)
.context(format!("{} (init_home)", ERROR_MESSAGE))?;
let version = docker
.version()
.await
.context(format!("{} (version_home)", ERROR_MESSAGE))?;
Ok((docker, version))
}
// Just return the original error.
#[cfg(not(unix))]
Err(err)
},
};
let (docker, version) = out?;

// Try to warn the user about their Docker version being too old. We don't error
// out if the version is too old in case we're wrong about the minimum version
Expand Down Expand Up @@ -68,7 +94,7 @@ pub async fn confirm_docker_available() -> Result<()> {
},
}

Ok(())
Ok(docker)
}

/// Delete a container. If the container doesn't exist, that's fine, just move on.
Expand All @@ -78,7 +104,7 @@ pub async fn delete_container(container_name: &str) -> Result<()> {
container_name
);

let docker = get_docker()?;
let docker = get_docker().await?;

let options = Some(RemoveContainerOptions {
force: true,
Expand Down Expand Up @@ -106,7 +132,7 @@ pub async fn stop_container(container_name: &str) -> Result<()> {
container_name
);

let docker = get_docker()?;
let docker = get_docker().await?;

let options = Some(StopContainerOptions {
// Timeout in seconds before we kill the container.
Expand All @@ -130,7 +156,7 @@ pub async fn stop_container(container_name: &str) -> Result<()> {
pub async fn pull_docker_image(image_name: &str) -> Result<()> {
info!("Checking if we have to pull docker image {}", image_name);

let docker = get_docker()?;
let docker = get_docker().await?;

let options = Some(CreateImageOptions {
from_image: image_name,
Expand Down Expand Up @@ -164,7 +190,7 @@ pub async fn pull_docker_image(image_name: &str) -> Result<()> {
}

pub async fn create_volume(volume_name: &str) -> Result<()> {
let docker = get_docker()?;
let docker = get_docker().await?;

info!("Creating volume {}", volume_name);

Expand All @@ -180,7 +206,7 @@ pub async fn create_volume(volume_name: &str) -> Result<()> {
}

pub async fn delete_volume(volume_name: &str) -> Result<()> {
let docker = get_docker()?;
let docker = get_docker().await?;

info!("Removing volume {}", volume_name);

Expand Down
8 changes: 4 additions & 4 deletions crates/aptos/src/node/local_testnet/indexer_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use super::{
docker::{
confirm_docker_available, delete_container, get_docker, pull_docker_image,
setup_docker_logging, StopContainerShutdownStep,
delete_container, get_docker, pull_docker_image, setup_docker_logging,
StopContainerShutdownStep,
},
health_checker::HealthChecker,
traits::{PostHealthyStep, ServiceManager, ShutdownStep},
Expand Down Expand Up @@ -89,7 +89,7 @@ impl ServiceManager for IndexerApiManager {

async fn pre_run(&self) -> Result<()> {
// Confirm Docker is available.
confirm_docker_available().await?;
get_docker().await?;

// Delete any existing indexer API container we find.
delete_container(INDEXER_API_CONTAINER_NAME).await?;
Expand Down Expand Up @@ -139,7 +139,7 @@ impl ServiceManager for IndexerApiManager {
..Default::default()
};

let docker = get_docker()?;
let docker = get_docker().await?;

// When using Docker Desktop you can and indeed must use the magic hostname
// host.docker.internal in order to access localhost on the host system from
Expand Down
8 changes: 4 additions & 4 deletions crates/aptos/src/node/local_testnet/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use super::{
docker::{
confirm_docker_available, create_volume, delete_container, delete_volume, get_docker,
pull_docker_image, setup_docker_logging, StopContainerShutdownStep,
create_volume, delete_container, delete_volume, get_docker, pull_docker_image,
setup_docker_logging, StopContainerShutdownStep,
},
health_checker::HealthChecker,
traits::{ServiceManager, ShutdownStep},
Expand Down Expand Up @@ -163,7 +163,7 @@ impl ServiceManager for PostgresManager {
}
} else {
// Confirm Docker is available.
confirm_docker_available().await?;
get_docker().await?;

// Kill any existing container we find.
delete_container(POSTGRES_CONTAINER_NAME).await?;
Expand Down Expand Up @@ -195,7 +195,7 @@ impl ServiceManager for PostgresManager {
// Let the user know where to go to see logs for postgres.
setup_docker_logging(&self.test_dir, "postgres", POSTGRES_CONTAINER_NAME)?;

let docker = get_docker()?;
let docker = get_docker().await?;

// If we're starting afresh, delete any existing volume.
if self.force_restart {
Expand Down

0 comments on commit f4887f2

Please sign in to comment.