1
0
Fork 0
mirror of https://codeberg.org/icewind/haze.git synced 2026-06-03 17:14:08 +02:00
This commit is contained in:
Robin Appelman 2022-01-11 17:22:51 +01:00
commit 701d3b2a82
20 changed files with 303 additions and 172 deletions

213
Cargo.lock generated
View file

@ -37,6 +37,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@ -176,37 +187,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"textwrap", "textwrap 0.11.0",
"unicode-width", "unicode-width",
] ]
[[package]]
name = "color-eyre"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"tracing-error",
]
[[package]]
name = "color-spantrace"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1"
dependencies = [
"once_cell",
"owo-colors",
"tracing-core",
"tracing-error",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.2.1" version = "1.2.1"
@ -309,16 +293,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "eyre"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b"
dependencies = [
"indenter",
"once_cell",
]
[[package]] [[package]]
name = "filetime" name = "filetime"
version = "0.2.15" version = "0.2.15"
@ -465,12 +439,12 @@ dependencies = [
"async-trait", "async-trait",
"bollard", "bollard",
"camino", "camino",
"color-eyre",
"directories-next", "directories-next",
"enum_dispatch", "enum_dispatch",
"flate2", "flate2",
"futures-util", "futures-util",
"maplit", "maplit",
"miette",
"opener", "opener",
"parse-display", "parse-display",
"petname", "petname",
@ -585,12 +559,6 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.7.0" version = "1.7.0"
@ -607,6 +575,12 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.9.0" version = "0.9.0"
@ -670,6 +644,36 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "miette"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd2adcfcced5d625bf90a958a82ae5b93231f57f3df1383fee28c9b5096d35ed"
dependencies = [
"atty",
"backtrace",
"miette-derive",
"once_cell",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"terminal_size",
"textwrap 0.14.2",
"thiserror",
]
[[package]]
name = "miette-derive"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c01a8b61312d367ce87956bb686731f87e4c6dd5dbc550e8f06e3c24fb1f67f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.16" version = "0.3.16"
@ -779,9 +783,9 @@ dependencies = [
[[package]] [[package]]
name = "owo-colors" name = "owo-colors"
version = "1.3.0" version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4"
[[package]] [[package]]
name = "parse-display" name = "parse-display"
@ -1101,21 +1105,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.4" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
[[package]]
name = "smawk"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.2" version = "0.4.2"
@ -1155,6 +1156,34 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "supports-color"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4872ced36b91d47bae8a214a683fe54e7078875b399dfa251df346c9b547d1f9"
dependencies = [
"atty",
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
dependencies = [
"atty",
]
[[package]]
name = "supports-unicode"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2"
dependencies = [
"atty",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.80" version = "1.0.80"
@ -1177,6 +1206,16 @@ dependencies = [
"xattr", "xattr",
] ]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "termion" name = "termion"
version = "1.5.6" version = "1.5.6"
@ -1198,6 +1237,17 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.30" version = "1.0.30"
@ -1218,15 +1268,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" version = "0.1.43"
@ -1317,21 +1358,9 @@ checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"pin-project-lite", "pin-project-lite",
"tracing-attributes",
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-attributes"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.21" version = "0.1.21"
@ -1341,27 +1370,6 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "tracing-error"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-subscriber"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71"
dependencies = [
"sharded-slab",
"thread_local",
"tracing-core",
]
[[package]] [[package]]
name = "try-lock" name = "try-lock"
version = "0.2.3" version = "0.2.3"
@ -1374,6 +1382,15 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-linebreak"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
version = "0.1.19" version = "0.1.19"

View file

@ -9,7 +9,6 @@ description = "Easy setup and management of Nextcloud test instances using docke
[dependencies] [dependencies]
bollard = { version = "0.11" } bollard = { version = "0.11" }
color-eyre = "0.5"
maplit = "1" maplit = "1"
camino = { version = "1", features = ["serde1"] } camino = { version = "1", features = ["serde1"] }
tokio = { version = "1" , features = ["fs", "macros"] } tokio = { version = "1" , features = ["fs", "macros"] }
@ -26,6 +25,7 @@ tar = "0.4"
flate2 = "1" flate2 = "1"
async-trait = "0.1" async-trait = "0.1"
enum_dispatch = "0.3" enum_dispatch = "0.3"
miette = { version = "3", features = ["fancy"] }
[profile.release] [profile.release]
lto = true lto = true

View file

@ -21,7 +21,9 @@ RUN DEBIAN_FRONTEND=noninteractive ;\
unzip awscliv2.zip && \ unzip awscliv2.zip && \
./aws/install && \ ./aws/install && \
pip3 install awscli-plugin-endpoint && \ pip3 install awscli-plugin-endpoint && \
wget https://phar.phpunit.de/phpunit-8.phar -O /usr/local/bin/phpunit.phar wget https://phar.phpunit.de/phpunit-8.phar -O /usr/local/bin/phpunit.phar && \
curl -L https://github.com/harness/drone-cli/releases/latest/download/drone_linux_amd64.tar.gz | tar zx && \
install -t /usr/bin drone
ADD configs/autoconfig_mariadb.php configs/autoconfig_mysql.php configs/autoconfig_pgsql.php configs/autoconfig_oci.php configs/s3.php configs/s3mb.php configs/swift.php configs/swiftv3.php configs/azure.php configs/config.php /root/ ADD configs/autoconfig_mariadb.php configs/autoconfig_mysql.php configs/autoconfig_pgsql.php configs/autoconfig_oci.php configs/s3.php configs/s3mb.php configs/swift.php configs/swiftv3.php configs/azure.php configs/config.php /root/
ADD configs/nginx-app.conf /etc/nginx/ ADD configs/nginx-app.conf /etc/nginx/

View file

@ -1,6 +1,6 @@
use crate::cloud::CloudOptions; use crate::cloud::CloudOptions;
use crate::service::{Service, ServiceTrait}; use crate::service::{Service, ServiceTrait};
use color_eyre::{Report, Result}; use miette::{IntoDiagnostic, Report, Result};
use parse_display::Display; use parse_display::Display;
use std::fmt::Display; use std::fmt::Display;
use std::str::FromStr; use std::str::FromStr;
@ -178,7 +178,11 @@ impl HazeArgs {
Ok(HazeArgs::Logs { Ok(HazeArgs::Logs {
filter, filter,
service, service,
count: args.next().map(|arg| arg.as_ref().parse()).transpose()?, count: args
.next()
.map(|arg| arg.as_ref().parse())
.transpose()
.into_diagnostic()?,
}) })
} }
HazeCommand::Open => Ok(HazeArgs::Open { filter }), HazeCommand::Open => Ok(HazeArgs::Open { filter }),

View file

@ -10,9 +10,9 @@ use bollard::models::ContainerState;
use bollard::network::CreateNetworkOptions; use bollard::network::CreateNetworkOptions;
use bollard::Docker; use bollard::Docker;
use camino::Utf8PathBuf; use camino::Utf8PathBuf;
use color_eyre::{eyre::WrapErr, Report, Result};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use futures_util::future::try_join_all; use futures_util::future::try_join_all;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use petname::petname; use petname::petname;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
@ -167,6 +167,7 @@ impl Cloud {
if !options.app_packages.is_empty() { if !options.app_packages.is_empty() {
create_dir_all(&app_package_dir) create_dir_all(&app_package_dir)
.await .await
.into_diagnostic()
.wrap_err("Failed to create directory for app packages")?; .wrap_err("Failed to create directory for app packages")?;
} }
@ -178,13 +179,15 @@ impl Cloud {
let app_dir = app_package_dir.join(app_name); let app_dir = app_package_dir.join(app_name);
let app_package_file = fs::File::open(&app_package) let app_package_file = fs::File::open(&app_package)
.into_diagnostic()
.wrap_err_with(|| format!("Failed to open app bundle {}", app_package))?; .wrap_err_with(|| format!("Failed to open app bundle {}", app_package))?;
if app_package.metadata()?.len() > 1024 * 1024 { if app_package.metadata().into_diagnostic()?.len() > 1024 * 1024 {
println!("Extracting app archive for {}...", app_name); println!("Extracting app archive for {}...", app_name);
} }
let gz = GzDecoder::new(app_package_file); let gz = GzDecoder::new(app_package_file);
tar::Archive::new(gz) tar::Archive::new(gz)
.unpack(&app_package_dir) .unpack(&app_package_dir)
.into_diagnostic()
.wrap_err_with(|| format!("Failed to extract app bundle {}", app_package))?; .wrap_err_with(|| format!("Failed to extract app bundle {}", app_package))?;
Ok(HazeVolumeConfig { Ok(HazeVolumeConfig {
@ -214,12 +217,16 @@ impl Cloud {
name: id.as_str(), name: id.as_str(),
..Default::default() ..Default::default()
}) })
.await? .await
.into_diagnostic()?
.id .id
.ok_or(Report::msg("No network id in response")) .ok_or(Report::msg("No network id in response"))
.wrap_err("Failed to create network")?; .wrap_err("Failed to create network")?;
let network_info = docker.inspect_network::<String>(&network, None).await?; let network_info = docker
.inspect_network::<String>(&network, None)
.await
.into_diagnostic()?;
let gateway = network_info let gateway = network_info
.ipam .ipam
.as_ref() .as_ref()
@ -234,7 +241,7 @@ impl Cloud {
let mut containers = Vec::new(); let mut containers = Vec::new();
let sources_meta = fs::metadata(&config.sources_root)?; let sources_meta = fs::metadata(&config.sources_root).into_diagnostic()?;
let uid = sources_meta.uid(); let uid = sources_meta.uid();
let gid = sources_meta.gid(); let gid = sources_meta.gid();
@ -293,7 +300,10 @@ impl Cloud {
let mut tries = 0; let mut tries = 0;
let ip = loop { let ip = loop {
let info = docker.inspect_container(&container, None).await?; let info = docker
.inspect_container(&container, None)
.await
.into_diagnostic()?;
if matches!( if matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {
@ -375,15 +385,18 @@ impl Cloud {
}), }),
) )
.await .await
.into_diagnostic()
.wrap_err("Failed to remove container")?; .wrap_err("Failed to remove container")?;
} }
docker docker
.remove_network(&self.network) .remove_network(&self.network)
.await .await
.into_diagnostic()
.wrap_err("Failed to remove network")?; .wrap_err("Failed to remove network")?;
if self.workdir.exists() { if self.workdir.exists() {
if let Err(e) = remove_dir_all(self.workdir) if let Err(e) = remove_dir_all(self.workdir)
.await .await
.into_diagnostic()
.wrap_err("Failed to remove work directory") .wrap_err("Failed to remove work directory")
{ {
eprintln!("{}", e); eprintln!("{}", e);
@ -435,7 +448,8 @@ impl Cloud {
all: true, all: true,
..Default::default() ..Default::default()
})) }))
.await?; .await
.into_diagnostic()?;
let mut containers_by_id: HashMap<String, (Option<_>, Vec<_>)> = HashMap::new(); let mut containers_by_id: HashMap<String, (Option<_>, Vec<_>)> = HashMap::new();
for container in containers { for container in containers {
let labels = container.labels.clone().unwrap_or_default(); let labels = container.labels.clone().unwrap_or_default();

View file

@ -1,6 +1,6 @@
use camino::Utf8PathBuf; use camino::Utf8PathBuf;
use color_eyre::{eyre::WrapErr, Report, Result};
use directories_next::ProjectDirs; use directories_next::ProjectDirs;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use serde::Deserialize; use serde::Deserialize;
use std::fs::read; use std::fs::read;
@ -66,7 +66,11 @@ impl HazeConfig {
file.to_string_lossy() file.to_string_lossy()
))); )));
} }
let content = read(&file).wrap_err("Failed to read config file")?; let content = read(&file)
toml::from_slice(&content).wrap_err("Failed to parse config file") .into_diagnostic()
.wrap_err("Failed to read config file")?;
toml::from_slice(&content)
.into_diagnostic()
.wrap_err("Failed to parse config file")
} }
} }

View file

@ -3,8 +3,8 @@ use crate::image::pull_image;
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig}; use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{EndpointSettings, HostConfig}; use bollard::models::{EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Report, Result};
use maplit::hashmap; use maplit::hashmap;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use std::io::{stdout, Stdout}; use std::io::{stdout, Stdout};
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
@ -208,8 +208,15 @@ impl Database {
}, },
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(Some(id)) Ok(Some(id))
} }
@ -280,6 +287,7 @@ impl Database {
Ok(()) Ok(())
}) })
.await .await
.into_diagnostic()
.wrap_err("Timeout after 15 seconds")? .wrap_err("Timeout after 15 seconds")?
} }
@ -297,7 +305,7 @@ impl Database {
Some(&mut output), Some(&mut output),
) )
.await?; .await?;
let output = String::from_utf8(output)?; let output = String::from_utf8(output).into_diagnostic()?;
Ok(!output.contains("ERROR")) Ok(!output.contains("ERROR"))
} }
DatabaseFamily::Postgres => { DatabaseFamily::Postgres => {

View file

@ -1,8 +1,8 @@
use bollard::container::LogsOptions; use bollard::container::LogsOptions;
use bollard::exec::{CreateExecOptions, ResizeExecOptions, StartExecResults}; use bollard::exec::{CreateExecOptions, ResizeExecOptions, StartExecResults};
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Report, Result};
use futures_util::StreamExt; use futures_util::StreamExt;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use std::io::{stdout, Read, Write}; use std::io::{stdout, Read, Write};
use std::time::Duration; use std::time::Duration;
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
@ -24,7 +24,7 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>>(
return exec(docker, container, user, cmd, env, Some(stdout)).await; return exec(docker, container, user, cmd, env, Some(stdout)).await;
} }
let tty_size = terminal_size()?; let tty_size = terminal_size().into_diagnostic()?;
let cmd = cmd.into_iter().map(S2::into).collect(); let cmd = cmd.into_iter().map(S2::into).collect();
let env = env.into_iter().map(String::from).collect(); let env = env.into_iter().map(String::from).collect();
let config = CreateExecOptions { let config = CreateExecOptions {
@ -40,6 +40,7 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>>(
let message = docker let message = docker
.create_exec(container.as_ref(), config) .create_exec(container.as_ref(), config)
.await .await
.into_diagnostic()
.wrap_err("Failed to setup exec")?; .wrap_err("Failed to setup exec")?;
if let StartExecResults::Attached { if let StartExecResults::Attached {
mut output, mut output,
@ -47,6 +48,7 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>>(
} = docker } = docker
.start_exec(&message.id, None) .start_exec(&message.id, None)
.await .await
.into_diagnostic()
.wrap_err("Failed to start exec")? .wrap_err("Failed to start exec")?
{ {
docker docker
@ -73,12 +75,14 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>>(
}); });
// set stdout in raw mode so we can do tty stuff // set stdout in raw mode so we can do tty stuff
let mut stdout = stdout.lock().into_raw_mode()?; let mut stdout = stdout.lock().into_raw_mode().into_diagnostic()?;
// pipe docker exec output into stdout // pipe docker exec output into stdout
while let Some(Ok(output)) = output.next().await { while let Some(Ok(output)) = output.next().await {
stdout.write(output.into_bytes().as_ref())?; stdout
stdout.flush()?; .write(output.into_bytes().as_ref())
.into_diagnostic()?;
stdout.flush().into_diagnostic()?;
} }
} else { } else {
unreachable!(); unreachable!();
@ -86,7 +90,8 @@ pub async fn exec_tty<S1: AsRef<str>, S2: Into<String>>(
Ok(docker Ok(docker
.inspect_exec(&message.id) .inspect_exec(&message.id)
.await? .await
.into_diagnostic()?
.exit_code .exit_code
.unwrap_or_default() .unwrap_or_default()
.into()) .into())
@ -114,15 +119,17 @@ pub async fn exec<S1: AsRef<str>, S2: Into<String>>(
let message = docker let message = docker
.create_exec(container.as_ref(), config) .create_exec(container.as_ref(), config)
.await .await
.into_diagnostic()
.wrap_err("Failed to setup exec")?; .wrap_err("Failed to setup exec")?;
if let StartExecResults::Attached { mut output, .. } = docker if let StartExecResults::Attached { mut output, .. } = docker
.start_exec(&message.id, None) .start_exec(&message.id, None)
.await .await
.into_diagnostic()
.wrap_err("Failed to start exec")? .wrap_err("Failed to start exec")?
{ {
while let Some(Ok(line)) = output.next().await { while let Some(Ok(line)) = output.next().await {
if let Some(std_out) = &mut std_out { if let Some(std_out) = &mut std_out {
write!(std_out, "{}", line)?; write!(std_out, "{}", line).into_diagnostic()?;
} }
} }
} else { } else {
@ -131,7 +138,8 @@ pub async fn exec<S1: AsRef<str>, S2: Into<String>>(
Ok(docker Ok(docker
.inspect_exec(&message.id) .inspect_exec(&message.id)
.await? .await
.into_diagnostic()?
.exit_code .exit_code
.unwrap_or_default() .unwrap_or_default()
.into()) .into())
@ -149,7 +157,7 @@ pub async fn container_logs(docker: &Docker, container: &str, count: usize) -> R
}), }),
); );
while let Some(line) = stream.next().await { while let Some(line) = stream.next().await {
logs.push(line?.to_string()); logs.push(line.into_diagnostic()?.to_string());
} }
Ok(logs) Ok(logs)
} }

View file

@ -1,8 +1,8 @@
use bollard::image::CreateImageOptions; use bollard::image::CreateImageOptions;
use bollard::models::CreateImageInfo; use bollard::models::CreateImageInfo;
use bollard::Docker; use bollard::Docker;
use color_eyre::Result;
use futures_util::StreamExt; use futures_util::StreamExt;
use miette::{IntoDiagnostic, Result};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::stdout; use std::io::stdout;
use std::io::Write; use std::io::Write;
@ -29,7 +29,7 @@ pub async fn pull_image(docker: &Docker, image: &str) -> Result<()> {
let mut stdout = stdout(); let mut stdout = stdout();
while let Some(info) = info_stream.next().await { while let Some(info) = info_stream.next().await {
let info: CreateImageInfo = info?; let info: CreateImageInfo = info.into_diagnostic()?;
// dbg!(&info); // dbg!(&info);
if let (Some(id), Some(status), Some(progress)) = (info.id, info.status, info.progress) if let (Some(id), Some(status), Some(progress)) = (info.id, info.status, info.progress)
{ {
@ -45,14 +45,16 @@ pub async fn pull_image(docker: &Docker, image: &str) -> Result<()> {
status, status,
progress, progress,
cursor::Restore cursor::Restore
)?; )
.into_diagnostic()?;
} }
None => { None => {
writeln!(stdout, "{} - {:12} {}", id, status, progress)?; writeln!(stdout, "{} - {:12} {}", id, status, progress)
.into_diagnostic()?;
bars.insert(id, bars.len() as u16); bars.insert(id, bars.len() as u16);
} }
} }
stdout.flush()?; stdout.flush().into_diagnostic()?;
} }
} }
} }

View file

@ -7,7 +7,7 @@ use crate::php::PhpVersion;
use crate::service::Service; use crate::service::Service;
use crate::service::ServiceTrait; use crate::service::ServiceTrait;
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Result}; use miette::{IntoDiagnostic, Result, WrapErr};
mod args; mod args;
mod cloud; mod cloud;
@ -22,8 +22,11 @@ mod service;
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let mut docker = miette::set_panic_hook();
Docker::connect_with_local_defaults().wrap_err("Failed to connect to docker")?;
let mut docker = Docker::connect_with_local_defaults()
.into_diagnostic()
.wrap_err("Failed to connect to docker")?;
let config = HazeConfig::load().wrap_err("Failed to load config")?; let config = HazeConfig::load().wrap_err("Failed to load config")?;
let args = HazeArgs::parse(std::env::args())?; let args = HazeArgs::parse(std::env::args())?;
@ -212,7 +215,7 @@ async fn main() -> Result<()> {
HazeArgs::Open { filter } => { HazeArgs::Open { filter } => {
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?; let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
match cloud.ip { match cloud.ip {
Some(ip) => opener::open(format!("http://{}", ip))?, Some(ip) => opener::open(format!("http://{}", ip)).into_diagnostic()?,
None => eprintln!("{} is not running", cloud.id), None => eprintln!("{} is not running", cloud.id),
} }
} }

View file

@ -1,6 +1,6 @@
use crate::config::{HazeConfig, HazeVolumeConfig}; use crate::config::{HazeConfig, HazeVolumeConfig};
use camino::Utf8Path; use camino::Utf8Path;
use color_eyre::Result; use miette::{IntoDiagnostic, Result};
use tokio::fs::{create_dir_all, write}; use tokio::fs::{create_dir_all, write};
#[derive(Debug)] #[derive(Debug)]
@ -71,8 +71,8 @@ impl<'a> Mapping<'a> {
MappingSourceType::Absolute => self.source.into(), MappingSourceType::Absolute => self.source.into(),
}; };
match self.mapping_type { match self.mapping_type {
MappingType::Folder => create_dir_all(source).await?, MappingType::Folder => create_dir_all(source).await.into_diagnostic()?,
MappingType::File => write(source, "").await?, MappingType::File => write(source, "").await.into_diagnostic()?,
} }
Ok(()) Ok(())
@ -151,6 +151,7 @@ pub fn default_mappings<'a>() -> impl IntoIterator<Item = Mapping<'a>> {
Mapping::new(Sources, ".htaccess", "/var/www/html/.htaccess") Mapping::new(Sources, ".htaccess", "/var/www/html/.htaccess")
.file() .file()
.read_only(), .read_only(),
Mapping::new(Absolute, "/var/run/docker.sock", "/var/run/docker.sock"),
]; ];
IntoIterator::into_iter(mappings) IntoIterator::into_iter(mappings)
} }

View file

@ -1,11 +1,12 @@
use bollard::network::CreateNetworkOptions; use bollard::network::CreateNetworkOptions;
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Result}; use miette::{IntoDiagnostic, Result, WrapErr};
pub async fn clear_networks(docker: &Docker) -> Result<()> { pub async fn clear_networks(docker: &Docker) -> Result<()> {
let networks = docker let networks = docker
.list_networks::<&str>(None) .list_networks::<&str>(None)
.await .await
.into_diagnostic()
.wrap_err("Failed to list docker networks")?; .wrap_err("Failed to list docker networks")?;
for network in networks { for network in networks {
match network.name.as_deref() { match network.name.as_deref() {
@ -13,6 +14,7 @@ pub async fn clear_networks(docker: &Docker) -> Result<()> {
docker docker
.remove_network(name) .remove_network(name)
.await .await
.into_diagnostic()
.wrap_err("Failed to remove docker network")?; .wrap_err("Failed to remove docker network")?;
} }
_ => {} _ => {}
@ -25,6 +27,7 @@ async fn get_network_id(docker: &Docker, name: &str) -> Result<Option<String>> {
let networks = docker let networks = docker
.list_networks::<&str>(None) .list_networks::<&str>(None)
.await .await
.into_diagnostic()
.wrap_err("Failed to list docker networks")?; .wrap_err("Failed to list docker networks")?;
Ok(networks.into_iter().find_map(|network| { Ok(networks.into_iter().find_map(|network| {
if network.name.as_deref() == Some(name) { if network.name.as_deref() == Some(name) {
@ -45,7 +48,8 @@ pub async fn ensure_network_exists(docker: &Docker, name: &str) -> Result<String
check_duplicate: true, check_duplicate: true,
..Default::default() ..Default::default()
}) })
.await? .await
.into_diagnostic()?
.id .id
.unwrap()) .unwrap())
} }

View file

@ -5,8 +5,8 @@ use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{EndpointSettings, HostConfig}; use bollard::models::{EndpointSettings, HostConfig};
use bollard::network::ConnectNetworkOptions; use bollard::network::ConnectNetworkOptions;
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Report, Result};
use maplit::hashmap; use maplit::hashmap;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use reqwest::{Client, Url}; use reqwest::{Client, Url};
use std::net::IpAddr; use std::net::IpAddr;
use std::str::FromStr; use std::str::FromStr;
@ -103,8 +103,15 @@ impl PhpVersion {
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
docker docker
.connect_network( .connect_network(
@ -117,7 +124,8 @@ impl PhpVersion {
}, },
}, },
) )
.await?; .await
.into_diagnostic()?;
Ok(id) Ok(id)
} }
@ -127,13 +135,15 @@ impl PhpVersion {
let url = Url::parse(&format!( let url = Url::parse(&format!(
"http://{}/status.php", "http://{}/status.php",
ip.ok_or(Report::msg("Container not running"))? ip.ok_or(Report::msg("Container not running"))?
))?; ))
.into_diagnostic()?;
timeout(Duration::from_secs(5), async { timeout(Duration::from_secs(5), async {
while !client.get(url.clone()).send().await.is_ok() { while !client.get(url.clone()).send().await.is_ok() {
sleep(Duration::from_millis(100)).await sleep(Duration::from_millis(100)).await
} }
}) })
.await .await
.into_diagnostic()
.wrap_err("Timeout after 5 seconds") .wrap_err("Timeout after 5 seconds")
} }
} }

View file

@ -14,8 +14,8 @@ pub use crate::service::push::NotifyPush;
use crate::service::smb::Smb; use crate::service::smb::Smb;
use bollard::models::ContainerState; use bollard::models::ContainerState;
use bollard::Docker; use bollard::Docker;
use color_eyre::{eyre::WrapErr, Result};
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use miette::{IntoDiagnostic, Result, WrapErr};
use std::time::Duration; use std::time::Duration;
use tokio::time::{sleep, timeout}; use tokio::time::{sleep, timeout};
@ -39,7 +39,8 @@ pub trait ServiceTrait {
async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> { async fn is_healthy(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
let info = docker let info = docker
.inspect_container(&self.container_name(cloud_id), None) .inspect_container(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
Ok(matches!( Ok(matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {
@ -98,6 +99,7 @@ impl Service {
Ok(()) Ok(())
}) })
.await .await
.into_diagnostic()
.wrap_err("Timeout after 30 seconds")? .wrap_err("Timeout after 30 seconds")?
} }
} }

View file

@ -6,8 +6,8 @@ use crate::Result;
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig}; use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{EndpointSettings, HostConfig}; use bollard::models::{EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use color_eyre::eyre::eyre;
use maplit::hashmap; use maplit::hashmap;
use miette::{bail, IntoDiagnostic};
use std::io::Stdout; use std::io::Stdout;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -32,7 +32,7 @@ impl ServiceTrait for Kaspersky {
) -> Result<String> { ) -> Result<String> {
let image = "kaspersky"; let image = "kaspersky";
if !image_exists(docker, image).await { if !image_exists(docker, image).await {
eyre!("You need to manually create the 'kaspersky' image"); bail!("You need to manually create the 'kaspersky' image");
} }
pull_image(docker, image).await?; pull_image(docker, image).await?;
let options = Some(CreateContainerOptions { let options = Some(CreateContainerOptions {
@ -58,8 +58,15 @@ impl ServiceTrait for Kaspersky {
}), }),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }

View file

@ -5,8 +5,8 @@ use crate::Result;
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig}; use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{ContainerState, EndpointSettings, HostConfig}; use bollard::models::{ContainerState, EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use color_eyre::Report;
use maplit::hashmap; use maplit::hashmap;
use miette::{IntoDiagnostic, Report};
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct LDAP; pub struct LDAP;
@ -55,8 +55,15 @@ impl ServiceTrait for LDAP {
cmd: Some(vec!["--copy-service"]), cmd: Some(vec!["--copy-service"]),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }
@ -116,8 +123,15 @@ impl ServiceTrait for LDAPAdmin {
cmd: Some(vec!["--copy-service"]), cmd: Some(vec!["--copy-service"]),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }
@ -128,7 +142,8 @@ impl ServiceTrait for LDAPAdmin {
async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>> { async fn start_message(&self, docker: &Docker, cloud_id: &str) -> Result<Option<String>> {
let info = docker let info = docker
.inspect_container(&self.container_name(cloud_id), None) .inspect_container(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
let ip = if matches!( let ip = if matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {

View file

@ -7,6 +7,7 @@ use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{EndpointSettings, HostConfig}; use bollard::models::{EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use maplit::hashmap; use maplit::hashmap;
use miette::IntoDiagnostic;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum ObjectStore { pub enum ObjectStore {
@ -84,8 +85,15 @@ impl ServiceTrait for ObjectStore {
}), }),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }
@ -100,7 +108,7 @@ impl ServiceTrait for ObjectStore {
Some(&mut output), Some(&mut output),
) )
.await?; .await?;
let output = String::from_utf8(output)?; let output = String::from_utf8(output).into_diagnostic()?;
Ok(output.contains(r#""s3": "running""#)) Ok(output.contains(r#""s3": "running""#))
} }

View file

@ -5,8 +5,8 @@ use crate::Result;
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig}; use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{ContainerState, EndpointSettings, HostConfig}; use bollard::models::{ContainerState, EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use color_eyre::Report;
use maplit::hashmap; use maplit::hashmap;
use miette::{IntoDiagnostic, Report};
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct OnlyOffice; pub struct OnlyOffice;
@ -53,8 +53,15 @@ impl ServiceTrait for OnlyOffice {
}), }),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }
@ -69,7 +76,8 @@ impl ServiceTrait for OnlyOffice {
async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> { async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> {
let info = docker let info = docker
.inspect_container(&self.container_name(cloud_id), None) .inspect_container(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
let ip = if matches!( let ip = if matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {

View file

@ -1,13 +1,11 @@
use crate::config::HazeConfig; use crate::config::HazeConfig;
use crate::image::pull_image; use crate::image::pull_image;
use crate::service::ServiceTrait; use crate::service::ServiceTrait;
use crate::Result;
use bollard::container::{Config, CreateContainerOptions, NetworkingConfig}; use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{ContainerState, EndpointSettings, HostConfig}; use bollard::models::{ContainerState, EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use color_eyre::eyre::WrapErr;
use color_eyre::Report;
use maplit::hashmap; use maplit::hashmap;
use miette::{IntoDiagnostic, Report, Result, WrapErr};
use std::time::Duration; use std::time::Duration;
use tokio::time::{sleep, timeout}; use tokio::time::{sleep, timeout};
@ -66,7 +64,11 @@ impl ServiceTrait for NotifyPush {
cmd: Some(vec!["/notify_push", "/config/config.php"]), cmd: Some(vec!["/notify_push", "/config/config.php"]),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
.create_container(options, config)
.await
.into_diagnostic()?
.id;
Ok(id) Ok(id)
} }
@ -85,14 +87,16 @@ impl ServiceTrait for NotifyPush {
async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> { async fn post_setup(&self, docker: &Docker, cloud_id: &str) -> Result<Vec<String>> {
docker docker
.start_container::<String>(&self.container_name(cloud_id), None) .start_container::<String>(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
self.wait_for_push(docker, cloud_id).await?; self.wait_for_push(docker, cloud_id).await?;
sleep(Duration::from_millis(100)).await; sleep(Duration::from_millis(100)).await;
let info = docker let info = docker
.inspect_container(&self.container_name(cloud_id), None) .inspect_container(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
let ip = if matches!( let ip = if matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {
@ -124,7 +128,8 @@ impl NotifyPush {
async fn is_push_running(&self, docker: &Docker, cloud_id: &str) -> Result<bool> { async fn is_push_running(&self, docker: &Docker, cloud_id: &str) -> Result<bool> {
let info = docker let info = docker
.inspect_container(&self.container_name(cloud_id), None) .inspect_container(&self.container_name(cloud_id), None)
.await?; .await
.into_diagnostic()?;
Ok(matches!( Ok(matches!(
info.state, info.state,
Some(ContainerState { Some(ContainerState {
@ -142,6 +147,7 @@ impl NotifyPush {
Ok(()) Ok(())
}) })
.await .await
.into_diagnostic()
.wrap_err("Timeout after 30 seconds")? .wrap_err("Timeout after 30 seconds")?
} }
} }

View file

@ -6,6 +6,7 @@ use bollard::container::{Config, CreateContainerOptions, NetworkingConfig};
use bollard::models::{EndpointSettings, HostConfig}; use bollard::models::{EndpointSettings, HostConfig};
use bollard::Docker; use bollard::Docker;
use maplit::hashmap; use maplit::hashmap;
use miette::IntoDiagnostic;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Smb; pub struct Smb;
@ -57,8 +58,15 @@ impl ServiceTrait for Smb {
}), }),
..Default::default() ..Default::default()
}; };
let id = docker.create_container(options, config).await?.id; let id = docker
docker.start_container::<String>(&id, None).await?; .create_container(options, config)
.await
.into_diagnostic()?
.id;
docker
.start_container::<String>(&id, None)
.await
.into_diagnostic()?;
Ok(id) Ok(id)
} }