Compare commits

...

36 Commits

Author SHA1 Message Date
Quentin Dufour a259f820a4 wip apple+windows 2023-04-10 16:36:38 +02:00
Alex 703ac43f1c Merge pull request 'Prepare for v0.8.2' (#530) from prepare-v082 into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/530
2023-03-13 18:34:33 +00:00
Alex Auvolat 000006d689 obsolete clippy lints 2023-03-13 18:50:07 +01:00
Alex Auvolat 0a1ddcf630 Prepare for v0.8.2 2023-03-13 18:46:31 +01:00
Alex d6ffa57f40 Merge pull request 'Increase Garage tests robustness' (#526) from tests/increase-robustness into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/526
Reviewed-by: Alex <alex@adnab.me>
Reviewed-by: trinity-1686a <trinity.pointard@gmail.com>
2023-03-13 17:26:21 +00:00
Alex 7fcc153e7c Merge pull request 'rpc/system_metrics.rs: Added rustversion label to garage_build_info metric.' (#524) from jpds/garage:rustversion-label into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/524
2023-03-13 15:46:48 +00:00
Alex Auvolat f37ec584b6 Merge branch 'main' into rustversion-label 2023-03-13 16:14:13 +01:00
Jonathan Davies dc6be39833 doc: cli.md: Added s5cmd example. 2023-03-13 14:15:18 +00:00
Quentin Dufour 70b5424b99 use one key per context to isolate tests 2023-03-13 15:06:05 +01:00
Quentin Dufour 2687fb7fa8 do not assume Garage boots in 2sec during tests 2023-03-13 15:06:05 +01:00
Alex 24e43f1aa0 Merge pull request 'Bump pnet_datalink 0.28 -> 0.33' (#514) from teutat3s/garage:pnet_datalink-0.33.0 into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/514
2023-03-13 13:43:04 +00:00
teutat3s 8ad6efb338 Merge branch 'main' into pnet_datalink-0.33.0 2023-03-13 13:59:42 +01:00
Alex Auvolat 3b498c7c47 update cargo.nix 2023-03-13 13:59:02 +01:00
Alex Auvolat 40fa1242f0 update cargo.nix 2023-03-10 18:15:06 +01:00
Jonathan Davies 9ea154ae9c admin/cluster.rs: Added rust_version. 2023-03-10 14:46:54 +00:00
Jonathan Davies 4421378023 garage/admin.rs: Display Rust version in stats output. 2023-03-10 14:46:54 +00:00
Jonathan Davies 25f2a46fc3 rpc/system_metrics.rs: Added rustversion label to garage_build_info metric. 2023-03-10 14:46:44 +00:00
Alex 3325928c13 Merge pull request 'block/repair.rs: Added migration for ScrubWorkerPersisted's time_next_run_scrub.' (#523) from jpds/garage:migrate-scrubworkerpersisted into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/523
2023-03-10 13:25:01 +00:00
Jonathan Davies d218f475cb block/manager.rs: Set defaults for scrub_persister. 2023-03-09 17:08:47 +00:00
Jonathan Davies 7b65dd24e2 block/repair.rs: Added a timestamp argument to
randomize_next_scrub_run_time().
2023-03-09 16:38:41 +00:00
Jonathan Davies b70cc0a940 block/repair.rs: Added migration for ScrubWorkerPersisted's time_next_run_scrub.
Fixes: #520.
2023-03-09 16:38:36 +00:00
Alex 9e061d5a70 Merge pull request 'Update logo for stickers' (#521) from logo_autocollants into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/521
2023-03-08 13:14:46 +00:00
vincent db69267a56 MàJ logo pour autocollants 2023-03-07 21:34:55 +01:00
Alex 2dc80abbb1 Merge pull request 'block/repair.rs: Added a random element of 10 days to SCRUB_INTERVAL' (#516) from jpds/garage:scrub-randomize-window into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/516
2023-03-06 14:11:25 +00:00
Jonathan Davies 148b66b843 block/manager.rs: Display scrub-next-run. 2023-03-06 13:43:09 +00:00
Jonathan Davies 53d09eb00f block/repair.rs: Added function and time_next_run_scrub with a random element of
10 days to SCRUB_INTERVAL to help balance scrub load across cluster.
2023-03-06 13:43:04 +00:00
Alex 00dcfc97a5 Merge pull request 'web_server.rs: Log X-Forwarded-For IP' (#504) from jpds/garage:web_server-log-x-forwarded-for into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/504
2023-03-06 12:33:06 +00:00
Jonathan Davies 4e0fc3d6c9 web/web_server.rs: Handle X-Forwarded-For here too. 2023-03-06 11:43:54 +00:00
Jonathan Davies e4e5196066 api/generic_server.rs: Use new handle_forwarded_for_headers() function. 2023-03-06 11:43:35 +00:00
Alex 0d0906b066 Merge pull request 'Clearer error message when LMDB has oom error (fix #517)' (#519) from lmdb-oom-message into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/519
2023-03-06 10:49:04 +00:00
Alex Auvolat b8123fb6cd Clearer error message when LMDB has oom error (fix #517) 2023-03-06 11:38:49 +01:00
Alex 3d37be33a8 Merge pull request 'binary-packages.md: Added.' (#515) from jpds/garage:doc-binary-packages into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/515
2023-03-06 10:17:19 +00:00
Jonathan Davies ff70e09aa0 util/forwarded_headers.rs: Generalized handle_forwarded_for_headers()
here.
2023-03-03 19:17:40 +00:00
Jonathan Davies f056ad569d binary-packages.md: Added. 2023-03-03 18:52:49 +00:00
Alex a5f7a79250 Merge pull request 'Add documentation on community Ansible roles' (#513) from baptiste/garage:doc_ansible into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/513
2023-03-02 11:59:07 +00:00
Baptiste Jonglez 3b22da251d Add documentation on community Ansible roles 2023-03-01 09:24:13 +01:00
43 changed files with 704 additions and 229 deletions
Generated
+10 -9
View File
@@ -1075,7 +1075,7 @@ dependencies = [
[[package]]
name = "garage"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"assert-json-diff",
"async-trait",
@@ -1122,7 +1122,7 @@ dependencies = [
[[package]]
name = "garage_api"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"async-trait",
"base64 0.21.0",
@@ -1167,7 +1167,7 @@ dependencies = [
[[package]]
name = "garage_block"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"arc-swap",
"async-compression",
@@ -1192,7 +1192,7 @@ dependencies = [
[[package]]
name = "garage_db"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"clap 4.1.4",
"err-derive",
@@ -1207,7 +1207,7 @@ dependencies = [
[[package]]
name = "garage_model"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"arc-swap",
"async-trait",
@@ -1234,7 +1234,7 @@ dependencies = [
[[package]]
name = "garage_rpc"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"arc-swap",
"async-trait",
@@ -1265,7 +1265,7 @@ dependencies = [
[[package]]
name = "garage_table"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"arc-swap",
"async-trait",
@@ -1287,7 +1287,7 @@ dependencies = [
[[package]]
name = "garage_util"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"arc-swap",
"async-trait",
@@ -1309,6 +1309,7 @@ dependencies = [
"opentelemetry",
"rand",
"rmp-serde",
"rustc_version",
"serde",
"serde_json",
"sha2 0.10.6",
@@ -1320,7 +1321,7 @@ dependencies = [
[[package]]
name = "garage_web"
version = "0.8.1"
version = "0.8.2"
dependencies = [
"err-derive",
"futures",
+99 -76
View File
@@ -32,7 +32,7 @@ args@{
ignoreLockHash,
}:
let
nixifiedLockHash = "9941a539c374cfd67691e633af6c6a5da9e8badbb7b14159b3ff24a7cf5ddf8a";
nixifiedLockHash = "af19dd561f2ce73d1f609040c1ebdf74420974d96959016da98d44b0e347f013";
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
lockHashIgnored = if ignoreLockHash
@@ -56,15 +56,15 @@ in
{
cargo2nixVersion = "0.11.0";
workspace = {
garage_db = rustPackages.unknown.garage_db."0.8.1";
garage_util = rustPackages.unknown.garage_util."0.8.1";
garage_rpc = rustPackages.unknown.garage_rpc."0.8.1";
garage_table = rustPackages.unknown.garage_table."0.8.1";
garage_block = rustPackages.unknown.garage_block."0.8.1";
garage_model = rustPackages.unknown.garage_model."0.8.1";
garage_api = rustPackages.unknown.garage_api."0.8.1";
garage_web = rustPackages.unknown.garage_web."0.8.1";
garage = rustPackages.unknown.garage."0.8.1";
garage_db = rustPackages.unknown.garage_db."0.8.2";
garage_util = rustPackages.unknown.garage_util."0.8.2";
garage_rpc = rustPackages.unknown.garage_rpc."0.8.2";
garage_table = rustPackages.unknown.garage_table."0.8.2";
garage_block = rustPackages.unknown.garage_block."0.8.2";
garage_model = rustPackages.unknown.garage_model."0.8.2";
garage_api = rustPackages.unknown.garage_api."0.8.2";
garage_web = rustPackages.unknown.garage_web."0.8.2";
garage = rustPackages.unknown.garage."0.8.2";
k2v-client = rustPackages.unknown.k2v-client."0.1.1";
};
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.19.0" = overridableMkRustCrate (profileName: rec {
@@ -1531,9 +1531,9 @@ in
};
});
"unknown".garage."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/garage");
features = builtins.concatLists [
@@ -1559,14 +1559,14 @@ in
bytesize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytesize."1.1.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_api = (rustPackages."unknown".garage_api."0.8.1" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_web = (rustPackages."unknown".garage_web."0.8.1" { inherit profileName; }).out;
garage_api = (rustPackages."unknown".garage_api."0.8.2" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.2" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.2" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.2" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.2" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
garage_web = (rustPackages."unknown".garage_web."0.8.2" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
sodiumoxide = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".kuska-sodiumoxide."0.2.5-0" { inherit profileName; }).out;
netapp = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".netapp."0.5.2" { inherit profileName; }).out;
@@ -1599,9 +1599,9 @@ in
};
});
"unknown".garage_api."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_api."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_api";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/api");
features = builtins.concatLists [
@@ -1620,11 +1620,11 @@ in
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.1.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.2" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.2" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.2" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
hmac = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hmac."0.12.1" { inherit profileName; }).out;
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.8" { inherit profileName; }).out;
@@ -1653,9 +1653,9 @@ in
};
});
"unknown".garage_block."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_block."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_block";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/block");
features = builtins.concatLists [
@@ -1668,10 +1668,10 @@ in
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.3.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.2" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.2" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
@@ -1684,9 +1684,9 @@ in
};
});
"unknown".garage_db."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_db."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_db";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/db");
features = builtins.concatLists [
@@ -1716,9 +1716,9 @@ in
};
});
"unknown".garage_model."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_model."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_model";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/model");
features = builtins.concatLists [
@@ -1736,11 +1736,11 @@ in
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_block = (rustPackages."unknown".garage_block."0.8.2" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.2" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.2" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
netapp = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".netapp."0.5.2" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
@@ -1753,9 +1753,9 @@ in
};
});
"unknown".garage_rpc."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_rpc."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_rpc";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
features = builtins.concatLists [
@@ -1775,7 +1775,7 @@ in
${ if rootFeatures' ? "garage/consul-discovery" || rootFeatures' ? "garage_rpc/consul-discovery" || rootFeatures' ? "garage_rpc/err-derive" then "err_derive" else null } = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
gethostname = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".gethostname."0.2.3" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
${ if rootFeatures' ? "garage/kubernetes-discovery" || rootFeatures' ? "garage_rpc/k8s-openapi" || rootFeatures' ? "garage_rpc/kubernetes-discovery" then "k8s_openapi" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".k8s-openapi."0.16.0" { inherit profileName; }).out;
@@ -1783,7 +1783,7 @@ in
sodiumoxide = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".kuska-sodiumoxide."0.2.5-0" { inherit profileName; }).out;
netapp = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".netapp."0.5.2" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
pnet_datalink = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_datalink."0.28.0" { inherit profileName; }).out;
pnet_datalink = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_datalink."0.33.0" { inherit profileName; }).out;
rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
${ if rootFeatures' ? "garage/consul-discovery" || rootFeatures' ? "garage_rpc/consul-discovery" || rootFeatures' ? "garage_rpc/reqwest" then "reqwest" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".reqwest."0.11.14" { inherit profileName; }).out;
${ if rootFeatures' ? "garage/kubernetes-discovery" || rootFeatures' ? "garage_rpc/kubernetes-discovery" || rootFeatures' ? "garage_rpc/schemars" then "schemars" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".schemars."0.8.11" { inherit profileName; }).out;
@@ -1797,9 +1797,9 @@ in
};
});
"unknown".garage_table."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_table."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_table";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/table");
dependencies = {
@@ -1808,9 +1808,9 @@ in
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.3.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.25" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.1" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.2" { inherit profileName; }).out;
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
@@ -1822,9 +1822,9 @@ in
};
});
"unknown".garage_util."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_util."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_util";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/util");
features = builtins.concatLists [
@@ -1839,7 +1839,7 @@ in
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.6" { inherit profileName; }).out;
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.1" { inherit profileName; }).out;
garage_db = (rustPackages."unknown".garage_db."0.8.2" { inherit profileName; }).out;
git_version = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".git-version."0.3.5" { inherit profileName; }).out;
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
@@ -1861,20 +1861,23 @@ in
devDependencies = {
mktemp = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".mktemp."0.5.0" { inherit profileName; }).out;
};
buildDependencies = {
rustc_version = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".rustc_version."0.4.0" { profileName = "__noProfile"; }).out;
};
});
"unknown".garage_web."0.8.1" = overridableMkRustCrate (profileName: rec {
"unknown".garage_web."0.8.2" = overridableMkRustCrate (profileName: rec {
name = "garage_web";
version = "0.8.1";
version = "0.8.2";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/web");
dependencies = {
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.25" { inherit profileName; }).out;
garage_api = (rustPackages."unknown".garage_api."0.8.1" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.1" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.1" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
garage_api = (rustPackages."unknown".garage_api."0.8.2" { inherit profileName; }).out;
garage_model = (rustPackages."unknown".garage_model."0.8.2" { inherit profileName; }).out;
garage_table = (rustPackages."unknown".garage_table."0.8.2" { inherit profileName; }).out;
garage_util = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.8" { inherit profileName; }).out;
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.23" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
@@ -2420,11 +2423,11 @@ in
];
});
"registry+https://github.com/rust-lang/crates.io-index".ipnetwork."0.18.0" = overridableMkRustCrate (profileName: rec {
"registry+https://github.com/rust-lang/crates.io-index".ipnetwork."0.20.0" = overridableMkRustCrate (profileName: rec {
name = "ipnetwork";
version = "0.18.0";
version = "0.20.0";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "4088d739b183546b239688ddbc79891831df421773df95e236daf7867866d355"; };
src = fetchCratesIo { inherit name version; sha256 = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"; };
features = builtins.concatLists [
[ "default" ]
[ "serde" ]
@@ -2552,7 +2555,7 @@ in
dependencies = {
base64 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64."0.21.0" { inherit profileName; }).out;
${ if rootFeatures' ? "k2v-client/clap" || rootFeatures' ? "k2v-client/cli" then "clap" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".clap."4.1.4" { inherit profileName; }).out;
${ if rootFeatures' ? "k2v-client/cli" || rootFeatures' ? "k2v-client/garage_util" then "garage_util" else null } = (rustPackages."unknown".garage_util."0.8.1" { inherit profileName; }).out;
${ if rootFeatures' ? "k2v-client/cli" || rootFeatures' ? "k2v-client/garage_util" then "garage_util" else null } = (rustPackages."unknown".garage_util."0.8.2" { inherit profileName; }).out;
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.8" { inherit profileName; }).out;
hyper_rustls = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper-rustls."0.23.2" { inherit profileName; }).out;
log = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".log."0.4.17" { inherit profileName; }).out;
@@ -3102,6 +3105,16 @@ in
};
});
"registry+https://github.com/rust-lang/crates.io-index".no-std-net."0.6.0" = overridableMkRustCrate (profileName: rec {
name = "no-std-net";
version = "0.6.0";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65"; };
features = builtins.concatLists [
[ "std" ]
];
});
"registry+https://github.com/rust-lang/crates.io-index".nom."7.1.3" = overridableMkRustCrate (profileName: rec {
name = "nom";
version = "7.1.3";
@@ -3636,32 +3649,42 @@ in
src = fetchCratesIo { inherit name version; sha256 = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"; };
});
"registry+https://github.com/rust-lang/crates.io-index".pnet_base."0.28.0" = overridableMkRustCrate (profileName: rec {
"registry+https://github.com/rust-lang/crates.io-index".pnet_base."0.33.0" = overridableMkRustCrate (profileName: rec {
name = "pnet_base";
version = "0.28.0";
version = "0.33.0";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "25488cd551a753dcaaa6fffc9f69a7610a412dd8954425bf7ffad5f7d1156fb8"; };
src = fetchCratesIo { inherit name version; sha256 = "872e46346144ebf35219ccaa64b1dffacd9c6f188cd7d012bd6977a2a838f42e"; };
features = builtins.concatLists [
[ "std" ]
];
dependencies = {
no_std_net = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".no-std-net."0.6.0" { inherit profileName; }).out;
};
});
"registry+https://github.com/rust-lang/crates.io-index".pnet_datalink."0.28.0" = overridableMkRustCrate (profileName: rec {
"registry+https://github.com/rust-lang/crates.io-index".pnet_datalink."0.33.0" = overridableMkRustCrate (profileName: rec {
name = "pnet_datalink";
version = "0.28.0";
version = "0.33.0";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "d4d1f8ab1ef6c914cf51dc5dfe0be64088ea5f3b08bbf5a31abc70356d271198"; };
src = fetchCratesIo { inherit name version; sha256 = "c302da22118d2793c312a35fb3da6846cb0fab6c3ad53fd67e37809b06cdafce"; };
features = builtins.concatLists [
[ "default" ]
[ "std" ]
];
dependencies = {
ipnetwork = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ipnetwork."0.18.0" { inherit profileName; }).out;
ipnetwork = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ipnetwork."0.20.0" { inherit profileName; }).out;
libc = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.139" { inherit profileName; }).out;
pnet_base = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_base."0.28.0" { inherit profileName; }).out;
pnet_sys = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_sys."0.28.0" { inherit profileName; }).out;
pnet_base = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_base."0.33.0" { inherit profileName; }).out;
pnet_sys = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pnet_sys."0.33.0" { inherit profileName; }).out;
${ if hostPlatform.isWindows then "winapi" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".winapi."0.3.9" { inherit profileName; }).out;
};
});
"registry+https://github.com/rust-lang/crates.io-index".pnet_sys."0.28.0" = overridableMkRustCrate (profileName: rec {
"registry+https://github.com/rust-lang/crates.io-index".pnet_sys."0.33.0" = overridableMkRustCrate (profileName: rec {
name = "pnet_sys";
version = "0.28.0";
version = "0.33.0";
registry = "registry+https://github.com/rust-lang/crates.io-index";
src = fetchCratesIo { inherit name version; sha256 = "d9a3f32b0df45515befd19eed04616f6b56a488da92afc61164ef455e955f07f"; };
src = fetchCratesIo { inherit name version; sha256 = "faf7a58b2803d818a374be9278a1fe8f88fce14b936afbe225000cfcd9c73f16"; };
dependencies = {
libc = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.139" { inherit profileName; }).out;
${ if hostPlatform.isWindows then "winapi" else null } = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".winapi."0.3.9" { inherit profileName; }).out;
+7
View File
@@ -32,6 +32,13 @@ in {
i386 = build_debug_and_release "i686-unknown-linux-musl";
arm64 = build_debug_and_release "aarch64-unknown-linux-musl";
arm = build_debug_and_release "armv6l-unknown-linux-musleabihf";
win = {
amd64 = build_debug_and_release "x86_64-w64-mingw32";
};
apple = {
arm64 = build_debug_and_release "aarch64-apple-darwin";
amd64 = build_debug_and_release "x86_64-apple-darwin";
};
};
test = {
amd64 = test (compile {
+21
View File
@@ -12,6 +12,7 @@ These tools are particularly suitable for debug, backups, website deployments or
| [AWS CLI](#aws-cli) | ✅ | Recommended |
| [rclone](#rclone) | ✅ | |
| [s3cmd](#s3cmd) | ✅ | |
| [s5cmd](#s5cmd) | ✅ | |
| [(Cyber)duck](#cyberduck) | ✅ | |
| [WinSCP (libs3)](#winscp) | ✅ | CLI instructions only |
| [sftpgo](#sftpgo) | ✅ | |
@@ -178,6 +179,26 @@ s3cmd put /tmp/hello.txt s3://my-bucket/
s3cmd get s3://my-bucket/hello.txt hello.txt
```
## `s5cmd`
Configure a credentials file as follows:
```bash
export AWS_ACCESS_KEY_ID=GK...
export AWS_SECRET_ACCESS_KEY=
export AWS_DEFAULT_REGION='garage'
export AWS_ENDPOINT='http://localhost:3900'
```
After adding these environment variables in your shell, `s5cmd` can be used
with:
```bash
s5cmd --endpoint-url=$AWS_ENDPOINT ls
```
See its usage output for other commands available.
## Cyberduck & duck {#cyberduck}
Both Cyberduck (the GUI) and duck (the CLI) have a concept of "Connection Profiles" that contain some presets for a specific provider.
+9 -1
View File
@@ -6,7 +6,7 @@ sort_by = "weight"
+++
A cookbook, when you cook, is a collection of recipes.
Similarly, Garage's cookbook contains a collection of recipes that are known to works well!
Similarly, Garage's cookbook contains a collection of recipes that are known to work well!
This chapter could also be referred as "Tutorials" or "Best practices".
- **[Multi-node deployment](@/documentation/cookbook/real-world.md):** This page will walk you through all of the necessary
@@ -16,6 +16,10 @@ This chapter could also be referred as "Tutorials" or "Best practices".
source in case a binary is not provided for your architecture, or if you want to
hack with us!
- **[Binary packages](@/documentation/cookbook/binary-packages.md):** This page
lists the different platforms that provide ready-built software packages for
Garage.
- **[Integration with Systemd](@/documentation/cookbook/systemd.md):** This page explains how to run Garage
as a Systemd service (instead of as a Docker container).
@@ -26,6 +30,10 @@ This chapter could also be referred as "Tutorials" or "Best practices".
- **[Configuring a reverse-proxy](@/documentation/cookbook/reverse-proxy.md):** This page explains how to configure a reverse-proxy to add TLS support to your S3 api endpoint.
- **[Deploying on Kubernetes](@/documentation/cookbook/kubernetes.md):** This page explains how to deploy Garage on Kubernetes using our Helm chart.
- **[Deploying with Ansible](@/documentation/cookbook/ansible.md):** This page lists available Ansible roles developed by the community to deploy Garage.
- **[Monitoring Garage](@/documentation/cookbook/monitoring.md)** This page
explains the Prometheus metrics available for monitoring the Garage
cluster/nodes.
+51
View File
@@ -0,0 +1,51 @@
+++
title = "Deploying with Ansible"
weight = 35
+++
While Ansible is not officially supported to deploy Garage, several community members
have published Ansible roles. We list them and compare them below.
## Comparison of Ansible roles
| Feature | [ansible-role-garage](#zorun-ansible-role-garage) | [garage-docker-ansible-deploy](#moan0s-garage-docker-ansible-deploy) |
|------------------------------------|---------------------------------------------|---------------------------------------------------------------|
| **Runtime** | Systemd | Docker |
| **Target OS** | Any Linux | Any Linux |
| **Architecture** | amd64, arm64, i686 | amd64, arm64 |
| **Additional software** | None | Traefik |
| **Automatic node connection** | ❌ | ✅ |
| **Layout management** | ❌ | ✅ |
| **Manage buckets & keys** | ❌ | ✅ (basic) |
| **Allow custom Garage config** | ✅ | ❌ |
| **Facilitate Garage upgrades** | ✅ | ❌ |
| **Multiple instances on one host** | ✅ | ✅ |
## zorun/ansible-role-garage
[Source code](https://github.com/zorun/ansible-role-garage), [Ansible galaxy](https://galaxy.ansible.com/zorun/garage)
This role is voluntarily simple: it relies on the official Garage static
binaries and only requires Systemd. As such, it should work on any
Linux-based OS.
To make things more flexible, the user has to provide a Garage
configuration template. This allows to customize Garage configuration in
any way.
Some more features might be added, such as a way to automatically connect
nodes to each other or to define a layout.
## moan0s/garage-docker-ansible-deploy
[Source code](https://github.com/moan0s/garage-docker-ansible-deploy), [Blog post](https://hyteck.de/post/garage/)
This role is based on the Docker image for Garage, and comes with
"batteries included": it will additionally install Docker and Traefik. In
addition, it is "opinionated" in the sense that it expects a particular
deployment structure (one instance per disk, one gateway per host,
structured DNS names, etc).
As a result, this role makes it easier to start with Garage on Ansible,
but is less flexible.
+28
View File
@@ -0,0 +1,28 @@
+++
title = "Binary packages"
weight = 11
+++
Garage is also available in binary packages on:
## Alpine Linux
```bash
apk install garage
```
## Arch Linux
Garage is available in the [AUR](https://aur.archlinux.org/packages/garage).
## FreeBSD
```bash
pkg install garage
```
## NixOS
```bash
nix-shell -p garage
```
+181 -1
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 74 KiB

+6 -6
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_api"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,11 +14,11 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_model = { version = "0.8.1", path = "../model" }
garage_table = { version = "0.8.1", path = "../table" }
garage_block = { version = "0.8.1", path = "../block" }
garage_util = { version = "0.8.1", path = "../util" }
garage_rpc = { version = "0.8.1", path = "../rpc" }
garage_model = { version = "0.8.2", path = "../model" }
garage_table = { version = "0.8.2", path = "../table" }
garage_block = { version = "0.8.2", path = "../block" }
garage_util = { version = "0.8.2", path = "../util" }
garage_rpc = { version = "0.8.2", path = "../rpc" }
async-trait = "0.1.7"
base64 = "0.21"
+2
View File
@@ -20,6 +20,7 @@ pub async fn handle_get_cluster_status(garage: &Arc<Garage>) -> Result<Response<
node: hex::encode(garage.system.id),
garage_version: garage_util::version::garage_version(),
garage_features: garage_util::version::garage_features(),
rust_version: garage_util::version::rust_version(),
db_engine: garage.db.engine(),
known_nodes: garage
.system
@@ -106,6 +107,7 @@ struct GetClusterStatusResponse {
node: String,
garage_version: &'static str,
garage_features: Option<&'static [&'static str]>,
rust_version: &'static str,
db_engine: String,
known_nodes: HashMap<String, KnownNodeResp>,
layout: GetClusterLayoutResponse,
+4 -9
View File
@@ -19,6 +19,7 @@ use opentelemetry::{
};
use garage_util::error::Error as GarageError;
use garage_util::forwarded_headers;
use garage_util::metrics::{gen_trace_id, RecordDuration};
pub(crate) trait ApiEndpoint: Send + Sync + 'static {
@@ -126,15 +127,9 @@ impl<A: ApiHandler> ApiServer<A> {
) -> Result<Response<Body>, GarageError> {
let uri = req.uri().clone();
let has_forwarded_for_header = req.headers().contains_key("x-forwarded-for");
if has_forwarded_for_header {
let forwarded_for_ip_addr = &req
.headers()
.get("x-forwarded-for")
.expect("Could not parse X-Forwarded-For header")
.to_str()
.unwrap_or_default();
if let Ok(forwarded_for_ip_addr) =
forwarded_headers::handle_forwarded_for_headers(&req.headers())
{
info!(
"{} (via {}) {} {}",
forwarded_for_ip_addr,
+5 -5
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_block"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,10 +14,10 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_db = { version = "0.8.1", path = "../db" }
garage_rpc = { version = "0.8.1", path = "../rpc" }
garage_util = { version = "0.8.1", path = "../util" }
garage_table = { version = "0.8.1", path = "../table" }
garage_db = { version = "0.8.2", path = "../db" }
garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_util = { version = "0.8.2", path = "../util" }
garage_table = { version = "0.8.2", path = "../table" }
opentelemetry = "0.17"
+4
View File
@@ -152,6 +152,7 @@ impl BlockManager {
tx_scrub_command: ArcSwapOption::new(None),
});
block_manager.endpoint.set_handler(block_manager.clone());
block_manager.scrub_persister.set_with(|_| ()).unwrap();
block_manager
}
@@ -185,6 +186,9 @@ impl BlockManager {
vars.register_ro(&self.scrub_persister, "scrub-last-completed", |p| {
p.get_with(|x| msec_to_rfc3339(x.time_last_complete_scrub))
});
vars.register_ro(&self.scrub_persister, "scrub-next-run", |p| {
p.get_with(|x| msec_to_rfc3339(x.time_next_run_scrub))
});
vars.register_ro(&self.scrub_persister, "scrub-corruptions_detected", |p| {
p.get_with(|x| x.corruptions_detected)
});
+79 -18
View File
@@ -4,7 +4,7 @@ use std::sync::Arc;
use std::time::Duration;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use rand::Rng;
use tokio::fs;
use tokio::select;
use tokio::sync::mpsc;
@@ -19,8 +19,8 @@ use garage_util::tranquilizer::Tranquilizer;
use crate::manager::*;
// Full scrub every 30 days
const SCRUB_INTERVAL: Duration = Duration::from_secs(3600 * 24 * 30);
// Full scrub every 25 days with a random element of 10 days mixed in below
const SCRUB_INTERVAL: Duration = Duration::from_secs(3600 * 24 * 25);
// Scrub tranquility is initially set to 4, but can be changed in the CLI
// and the updated version is persisted over Garage restarts
const INITIAL_SCRUB_TRANQUILITY: u32 = 4;
@@ -161,6 +161,51 @@ impl Worker for RepairWorker {
// and whose parameter (esp. speed) can be controlled at runtime.
// ---- ---- ----
mod v081 {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ScrubWorkerPersisted {
pub tranquility: u32,
pub(crate) time_last_complete_scrub: u64,
pub(crate) corruptions_detected: u64,
}
impl garage_util::migrate::InitialFormat for ScrubWorkerPersisted {}
}
mod v082 {
use serde::{Deserialize, Serialize};
use super::v081;
#[derive(Serialize, Deserialize)]
pub struct ScrubWorkerPersisted {
pub tranquility: u32,
pub(crate) time_last_complete_scrub: u64,
pub(crate) time_next_run_scrub: u64,
pub(crate) corruptions_detected: u64,
}
impl garage_util::migrate::Migrate for ScrubWorkerPersisted {
type Previous = v081::ScrubWorkerPersisted;
const VERSION_MARKER: &'static [u8] = b"G082bswp";
fn migrate(old: v081::ScrubWorkerPersisted) -> ScrubWorkerPersisted {
use crate::repair::randomize_next_scrub_run_time;
ScrubWorkerPersisted {
tranquility: old.tranquility,
time_last_complete_scrub: old.time_last_complete_scrub,
time_next_run_scrub: randomize_next_scrub_run_time(old.time_last_complete_scrub),
corruptions_detected: old.corruptions_detected,
}
}
}
}
pub use v082::*;
pub struct ScrubWorker {
manager: Arc<BlockManager>,
rx_cmd: mpsc::Receiver<ScrubWorkerCommand>,
@@ -171,17 +216,25 @@ pub struct ScrubWorker {
persister: PersisterShared<ScrubWorkerPersisted>,
}
#[derive(Serialize, Deserialize)]
pub struct ScrubWorkerPersisted {
pub tranquility: u32,
pub(crate) time_last_complete_scrub: u64,
pub(crate) corruptions_detected: u64,
fn randomize_next_scrub_run_time(timestamp: u64) -> u64 {
// Take SCRUB_INTERVAL and mix in a random interval of 10 days to attempt to
// balance scrub load across different cluster nodes.
let next_run_timestamp = timestamp
+ SCRUB_INTERVAL
.saturating_add(Duration::from_secs(
rand::thread_rng().gen_range(0..3600 * 24 * 10),
))
.as_millis() as u64;
next_run_timestamp
}
impl garage_util::migrate::InitialFormat for ScrubWorkerPersisted {}
impl Default for ScrubWorkerPersisted {
fn default() -> Self {
ScrubWorkerPersisted {
time_last_complete_scrub: 0,
time_next_run_scrub: randomize_next_scrub_run_time(now_msec()),
tranquility: INITIAL_SCRUB_TRANQUILITY,
corruptions_detected: 0,
}
@@ -279,12 +332,13 @@ impl Worker for ScrubWorker {
}
fn status(&self) -> WorkerStatus {
let (corruptions_detected, tranquility, time_last_complete_scrub) =
let (corruptions_detected, tranquility, time_last_complete_scrub, time_next_run_scrub) =
self.persister.get_with(|p| {
(
p.corruptions_detected,
p.tranquility,
p.time_last_complete_scrub,
p.time_next_run_scrub,
)
});
@@ -302,10 +356,16 @@ impl Worker for ScrubWorker {
s.freeform = vec![format!("Scrub paused, resumes at {}", msec_to_rfc3339(*rt))];
}
ScrubWorkerState::Finished => {
s.freeform = vec![format!(
"Last scrub completed at {}",
msec_to_rfc3339(time_last_complete_scrub)
)];
s.freeform = vec![
format!(
"Last scrub completed at {}",
msec_to_rfc3339(time_last_complete_scrub),
),
format!(
"Next scrub scheduled for {}",
msec_to_rfc3339(time_next_run_scrub)
),
];
}
}
s
@@ -334,8 +394,10 @@ impl Worker for ScrubWorker {
.tranquilizer
.tranquilize_worker(self.persister.get_with(|p| p.tranquility)))
} else {
self.persister
.set_with(|p| p.time_last_complete_scrub = now_msec())?;
self.persister.set_with(|p| {
p.time_last_complete_scrub = now_msec();
p.time_next_run_scrub = randomize_next_scrub_run_time(now_msec());
})?;
self.work = ScrubWorkerState::Finished;
self.tranquilizer.clear();
Ok(WorkerState::Idle)
@@ -350,8 +412,7 @@ impl Worker for ScrubWorker {
ScrubWorkerState::Running(_) => return WorkerState::Busy,
ScrubWorkerState::Paused(_, resume_time) => (*resume_time, ScrubWorkerCommand::Resume),
ScrubWorkerState::Finished => (
self.persister.get_with(|p| p.time_last_complete_scrub)
+ SCRUB_INTERVAL.as_millis() as u64,
self.persister.get_with(|p| p.time_next_run_scrub),
ScrubWorkerCommand::Start,
),
};
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_db"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
+9 -9
View File
@@ -1,6 +1,6 @@
[package]
name = "garage"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -21,14 +21,14 @@ path = "tests/lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_db = { version = "0.8.1", path = "../db" }
garage_api = { version = "0.8.1", path = "../api" }
garage_block = { version = "0.8.1", path = "../block" }
garage_model = { version = "0.8.1", path = "../model" }
garage_rpc = { version = "0.8.1", path = "../rpc" }
garage_table = { version = "0.8.1", path = "../table" }
garage_util = { version = "0.8.1", path = "../util" }
garage_web = { version = "0.8.1", path = "../web" }
garage_db = { version = "0.8.2", path = "../db" }
garage_api = { version = "0.8.2", path = "../api" }
garage_block = { version = "0.8.2", path = "../block" }
garage_model = { version = "0.8.2", path = "../model" }
garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_table = { version = "0.8.2", path = "../table" }
garage_util = { version = "0.8.2", path = "../util" }
garage_web = { version = "0.8.2", path = "../web" }
backtrace = "0.3"
bytes = "1.0"
+2 -1
View File
@@ -820,11 +820,12 @@ impl AdminRpcHandler {
let mut ret = String::new();
writeln!(
&mut ret,
"\nGarage version: {} [features: {}]",
"\nGarage version: {} [features: {}]\nRust compiler version: {}",
garage_util::version::garage_version(),
garage_util::version::garage_features()
.map(|list| list.join(", "))
.unwrap_or_else(|| "(unknown)".into()),
garage_util::version::rust_version(),
)
.unwrap();
+3 -24
View File
@@ -21,14 +21,7 @@ async fn test_admin_bucket_perms() {
ctx.garage
.command()
.args([
"bucket",
"allow",
"--read",
"--key",
&ctx.garage.key.id,
BCKT_NAME,
])
.args(["bucket", "allow", "--read", "--key", &ctx.key.id, BCKT_NAME])
.quiet()
.expect_success_status("Could not create bucket");
@@ -36,14 +29,7 @@ async fn test_admin_bucket_perms() {
ctx.garage
.command()
.args([
"bucket",
"deny",
"--read",
"--key",
&ctx.garage.key.name,
BCKT_NAME,
])
.args(["bucket", "deny", "--read", "--key", &ctx.key.id, BCKT_NAME])
.quiet()
.expect_success_status("Could not create bucket");
@@ -51,14 +37,7 @@ async fn test_admin_bucket_perms() {
ctx.garage
.command()
.args([
"bucket",
"allow",
"--read",
"--key",
&ctx.garage.key.name,
BCKT_NAME,
])
.args(["bucket", "allow", "--read", "--key", &ctx.key.id, BCKT_NAME])
.quiet()
.expect_success_status("Could not create bucket");
+2 -2
View File
@@ -13,7 +13,7 @@ async fn test_bucket_all() {
ctx.garage
.command()
.args(["key", "deny"])
.args(["--create-bucket", &ctx.garage.key.id])
.args(["--create-bucket", &ctx.key.id])
.quiet()
.expect_success_output("Could not deny key to create buckets");
@@ -26,7 +26,7 @@ async fn test_bucket_all() {
ctx.garage
.command()
.args(["key", "allow"])
.args(["--create-bucket", &ctx.garage.key.id])
.args(["--create-bucket", &ctx.key.id])
.quiet()
.expect_success_output("Could not deny key to create buckets");
+3 -9
View File
@@ -1,15 +1,9 @@
use aws_sdk_s3::{Client, Config, Credentials, Endpoint};
use super::garage::Instance;
use super::garage::{Instance, Key};
pub fn build_client(instance: &Instance) -> Client {
let credentials = Credentials::new(
&instance.key.id,
&instance.key.secret,
None,
None,
"garage-integ-test",
);
pub fn build_client(instance: &Instance, key: &Key) -> Client {
let credentials = Credentials::new(&key.id, &key.secret, None, None, "garage-integ-test");
let endpoint = Endpoint::immutable(instance.s3_uri());
let config = Config::builder()
+5 -4
View File
@@ -14,6 +14,7 @@ use garage_api::signature;
/// You should ever only use this to send requests AWS sdk won't send,
/// like to reproduce behavior of unusual implementations found to be
/// problematic.
#[derive(Clone)]
pub struct CustomRequester {
key: Key,
uri: Uri,
@@ -22,18 +23,18 @@ pub struct CustomRequester {
}
impl CustomRequester {
pub fn new_s3(instance: &Instance) -> Self {
pub fn new_s3(instance: &Instance, key: &Key) -> Self {
CustomRequester {
key: instance.key.clone(),
key: key.clone(),
uri: instance.s3_uri(),
service: "s3",
client: Client::new(),
}
}
pub fn new_k2v(instance: &Instance) -> Self {
pub fn new_k2v(instance: &Instance, key: &Key) -> Self {
CustomRequester {
key: instance.key.clone(),
key: key.clone(),
uri: instance.k2v_uri(),
service: "k2v",
client: Client::new(),
+32 -16
View File
@@ -13,7 +13,7 @@ static GARAGE_TEST_SECRET: &str =
#[derive(Debug, Default, Clone)]
pub struct Key {
pub name: String,
pub name: Option<String>,
pub id: String,
pub secret: String,
}
@@ -21,7 +21,7 @@ pub struct Key {
pub struct Instance {
process: process::Child,
pub path: PathBuf,
pub key: Key,
pub default_key: Key,
pub s3_port: u16,
pub k2v_port: u16,
pub web_port: u16,
@@ -102,7 +102,7 @@ api_bind_addr = "127.0.0.1:{admin_port}"
Instance {
process: child,
path,
key: Key::default(),
default_key: Key::default(),
s3_port: port,
k2v_port: port + 1,
web_port: port + 3,
@@ -111,14 +111,27 @@ api_bind_addr = "127.0.0.1:{admin_port}"
}
fn setup(&mut self) {
self.wait_for_boot();
self.setup_layout();
self.default_key = self.key(Some("garage_test"));
}
fn wait_for_boot(&mut self) {
use std::{thread, time::Duration};
// Wait for node to be ready
thread::sleep(Duration::from_secs(2));
self.setup_layout();
self.key = self.new_key("garage_test");
// 60 * 2 seconds = 120 seconds = 2min
for _ in 0..60 {
let termination = self
.command()
.args(["status"])
.quiet()
.status()
.expect("Unable to run command");
if termination.success() {
break;
}
thread::sleep(Duration::from_secs(2));
}
}
fn setup_layout(&self) {
@@ -169,14 +182,17 @@ api_bind_addr = "127.0.0.1:{admin_port}"
.expect("Could not build garage endpoint URI")
}
pub fn new_key(&self, name: &str) -> Key {
pub fn key(&self, maybe_name: Option<&str>) -> Key {
let mut key = Key::default();
let output = self
.command()
.args(["key", "new"])
.args(["--name", name])
.expect_success_output("Could not create key");
let mut cmd = self.command();
let base = cmd.args(["key", "new"]);
let with_name = match maybe_name {
Some(name) => base.args(["--name", name]),
None => base,
};
let output = with_name.expect_success_output("Could not create key");
let stdout = String::from_utf8(output.stdout).unwrap();
for line in stdout.lines() {
@@ -193,7 +209,7 @@ api_bind_addr = "127.0.0.1:{admin_port}"
assert!(!key.secret.is_empty(), "Invalid key: Key secret is empty");
Key {
name: name.to_owned(),
name: maybe_name.map(String::from),
..key
}
}
+9 -4
View File
@@ -13,13 +13,16 @@ use custom_requester::CustomRequester;
const REGION: Region = Region::from_static("garage-integ-test");
#[derive(Clone)]
pub struct Context {
pub garage: &'static garage::Instance,
pub key: garage::Key,
pub client: Client,
pub custom_request: CustomRequester,
pub k2v: K2VContext,
}
#[derive(Clone)]
pub struct K2VContext {
pub request: CustomRequester,
}
@@ -27,13 +30,15 @@ pub struct K2VContext {
impl Context {
fn new() -> Self {
let garage = garage::instance();
let client = client::build_client(garage);
let custom_request = CustomRequester::new_s3(garage);
let k2v_request = CustomRequester::new_k2v(garage);
let key = garage.key(None);
let client = client::build_client(garage, &key);
let custom_request = CustomRequester::new_s3(garage, &key);
let k2v_request = CustomRequester::new_k2v(garage, &key);
Context {
garage,
client,
key,
custom_request,
k2v: K2VContext {
request: k2v_request,
@@ -57,7 +62,7 @@ impl Context {
.args(["bucket", "allow"])
.args(["--owner", "--read", "--write"])
.arg(&bucket_name)
.args(["--key", &self.garage.key.name])
.args(["--key", &self.key.id])
.quiet()
.expect_success_status("Could not allow key for bucket");
+3 -3
View File
@@ -57,8 +57,8 @@ async fn test_poll_item() {
let poll = {
let bucket = bucket.clone();
let ct = ct.clone();
let ctx = ctx.clone();
tokio::spawn(async move {
let ctx = common::context();
ctx.k2v
.request
.builder(bucket.clone())
@@ -171,8 +171,8 @@ async fn test_poll_range() {
// Second poll range, which will complete later
let poll = {
let bucket = bucket.clone();
let ctx = ctx.clone();
tokio::spawn(async move {
let ctx = common::context();
ctx.k2v
.request
.builder(bucket.clone())
@@ -220,8 +220,8 @@ async fn test_poll_range() {
// Start a new poll operation
let poll = {
let bucket = bucket.clone();
let ctx = ctx.clone();
tokio::spawn(async move {
let ctx = common::context();
ctx.k2v
.request
.builder(bucket.clone())
+1 -1
View File
@@ -109,7 +109,7 @@ async fn test_create_bucket_streaming() {
ctx.garage
.command()
.args(["key", "allow"])
.args(["--create-bucket", &ctx.garage.key.id])
.args(["--create-bucket", &ctx.key.id])
.quiet()
.expect_success_output("Could not allow key to create buckets");
+1 -1
View File
@@ -23,7 +23,7 @@ tokio = "1.24"
# cli deps
clap = { version = "4.1", optional = true, features = ["derive", "env"] }
garage_util = { version = "0.8.1", path = "../util", optional = true }
garage_util = { version = "0.8.2", path = "../util", optional = true }
[features]
+6 -6
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_model"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,11 +14,11 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_db = { version = "0.8.1", default-features = false, path = "../db" }
garage_rpc = { version = "0.8.1", path = "../rpc" }
garage_table = { version = "0.8.1", path = "../table" }
garage_block = { version = "0.8.1", path = "../block" }
garage_util = { version = "0.8.1", path = "../util" }
garage_db = { version = "0.8.2", default-features = false, path = "../db" }
garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_table = { version = "0.8.2", path = "../table" }
garage_block = { version = "0.8.2", path = "../block" }
garage_util = { version = "0.8.2", path = "../util" }
async-trait = "0.1.7"
arc-swap = "1.0"
+10 -3
View File
@@ -136,9 +136,16 @@ impl Garage {
env_builder.flag(heed::flags::Flags::MdbNoSync);
env_builder.flag(heed::flags::Flags::MdbNoMetaSync);
}
let db = env_builder
.open(&db_path)
.ok_or_message("Unable to open LMDB DB")?;
let db = match env_builder.open(&db_path) {
Err(heed::Error::Io(e)) if e.kind() == std::io::ErrorKind::OutOfMemory => {
return Err(Error::Message(
"OutOfMemory error while trying to open LMDB database. This can happen \
if your operating system is not allowing you to use sufficient virtual \
memory address space. Please check that no limit is set (ulimit -v). \
On 32-bit machines, you should probably switch to another database engine.".into()))
}
x => x.ok_or_message("Unable to open LMDB DB")?,
};
db::lmdb_adapter::LmdbDb::init(db)
}
#[cfg(not(feature = "lmdb"))]
-1
View File
@@ -269,7 +269,6 @@ impl CountedItem for K2VItem {
&self.partition.partition_key
}
#[allow(clippy::bool_to_int_with_if)]
fn counts(&self) -> Vec<(&'static str, i64)> {
let values = self.values();
-1
View File
@@ -355,7 +355,6 @@ impl CountedItem for Object {
fn counts(&self) -> Vec<(&'static str, i64)> {
let versions = self.versions();
#[allow(clippy::bool_to_int_with_if)]
let n_objects = if versions.iter().any(|v| v.is_data()) {
1
} else {
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_rpc"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,7 +14,7 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_util = { version = "0.8.1", path = "../util" }
garage_util = { version = "0.8.2", path = "../util" }
arc-swap = "1.0"
bytes = "1.0"
+4 -4
View File
@@ -31,10 +31,10 @@ impl SystemMetrics {
.u64_value_observer("garage_build_info", move |observer| {
observer.observe(
1,
&[KeyValue::new(
"version",
garage_util::version::garage_version(),
)],
&[
KeyValue::new("rustversion", garage_util::version::rust_version()),
KeyValue::new("version", garage_util::version::garage_version()),
],
)
})
.with_description("Garage build info")
+4 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_table"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,9 +14,9 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_db = { version = "0.8.1", path = "../db" }
garage_rpc = { version = "0.8.1", path = "../rpc" }
garage_util = { version = "0.8.1", path = "../util" }
garage_db = { version = "0.8.2", path = "../db" }
garage_rpc = { version = "0.8.2", path = "../rpc" }
garage_util = { version = "0.8.2", path = "../util" }
opentelemetry = "0.17"
+5 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_util"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,7 +14,7 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_db = { version = "0.8.1", path = "../db" }
garage_db = { version = "0.8.2", path = "../db" }
arc-swap = "1.0"
async-trait = "0.1"
@@ -47,6 +47,9 @@ hyper = "0.14"
opentelemetry = { version = "0.17", features = [ "rt-tokio", "metrics", "trace" ] }
[build-dependencies]
rustc_version = "0.4.0"
[dev-dependencies]
mktemp = "0.5"
+8
View File
@@ -0,0 +1,8 @@
use rustc_version::version;
fn main() {
// Acquire the version of Rust used to compile, this is added as a label to
// the garage_build_info metric.
let v = version().unwrap();
println!("cargo:rustc-env=RUSTC_VERSION={v}");
}
+63
View File
@@ -0,0 +1,63 @@
use http::{HeaderMap, HeaderValue};
use std::net::IpAddr;
use std::str::FromStr;
use crate::error::{Error, OkOrMessage};
pub fn handle_forwarded_for_headers(headers: &HeaderMap<HeaderValue>) -> Result<String, Error> {
let forwarded_for_header = headers
.get("x-forwarded-for")
.ok_or_message("X-Forwarded-For header not provided")?;
let forwarded_for_ip_str = forwarded_for_header
.to_str()
.ok_or_message("Error parsing X-Forwarded-For header")?;
let client_ip = IpAddr::from_str(&forwarded_for_ip_str)
.ok_or_message("Valid IP address not found in X-Forwarded-For header")?;
Ok(client_ip.to_string())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_handle_forwarded_for_headers_ipv4_client() {
let mut test_headers = HeaderMap::new();
test_headers.insert("X-Forwarded-For", "192.0.2.100".parse().unwrap());
if let Ok(forwarded_ip) = handle_forwarded_for_headers(&test_headers) {
assert_eq!(forwarded_ip, "192.0.2.100");
}
}
#[test]
fn test_handle_forwarded_for_headers_ipv6_client() {
let mut test_headers = HeaderMap::new();
test_headers.insert("X-Forwarded-For", "2001:db8::f00d:cafe".parse().unwrap());
if let Ok(forwarded_ip) = handle_forwarded_for_headers(&test_headers) {
assert_eq!(forwarded_ip, "2001:db8::f00d:cafe");
}
}
#[test]
fn test_handle_forwarded_for_headers_invalid_ip() {
let mut test_headers = HeaderMap::new();
test_headers.insert("X-Forwarded-For", "www.example.com".parse().unwrap());
let result = handle_forwarded_for_headers(&test_headers);
assert!(result.is_err());
}
#[test]
fn test_handle_forwarded_for_headers_missing() {
let mut test_headers = HeaderMap::new();
test_headers.insert("Host", "www.deuxfleurs.fr".parse().unwrap());
let result = handle_forwarded_for_headers(&test_headers);
assert!(result.is_err());
}
}
+1
View File
@@ -11,6 +11,7 @@ pub mod data;
pub mod encode;
pub mod error;
pub mod formater;
pub mod forwarded_headers;
pub mod metrics;
pub mod migrate;
pub mod persister;
+4
View File
@@ -26,3 +26,7 @@ pub fn init_version(version: &'static str) {
pub fn init_features(features: &'static [&'static str]) {
FEATURES.store(Some(Arc::new(features)));
}
pub fn rust_version() -> &'static str {
env!("RUSTC_VERSION")
}
+5 -5
View File
@@ -1,6 +1,6 @@
[package]
name = "garage_web"
version = "0.8.1"
version = "0.8.2"
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
edition = "2018"
license = "AGPL-3.0"
@@ -14,10 +14,10 @@ path = "lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
garage_api = { version = "0.8.1", path = "../api" }
garage_model = { version = "0.8.1", path = "../model" }
garage_util = { version = "0.8.1", path = "../util" }
garage_table = { version = "0.8.1", path = "../table" }
garage_api = { version = "0.8.2", path = "../api" }
garage_model = { version = "0.8.2", path = "../model" }
garage_util = { version = "0.8.2", path = "../util" }
garage_table = { version = "0.8.2", path = "../table" }
err-derive = "0.3"
tracing = "0.1"
+14 -1
View File
@@ -29,6 +29,7 @@ use garage_model::garage::Garage;
use garage_table::*;
use garage_util::error::Error as GarageError;
use garage_util::forwarded_headers;
use garage_util::metrics::{gen_trace_id, RecordDuration};
struct WebMetrics {
@@ -104,7 +105,19 @@ impl WebServer {
req: Request<Body>,
addr: SocketAddr,
) -> Result<Response<Body>, Infallible> {
info!("{} {} {}", addr, req.method(), req.uri());
if let Ok(forwarded_for_ip_addr) =
forwarded_headers::handle_forwarded_for_headers(&req.headers())
{
info!(
"{} (via {}) {} {}",
forwarded_for_ip_addr,
addr,
req.method(),
req.uri()
);
} else {
info!("{} {} {}", addr, req.method(), req.uri());
}
// Lots of instrumentation
let tracer = opentelemetry::global::tracer("garage");