Skip to content

Commit

Permalink
merge: #2596
Browse files Browse the repository at this point in the history
2596: fix(si): determine Docker socket location on macOS r=fnichol a=fnichol

This change refactors how the various Docker clients are configured in `lib/si-cli` by moving container (currently only Docker) related functions into a `DockerClient` type as methods. A first-pass refactoring extracts the hardcoded paths of `//var/run/docker.sock` into one location, early in the launcher's `main()` function.

As Docker Desktop on macOS doesn't necessarily mount the Docker socket at `/var/run/docker.sock`, the socket is first looked for in `$HOME/.docker/run/docker.sock` before falling back on the system location. If neither is found, then an error message is displayed, indicating a suitable Docker socket was not found.

Co-authored-by: Fletcher Nichol <[email protected]>
  • Loading branch information
si-bors-ng[bot] and fnichol authored Aug 16, 2023
2 parents fd8fb67 + b72ae61 commit f103859
Show file tree
Hide file tree
Showing 11 changed files with 381 additions and 285 deletions.
44 changes: 34 additions & 10 deletions bin/si/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::args::{Commands, Engine};
use color_eyre::Result;
use si_cli::state::AppState;
use color_eyre::{eyre::eyre, Result};
use si_cli::{state::AppState, DockerClient};
use std::sync::Arc;
use telemetry_application::{prelude::*, TelemetryConfig};
use tokio::sync::oneshot::Sender;
Expand Down Expand Up @@ -32,6 +32,24 @@ async fn main() -> Result<()> {

tokio::spawn(wait_for_posthog_flush(ph_done_sender, ph_sender));

let docker_socket_candidates = vec![
#[allow(clippy::disallowed_methods)] // Used to determine a path relative to users's home
std::path::Path::new(&std::env::var("HOME")?)
.join(".docker")
.join("run")
.join("docker.sock"),
std::path::Path::new("/var/run/docker.sock").to_path_buf(),
];

let docker_socket = docker_socket_candidates
.iter()
.find(|candidate| candidate.exists())
.ok_or(eyre!(
"failed to determine Docker socket location; candidates={docker_socket_candidates:?}"
))?;

let docker = DockerClient::unix(docker_socket);

let state = AppState::new(
ph_client,
Arc::from(current_version),
Expand All @@ -52,7 +70,10 @@ async fn main() -> Result<()> {
let auth_api_host = std::env::var("AUTH_API").ok();

if !matches!(args.command, Commands::Update(_)) {
match state.find(current_version, auth_api_host.as_deref()).await {
match state
.find(&docker, current_version, auth_api_host.as_deref())
.await
{
Ok(update) => {
if update.si.is_some() {
println!("Launcher update found, please run `si update` to install it");
Expand Down Expand Up @@ -80,32 +101,33 @@ async fn main() -> Result<()> {

match args.command {
Commands::Install(_args) => {
state.install().await?;
state.install(&docker).await?;
}
Commands::Check(_args) => {
state.check(false).await?;
state.check(&docker, false).await?;
}
Commands::Launch(args) => {
state.launch(args.metrics).await?;
}
Commands::Start(_args) => {
state.start().await?;
state.start(&docker).await?;
}
Commands::Configure(args) => {
state.configure(args.force_reconfigure).await?;
}
Commands::Delete(_args) => {
state.delete().await?;
state.delete(&docker).await?;
}
Commands::Restart(_args) => {
state.restart().await?;
state.restart(&docker).await?;
}
Commands::Stop(_args) => {
state.stop().await?;
state.stop(&docker).await?;
}
Commands::Update(args) => {
state
.update(
&docker,
current_version,
auth_api_host.as_deref(),
args.skip_confirmation,
Expand All @@ -114,7 +136,9 @@ async fn main() -> Result<()> {
.await?;
}
Commands::Status(args) => {
state.status(args.show_logs, args.log_lines).await?;
state
.status(&docker, args.show_logs, args.log_lines)
.await?;
} // Commands::Report(_args) => {
// state.report().await?;
// }
Expand Down
9 changes: 4 additions & 5 deletions lib/si-cli/src/cmd/check.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use crate::containers::DockerClient;
use crate::key_management::get_user_email;
use crate::state::AppState;
use crate::{CliResult, SiCliError};
use comfy_table::presets::UTF8_FULL;
use comfy_table::*;
use docker_api::Docker;

impl AppState {
pub async fn check(&self, silent: bool) -> CliResult<()> {
pub async fn check(&self, docker: &DockerClient, silent: bool) -> CliResult<()> {
self.track(
get_user_email().await?,
serde_json::json!({"command-name": "check-dependencies"}),
);
invoke(silent, self.is_preview()).await?;
invoke(docker, silent, self.is_preview()).await?;
Ok(())
}
}

async fn invoke(silent: bool, is_preview: bool) -> CliResult<()> {
async fn invoke(docker: &DockerClient, silent: bool, is_preview: bool) -> CliResult<()> {
if !silent {
println!("Checking that the system is able to interact with the docker engine to control System Initiative...");
}
Expand All @@ -25,7 +25,6 @@ async fn invoke(silent: bool, is_preview: bool) -> CliResult<()> {
return Ok(());
}

let docker = Docker::unix("//var/run/docker.sock");
if let Err(_e) = docker.ping().await {
return Err(SiCliError::DockerEngine);
}
Expand Down
23 changes: 12 additions & 11 deletions lib/si-cli/src/cmd/delete.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
use crate::containers::{cleanup_image, delete_container, get_existing_container};
use crate::containers::DockerClient;
use crate::key_management::get_user_email;
use crate::state::AppState;
use crate::{CliResult, CONTAINER_NAMES};
use docker_api::Docker;

impl AppState {
pub async fn delete(&self) -> CliResult<()> {
pub async fn delete(&self, docker: &DockerClient) -> CliResult<()> {
self.track(
get_user_email().await?,
serde_json::json!({"command-name": "delete-system"}),
);
invoke(self, self.is_preview()).await?;
invoke(self, docker, self.is_preview()).await?;
Ok(())
}
}

async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
app.check(true).await?;

let docker = Docker::unix("//var/run/docker.sock");
async fn invoke(app: &AppState, docker: &DockerClient, is_preview: bool) -> CliResult<()> {
app.check(docker, true).await?;

if is_preview {
println!("Deleted the following containers and associated images:");
Expand All @@ -30,10 +27,14 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
println!("{}", container_name);
continue;
}
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(container_summary) = container_summary {
delete_container(&docker, container_summary, container_name.clone()).await?;
cleanup_image(&docker, name.to_string()).await?;
docker
.delete_container(container_summary, container_name.clone())
.await?;
docker.cleanup_image(name.to_string()).await?;
}
}

Expand Down
14 changes: 8 additions & 6 deletions lib/si-cli/src/cmd/install.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use crate::containers::{download_missing_containers, missing_containers};
use crate::containers::DockerClient;
use crate::key_management::get_user_email;
use crate::state::AppState;
use crate::CliResult;

impl AppState {
pub async fn install(&self) -> CliResult<()> {
pub async fn install(&self, docker: &DockerClient) -> CliResult<()> {
self.track(
get_user_email().await?,
serde_json::json!({"command-name": "install"}),
);
invoke(self.is_preview()).await?;
invoke(docker, self.is_preview()).await?;
Ok(())
}
}

async fn invoke(is_preview: bool) -> CliResult<()> {
let missing_containers = missing_containers().await?;
async fn invoke(docker: &DockerClient, is_preview: bool) -> CliResult<()> {
let missing_containers = docker.missing_containers().await?;
if missing_containers.is_empty() {
println!("All containers downloaded\n");
return Ok(());
Expand All @@ -30,7 +30,9 @@ async fn invoke(is_preview: bool) -> CliResult<()> {
}

println!("Downloading the containers required to run System Initiative");
download_missing_containers(missing_containers).await?;
docker
.download_missing_containers(missing_containers)
.await?;

Ok(())
}
11 changes: 6 additions & 5 deletions lib/si-cli/src/cmd/restart.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
use crate::containers::DockerClient;
use crate::key_management::get_user_email;
use crate::state::AppState;
use crate::CliResult;

impl AppState {
pub async fn restart(&self) -> CliResult<()> {
pub async fn restart(&self, docker: &DockerClient) -> CliResult<()> {
self.track(
get_user_email().await?,
serde_json::json!({"command-name": "restart-system"}),
);
invoke(self).await?;
invoke(self, docker).await?;
Ok(())
}
}

async fn invoke(app: &AppState) -> CliResult<()> {
app.stop().await?;
app.start().await?;
async fn invoke(app: &AppState, docker: &DockerClient) -> CliResult<()> {
app.stop(docker).await?;
app.start(docker).await?;

Ok(())
}
51 changes: 33 additions & 18 deletions lib/si-cli/src/cmd/start.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
use crate::containers::get_existing_container;
use crate::containers::DockerClient;
use crate::key_management::{
ensure_encryption_keys, ensure_jwt_public_signing_key, format_credentials_for_veritech,
get_si_data_dir, get_user_email,
};
use crate::state::AppState;
use crate::{CliResult, CONTAINER_NAMES};
use docker_api::opts::{ContainerCreateOpts, HostPort, PublishPort};
use docker_api::Docker;

impl AppState {
pub async fn start(&self) -> CliResult<()> {
pub async fn start(&self, docker: &DockerClient) -> CliResult<()> {
self.track(
get_user_email().await?,
serde_json::json!({"command-name": "start-system"}),
);
invoke(self, self.is_preview()).await?;
invoke(self, docker, self.is_preview()).await?;
Ok(())
}
}

async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
async fn invoke(app: &AppState, docker: &DockerClient, is_preview: bool) -> CliResult<()> {
app.configure(false).await?;
app.check(false).await?;
app.install().await?;

let docker = Docker::unix("//var/run/docker.sock");
app.check(docker, false).await?;
app.install(docker).await?;

if is_preview {
println!("Started the following containers:");
Expand All @@ -38,7 +35,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
let container = format!("systeminit/{0}", name);
let container_name = format!("local-{0}-1", name);
if container == "systeminit/otelcol" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -77,7 +76,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/jaeger" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -115,7 +116,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/nats" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -153,7 +156,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/postgres" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -196,7 +201,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/council" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -237,7 +244,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/veritech" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -282,7 +291,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/pinga" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -330,7 +341,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/sdf" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down Expand Up @@ -388,7 +401,9 @@ async fn invoke(app: &AppState, is_preview: bool) -> CliResult<()> {
container.start().await?;
}
if container == "systeminit/web" {
let container_summary = get_existing_container(&docker, container_name.clone()).await?;
let container_summary = docker
.get_existing_container(container_name.clone())
.await?;
if let Some(existing) = container_summary {
// it means we have an existing container
// If it's running, we have nothing to do here
Expand Down
Loading

0 comments on commit f103859

Please sign in to comment.