aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2023-01-02 15:07:44 +0100
committerAlex Auvolat <alex@adnab.me>2023-01-02 15:07:44 +0100
commit939a6d67e8ace1aa38998281f52511a61f4b4d94 (patch)
treeb94c84bd21ef45e2480c653dc7ed2b37fd5907fb
parent6b857a9b8cd454721a2a1e69e108794be07d36a2 (diff)
parent76230f20282e73a5a5afa33af68152acaf732cf5 (diff)
downloadgarage-939a6d67e8ace1aa38998281f52511a61f4b4d94.tar.gz
garage-939a6d67e8ace1aa38998281f52511a61f4b4d94.zip
Merge branch 'main' into internals-reworkinternals-rework
-rw-r--r--Cargo.lock18
-rw-r--r--Cargo.nix120
-rw-r--r--doc/book/build/python.md59
-rw-r--r--doc/book/connect/apps/index.md11
-rw-r--r--src/api/Cargo.toml12
-rw-r--r--src/api/admin/router.rs15
-rw-r--r--src/api/k2v/router.rs43
-rw-r--r--src/api/router_macros.rs131
-rw-r--r--src/api/s3/router.rs121
-rw-r--r--src/block/Cargo.toml10
-rw-r--r--src/db/Cargo.toml2
-rw-r--r--src/garage/Cargo.toml18
-rw-r--r--src/k2v-client/Cargo.toml2
-rw-r--r--src/model/Cargo.toml12
-rw-r--r--src/rpc/Cargo.toml4
-rw-r--r--src/table/Cargo.toml8
-rw-r--r--src/util/Cargo.toml4
-rw-r--r--src/web/Cargo.toml10
18 files changed, 332 insertions, 268 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a8751d17..b1bbf35e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1048,7 +1048,7 @@ dependencies = [
[[package]]
name = "garage"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"assert-json-diff",
"async-trait",
@@ -1096,7 +1096,7 @@ dependencies = [
[[package]]
name = "garage_api"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"async-trait",
"base64",
@@ -1141,7 +1141,7 @@ dependencies = [
[[package]]
name = "garage_block"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"arc-swap",
"async-compression",
@@ -1167,7 +1167,7 @@ dependencies = [
[[package]]
name = "garage_db"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"clap 3.1.18",
"err-derive",
@@ -1182,7 +1182,7 @@ dependencies = [
[[package]]
name = "garage_model"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"arc-swap",
"async-trait",
@@ -1210,7 +1210,7 @@ dependencies = [
[[package]]
name = "garage_rpc"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"arc-swap",
"async-trait",
@@ -1241,7 +1241,7 @@ dependencies = [
[[package]]
name = "garage_table"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"arc-swap",
"async-trait",
@@ -1264,7 +1264,7 @@ dependencies = [
[[package]]
name = "garage_util"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"arc-swap",
"async-trait",
@@ -1295,7 +1295,7 @@ dependencies = [
[[package]]
name = "garage_web"
-version = "0.8.0"
+version = "0.8.1"
dependencies = [
"err-derive",
"futures",
diff --git a/Cargo.nix b/Cargo.nix
index 603a70be..60e48034 100644
--- a/Cargo.nix
+++ b/Cargo.nix
@@ -32,7 +32,7 @@ args@{
ignoreLockHash,
}:
let
- nixifiedLockHash = "a1d84930f23d3d8abc8abbed59b8ce3c9adf9f25d06bc1f39cbdf5bd90aceead";
+ nixifiedLockHash = "4639f63ff4c54c01f66ec3d0d362f6905456dd768d6e94df1a7367c763721fd7";
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.0";
- garage_util = rustPackages.unknown.garage_util."0.8.0";
- garage_rpc = rustPackages.unknown.garage_rpc."0.8.0";
- garage_table = rustPackages.unknown.garage_table."0.8.0";
- garage_block = rustPackages.unknown.garage_block."0.8.0";
- garage_model = rustPackages.unknown.garage_model."0.8.0";
- garage_api = rustPackages.unknown.garage_api."0.8.0";
- garage_web = rustPackages.unknown.garage_web."0.8.0";
- garage = rustPackages.unknown.garage."0.8.0";
+ 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";
k2v-client = rustPackages.unknown.k2v-client."0.0.1";
};
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.17.0" = overridableMkRustCrate (profileName: rec {
@@ -1494,9 +1494,9 @@ in
};
});
- "unknown".garage."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/garage");
features = builtins.concatLists [
@@ -1522,14 +1522,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.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_api = (rustPackages."unknown".garage_api."0.8.0" { inherit profileName; }).out;
- garage_block = (rustPackages."unknown".garage_block."0.8.0" { inherit profileName; }).out;
- garage_db = (rustPackages."unknown".garage_db."0.8.0" { inherit profileName; }).out;
- garage_model = (rustPackages."unknown".garage_model."0.8.0" { inherit profileName; }).out;
- garage_rpc = (rustPackages."unknown".garage_rpc."0.8.0" { inherit profileName; }).out;
- garage_table = (rustPackages."unknown".garage_table."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { inherit profileName; }).out;
- garage_web = (rustPackages."unknown".garage_web."0.8.0" { 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;
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;
@@ -1563,9 +1563,9 @@ in
};
});
- "unknown".garage_api."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_api."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_api";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/api");
features = builtins.concatLists [
@@ -1584,11 +1584,11 @@ in
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.0.1" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_block = (rustPackages."unknown".garage_block."0.8.0" { inherit profileName; }).out;
- garage_model = (rustPackages."unknown".garage_model."0.8.0" { inherit profileName; }).out;
- garage_rpc = (rustPackages."unknown".garage_rpc."0.8.0" { inherit profileName; }).out;
- garage_table = (rustPackages."unknown".garage_table."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { 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;
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;
@@ -1617,9 +1617,9 @@ in
};
});
- "unknown".garage_block."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_block."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_block";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/block");
features = builtins.concatLists [
@@ -1632,10 +1632,10 @@ in
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.2.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_db = (rustPackages."unknown".garage_db."0.8.0" { inherit profileName; }).out;
- garage_rpc = (rustPackages."unknown".garage_rpc."0.8.0" { inherit profileName; }).out;
- garage_table = (rustPackages."unknown".garage_table."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { 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;
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;
@@ -1649,9 +1649,9 @@ in
};
});
- "unknown".garage_db."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_db."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_db";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/db");
features = builtins.concatLists [
@@ -1681,9 +1681,9 @@ in
};
});
- "unknown".garage_model."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_model."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_model";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/model");
features = builtins.concatLists [
@@ -1701,11 +1701,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.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_block = (rustPackages."unknown".garage_block."0.8.0" { inherit profileName; }).out;
- garage_db = (rustPackages."unknown".garage_db."0.8.0" { inherit profileName; }).out;
- garage_rpc = (rustPackages."unknown".garage_rpc."0.8.0" { inherit profileName; }).out;
- garage_table = (rustPackages."unknown".garage_table."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { 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;
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;
@@ -1719,9 +1719,9 @@ in
};
});
- "unknown".garage_rpc."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_rpc."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_rpc";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
features = builtins.concatLists [
@@ -1741,7 +1741,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.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { inherit profileName; }).out;
+ garage_util = (rustPackages."unknown".garage_util."0.8.1" { 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;
@@ -1763,9 +1763,9 @@ in
};
});
- "unknown".garage_table."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_table."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_table";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/table");
dependencies = {
@@ -1774,9 +1774,9 @@ in
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.2.0" { inherit profileName; }).out;
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.21" { inherit profileName; }).out;
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.21" { inherit profileName; }).out;
- garage_db = (rustPackages."unknown".garage_db."0.8.0" { inherit profileName; }).out;
- garage_rpc = (rustPackages."unknown".garage_rpc."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { 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;
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;
@@ -1789,9 +1789,9 @@ in
};
});
- "unknown".garage_util."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_util."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_util";
- version = "0.8.0";
+ version = "0.8.1";
registry = "unknown";
src = fetchCrateLocal (workspaceSrc + "/src/util");
features = builtins.concatLists [
@@ -1806,7 +1806,7 @@ in
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.3" { 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.21" { inherit profileName; }).out;
- garage_db = (rustPackages."unknown".garage_db."0.8.0" { inherit profileName; }).out;
+ garage_db = (rustPackages."unknown".garage_db."0.8.1" { 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;
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.8" { inherit profileName; }).out;
@@ -1826,18 +1826,18 @@ in
};
});
- "unknown".garage_web."0.8.0" = overridableMkRustCrate (profileName: rec {
+ "unknown".garage_web."0.8.1" = overridableMkRustCrate (profileName: rec {
name = "garage_web";
- version = "0.8.0";
+ version = "0.8.1";
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.21" { inherit profileName; }).out;
- garage_api = (rustPackages."unknown".garage_api."0.8.0" { inherit profileName; }).out;
- garage_model = (rustPackages."unknown".garage_model."0.8.0" { inherit profileName; }).out;
- garage_table = (rustPackages."unknown".garage_table."0.8.0" { inherit profileName; }).out;
- garage_util = (rustPackages."unknown".garage_util."0.8.0" { 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;
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.18" { inherit profileName; }).out;
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
@@ -2451,7 +2451,7 @@ in
dependencies = {
base64 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64."0.13.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."3.1.18" { inherit profileName; }).out;
- ${ if rootFeatures' ? "k2v-client/cli" || rootFeatures' ? "k2v-client/garage_util" then "garage_util" else null } = (rustPackages."unknown".garage_util."0.8.0" { 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;
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.8" { inherit profileName; }).out;
log = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".log."0.4.16" { inherit profileName; }).out;
rusoto_core = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rusoto_core."0.48.0" { inherit profileName; }).out;
diff --git a/doc/book/build/python.md b/doc/book/build/python.md
index 19912e85..5b797897 100644
--- a/doc/book/build/python.md
+++ b/doc/book/build/python.md
@@ -5,16 +5,59 @@ weight = 20
## S3
-*Coming soon*
+### Using Minio SDK
+
+First install the SDK:
+
+```bash
+pip3 install minio
+```
+
+Then instantiate a client object using garage root domain, api key and secret:
+
+```python
+import minio
+
+client = minio.Minio(
+ "your.domain.tld",
+ "GKyourapikey",
+ "abcd[...]1234",
+ # Force the region, this is specific to garage
+ region="region",
+)
+```
-Some refs:
- - Minio SDK
- - [Reference](https://docs.min.io/docs/python-client-api-reference.html)
+Then use all the standard S3 endpoints as implemented by the Minio SDK:
+
+```
+# List buckets
+print(client.list_buckets())
+
+# Put an object containing 'content' to /path in bucket named 'bucket':
+content = b"content"
+client.put_object(
+ "bucket",
+ "path",
+ io.BytesIO(content),
+ len(content),
+)
+
+# Read the object back and check contents
+data = client.get_object("bucket", "path").read()
+assert data == content
+```
+
+For further documentation, see the Minio SDK
+[Reference](https://docs.min.io/docs/python-client-api-reference.html)
+
+### Using Amazon boto3
+
+*Coming soon*
- - Amazon boto3
- - [Installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)
- - [Reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)
- - [Example](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html)
+See the official documentation:
+ - [Installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)
+ - [Reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)
+ - [Example](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html)
## K2V
diff --git a/doc/book/connect/apps/index.md b/doc/book/connect/apps/index.md
index 05e7cad9..737351a0 100644
--- a/doc/book/connect/apps/index.md
+++ b/doc/book/connect/apps/index.md
@@ -8,7 +8,7 @@ In this section, we cover the following web applications:
| Name | Status | Note |
|------|--------|------|
| [Nextcloud](#nextcloud) | ✅ | Both Primary Storage and External Storage are supported |
-| [Peertube](#peertube) | ✅ | Must be configured with the website endpoint |
+| [Peertube](#peertube) | ✅ | Supported with the website endpoint, proxifying private videos unsupported |
| [Mastodon](#mastodon) | ✅ | Natively supported |
| [Matrix](#matrix) | ✅ | Tested with `synapse-s3-storage-provider` |
| [Pixelfed](#pixelfed) | ❓ | Not yet tested |
@@ -128,6 +128,10 @@ In other words, Peertube is only responsible of the "control plane" and offload
In return, this system is a bit harder to configure.
We show how it is still possible to configure Garage with Peertube, allowing you to spread the load and the bandwidth usage on the Garage cluster.
+Starting from version 5.0, Peertube also supports improving the security for private videos by not exposing them directly
+but relying on a single control point in the Peertube instance. This is based on S3 per-object and prefix ACL, which are not currently supported
+in Garage, so this feature is unsupported. While this technically impedes security for private videos, it is not a blocking issue and could be
+a reasonable trade-off for some instances.
### Create resources in Garage
@@ -195,6 +199,11 @@ object_storage:
max_upload_part: 2GB
+ proxy:
+ # You may enable this feature, yet it will not provide any security benefit, so
+ # you should rather benefit from Garage public endpoint for all videos
+ proxify_private_files: false
+
streaming_playlists:
bucket_name: 'peertube-playlist'
diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml
index 4d9a6ab6..dba0bbef 100644
--- a/src/api/Cargo.toml
+++ b/src/api/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_api"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../model" }
-garage_table = { version = "0.8.0", path = "../table" }
-garage_block = { version = "0.8.0", path = "../block" }
-garage_util = { version = "0.8.0", path = "../util" }
-garage_rpc = { version = "0.8.0", path = "../rpc" }
+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" }
async-trait = "0.1.7"
base64 = "0.13"
diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs
index 3fa07b3c..62e6abc3 100644
--- a/src/api/admin/router.rs
+++ b/src/api/admin/router.rs
@@ -143,10 +143,13 @@ impl Endpoint {
}
generateQueryParameters! {
- "format" => format,
- "id" => id,
- "search" => search,
- "globalAlias" => global_alias,
- "alias" => alias,
- "accessKeyId" => access_key_id
+ keywords: [],
+ fields: [
+ "format" => format,
+ "id" => id,
+ "search" => search,
+ "globalAlias" => global_alias,
+ "alias" => alias,
+ "accessKeyId" => access_key_id
+ ]
}
diff --git a/src/api/k2v/router.rs b/src/api/k2v/router.rs
index 50e6965b..e7a3dd69 100644
--- a/src/api/k2v/router.rs
+++ b/src/api/k2v/router.rs
@@ -96,7 +96,7 @@ impl Endpoint {
fn from_get(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
EMPTY if causality_token => PollItem (query::sort_key, query::causality_token, opt_parse::timeout),
EMPTY => ReadItem (query::sort_key),
@@ -111,7 +111,7 @@ impl Endpoint {
fn from_search(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
],
no_key: [
@@ -125,7 +125,7 @@ impl Endpoint {
fn from_head(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
EMPTY => HeadObject(opt_parse::part_number, query_opt::version_id),
],
@@ -140,7 +140,7 @@ impl Endpoint {
fn from_post(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
],
no_key: [
@@ -155,7 +155,7 @@ impl Endpoint {
fn from_put(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
EMPTY => InsertItem (query::sort_key),
@@ -169,7 +169,7 @@ impl Endpoint {
fn from_delete(partition_key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), partition_key, query, None),
+ (query.keyword.take().unwrap_or_default(), partition_key, query, None),
key: [
EMPTY => DeleteItem (query::sort_key),
],
@@ -232,21 +232,18 @@ impl Endpoint {
// parameter name => struct field
generateQueryParameters! {
- "prefix" => prefix,
- "start" => start,
- "causality_token" => causality_token,
- "end" => end,
- "limit" => limit,
- "reverse" => reverse,
- "sort_key" => sort_key,
- "timeout" => timeout
-}
-
-mod keywords {
- //! This module contain all query parameters with no associated value
- //! used to differentiate endpoints.
- pub const EMPTY: &str = "";
-
- pub const DELETE: &str = "delete";
- pub const SEARCH: &str = "search";
+ keywords: [
+ "delete" => DELETE,
+ "search" => SEARCH
+ ],
+ fields: [
+ "prefix" => prefix,
+ "start" => start,
+ "causality_token" => causality_token,
+ "end" => end,
+ "limit" => limit,
+ "reverse" => reverse,
+ "sort_key" => sort_key,
+ "timeout" => timeout
+ ]
}
diff --git a/src/api/router_macros.rs b/src/api/router_macros.rs
index 4c593300..959e69a3 100644
--- a/src/api/router_macros.rs
+++ b/src/api/router_macros.rs
@@ -4,10 +4,9 @@ macro_rules! router_match {
(@match $enum:expr , [ $($endpoint:ident,)* ]) => {{
// usage: router_match {@match my_enum, [ VariantWithField1, VariantWithField2 ..] }
// returns true if the variant was one of the listed variants, false otherwise.
- use Endpoint::*;
match $enum {
$(
- $endpoint { .. } => true,
+ Endpoint::$endpoint { .. } => true,
)*
_ => false
}
@@ -15,37 +14,35 @@ macro_rules! router_match {
(@extract $enum:expr , $param:ident, [ $($endpoint:ident,)* ]) => {{
// usage: router_match {@extract my_enum, field_name, [ VariantWithField1, VariantWithField2 ..] }
// returns Some(field_value), or None if the variant was not one of the listed variants.
- use Endpoint::*;
match $enum {
$(
- $endpoint {$param, ..} => Some($param),
+ Endpoint::$endpoint {$param, ..} => Some($param),
)*
_ => None
}
}};
- (@gen_path_parser ($method:expr, $reqpath:expr, $query:expr)
- [
- $($meth:ident $path:pat $(if $required:ident)? => $api:ident $(($($conv:ident :: $param:ident),*))?,)*
- ]) => {{
- {
- use Endpoint::*;
- match ($method, $reqpath) {
- $(
- (&Method::$meth, $path) if true $(&& $query.$required.is_some())? => $api {
- $($(
- $param: router_match!(@@parse_param $query, $conv, $param),
- )*)?
- },
- )*
- (m, p) => {
- return Err(Error::bad_request(format!(
- "Unknown API endpoint: {} {}",
- m, p
- )))
- }
- }
- }
- }};
+ (@gen_path_parser ($method:expr, $reqpath:expr, $query:expr)
+ [
+ $($meth:ident $path:pat $(if $required:ident)? => $api:ident $(($($conv:ident :: $param:ident),*))?,)*
+ ]) => {{
+ {
+ match ($method, $reqpath) {
+ $(
+ (&Method::$meth, $path) if true $(&& $query.$required.is_some())? => Endpoint::$api {
+ $($(
+ $param: router_match!(@@parse_param $query, $conv, $param),
+ )*)?
+ },
+ )*
+ (m, p) => {
+ return Err(Error::bad_request(format!(
+ "Unknown API endpoint: {} {}",
+ m, p
+ )))
+ }
+ }
+ }
+ }};
(@gen_parser ($keyword:expr, $key:ident, $query:expr, $header:expr),
key: [$($kw_k:ident $(if $required_k:ident)? $(header $header_k:expr)? => $api_k:ident $(($($conv_k:ident :: $param_k:ident),*))?,)*],
no_key: [$($kw_nk:ident $(if $required_nk:ident)? $(if_header $header_nk:expr)? => $api_nk:ident $(($($conv_nk:ident :: $param_nk:ident),*))?,)*]) => {{
@@ -60,11 +57,9 @@ macro_rules! router_match {
// ]
// }
// See in from_{method} for more detailed usage.
- use Endpoint::*;
- use keywords::*;
match ($keyword, !$key.is_empty()){
$(
- ($kw_k, true) if true $(&& $query.$required_k.is_some())? $(&& $header.contains_key($header_k))? => Ok($api_k {
+ (Keyword::$kw_k, true) if true $(&& $query.$required_k.is_some())? $(&& $header.contains_key($header_k))? => Ok(Endpoint::$api_k {
$key,
$($(
$param_k: router_match!(@@parse_param $query, $conv_k, $param_k),
@@ -72,7 +67,7 @@ macro_rules! router_match {
}),
)*
$(
- ($kw_nk, false) $(if $query.$required_nk.is_some())? $(if $header.contains($header_nk))? => Ok($api_nk {
+ (Keyword::$kw_nk, false) $(if $query.$required_nk.is_some())? $(if $header.contains($header_nk))? => Ok(Endpoint::$api_nk {
$($(
$param_nk: router_match!(@@parse_param $query, $conv_nk, $param_nk),
)*)?
@@ -84,7 +79,7 @@ macro_rules! router_match {
(@@parse_param $query:expr, query_opt, $param:ident) => {{
// extract optional query parameter
- $query.$param.take().map(|param| param.into_owned())
+ $query.$param.take().map(|param| param.into_owned())
}};
(@@parse_param $query:expr, query, $param:ident) => {{
// extract mendatory query parameter
@@ -93,7 +88,7 @@ macro_rules! router_match {
(@@parse_param $query:expr, opt_parse, $param:ident) => {{
// extract and parse optional query parameter
// missing parameter is file, however parse error is reported as an error
- $query.$param
+ $query.$param
.take()
.map(|param| param.parse())
.transpose()
@@ -144,14 +139,39 @@ macro_rules! router_match {
/// This macro is used to generate part of the code in this module. It must be called only one, and
/// is useless outside of this module.
macro_rules! generateQueryParameters {
- ( $($rest:expr => $name:ident),* ) => {
+ (
+ keywords: [ $($kw_param:expr => $kw_name: ident),* ],
+ fields: [ $($f_param:expr => $f_name:ident),* ]
+ ) => {
+ #[derive(Debug)]
+ #[allow(non_camel_case_types)]
+ enum Keyword {
+ EMPTY,
+ $( $kw_name, )*
+ }
+
+ impl std::fmt::Display for Keyword {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Keyword::EMPTY => write!(f, "``"),
+ $( Keyword::$kw_name => write!(f, "`{}`", $kw_param), )*
+ }
+ }
+ }
+
+ impl Default for Keyword {
+ fn default() -> Self {
+ Keyword::EMPTY
+ }
+ }
+
/// Struct containing all query parameters used in endpoints. Think of it as an HashMap,
/// but with keys statically known.
#[derive(Debug, Default)]
struct QueryParameters<'a> {
- keyword: Option<Cow<'a, str>>,
+ keyword: Option<Keyword>,
$(
- $name: Option<Cow<'a, str>>,
+ $f_name: Option<Cow<'a, str>>,
)*
}
@@ -160,34 +180,29 @@ macro_rules! generateQueryParameters {
fn from_query(query: &'a str) -> Result<Self, Error> {
let mut res: Self = Default::default();
for (k, v) in url::form_urlencoded::parse(query.as_bytes()) {
- let repeated = match k.as_ref() {
+ match k.as_ref() {
$(
- $rest => if !v.is_empty() {
- res.$name.replace(v).is_some()
- } else {
- false
+ $kw_param => if let Some(prev_kw) = res.keyword.replace(Keyword::$kw_name) {
+ return Err(Error::bad_request(format!(
+ "Multiple keywords: '{}' and '{}'", prev_kw, $kw_param
+ )));
},
)*
- _ => {
- if k.starts_with("response-") || k.starts_with("X-Amz-") {
- false
- } else if v.as_ref().is_empty() {
- if res.keyword.replace(k).is_some() {
- return Err(Error::bad_request("Multiple keywords"));
+ $(
+ $f_param => if !v.is_empty() {
+ if res.$f_name.replace(v).is_some() {
+ return Err(Error::bad_request(format!(
+ "Query parameter repeated: '{}'", k
+ )));
}
- continue;
- } else {
+ },
+ )*
+ _ => {
+ if !(k.starts_with("response-") || k.starts_with("X-Amz-")) {
debug!("Received an unknown query parameter: '{}'", k);
- false
}
}
};
- if repeated {
- return Err(Error::bad_request(format!(
- "Query parameter repeated: '{}'",
- k
- )));
- }
}
Ok(res)
}
@@ -198,8 +213,8 @@ macro_rules! generateQueryParameters {
if self.keyword.is_some() {
Some("Keyword not used")
} $(
- else if self.$name.is_some() {
- Some(concat!("'", $rest, "'"))
+ else if self.$f_name.is_some() {
+ Some(concat!("'", $f_param, "'"))
}
)* else {
None
diff --git a/src/api/s3/router.rs b/src/api/s3/router.rs
index 44f581ff..821b0e07 100644
--- a/src/api/s3/router.rs
+++ b/src/api/s3/router.rs
@@ -355,7 +355,7 @@ impl Endpoint {
fn from_get(key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), key, query, None),
+ (query.keyword.take().unwrap_or_default(), key, query, None),
key: [
EMPTY if upload_id => ListParts (query::upload_id, opt_parse::max_parts, opt_parse::part_number_marker),
EMPTY => GetObject (query_opt::version_id, opt_parse::part_number),
@@ -412,7 +412,7 @@ impl Endpoint {
fn from_head(key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), key, query, None),
+ (query.keyword.take().unwrap_or_default(), key, query, None),
key: [
EMPTY => HeadObject(opt_parse::part_number, query_opt::version_id),
],
@@ -426,7 +426,7 @@ impl Endpoint {
fn from_post(key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), key, query, None),
+ (query.keyword.take().unwrap_or_default(), key, query, None),
key: [
EMPTY if upload_id => CompleteMultipartUpload (query::upload_id),
RESTORE => RestoreObject (query_opt::version_id),
@@ -448,7 +448,7 @@ impl Endpoint {
) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), key, query, headers),
+ (query.keyword.take().unwrap_or_default(), key, query, headers),
key: [
EMPTY if part_number header "x-amz-copy-source" => UploadPartCopy (parse::part_number, query::upload_id),
EMPTY header "x-amz-copy-source" => CopyObject,
@@ -490,7 +490,7 @@ impl Endpoint {
fn from_delete(key: String, query: &mut QueryParameters<'_>) -> Result<Self, Error> {
router_match! {
@gen_parser
- (query.keyword.take().unwrap_or_default().as_ref(), key, query, None),
+ (query.keyword.take().unwrap_or_default(), key, query, None),
key: [
EMPTY if upload_id => AbortMultipartUpload (query::upload_id),
EMPTY => DeleteObject (query_opt::version_id),
@@ -624,63 +624,60 @@ impl Endpoint {
// parameter name => struct field
generateQueryParameters! {
- "continuation-token" => continuation_token,
- "delimiter" => delimiter,
- "encoding-type" => encoding_type,
- "fetch-owner" => fetch_owner,
- "id" => id,
- "key-marker" => key_marker,
- "list-type" => list_type,
- "marker" => marker,
- "max-keys" => max_keys,
- "max-parts" => max_parts,
- "max-uploads" => max_uploads,
- "partNumber" => part_number,
- "part-number-marker" => part_number_marker,
- "prefix" => prefix,
- "select-type" => select_type,
- "start-after" => start_after,
- "uploadId" => upload_id,
- "upload-id-marker" => upload_id_marker,
- "versionId" => version_id,
- "version-id-marker" => version_id_marker
-}
-
-mod keywords {
- //! This module contain all query parameters with no associated value S3 uses to differentiate
- //! endpoints.
- pub const EMPTY: &str = "";
-
- pub const ACCELERATE: &str = "accelerate";
- pub const ACL: &str = "acl";
- pub const ANALYTICS: &str = "analytics";
- pub const CORS: &str = "cors";
- pub const DELETE: &str = "delete";
- pub const ENCRYPTION: &str = "encryption";
- pub const INTELLIGENT_TIERING: &str = "intelligent-tiering";
- pub const INVENTORY: &str = "inventory";
- pub const LEGAL_HOLD: &str = "legal-hold";
- pub const LIFECYCLE: &str = "lifecycle";
- pub const LOCATION: &str = "location";
- pub const LOGGING: &str = "logging";
- pub const METRICS: &str = "metrics";
- pub const NOTIFICATION: &str = "notification";
- pub const OBJECT_LOCK: &str = "object-lock";
- pub const OWNERSHIP_CONTROLS: &str = "ownershipControls";
- pub const POLICY: &str = "policy";
- pub const POLICY_STATUS: &str = "policyStatus";
- pub const PUBLIC_ACCESS_BLOCK: &str = "publicAccessBlock";
- pub const REPLICATION: &str = "replication";
- pub const REQUEST_PAYMENT: &str = "requestPayment";
- pub const RESTORE: &str = "restore";
- pub const RETENTION: &str = "retention";
- pub const SELECT: &str = "select";
- pub const TAGGING: &str = "tagging";
- pub const TORRENT: &str = "torrent";
- pub const UPLOADS: &str = "uploads";
- pub const VERSIONING: &str = "versioning";
- pub const VERSIONS: &str = "versions";
- pub const WEBSITE: &str = "website";
+ keywords: [
+ "accelerate" => ACCELERATE,
+ "acl" => ACL,
+ "analytics" => ANALYTICS,
+ "cors" => CORS,
+ "delete" => DELETE,
+ "encryption" => ENCRYPTION,
+ "intelligent-tiering" => INTELLIGENT_TIERING,
+ "inventory" => INVENTORY,
+ "legal-hold" => LEGAL_HOLD,
+ "lifecycle" => LIFECYCLE,
+ "location" => LOCATION,
+ "logging" => LOGGING,
+ "metrics" => METRICS,
+ "notification" => NOTIFICATION,
+ "object-lock" => OBJECT_LOCK,
+ "ownershipControls" => OWNERSHIP_CONTROLS,
+ "policy" => POLICY,
+ "policyStatus" => POLICY_STATUS,
+ "publicAccessBlock" => PUBLIC_ACCESS_BLOCK,
+ "replication" => REPLICATION,
+ "requestPayment" => REQUEST_PAYMENT,
+ "restore" => RESTORE,
+ "retention" => RETENTION,
+ "select" => SELECT,
+ "tagging" => TAGGING,
+ "torrent" => TORRENT,
+ "uploads" => UPLOADS,
+ "versioning" => VERSIONING,
+ "versions" => VERSIONS,
+ "website" => WEBSITE
+ ],
+ fields: [
+ "continuation-token" => continuation_token,
+ "delimiter" => delimiter,
+ "encoding-type" => encoding_type,
+ "fetch-owner" => fetch_owner,
+ "id" => id,
+ "key-marker" => key_marker,
+ "list-type" => list_type,
+ "marker" => marker,
+ "max-keys" => max_keys,
+ "max-parts" => max_parts,
+ "max-uploads" => max_uploads,
+ "partNumber" => part_number,
+ "part-number-marker" => part_number_marker,
+ "prefix" => prefix,
+ "select-type" => select_type,
+ "start-after" => start_after,
+ "uploadId" => upload_id,
+ "upload-id-marker" => upload_id_marker,
+ "versionId" => version_id,
+ "version-id-marker" => version_id_marker
+ ]
}
#[cfg(test)]
diff --git a/src/block/Cargo.toml b/src/block/Cargo.toml
index cd409001..cbd58d32 100644
--- a/src/block/Cargo.toml
+++ b/src/block/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_block"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../db" }
-garage_rpc = { version = "0.8.0", path = "../rpc" }
-garage_util = { version = "0.8.0", path = "../util" }
-garage_table = { version = "0.8.0", path = "../table" }
+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" }
opentelemetry = "0.17"
diff --git a/src/db/Cargo.toml b/src/db/Cargo.toml
index 82cf49dc..c479d9d1 100644
--- a/src/db/Cargo.toml
+++ b/src/db/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_db"
-version = "0.8.0"
+version = "0.8.1"
authors = ["Alex Auvolat <alex@adnab.me>"]
edition = "2018"
license = "AGPL-3.0"
diff --git a/src/garage/Cargo.toml b/src/garage/Cargo.toml
index f9d7cf3a..cee7060e 100644
--- a/src/garage/Cargo.toml
+++ b/src/garage/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../db" }
-garage_api = { version = "0.8.0", path = "../api" }
-garage_block = { version = "0.8.0", path = "../block" }
-garage_model = { version = "0.8.0", path = "../model" }
-garage_rpc = { version = "0.8.0", path = "../rpc" }
-garage_table = { version = "0.8.0", path = "../table" }
-garage_util = { version = "0.8.0", path = "../util" }
-garage_web = { version = "0.8.0", path = "../web" }
+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" }
backtrace = "0.3"
bytes = "1.0"
diff --git a/src/k2v-client/Cargo.toml b/src/k2v-client/Cargo.toml
index 9d2b4e30..f57ce849 100644
--- a/src/k2v-client/Cargo.toml
+++ b/src/k2v-client/Cargo.toml
@@ -22,7 +22,7 @@ tokio = "1.17.0"
# cli deps
clap = { version = "3.1.18", optional = true, features = ["derive", "env"] }
-garage_util = { version = "0.8.0", path = "../util", optional = true }
+garage_util = { version = "0.8.1", path = "../util", optional = true }
[features]
diff --git a/src/model/Cargo.toml b/src/model/Cargo.toml
index 08baf81f..3d3fb693 100644
--- a/src/model/Cargo.toml
+++ b/src/model/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_model"
-version = "0.8.0"
+version = "0.8.1"
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.0", default-features = false, path = "../db" }
-garage_rpc = { version = "0.8.0", path = "../rpc" }
-garage_table = { version = "0.8.0", path = "../table" }
-garage_block = { version = "0.8.0", path = "../block" }
-garage_util = { version = "0.8.0", path = "../util" }
+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" }
async-trait = "0.1.7"
arc-swap = "1.0"
diff --git a/src/rpc/Cargo.toml b/src/rpc/Cargo.toml
index 2c2ddc0b..b87374ad 100644
--- a/src/rpc/Cargo.toml
+++ b/src/rpc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_rpc"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../util" }
+garage_util = { version = "0.8.1", path = "../util" }
arc-swap = "1.0"
bytes = "1.0"
diff --git a/src/table/Cargo.toml b/src/table/Cargo.toml
index a8d9b5e6..e1a74553 100644
--- a/src/table/Cargo.toml
+++ b/src/table/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_table"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../db" }
-garage_rpc = { version = "0.8.0", path = "../rpc" }
-garage_util = { version = "0.8.0", path = "../util" }
+garage_db = { version = "0.8.1", path = "../db" }
+garage_rpc = { version = "0.8.1", path = "../rpc" }
+garage_util = { version = "0.8.1", path = "../util" }
opentelemetry = "0.17"
diff --git a/src/util/Cargo.toml b/src/util/Cargo.toml
index 8e978fc2..11640027 100644
--- a/src/util/Cargo.toml
+++ b/src/util/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_util"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../db" }
+garage_db = { version = "0.8.1", path = "../db" }
arc-swap = "1.0"
async-trait = "0.1"
diff --git a/src/web/Cargo.toml b/src/web/Cargo.toml
index 7bf70c55..dbc5e5fb 100644
--- a/src/web/Cargo.toml
+++ b/src/web/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "garage_web"
-version = "0.8.0"
+version = "0.8.1"
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.0", path = "../api" }
-garage_model = { version = "0.8.0", path = "../model" }
-garage_util = { version = "0.8.0", path = "../util" }
-garage_table = { version = "0.8.0", path = "../table" }
+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" }
err-derive = "0.3"
tracing = "0.1.30"