Skip to content

Commit

Permalink
[CLI] Support Docker socket in home directory for local testnet (#10654)
Browse files Browse the repository at this point in the history
  • Loading branch information
banool authored Oct 25, 2023
1 parent 23b5aa2 commit b5cdf0f
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 46 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/aptos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
All notable changes to the Aptos CLI will be captured in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the format set out by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased

## [2.3.0] - 2023/10/25
### Added
- Added `--node-api-key`. This lets you set an API key for the purpose of not being ratelimited.

### Updated
- Made the local testnet exit more quickly if a service fails to start.
- Updated processor code from https://github.com/aptos-labs/aptos-indexer-processors for the local testnet to bcba94c26c8a6372056d2b69ce411c5719f98965.

### Fixed
- Fixed an infrequent bug that caused startup failures for the local testnet with `--force-restart` + `--with-indexer-api` by using a Docker volume rather than a bind mount for the postgres storage.
- Fixed an issue where the CLI could not find the Docker socket with some Docker Desktop configurations.

## [2.2.2] - 2023/10/16
### Updated
Expand Down
6 changes: 3 additions & 3 deletions crates/aptos/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "aptos"
description = "Aptos tool for management of nodes and interacting with the blockchain"
version = "2.2.2"
version = "2.3.0"

# Workspace inherited keys
authors = { workspace = true }
Expand Down Expand Up @@ -79,15 +79,15 @@ move-unit-test = { workspace = true, features = [ "debugging" ] }
move-vm-runtime = { workspace = true, features = [ "testing" ] }
once_cell = { workspace = true }
poem = { workspace = true }
processor = { git = "https://github.com/aptos-labs/aptos-indexer-processors.git", rev = "a9e42dc9d80a69e9d02cd5f19c39e0f3f5cfbeb0" }
processor = { git = "https://github.com/aptos-labs/aptos-indexer-processors.git", rev = "bcba94c26c8a6372056d2b69ce411c5719f98965" }
rand = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true }
self_update = { version = "0.38.0", features = ["archive-zip", "compression-zip-deflate"] }
serde = { workspace = true }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
server-framework = { git = "https://github.com/aptos-labs/aptos-indexer-processors.git", rev = "a9e42dc9d80a69e9d02cd5f19c39e0f3f5cfbeb0" }
server-framework = { git = "https://github.com/aptos-labs/aptos-indexer-processors.git", rev = "bcba94c26c8a6372056d2b69ce411c5719f98965" }
tempfile = { workspace = true }
termcolor = { workspace = true }
thiserror = { workspace = true }
Expand Down
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!(
"Received 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
8 changes: 5 additions & 3 deletions developer-docs-site/docs/guides/local-development-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,9 @@ Make sure the socket for connecting to Docker is present on your machine in the
/var/run/docker.sock
```
If it doesn't, you can find where it is like this:
If it doesn't, open Docker Desktop and enable `Settings -> Advanced -> Allow the default Docker socket to be used`.
Alternatively, you can find where it is like this:
```
$ docker context inspect | grep Host
"Host": "unix:///Users/dport/.docker/run/docker.sock",
Expand All @@ -247,7 +249,7 @@ Alternatively, run the CLI like this to tell it where the socket is:
DEFAULT_SOCKET=/Users/dport/.docker/run/docker.sock aptos node run-local-testnet --with-indexer-api
```
Note: If you're on Mac or Windows, we recommend you use Docker Desktop rather than installing Docker via a package manager (e.g. Homebrew or Choco).
Note: As mentioned above, if you're on Mac or Windows, we recommend you use Docker Desktop rather than installing Docker via a package manager (e.g. Homebrew or Choco).
### The local network seems to hang on startup
If the CLI seems to sit there and do nothing when you are using `--with-indexer-api`, consider quitting and restarting Docker. Sometimes Docker gets in a bad state. Note that Docker is only required if you are using `--with-indexer-api`.
Expand All @@ -264,7 +266,7 @@ When running the CLI interactively, you can see if the network is alive by waiti
Setup is complete, you can now use the local testnet!
```
If you writing a script and would like to wait for the local network to come up, you can make a GET request to `http://127.0.0.1:8070`. At first this will return [503](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503). When it returns [200](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200) it means all the services are ready.
If you are writing a script and would like to wait for the local network to come up, you can make a GET request to `http://127.0.0.1:8070`. At first this will return [503](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503). When it returns [200](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200) it means all the services are ready.
You can inspect the response to see which services are ready.
Expand Down

0 comments on commit b5cdf0f

Please sign in to comment.