mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-18 01:17:50 +00:00
Compare commits
22 Commits
v0.9.0-beta4
...
v0.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 952c9570c4 | |||
| 3d7892477d | |||
| d4932c31ea | |||
| e75fe2157d | |||
| 2d5d7a7031 | |||
| 0c431b0c03 | |||
| 1c13135f25 | |||
| 2448eb7713 | |||
| 6790e24f5a | |||
| 9ccc1d6f4a | |||
| 920dec393a | |||
| 2e656b541b | |||
| 1243db87f2 | |||
| 6f8a87814b | |||
| 7907a09acc | |||
| 16aa418e47 | |||
| cb359b4434 | |||
| 8ec6a53b35 | |||
| 7353038a64 | |||
| 10195f1567 | |||
| 6086a3fa07 | |||
| 9ac1d5be0e |
+13
-3
@@ -65,11 +65,16 @@ steps:
|
|||||||
- nix-build --no-build-output --attr pkgs.amd64.release --argstr git_version ${DRONE_TAG:-$DRONE_COMMIT}
|
- nix-build --no-build-output --attr pkgs.amd64.release --argstr git_version ${DRONE_TAG:-$DRONE_COMMIT}
|
||||||
- nix-shell --attr rust --run "./script/not-dynamic.sh result-bin/bin/garage"
|
- nix-shell --attr rust --run "./script/not-dynamic.sh result-bin/bin/garage"
|
||||||
|
|
||||||
- name: integration
|
- name: integration tests
|
||||||
image: nixpkgs/nix:nixos-22.05
|
image: nixpkgs/nix:nixos-22.05
|
||||||
commands:
|
commands:
|
||||||
- nix-shell --attr integration --run ./script/test-smoke.sh || (cat /tmp/garage.log; false)
|
- nix-shell --attr integration --run ./script/test-smoke.sh || (cat /tmp/garage.log; false)
|
||||||
|
|
||||||
|
- name: upgrade tests
|
||||||
|
image: nixpkgs/nix:nixos-22.05
|
||||||
|
commands:
|
||||||
|
- nix-shell --attr integration --run "./script/test-upgrade.sh v0.8.4 x86_64-unknown-linux-musl" || (cat /tmp/garage.log; false)
|
||||||
|
|
||||||
- name: push static binary
|
- name: push static binary
|
||||||
image: nixpkgs/nix:nixos-22.05
|
image: nixpkgs/nix:nixos-22.05
|
||||||
environment:
|
environment:
|
||||||
@@ -116,11 +121,16 @@ steps:
|
|||||||
- nix-build --no-build-output --attr pkgs.i386.release --argstr git_version ${DRONE_TAG:-$DRONE_COMMIT}
|
- nix-build --no-build-output --attr pkgs.i386.release --argstr git_version ${DRONE_TAG:-$DRONE_COMMIT}
|
||||||
- nix-shell --attr rust --run "./script/not-dynamic.sh result-bin/bin/garage"
|
- nix-shell --attr rust --run "./script/not-dynamic.sh result-bin/bin/garage"
|
||||||
|
|
||||||
- name: integration
|
- name: integration tests
|
||||||
image: nixpkgs/nix:nixos-22.05
|
image: nixpkgs/nix:nixos-22.05
|
||||||
commands:
|
commands:
|
||||||
- nix-shell --attr integration --run ./script/test-smoke.sh || (cat /tmp/garage.log; false)
|
- nix-shell --attr integration --run ./script/test-smoke.sh || (cat /tmp/garage.log; false)
|
||||||
|
|
||||||
|
- name: upgrade tests
|
||||||
|
image: nixpkgs/nix:nixos-22.05
|
||||||
|
commands:
|
||||||
|
- nix-shell --attr integration --run "./script/test-upgrade.sh v0.8.4 i686-unknown-linux-musl" || (cat /tmp/garage.log; false)
|
||||||
|
|
||||||
- name: push static binary
|
- name: push static binary
|
||||||
image: nixpkgs/nix:nixos-22.05
|
image: nixpkgs/nix:nixos-22.05
|
||||||
environment:
|
environment:
|
||||||
@@ -285,6 +295,6 @@ trigger:
|
|||||||
|
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: 24aebbcdba84fd0cdf963061d7bb72ae5b915bfdd0f50c7b019001126fb7fa56
|
hmac: 0c4b57eb4b27b7c6a6ff21ab87f0767fe3eb90f5d95d5cbcdccf794e9d2a5d86
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
Generated
+25
-9
@@ -1198,7 +1198,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage"
|
name = "garage"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert-json-diff",
|
"assert-json-diff",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1249,7 +1249,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_api"
|
name = "garage_api"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.21.3",
|
"base64 0.21.3",
|
||||||
@@ -1271,6 +1271,7 @@ dependencies = [
|
|||||||
"http-range",
|
"http-range",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"hyperlocal",
|
||||||
"idna",
|
"idna",
|
||||||
"md-5",
|
"md-5",
|
||||||
"multer",
|
"multer",
|
||||||
@@ -1294,7 +1295,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_block"
|
name = "garage_block"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-compression",
|
"async-compression",
|
||||||
@@ -1320,7 +1321,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_db"
|
name = "garage_db"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 4.4.0",
|
"clap 4.4.0",
|
||||||
"err-derive",
|
"err-derive",
|
||||||
@@ -1335,7 +1336,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_model"
|
name = "garage_model"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1363,7 +1364,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_rpc"
|
name = "garage_rpc"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1398,7 +1399,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_table"
|
name = "garage_table"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1420,7 +1421,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_util"
|
name = "garage_util"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1454,7 +1455,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "garage_web"
|
name = "garage_web"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"err-derive",
|
"err-derive",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -1464,8 +1465,10 @@ dependencies = [
|
|||||||
"garage_util",
|
"garage_util",
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"hyperlocal",
|
||||||
"opentelemetry",
|
"opentelemetry",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1775,6 +1778,19 @@ dependencies = [
|
|||||||
"tokio-io-timeout",
|
"tokio-io-timeout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyperlocal"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"hex",
|
||||||
|
"hyper",
|
||||||
|
"pin-project",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.57"
|
version = "0.1.57"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ args@{
|
|||||||
ignoreLockHash,
|
ignoreLockHash,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
nixifiedLockHash = "8ff415a3cc93dd7330ffcc18ee0b3a76c2863e1108be1c88d8e37f29182651f2";
|
nixifiedLockHash = "1a87886681a3ef0b83c95addc26674a538b8a93d35bc80db8998e1fcd0821f6c";
|
||||||
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
|
workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc;
|
||||||
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
|
currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock);
|
||||||
lockHashIgnored = if ignoreLockHash
|
lockHashIgnored = if ignoreLockHash
|
||||||
@@ -57,16 +57,16 @@ in
|
|||||||
{
|
{
|
||||||
cargo2nixVersion = "0.11.0";
|
cargo2nixVersion = "0.11.0";
|
||||||
workspace = {
|
workspace = {
|
||||||
garage_db = rustPackages.unknown.garage_db."0.8.4";
|
garage_db = rustPackages.unknown.garage_db."0.9.0";
|
||||||
garage_util = rustPackages.unknown.garage_util."0.8.4";
|
garage_util = rustPackages.unknown.garage_util."0.9.0";
|
||||||
garage_rpc = rustPackages.unknown.garage_rpc."0.8.4";
|
garage_rpc = rustPackages.unknown.garage_rpc."0.9.0";
|
||||||
format_table = rustPackages.unknown.format_table."0.1.1";
|
format_table = rustPackages.unknown.format_table."0.1.1";
|
||||||
garage_table = rustPackages.unknown.garage_table."0.8.4";
|
garage_table = rustPackages.unknown.garage_table."0.9.0";
|
||||||
garage_block = rustPackages.unknown.garage_block."0.8.4";
|
garage_block = rustPackages.unknown.garage_block."0.9.0";
|
||||||
garage_model = rustPackages.unknown.garage_model."0.8.4";
|
garage_model = rustPackages.unknown.garage_model."0.9.0";
|
||||||
garage_api = rustPackages.unknown.garage_api."0.8.4";
|
garage_api = rustPackages.unknown.garage_api."0.9.0";
|
||||||
garage_web = rustPackages.unknown.garage_web."0.8.4";
|
garage_web = rustPackages.unknown.garage_web."0.9.0";
|
||||||
garage = rustPackages.unknown.garage."0.8.4";
|
garage = rustPackages.unknown.garage."0.9.0";
|
||||||
k2v-client = rustPackages.unknown.k2v-client."0.0.4";
|
k2v-client = rustPackages.unknown.k2v-client."0.0.4";
|
||||||
};
|
};
|
||||||
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.21.0" = overridableMkRustCrate (profileName: rec {
|
"registry+https://github.com/rust-lang/crates.io-index".addr2line."0.21.0" = overridableMkRustCrate (profileName: rec {
|
||||||
@@ -1705,9 +1705,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage";
|
name = "garage";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/garage");
|
src = fetchCrateLocal (workspaceSrc + "/src/garage");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1734,14 +1734,14 @@ in
|
|||||||
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_api = (rustPackages."unknown".garage_api."0.8.4" { inherit profileName; }).out;
|
garage_api = (rustPackages."unknown".garage_api."0.9.0" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."0.8.4" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."0.9.0" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."0.8.4" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."0.9.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.4" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."0.9.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."0.8.4" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
garage_web = (rustPackages."unknown".garage_web."0.8.4" { inherit profileName; }).out;
|
garage_web = (rustPackages."unknown".garage_web."0.9.0" { inherit profileName; }).out;
|
||||||
git_version = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".git-version."0.3.5" { 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;
|
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;
|
sodiumoxide = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".kuska-sodiumoxide."0.2.5-0" { inherit profileName; }).out;
|
||||||
@@ -1777,9 +1777,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_api."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_api."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_api";
|
name = "garage_api";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/api");
|
src = fetchCrateLocal (workspaceSrc + "/src/api");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1798,17 +1798,18 @@ in
|
|||||||
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.2.0" { inherit profileName; }).out;
|
form_urlencoded = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".form_urlencoded."1.2.0" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."0.8.4" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."0.9.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."0.8.4" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."0.9.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.4" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."0.9.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."0.8.4" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { 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;
|
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.9" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.9" { inherit profileName; }).out;
|
||||||
http_range = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http-range."0.1.5" { inherit profileName; }).out;
|
http_range = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http-range."0.1.5" { inherit profileName; }).out;
|
||||||
httpdate = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".httpdate."1.0.3" { inherit profileName; }).out;
|
httpdate = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".httpdate."1.0.3" { inherit profileName; }).out;
|
||||||
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.27" { inherit profileName; }).out;
|
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.27" { inherit profileName; }).out;
|
||||||
|
hyperlocal = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyperlocal."0.8.0" { inherit profileName; }).out;
|
||||||
idna = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".idna."0.4.0" { inherit profileName; }).out;
|
idna = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".idna."0.4.0" { inherit profileName; }).out;
|
||||||
md5 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".md-5."0.10.5" { inherit profileName; }).out;
|
md5 = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".md-5."0.10.5" { inherit profileName; }).out;
|
||||||
multer = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".multer."2.1.0" { inherit profileName; }).out;
|
multer = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".multer."2.1.0" { inherit profileName; }).out;
|
||||||
@@ -1831,9 +1832,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_block."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_block."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_block";
|
name = "garage_block";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/block");
|
src = fetchCrateLocal (workspaceSrc + "/src/block");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1847,10 +1848,10 @@ in
|
|||||||
bytesize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytesize."1.3.0" { inherit profileName; }).out;
|
bytesize = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytesize."1.3.0" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.4" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."0.9.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."0.8.4" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { 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;
|
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;
|
rand = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand."0.8.5" { inherit profileName; }).out;
|
||||||
@@ -1863,9 +1864,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_db."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_db."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_db";
|
name = "garage_db";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/db");
|
src = fetchCrateLocal (workspaceSrc + "/src/db");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1895,9 +1896,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_model."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_model."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_model";
|
name = "garage_model";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/model");
|
src = fetchCrateLocal (workspaceSrc + "/src/model");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1916,11 +1917,11 @@ in
|
|||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).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.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_block = (rustPackages."unknown".garage_block."0.8.4" { inherit profileName; }).out;
|
garage_block = (rustPackages."unknown".garage_block."0.9.0" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.4" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."0.9.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."0.8.4" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { 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.10.0" { inherit profileName; }).out;
|
netapp = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".netapp."0.10.0" { inherit profileName; }).out;
|
||||||
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
@@ -1933,9 +1934,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_rpc."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_rpc."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_rpc";
|
name = "garage_rpc";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
|
src = fetchCrateLocal (workspaceSrc + "/src/rpc");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -1957,8 +1958,8 @@ in
|
|||||||
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
format_table = (rustPackages."unknown".format_table."0.1.1" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
gethostname = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".gethostname."0.4.3" { inherit profileName; }).out;
|
gethostname = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".gethostname."0.4.3" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
itertools = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".itertools."0.10.5" { inherit profileName; }).out;
|
itertools = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".itertools."0.10.5" { inherit profileName; }).out;
|
||||||
@@ -1981,9 +1982,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_table."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_table."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_table";
|
name = "garage_table";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/table");
|
src = fetchCrateLocal (workspaceSrc + "/src/table");
|
||||||
dependencies = {
|
dependencies = {
|
||||||
@@ -1992,9 +1993,9 @@ in
|
|||||||
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.4.0" { inherit profileName; }).out;
|
bytes = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.4.0" { inherit profileName; }).out;
|
||||||
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
garage_rpc = (rustPackages."unknown".garage_rpc."0.8.4" { inherit profileName; }).out;
|
garage_rpc = (rustPackages."unknown".garage_rpc."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { 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;
|
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;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
@@ -2006,9 +2007,9 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_util."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_util."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_util";
|
name = "garage_util";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/util");
|
src = fetchCrateLocal (workspaceSrc + "/src/util");
|
||||||
features = builtins.concatLists [
|
features = builtins.concatLists [
|
||||||
@@ -2024,7 +2025,7 @@ in
|
|||||||
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { inherit profileName; }).out;
|
digest = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { inherit profileName; }).out;
|
||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).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.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
garage_db = (rustPackages."unknown".garage_db."0.8.4" { inherit profileName; }).out;
|
garage_db = (rustPackages."unknown".garage_db."0.9.0" { inherit profileName; }).out;
|
||||||
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { 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;
|
hexdump = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hexdump."0.1.1" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.9" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.9" { inherit profileName; }).out;
|
||||||
@@ -2050,22 +2051,24 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
"unknown".garage_web."0.8.4" = overridableMkRustCrate (profileName: rec {
|
"unknown".garage_web."0.9.0" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "garage_web";
|
name = "garage_web";
|
||||||
version = "0.8.4";
|
version = "0.9.0";
|
||||||
registry = "unknown";
|
registry = "unknown";
|
||||||
src = fetchCrateLocal (workspaceSrc + "/src/web");
|
src = fetchCrateLocal (workspaceSrc + "/src/web");
|
||||||
dependencies = {
|
dependencies = {
|
||||||
err_derive = (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".err-derive."0.3.1" { profileName = "__noProfile"; }).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.28" { inherit profileName; }).out;
|
futures = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures."0.3.28" { inherit profileName; }).out;
|
||||||
garage_api = (rustPackages."unknown".garage_api."0.8.4" { inherit profileName; }).out;
|
garage_api = (rustPackages."unknown".garage_api."0.9.0" { inherit profileName; }).out;
|
||||||
garage_model = (rustPackages."unknown".garage_model."0.8.4" { inherit profileName; }).out;
|
garage_model = (rustPackages."unknown".garage_model."0.9.0" { inherit profileName; }).out;
|
||||||
garage_table = (rustPackages."unknown".garage_table."0.8.4" { inherit profileName; }).out;
|
garage_table = (rustPackages."unknown".garage_table."0.9.0" { inherit profileName; }).out;
|
||||||
garage_util = (rustPackages."unknown".garage_util."0.8.4" { inherit profileName; }).out;
|
garage_util = (rustPackages."unknown".garage_util."0.9.0" { inherit profileName; }).out;
|
||||||
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.9" { inherit profileName; }).out;
|
http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."0.2.9" { inherit profileName; }).out;
|
||||||
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.27" { inherit profileName; }).out;
|
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.27" { inherit profileName; }).out;
|
||||||
|
hyperlocal = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyperlocal."0.8.0" { inherit profileName; }).out;
|
||||||
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
opentelemetry = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".opentelemetry."0.17.0" { inherit profileName; }).out;
|
||||||
percent_encoding = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".percent-encoding."2.3.0" { inherit profileName; }).out;
|
percent_encoding = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".percent-encoding."2.3.0" { inherit profileName; }).out;
|
||||||
|
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.32.0" { inherit profileName; }).out;
|
||||||
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.37" { inherit profileName; }).out;
|
tracing = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.37" { inherit profileName; }).out;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -2491,6 +2494,23 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
"registry+https://github.com/rust-lang/crates.io-index".hyperlocal."0.8.0" = overridableMkRustCrate (profileName: rec {
|
||||||
|
name = "hyperlocal";
|
||||||
|
version = "0.8.0";
|
||||||
|
registry = "registry+https://github.com/rust-lang/crates.io-index";
|
||||||
|
src = fetchCratesIo { inherit name version; sha256 = "0fafdf7b2b2de7c9784f76e02c0935e65a8117ec3b768644379983ab333ac98c"; };
|
||||||
|
features = builtins.concatLists [
|
||||||
|
[ "server" ]
|
||||||
|
];
|
||||||
|
dependencies = {
|
||||||
|
futures_util = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.28" { inherit profileName; }).out;
|
||||||
|
hex = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; }).out;
|
||||||
|
hyper = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.27" { inherit profileName; }).out;
|
||||||
|
pin_project = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-project."1.1.3" { inherit profileName; }).out;
|
||||||
|
tokio = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.32.0" { inherit profileName; }).out;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
"registry+https://github.com/rust-lang/crates.io-index".iana-time-zone."0.1.57" = overridableMkRustCrate (profileName: rec {
|
"registry+https://github.com/rust-lang/crates.io-index".iana-time-zone."0.1.57" = overridableMkRustCrate (profileName: rec {
|
||||||
name = "iana-time-zone";
|
name = "iana-time-zone";
|
||||||
version = "0.1.57";
|
version = "0.1.57";
|
||||||
|
|||||||
+8
-8
@@ -18,14 +18,14 @@ default-members = ["src/garage"]
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
format_table = { version = "0.1.1", path = "src/format-table" }
|
format_table = { version = "0.1.1", path = "src/format-table" }
|
||||||
garage_api = { version = "0.8.4", path = "src/api" }
|
garage_api = { version = "0.9.0", path = "src/api" }
|
||||||
garage_block = { version = "0.8.4", path = "src/block" }
|
garage_block = { version = "0.9.0", path = "src/block" }
|
||||||
garage_db = { version = "0.8.4", path = "src/db", default-features = false }
|
garage_db = { version = "0.9.0", path = "src/db", default-features = false }
|
||||||
garage_model = { version = "0.8.4", path = "src/model", default-features = false }
|
garage_model = { version = "0.9.0", path = "src/model", default-features = false }
|
||||||
garage_rpc = { version = "0.8.4", path = "src/rpc" }
|
garage_rpc = { version = "0.9.0", path = "src/rpc" }
|
||||||
garage_table = { version = "0.8.4", path = "src/table" }
|
garage_table = { version = "0.9.0", path = "src/table" }
|
||||||
garage_util = { version = "0.8.4", path = "src/util" }
|
garage_util = { version = "0.9.0", path = "src/util" }
|
||||||
garage_web = { version = "0.8.4", path = "src/web" }
|
garage_web = { version = "0.9.0", path = "src/web" }
|
||||||
k2v-client = { version = "0.0.4", path = "src/k2v-client" }
|
k2v-client = { version = "0.0.4", path = "src/k2v-client" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ Now we can write a simple script (eg `~/.local/bin/matrix-cache-gc`):
|
|||||||
## CONFIGURATION ##
|
## CONFIGURATION ##
|
||||||
AWS_ACCESS_KEY_ID=GKxxx
|
AWS_ACCESS_KEY_ID=GKxxx
|
||||||
AWS_SECRET_ACCESS_KEY=xxxx
|
AWS_SECRET_ACCESS_KEY=xxxx
|
||||||
S3_ENDPOINT=http://localhost:3900
|
AWS_ENDPOINT_URL=http://localhost:3900
|
||||||
S3_BUCKET=matrix
|
S3_BUCKET=matrix
|
||||||
MEDIA_STORE=/var/lib/matrix-synapse/media
|
MEDIA_STORE=/var/lib/matrix-synapse/media
|
||||||
PG_USER=matrix
|
PG_USER=matrix
|
||||||
@@ -442,7 +442,7 @@ EOF
|
|||||||
|
|
||||||
s3_media_upload update-db 1d
|
s3_media_upload update-db 1d
|
||||||
s3_media_upload --no-progress check-deleted $MEDIA_STORE
|
s3_media_upload --no-progress check-deleted $MEDIA_STORE
|
||||||
s3_media_upload --no-progress upload $MEDIA_STORE $S3_BUCKET --delete --endpoint-url $S3_ENDPOINT
|
s3_media_upload --no-progress upload $MEDIA_STORE $S3_BUCKET --delete --endpoint-url $AWS_ENDPOINT_URL
|
||||||
```
|
```
|
||||||
|
|
||||||
This script will list all the medias that were not accessed in the 24 hours according to your database.
|
This script will list all the medias that were not accessed in the 24 hours according to your database.
|
||||||
|
|||||||
@@ -70,16 +70,17 @@ Then a file named `~/.aws/config` and put:
|
|||||||
```toml
|
```toml
|
||||||
[default]
|
[default]
|
||||||
region=garage
|
region=garage
|
||||||
|
endpoint_url=http://127.0.0.1:3900
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, supposing Garage is listening on `http://127.0.0.1:3900`, you can list your buckets with:
|
Now, supposing Garage is listening on `http://127.0.0.1:3900`, you can list your buckets with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
aws --endpoint-url http://127.0.0.1:3900 s3 ls
|
aws s3 ls
|
||||||
```
|
```
|
||||||
|
|
||||||
Passing the `--endpoint-url` parameter to each command is annoying but AWS developers do not provide a corresponding configuration entry.
|
If you're using awscli `<1.29.0` or `<2.13.0`, you need to pass `--endpoint-url` to each CLI invocation explicitly.
|
||||||
As a workaround, you can redefine the aws command by editing the file `~/.bashrc`:
|
As a workaround, you can redefine the aws command by editing the file `~/.bashrc` in this case:
|
||||||
|
|
||||||
```
|
```
|
||||||
function aws { command aws --endpoint-url http://127.0.0.1:3900 $@ ; }
|
function aws { command aws --endpoint-url http://127.0.0.1:3900 $@ ; }
|
||||||
|
|||||||
@@ -269,12 +269,14 @@ named `~/.awsrc` with this content:
|
|||||||
export AWS_ACCESS_KEY_ID=xxxx # put your Key ID here
|
export AWS_ACCESS_KEY_ID=xxxx # put your Key ID here
|
||||||
export AWS_SECRET_ACCESS_KEY=xxxx # put your Secret key here
|
export AWS_SECRET_ACCESS_KEY=xxxx # put your Secret key here
|
||||||
export AWS_DEFAULT_REGION='garage'
|
export AWS_DEFAULT_REGION='garage'
|
||||||
export AWS_ENDPOINT='http://localhost:3900'
|
export AWS_ENDPOINT_URL='http://localhost:3900'
|
||||||
|
|
||||||
function aws { command aws --endpoint-url $AWS_ENDPOINT $@ ; }
|
|
||||||
aws --version
|
aws --version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note you need to have at least `awscli` `>=1.29.0` or `>=2.13.0`, otherwise you
|
||||||
|
need to specify `--endpoint-url` explicitly on each `awscli` invocation.
|
||||||
|
|
||||||
Now, each time you want to use `awscli` on this target, run:
|
Now, each time you want to use `awscli` on this target, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -468,6 +468,8 @@ manually.
|
|||||||
The IP and port on which to bind for accepting S3 API calls.
|
The IP and port on which to bind for accepting S3 API calls.
|
||||||
This endpoint does not suport TLS: a reverse proxy should be used to provide it.
|
This endpoint does not suport TLS: a reverse proxy should be used to provide it.
|
||||||
|
|
||||||
|
Alternatively, since `v0.8.5`, a path can be used to create a unix socket with 0222 mode.
|
||||||
|
|
||||||
### `s3_region`
|
### `s3_region`
|
||||||
|
|
||||||
Garage will accept S3 API calls that are targetted to the S3 region defined here.
|
Garage will accept S3 API calls that are targetted to the S3 region defined here.
|
||||||
@@ -497,6 +499,8 @@ The IP and port on which to bind for accepting HTTP requests to buckets configur
|
|||||||
for website access.
|
for website access.
|
||||||
This endpoint does not suport TLS: a reverse proxy should be used to provide it.
|
This endpoint does not suport TLS: a reverse proxy should be used to provide it.
|
||||||
|
|
||||||
|
Alternatively, since `v0.8.5`, a path can be used to create a unix socket with 0222 mode.
|
||||||
|
|
||||||
### `root_domain`
|
### `root_domain`
|
||||||
|
|
||||||
The optional suffix appended to bucket names for the corresponding HTTP Host.
|
The optional suffix appended to bucket names for the corresponding HTTP Host.
|
||||||
@@ -516,6 +520,9 @@ If specified, Garage will bind an HTTP server to this port and address, on
|
|||||||
which it will listen to requests for administration features.
|
which it will listen to requests for administration features.
|
||||||
See [administration API reference](@/documentation/reference-manual/admin-api.md) to learn more about these features.
|
See [administration API reference](@/documentation/reference-manual/admin-api.md) to learn more about these features.
|
||||||
|
|
||||||
|
Alternatively, since `v0.8.5`, a path can be used to create a unix socket. Note that for security reasons,
|
||||||
|
the socket will have 0220 mode. Make sure to set user and group permissions accordingly.
|
||||||
|
|
||||||
### `metrics_token`, `metrics_token_file` or `GARAGE_METRICS_TOKEN` (env)
|
### `metrics_token`, `metrics_token_file` or `GARAGE_METRICS_TOKEN` (env)
|
||||||
|
|
||||||
The token for accessing the Metrics endpoint. If this token is not set, the
|
The token for accessing the Metrics endpoint. If this token is not set, the
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
+++
|
||||||
|
title = "Migrating from 0.8 to 0.9"
|
||||||
|
weight = 14
|
||||||
|
+++
|
||||||
|
|
||||||
|
**This guide explains how to migrate to 0.9 if you have an existing 0.8 cluster.
|
||||||
|
We don't recommend trying to migrate to 0.9 directly from 0.7 or older.**
|
||||||
|
|
||||||
|
**We make no guarantee that this migration will work perfectly:
|
||||||
|
back up all your data before attempting it!**
|
||||||
|
|
||||||
|
The following are **breaking changes** in Garage v0.9 that require your attention when migrating:
|
||||||
|
|
||||||
|
- LMDB is now the default metadata db engine and Sled is deprecated. If you were using Sled, make sure to specify `db_engine = "sled"` in your configuration file, or take the time to [convert your database](https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db-engine-since-v0-8-0).
|
||||||
|
|
||||||
|
- Capacity values are now in actual byte units. The translation from the old layout will assign 1 capacity = 1Gb by default, which might be wrong for your cluster. This does not cause any data to be moved around, but you might want to re-assign correct capacity values post-migration.
|
||||||
|
|
||||||
|
- Multipart uploads that were started in Garage v0.8 will not be visible in Garage v0.9 and will have to be restarted from scratch.
|
||||||
|
|
||||||
|
- Changes to the admin API: some `v0/` endpoints have been replaced by `v1/` counterparts with updated/uniformized syntax. All other endpoints have also moved to `v1/` by default, without syntax changes, but are still available under `v0/` for compatibility.
|
||||||
|
|
||||||
|
|
||||||
|
## Simple migration procedure (takes cluster offline for a while)
|
||||||
|
|
||||||
|
The migration steps are as follows:
|
||||||
|
|
||||||
|
1. Disable API and web access. You may do this by stopping your reverse proxy or by commenting out
|
||||||
|
the `api_bind_addr` values in your `config.toml` file and restarting Garage.
|
||||||
|
2. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`,
|
||||||
|
check the logs and check that all data seems to be synced correctly between
|
||||||
|
nodes. If you have time, do additional checks (`versions`, `block_refs`, etc.)
|
||||||
|
3. Check that the block resync queue and Merkle queue are empty:
|
||||||
|
run `garage stats -a` to query them or inspect metrics in the Grafana dashboard.
|
||||||
|
4. Turn off Garage v0.8
|
||||||
|
5. **Backup the metadata folder of all your nodes!** For instance, use the following command
|
||||||
|
if your metadata directory is `/var/lib/garage/meta`: `cd /var/lib/garage ; tar -acf meta-v0.8.tar.zst meta/`
|
||||||
|
6. Install Garage v0.9
|
||||||
|
7. Update your configuration file if necessary.
|
||||||
|
8. Turn on Garage v0.9
|
||||||
|
9. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`.
|
||||||
|
Wait for a full table sync to run.
|
||||||
|
10. Your upgraded cluster should be in a working state. Re-enable API and Web
|
||||||
|
access and check that everything went well.
|
||||||
|
11. Monitor your cluster in the next hours to see if it works well under your production load, report any issue.
|
||||||
|
12. You might want to assign correct capacity values to all your nodes. Doing so might cause data to be moved
|
||||||
|
in your cluster, which should also be monitored carefully.
|
||||||
|
|
||||||
|
## Minimal downtime migration procedure
|
||||||
|
|
||||||
|
The migration to Garage v0.9 can be done with almost no downtime,
|
||||||
|
by restarting all nodes at once in the new version.
|
||||||
|
|
||||||
|
The migration steps are as follows:
|
||||||
|
|
||||||
|
1. Do `garage repair --all-nodes --yes tables` and `garage repair --all-nodes --yes blocks`,
|
||||||
|
check the logs and check that all data seems to be synced correctly between
|
||||||
|
nodes. If you have time, do additional checks (`versions`, `block_refs`, etc.)
|
||||||
|
|
||||||
|
2. Turn off each node individually; back up its metadata folder (see above); turn it back on again.
|
||||||
|
This will allow you to take a backup of all nodes without impacting global cluster availability.
|
||||||
|
You can do all nodes of a single zone at once as this does not impact the availability of Garage.
|
||||||
|
|
||||||
|
3. Prepare your binaries and configuration files for Garage v0.9
|
||||||
|
|
||||||
|
4. Shut down all v0.8 nodes simultaneously, and restart them all simultaneously in v0.9.
|
||||||
|
Use your favorite deployment tool (Ansible, Kubernetes, Nomad) to achieve this as fast as possible.
|
||||||
|
Garage v0.9 should be in a working state as soon as it starts.
|
||||||
|
|
||||||
|
5. Proceed with repair and monitoring as described in steps 9-12 above.
|
||||||
+14
-3
@@ -9,11 +9,22 @@ GARAGE_RELEASE="${REPO_FOLDER}/target/release/"
|
|||||||
NIX_RELEASE="${REPO_FOLDER}/result/bin/"
|
NIX_RELEASE="${REPO_FOLDER}/result/bin/"
|
||||||
PATH="${GARAGE_DEBUG}:${GARAGE_RELEASE}:${NIX_RELEASE}:$PATH"
|
PATH="${GARAGE_DEBUG}:${GARAGE_RELEASE}:${NIX_RELEASE}:$PATH"
|
||||||
|
|
||||||
garage -c /tmp/config.1.toml bucket create eprouvette
|
if [ -z "$GARAGE_BIN" ]; then
|
||||||
KEY_INFO=$(garage -c /tmp/config.1.toml key create opérateur)
|
GARAGE_BIN=$(which garage || exit 1)
|
||||||
|
echo -en "Found garage at: ${GARAGE_BIN}\n"
|
||||||
|
else
|
||||||
|
echo -en "Using garage binary at: ${GARAGE_BIN}\n"
|
||||||
|
fi
|
||||||
|
|
||||||
|
$GARAGE_BIN -c /tmp/config.1.toml bucket create eprouvette
|
||||||
|
if [ "$GARAGE_08" = "1" ]; then
|
||||||
|
KEY_INFO=$($GARAGE_BIN -c /tmp/config.1.toml key new --name opérateur)
|
||||||
|
else
|
||||||
|
KEY_INFO=$($GARAGE_BIN -c /tmp/config.1.toml key create opérateur)
|
||||||
|
fi
|
||||||
ACCESS_KEY=`echo $KEY_INFO|grep -Po 'GK[a-f0-9]+'`
|
ACCESS_KEY=`echo $KEY_INFO|grep -Po 'GK[a-f0-9]+'`
|
||||||
SECRET_KEY=`echo $KEY_INFO|grep -Po 'Secret key: [a-f0-9]+'|grep -Po '[a-f0-9]+$'`
|
SECRET_KEY=`echo $KEY_INFO|grep -Po 'Secret key: [a-f0-9]+'|grep -Po '[a-f0-9]+$'`
|
||||||
garage -c /tmp/config.1.toml bucket allow eprouvette --read --write --owner --key $ACCESS_KEY
|
$GARAGE_BIN -c /tmp/config.1.toml bucket allow eprouvette --read --write --owner --key $ACCESS_KEY
|
||||||
echo "$ACCESS_KEY $SECRET_KEY" > /tmp/garage.s3
|
echo "$ACCESS_KEY $SECRET_KEY" > /tmp/garage.s3
|
||||||
|
|
||||||
echo "Bucket s3://eprouvette created. Credentials stored in /tmp/garage.s3."
|
echo "Bucket s3://eprouvette created. Credentials stored in /tmp/garage.s3."
|
||||||
|
|||||||
+12
-6
@@ -14,8 +14,13 @@ export RUST_BACKTRACE=1
|
|||||||
export RUST_LOG=garage=info,garage_api=debug
|
export RUST_LOG=garage=info,garage_api=debug
|
||||||
MAIN_LABEL="\e[${FANCYCOLORS[0]}[main]\e[49m"
|
MAIN_LABEL="\e[${FANCYCOLORS[0]}[main]\e[49m"
|
||||||
|
|
||||||
WHICH_GARAGE=$(which garage || exit 1)
|
if [ -z "$GARAGE_BIN" ]; then
|
||||||
echo -en "${MAIN_LABEL} Found garage at: ${WHICH_GARAGE}\n"
|
GARAGE_BIN=$(which garage || exit 1)
|
||||||
|
echo -en "${MAIN_LABEL} Found garage at: ${GARAGE_BIN}\n"
|
||||||
|
else
|
||||||
|
echo -en "${MAIN_LABEL} Using garage binary at: ${GARAGE_BIN}\n"
|
||||||
|
fi
|
||||||
|
$GARAGE_BIN --version
|
||||||
|
|
||||||
NETWORK_SECRET="$(openssl rand -hex 32)"
|
NETWORK_SECRET="$(openssl rand -hex 32)"
|
||||||
|
|
||||||
@@ -28,6 +33,7 @@ LABEL="\e[${FANCYCOLORS[$count]}[$count]\e[49m"
|
|||||||
cat > $CONF_PATH <<EOF
|
cat > $CONF_PATH <<EOF
|
||||||
block_size = 1048576 # objects are split in blocks of maximum this number of bytes
|
block_size = 1048576 # objects are split in blocks of maximum this number of bytes
|
||||||
metadata_dir = "/tmp/garage-meta-$count"
|
metadata_dir = "/tmp/garage-meta-$count"
|
||||||
|
db_engine = "lmdb"
|
||||||
data_dir = "/tmp/garage-data-$count"
|
data_dir = "/tmp/garage-data-$count"
|
||||||
rpc_bind_addr = "0.0.0.0:$((3900+$count))" # the port other Garage nodes will use to talk to this node
|
rpc_bind_addr = "0.0.0.0:$((3900+$count))" # the port other Garage nodes will use to talk to this node
|
||||||
rpc_public_addr = "127.0.0.1:$((3900+$count))"
|
rpc_public_addr = "127.0.0.1:$((3900+$count))"
|
||||||
@@ -51,7 +57,7 @@ EOF
|
|||||||
|
|
||||||
echo -en "$LABEL configuration written to $CONF_PATH\n"
|
echo -en "$LABEL configuration written to $CONF_PATH\n"
|
||||||
|
|
||||||
(garage -c /tmp/config.$count.toml server 2>&1|while read r; do echo -en "$LABEL $r\n"; done) &
|
($GARAGE_BIN -c /tmp/config.$count.toml server 2>&1|while read r; do echo -en "$LABEL $r\n"; done) &
|
||||||
done
|
done
|
||||||
# >>>>>>>>>>>>>>>> END FOR LOOP ON NODES
|
# >>>>>>>>>>>>>>>> END FOR LOOP ON NODES
|
||||||
|
|
||||||
@@ -73,14 +79,14 @@ fi
|
|||||||
sleep 3
|
sleep 3
|
||||||
# Establish connections between nodes
|
# Establish connections between nodes
|
||||||
for count in $(seq 1 3); do
|
for count in $(seq 1 3); do
|
||||||
NODE=$(garage -c /tmp/config.$count.toml node id -q)
|
NODE=$($GARAGE_BIN -c /tmp/config.$count.toml node id -q)
|
||||||
for count2 in $(seq 1 3); do
|
for count2 in $(seq 1 3); do
|
||||||
garage -c /tmp/config.$count2.toml node connect $NODE
|
$GARAGE_BIN -c /tmp/config.$count2.toml node connect $NODE
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
RETRY=120
|
RETRY=120
|
||||||
until garage -c /tmp/config.1.toml status 2>&1|grep -q HEALTHY ; do
|
until $GARAGE_BIN -c /tmp/config.1.toml status 2>&1|grep -q HEALTHY ; do
|
||||||
(( RETRY-- ))
|
(( RETRY-- ))
|
||||||
if (( RETRY <= 0 )); then
|
if (( RETRY <= 0 )); then
|
||||||
echo -en "${MAIN_LABEL} Garage did not start"
|
echo -en "${MAIN_LABEL} Garage did not start"
|
||||||
|
|||||||
+25
-9
@@ -9,9 +9,17 @@ GARAGE_RELEASE="${REPO_FOLDER}/target/release/"
|
|||||||
NIX_RELEASE="${REPO_FOLDER}/result/bin/"
|
NIX_RELEASE="${REPO_FOLDER}/result/bin/"
|
||||||
PATH="${GARAGE_DEBUG}:${GARAGE_RELEASE}:${NIX_RELEASE}:$PATH"
|
PATH="${GARAGE_DEBUG}:${GARAGE_RELEASE}:${NIX_RELEASE}:$PATH"
|
||||||
|
|
||||||
|
if [ -z "$GARAGE_BIN" ]; then
|
||||||
|
GARAGE_BIN=$(which garage || exit 1)
|
||||||
|
echo -en "Found garage at: ${GARAGE_BIN}\n"
|
||||||
|
else
|
||||||
|
echo -en "Using garage binary at: ${GARAGE_BIN}\n"
|
||||||
|
fi
|
||||||
|
$GARAGE_BIN --version
|
||||||
|
|
||||||
sleep 5
|
sleep 5
|
||||||
RETRY=120
|
RETRY=120
|
||||||
until garage -c /tmp/config.1.toml status 2>&1|grep -q HEALTHY ; do
|
until $GARAGE_BIN -c /tmp/config.1.toml status 2>&1|grep -q HEALTHY ; do
|
||||||
(( RETRY-- ))
|
(( RETRY-- ))
|
||||||
if (( RETRY <= 0 )); then
|
if (( RETRY <= 0 )); then
|
||||||
echo "garage did not start in time, failing."
|
echo "garage did not start in time, failing."
|
||||||
@@ -21,12 +29,20 @@ until garage -c /tmp/config.1.toml status 2>&1|grep -q HEALTHY ; do
|
|||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
garage -c /tmp/config.1.toml status \
|
if [ "$GARAGE_08" = "1" ]; then
|
||||||
| grep 'NO ROLE' \
|
$GARAGE_BIN -c /tmp/config.1.toml status \
|
||||||
| grep -Po '^[0-9a-f]+' \
|
| grep 'NO ROLE' \
|
||||||
| while read id; do
|
| grep -Po '^[0-9a-f]+' \
|
||||||
garage -c /tmp/config.1.toml layout assign $id -z dc1 -c 1G
|
| while read id; do
|
||||||
done
|
$GARAGE_BIN -c /tmp/config.1.toml layout assign $id -z dc1 -c 1
|
||||||
|
done
|
||||||
|
else
|
||||||
|
$GARAGE_BIN -c /tmp/config.1.toml status \
|
||||||
|
| grep 'NO ROLE' \
|
||||||
|
| grep -Po '^[0-9a-f]+' \
|
||||||
|
| while read id; do
|
||||||
|
$GARAGE_BIN -c /tmp/config.1.toml layout assign $id -z dc1 -c 1G
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
garage -c /tmp/config.1.toml layout config -r 1
|
$GARAGE_BIN -c /tmp/config.1.toml layout apply --version 1
|
||||||
garage -c /tmp/config.1.toml layout apply --version 1
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export AWS_ACCESS_KEY_ID=`cat /tmp/garage.s3 |cut -d' ' -f1`
|
export AWS_ACCESS_KEY_ID=`cat /tmp/garage.s3 |cut -d' ' -f1`
|
||||||
export AWS_SECRET_ACCESS_KEY=`cat /tmp/garage.s3 |cut -d' ' -f2`
|
export AWS_SECRET_ACCESS_KEY=`cat /tmp/garage.s3 |cut -d' ' -f2`
|
||||||
export AWS_DEFAULT_REGION='garage'
|
export AWS_DEFAULT_REGION='garage'
|
||||||
|
# FUTUREWORK: set AWS_ENDPOINT_URL instead, once nixpkgs bumps awscli to >=2.13.0.
|
||||||
function aws { command aws --endpoint-url http://127.0.0.1:3911 $@ ; }
|
function aws { command aws --endpoint-url http://127.0.0.1:3911 $@ ; }
|
||||||
|
|
||||||
aws --version
|
aws --version
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ version: 0.4.1
|
|||||||
# incremented each time you make changes to the application. Versions are not expected to
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
# It is recommended to use it with quotes.
|
# It is recommended to use it with quotes.
|
||||||
appVersion: "v0.8.4"
|
appVersion: "v0.9.0"
|
||||||
|
|||||||
Executable
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
export LANG=C.UTF-8
|
||||||
|
SCRIPT_FOLDER="`dirname \"$0\"`"
|
||||||
|
REPO_FOLDER="${SCRIPT_FOLDER}/../"
|
||||||
|
GARAGE_DEBUG="${REPO_FOLDER}/target/debug/"
|
||||||
|
GARAGE_RELEASE="${REPO_FOLDER}/target/release/"
|
||||||
|
NIX_RELEASE="${REPO_FOLDER}/result/bin/:${REPO_FOLDER}/result-bin/bin/"
|
||||||
|
PATH="${GARAGE_DEBUG}:${GARAGE_RELEASE}:${NIX_RELEASE}:$PATH"
|
||||||
|
|
||||||
|
OLD_VERSION="$1"
|
||||||
|
ARCH="$2"
|
||||||
|
|
||||||
|
|
||||||
|
echo "Downloading old garage binary..."
|
||||||
|
curl https://garagehq.deuxfleurs.fr/_releases/$OLD_VERSION/$ARCH/garage > /tmp/old_garage
|
||||||
|
chmod +x /tmp/old_garage
|
||||||
|
|
||||||
|
echo "============= insert data into old version cluster ================="
|
||||||
|
|
||||||
|
export GARAGE_BIN=/tmp/old_garage
|
||||||
|
if echo $OLD_VERSION | grep 'v0\.8\.'; then
|
||||||
|
echo "Detected Garage v0.8.x"
|
||||||
|
export GARAGE_08=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "⏳ Setup cluster using old version"
|
||||||
|
$GARAGE_BIN --version
|
||||||
|
${SCRIPT_FOLDER}/dev-clean.sh
|
||||||
|
${SCRIPT_FOLDER}/dev-cluster.sh > /tmp/garage.log 2>&1 &
|
||||||
|
sleep 6
|
||||||
|
${SCRIPT_FOLDER}/dev-configure.sh
|
||||||
|
${SCRIPT_FOLDER}/dev-bucket.sh
|
||||||
|
|
||||||
|
echo "🛠️ Inserting data in old cluster"
|
||||||
|
source ${SCRIPT_FOLDER}/dev-env-rclone.sh
|
||||||
|
rclone copy "${SCRIPT_FOLDER}/../.git/" garage:eprouvette/test_dotgit --stats=1s --stats-log-level=NOTICE --stats-one-line
|
||||||
|
|
||||||
|
echo "🏁 Stopping old cluster"
|
||||||
|
killall -INT old_garage
|
||||||
|
sleep 2
|
||||||
|
killall -9 old_garage || true
|
||||||
|
|
||||||
|
echo "🏁 Removing old garage version"
|
||||||
|
rm -rv $GARAGE_BIN
|
||||||
|
export -n GARAGE_BIN
|
||||||
|
export -n GARAGE_08
|
||||||
|
|
||||||
|
echo "================ read data from new cluster ==================="
|
||||||
|
|
||||||
|
echo "⏳ Setup cluster using new version"
|
||||||
|
pwd
|
||||||
|
ls
|
||||||
|
export GARAGE_BIN=$(which garage)
|
||||||
|
$GARAGE_BIN --version
|
||||||
|
${SCRIPT_FOLDER}/dev-cluster.sh >> /tmp/garage.log 2>&1 &
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo "🛠️ Retrieving data from old cluster"
|
||||||
|
rclone copy garage:eprouvette/test_dotgit /tmp/test_dotgit --stats=1s --stats-log-level=NOTICE --stats-one-line --fast-list
|
||||||
|
|
||||||
|
if ! diff <(find "${SCRIPT_FOLDER}/../.git" -type f | xargs md5sum | cut -d ' ' -f 1 | sort) <(find /tmp/test_dotgit -type f | xargs md5sum | cut -d ' ' -f 1 | sort); then
|
||||||
|
echo "TEST FAILURE: directories are different"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm -r /tmp/test_dotgit
|
||||||
|
|
||||||
|
echo "🏁 Teardown"
|
||||||
|
rm -rf /tmp/garage-{data,meta}-*
|
||||||
|
rm -rf /tmp/config.*.toml
|
||||||
|
|
||||||
|
echo "✅ Success"
|
||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_api"
|
name = "garage_api"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
@@ -45,6 +45,7 @@ http = "0.2"
|
|||||||
httpdate = "1.0"
|
httpdate = "1.0"
|
||||||
http-range = "0.1"
|
http-range = "0.1"
|
||||||
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
||||||
|
hyperlocal = { version = "0.8.0", default-features = false, features = ["server"] }
|
||||||
multer = "2.0"
|
multer = "2.0"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
roxmltree = "0.18"
|
roxmltree = "0.18"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -18,6 +17,7 @@ use prometheus::{Encoder, TextEncoder};
|
|||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
use garage_rpc::system::ClusterHealthStatus;
|
use garage_rpc::system::ClusterHealthStatus;
|
||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
|
use garage_util::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
use crate::generic_server::*;
|
use crate::generic_server::*;
|
||||||
|
|
||||||
@@ -25,7 +25,8 @@ use crate::admin::bucket::*;
|
|||||||
use crate::admin::cluster::*;
|
use crate::admin::cluster::*;
|
||||||
use crate::admin::error::*;
|
use crate::admin::error::*;
|
||||||
use crate::admin::key::*;
|
use crate::admin::key::*;
|
||||||
use crate::admin::router::{Authorization, Endpoint};
|
use crate::admin::router_v0;
|
||||||
|
use crate::admin::router_v1::{Authorization, Endpoint};
|
||||||
use crate::helpers::host_to_bucket;
|
use crate::helpers::host_to_bucket;
|
||||||
|
|
||||||
pub struct AdminApiServer {
|
pub struct AdminApiServer {
|
||||||
@@ -61,12 +62,12 @@ impl AdminApiServer {
|
|||||||
|
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
self,
|
self,
|
||||||
bind_addr: SocketAddr,
|
bind_addr: UnixOrTCPSocketAddress,
|
||||||
shutdown_signal: impl Future<Output = ()>,
|
shutdown_signal: impl Future<Output = ()>,
|
||||||
) -> Result<(), GarageError> {
|
) -> Result<(), GarageError> {
|
||||||
let region = self.garage.config.s3_api.s3_region.clone();
|
let region = self.garage.config.s3_api.s3_region.clone();
|
||||||
ApiServer::new(region, self)
|
ApiServer::new(region, self)
|
||||||
.run_server(bind_addr, shutdown_signal)
|
.run_server(bind_addr, Some(0o220), shutdown_signal)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +230,12 @@ impl ApiHandler for AdminApiServer {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn parse_endpoint(&self, req: &Request<Body>) -> Result<Endpoint, Error> {
|
fn parse_endpoint(&self, req: &Request<Body>) -> Result<Endpoint, Error> {
|
||||||
Endpoint::from_request(req)
|
if req.uri().path().starts_with("/v0/") {
|
||||||
|
let endpoint_v0 = router_v0::Endpoint::from_request(req)?;
|
||||||
|
Endpoint::from_v0(endpoint_v0)
|
||||||
|
} else {
|
||||||
|
Endpoint::from_request(req)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle(
|
async fn handle(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pub mod api_server;
|
pub mod api_server;
|
||||||
mod error;
|
mod error;
|
||||||
mod router;
|
mod router_v0;
|
||||||
|
mod router_v1;
|
||||||
|
|
||||||
mod bucket;
|
mod bucket;
|
||||||
mod cluster;
|
mod cluster;
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use hyper::{Method, Request};
|
|
||||||
|
|
||||||
use crate::admin::error::*;
|
|
||||||
use crate::router_macros::*;
|
|
||||||
|
|
||||||
pub enum Authorization {
|
|
||||||
None,
|
|
||||||
MetricsToken,
|
|
||||||
AdminToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
router_match! {@func
|
|
||||||
|
|
||||||
/// List of all Admin API endpoints.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Endpoint {
|
|
||||||
Options,
|
|
||||||
CheckDomain,
|
|
||||||
Health,
|
|
||||||
Metrics,
|
|
||||||
GetClusterStatus,
|
|
||||||
GetClusterHealth,
|
|
||||||
ConnectClusterNodes,
|
|
||||||
// Layout
|
|
||||||
GetClusterLayout,
|
|
||||||
UpdateClusterLayout,
|
|
||||||
ApplyClusterLayout,
|
|
||||||
RevertClusterLayout,
|
|
||||||
// Keys
|
|
||||||
ListKeys,
|
|
||||||
CreateKey,
|
|
||||||
ImportKey,
|
|
||||||
GetKeyInfo {
|
|
||||||
id: Option<String>,
|
|
||||||
search: Option<String>,
|
|
||||||
show_secret_key: Option<String>,
|
|
||||||
},
|
|
||||||
DeleteKey {
|
|
||||||
id: String,
|
|
||||||
},
|
|
||||||
UpdateKey {
|
|
||||||
id: String,
|
|
||||||
},
|
|
||||||
// Buckets
|
|
||||||
ListBuckets,
|
|
||||||
CreateBucket,
|
|
||||||
GetBucketInfo {
|
|
||||||
id: Option<String>,
|
|
||||||
global_alias: Option<String>,
|
|
||||||
},
|
|
||||||
DeleteBucket {
|
|
||||||
id: String,
|
|
||||||
},
|
|
||||||
UpdateBucket {
|
|
||||||
id: String,
|
|
||||||
},
|
|
||||||
// Bucket-Key Permissions
|
|
||||||
BucketAllowKey,
|
|
||||||
BucketDenyKey,
|
|
||||||
// Bucket aliases
|
|
||||||
GlobalAliasBucket {
|
|
||||||
id: String,
|
|
||||||
alias: String,
|
|
||||||
},
|
|
||||||
GlobalUnaliasBucket {
|
|
||||||
id: String,
|
|
||||||
alias: String,
|
|
||||||
},
|
|
||||||
LocalAliasBucket {
|
|
||||||
id: String,
|
|
||||||
access_key_id: String,
|
|
||||||
alias: String,
|
|
||||||
},
|
|
||||||
LocalUnaliasBucket {
|
|
||||||
id: String,
|
|
||||||
access_key_id: String,
|
|
||||||
alias: String,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
impl Endpoint {
|
|
||||||
/// Determine which S3 endpoint a request is for using the request, and a bucket which was
|
|
||||||
/// possibly extracted from the Host header.
|
|
||||||
/// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets
|
|
||||||
pub fn from_request<T>(req: &Request<T>) -> Result<Self, Error> {
|
|
||||||
let uri = req.uri();
|
|
||||||
let path = uri.path();
|
|
||||||
let query = uri.query();
|
|
||||||
|
|
||||||
let mut query = QueryParameters::from_query(query.unwrap_or_default())?;
|
|
||||||
|
|
||||||
let res = router_match!(@gen_path_parser (req.method(), path, query) [
|
|
||||||
OPTIONS _ => Options,
|
|
||||||
GET "/check" => CheckDomain,
|
|
||||||
GET "/health" => Health,
|
|
||||||
GET "/metrics" => Metrics,
|
|
||||||
GET "/v1/status" => GetClusterStatus,
|
|
||||||
GET "/v1/health" => GetClusterHealth,
|
|
||||||
POST ("/v0/connect" | "/v1/connect") => ConnectClusterNodes,
|
|
||||||
// Layout endpoints
|
|
||||||
GET "/v1/layout" => GetClusterLayout,
|
|
||||||
POST "/v1/layout" => UpdateClusterLayout,
|
|
||||||
POST "/v1/layout/apply" => ApplyClusterLayout,
|
|
||||||
POST ("/v0/layout/revert" | "/v1/layout/revert") => RevertClusterLayout,
|
|
||||||
// API key endpoints
|
|
||||||
GET "/v1/key" if id => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key),
|
|
||||||
GET "/v1/key" if search => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key),
|
|
||||||
POST "/v1/key" if id => UpdateKey (query::id),
|
|
||||||
POST "/v1/key" => CreateKey,
|
|
||||||
POST "/v1/key/import" => ImportKey,
|
|
||||||
DELETE ("/v0/key" | "/v1/key") if id => DeleteKey (query::id),
|
|
||||||
GET ("/v0/key" | "/v1/key") => ListKeys,
|
|
||||||
// Bucket endpoints
|
|
||||||
GET ("/v0/bucket" | "/v1/bucket") if id => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
|
||||||
GET ("/v0/bucket" | "/v1/bucket") if global_alias => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
|
||||||
GET ("/v0/bucket" | "/v1/bucket") => ListBuckets,
|
|
||||||
POST ("/v0/bucket" | "/v1/bucket") => CreateBucket,
|
|
||||||
DELETE ("/v0/bucket" | "/v1/bucket") if id => DeleteBucket (query::id),
|
|
||||||
PUT ("/v0/bucket" | "/v1/bucket") if id => UpdateBucket (query::id),
|
|
||||||
// Bucket-key permissions
|
|
||||||
POST ("/v0/bucket/allow" | "/v1/bucket/allow") => BucketAllowKey,
|
|
||||||
POST ("/v0/bucket/deny" | "/v1/bucket/deny") => BucketDenyKey,
|
|
||||||
// Bucket aliases
|
|
||||||
PUT ("/v0/bucket/alias/global" | "/v1/bucket/alias/global") => GlobalAliasBucket (query::id, query::alias),
|
|
||||||
DELETE ("/v0/bucket/alias/global" | "/v1/bucket/alias/global") => GlobalUnaliasBucket (query::id, query::alias),
|
|
||||||
PUT ("/v0/bucket/alias/local" | "/v1/bucket/alias/local") => LocalAliasBucket (query::id, query::access_key_id, query::alias),
|
|
||||||
DELETE ("/v0/bucket/alias/local" | "/v1/bucket/alias/local") => LocalUnaliasBucket (query::id, query::access_key_id, query::alias),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if let Some(message) = query.nonempty_message() {
|
|
||||||
debug!("Unused query parameter: {}", message)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
/// Get the kind of authorization which is required to perform the operation.
|
|
||||||
pub fn authorization_type(&self) -> Authorization {
|
|
||||||
match self {
|
|
||||||
Self::Health => Authorization::None,
|
|
||||||
Self::CheckDomain => Authorization::None,
|
|
||||||
Self::Metrics => Authorization::MetricsToken,
|
|
||||||
_ => Authorization::AdminToken,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
generateQueryParameters! {
|
|
||||||
keywords: [],
|
|
||||||
fields: [
|
|
||||||
"format" => format,
|
|
||||||
"id" => id,
|
|
||||||
"search" => search,
|
|
||||||
"globalAlias" => global_alias,
|
|
||||||
"alias" => alias,
|
|
||||||
"accessKeyId" => access_key_id,
|
|
||||||
"showSecretKey" => show_secret_key
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use hyper::{Method, Request};
|
||||||
|
|
||||||
|
use crate::admin::error::*;
|
||||||
|
use crate::router_macros::*;
|
||||||
|
|
||||||
|
router_match! {@func
|
||||||
|
|
||||||
|
/// List of all Admin API endpoints.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Endpoint {
|
||||||
|
Options,
|
||||||
|
CheckDomain,
|
||||||
|
Health,
|
||||||
|
Metrics,
|
||||||
|
GetClusterStatus,
|
||||||
|
GetClusterHealth,
|
||||||
|
ConnectClusterNodes,
|
||||||
|
// Layout
|
||||||
|
GetClusterLayout,
|
||||||
|
UpdateClusterLayout,
|
||||||
|
ApplyClusterLayout,
|
||||||
|
RevertClusterLayout,
|
||||||
|
// Keys
|
||||||
|
ListKeys,
|
||||||
|
CreateKey,
|
||||||
|
ImportKey,
|
||||||
|
GetKeyInfo {
|
||||||
|
id: Option<String>,
|
||||||
|
search: Option<String>,
|
||||||
|
},
|
||||||
|
DeleteKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
UpdateKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
// Buckets
|
||||||
|
ListBuckets,
|
||||||
|
CreateBucket,
|
||||||
|
GetBucketInfo {
|
||||||
|
id: Option<String>,
|
||||||
|
global_alias: Option<String>,
|
||||||
|
},
|
||||||
|
DeleteBucket {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
UpdateBucket {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
// Bucket-Key Permissions
|
||||||
|
BucketAllowKey,
|
||||||
|
BucketDenyKey,
|
||||||
|
// Bucket aliases
|
||||||
|
GlobalAliasBucket {
|
||||||
|
id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
GlobalUnaliasBucket {
|
||||||
|
id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
LocalAliasBucket {
|
||||||
|
id: String,
|
||||||
|
access_key_id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
LocalUnaliasBucket {
|
||||||
|
id: String,
|
||||||
|
access_key_id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Endpoint {
|
||||||
|
/// Determine which S3 endpoint a request is for using the request, and a bucket which was
|
||||||
|
/// possibly extracted from the Host header.
|
||||||
|
/// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets
|
||||||
|
pub fn from_request<T>(req: &Request<T>) -> Result<Self, Error> {
|
||||||
|
let uri = req.uri();
|
||||||
|
let path = uri.path();
|
||||||
|
let query = uri.query();
|
||||||
|
|
||||||
|
let mut query = QueryParameters::from_query(query.unwrap_or_default())?;
|
||||||
|
|
||||||
|
let res = router_match!(@gen_path_parser (req.method(), path, query) [
|
||||||
|
OPTIONS _ => Options,
|
||||||
|
GET "/check" => CheckDomain,
|
||||||
|
GET "/health" => Health,
|
||||||
|
GET "/metrics" => Metrics,
|
||||||
|
GET "/v0/status" => GetClusterStatus,
|
||||||
|
GET "/v0/health" => GetClusterHealth,
|
||||||
|
POST "/v0/connect" => ConnectClusterNodes,
|
||||||
|
// Layout endpoints
|
||||||
|
GET "/v0/layout" => GetClusterLayout,
|
||||||
|
POST "/v0/layout" => UpdateClusterLayout,
|
||||||
|
POST "/v0/layout/apply" => ApplyClusterLayout,
|
||||||
|
POST "/v0/layout/revert" => RevertClusterLayout,
|
||||||
|
// API key endpoints
|
||||||
|
GET "/v0/key" if id => GetKeyInfo (query_opt::id, query_opt::search),
|
||||||
|
GET "/v0/key" if search => GetKeyInfo (query_opt::id, query_opt::search),
|
||||||
|
POST "/v0/key" if id => UpdateKey (query::id),
|
||||||
|
POST "/v0/key" => CreateKey,
|
||||||
|
POST "/v0/key/import" => ImportKey,
|
||||||
|
DELETE "/v0/key" if id => DeleteKey (query::id),
|
||||||
|
GET "/v0/key" => ListKeys,
|
||||||
|
// Bucket endpoints
|
||||||
|
GET "/v0/bucket" if id => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
||||||
|
GET "/v0/bucket" if global_alias => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
||||||
|
GET "/v0/bucket" => ListBuckets,
|
||||||
|
POST "/v0/bucket" => CreateBucket,
|
||||||
|
DELETE "/v0/bucket" if id => DeleteBucket (query::id),
|
||||||
|
PUT "/v0/bucket" if id => UpdateBucket (query::id),
|
||||||
|
// Bucket-key permissions
|
||||||
|
POST "/v0/bucket/allow" => BucketAllowKey,
|
||||||
|
POST "/v0/bucket/deny" => BucketDenyKey,
|
||||||
|
// Bucket aliases
|
||||||
|
PUT "/v0/bucket/alias/global" => GlobalAliasBucket (query::id, query::alias),
|
||||||
|
DELETE "/v0/bucket/alias/global" => GlobalUnaliasBucket (query::id, query::alias),
|
||||||
|
PUT "/v0/bucket/alias/local" => LocalAliasBucket (query::id, query::access_key_id, query::alias),
|
||||||
|
DELETE "/v0/bucket/alias/local" => LocalUnaliasBucket (query::id, query::access_key_id, query::alias),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if let Some(message) = query.nonempty_message() {
|
||||||
|
debug!("Unused query parameter: {}", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateQueryParameters! {
|
||||||
|
keywords: [],
|
||||||
|
fields: [
|
||||||
|
"format" => format,
|
||||||
|
"id" => id,
|
||||||
|
"search" => search,
|
||||||
|
"globalAlias" => global_alias,
|
||||||
|
"alias" => alias,
|
||||||
|
"accessKeyId" => access_key_id
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use hyper::{Method, Request};
|
||||||
|
|
||||||
|
use crate::admin::error::*;
|
||||||
|
use crate::admin::router_v0;
|
||||||
|
use crate::router_macros::*;
|
||||||
|
|
||||||
|
pub enum Authorization {
|
||||||
|
None,
|
||||||
|
MetricsToken,
|
||||||
|
AdminToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
router_match! {@func
|
||||||
|
|
||||||
|
/// List of all Admin API endpoints.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Endpoint {
|
||||||
|
Options,
|
||||||
|
CheckDomain,
|
||||||
|
Health,
|
||||||
|
Metrics,
|
||||||
|
GetClusterStatus,
|
||||||
|
GetClusterHealth,
|
||||||
|
ConnectClusterNodes,
|
||||||
|
// Layout
|
||||||
|
GetClusterLayout,
|
||||||
|
UpdateClusterLayout,
|
||||||
|
ApplyClusterLayout,
|
||||||
|
RevertClusterLayout,
|
||||||
|
// Keys
|
||||||
|
ListKeys,
|
||||||
|
CreateKey,
|
||||||
|
ImportKey,
|
||||||
|
GetKeyInfo {
|
||||||
|
id: Option<String>,
|
||||||
|
search: Option<String>,
|
||||||
|
show_secret_key: Option<String>,
|
||||||
|
},
|
||||||
|
DeleteKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
UpdateKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
// Buckets
|
||||||
|
ListBuckets,
|
||||||
|
CreateBucket,
|
||||||
|
GetBucketInfo {
|
||||||
|
id: Option<String>,
|
||||||
|
global_alias: Option<String>,
|
||||||
|
},
|
||||||
|
DeleteBucket {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
UpdateBucket {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
// Bucket-Key Permissions
|
||||||
|
BucketAllowKey,
|
||||||
|
BucketDenyKey,
|
||||||
|
// Bucket aliases
|
||||||
|
GlobalAliasBucket {
|
||||||
|
id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
GlobalUnaliasBucket {
|
||||||
|
id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
LocalAliasBucket {
|
||||||
|
id: String,
|
||||||
|
access_key_id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
LocalUnaliasBucket {
|
||||||
|
id: String,
|
||||||
|
access_key_id: String,
|
||||||
|
alias: String,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
impl Endpoint {
|
||||||
|
/// Determine which S3 endpoint a request is for using the request, and a bucket which was
|
||||||
|
/// possibly extracted from the Host header.
|
||||||
|
/// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets
|
||||||
|
pub fn from_request<T>(req: &Request<T>) -> Result<Self, Error> {
|
||||||
|
let uri = req.uri();
|
||||||
|
let path = uri.path();
|
||||||
|
let query = uri.query();
|
||||||
|
|
||||||
|
let mut query = QueryParameters::from_query(query.unwrap_or_default())?;
|
||||||
|
|
||||||
|
let res = router_match!(@gen_path_parser (req.method(), path, query) [
|
||||||
|
OPTIONS _ => Options,
|
||||||
|
GET "/check" => CheckDomain,
|
||||||
|
GET "/health" => Health,
|
||||||
|
GET "/metrics" => Metrics,
|
||||||
|
GET "/v1/status" => GetClusterStatus,
|
||||||
|
GET "/v1/health" => GetClusterHealth,
|
||||||
|
POST "/v1/connect" => ConnectClusterNodes,
|
||||||
|
// Layout endpoints
|
||||||
|
GET "/v1/layout" => GetClusterLayout,
|
||||||
|
POST "/v1/layout" => UpdateClusterLayout,
|
||||||
|
POST "/v1/layout/apply" => ApplyClusterLayout,
|
||||||
|
POST "/v1/layout/revert" => RevertClusterLayout,
|
||||||
|
// API key endpoints
|
||||||
|
GET "/v1/key" if id => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key),
|
||||||
|
GET "/v1/key" if search => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key),
|
||||||
|
POST "/v1/key" if id => UpdateKey (query::id),
|
||||||
|
POST "/v1/key" => CreateKey,
|
||||||
|
POST "/v1/key/import" => ImportKey,
|
||||||
|
DELETE "/v1/key" if id => DeleteKey (query::id),
|
||||||
|
GET "/v1/key" => ListKeys,
|
||||||
|
// Bucket endpoints
|
||||||
|
GET "/v1/bucket" if id => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
||||||
|
GET "/v1/bucket" if global_alias => GetBucketInfo (query_opt::id, query_opt::global_alias),
|
||||||
|
GET "/v1/bucket" => ListBuckets,
|
||||||
|
POST "/v1/bucket" => CreateBucket,
|
||||||
|
DELETE "/v1/bucket" if id => DeleteBucket (query::id),
|
||||||
|
PUT "/v1/bucket" if id => UpdateBucket (query::id),
|
||||||
|
// Bucket-key permissions
|
||||||
|
POST "/v1/bucket/allow" => BucketAllowKey,
|
||||||
|
POST "/v1/bucket/deny" => BucketDenyKey,
|
||||||
|
// Bucket aliases
|
||||||
|
PUT "/v1/bucket/alias/global" => GlobalAliasBucket (query::id, query::alias),
|
||||||
|
DELETE "/v1/bucket/alias/global" => GlobalUnaliasBucket (query::id, query::alias),
|
||||||
|
PUT "/v1/bucket/alias/local" => LocalAliasBucket (query::id, query::access_key_id, query::alias),
|
||||||
|
DELETE "/v1/bucket/alias/local" => LocalUnaliasBucket (query::id, query::access_key_id, query::alias),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if let Some(message) = query.nonempty_message() {
|
||||||
|
debug!("Unused query parameter: {}", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
/// Some endpoints work exactly the same in their v1/ version as they did in their v0/ version.
|
||||||
|
/// For these endpoints, we can convert a v0/ call to its equivalent as if it was made using
|
||||||
|
/// its v1/ URL.
|
||||||
|
pub fn from_v0(v0_endpoint: router_v0::Endpoint) -> Result<Self, Error> {
|
||||||
|
match v0_endpoint {
|
||||||
|
// Cluster endpoints
|
||||||
|
router_v0::Endpoint::ConnectClusterNodes => Ok(Self::ConnectClusterNodes),
|
||||||
|
// - GetClusterStatus: response format changed
|
||||||
|
// - GetClusterHealth: response format changed
|
||||||
|
|
||||||
|
// Layout endpoints
|
||||||
|
router_v0::Endpoint::RevertClusterLayout => Ok(Self::RevertClusterLayout),
|
||||||
|
// - GetClusterLayout: response format changed
|
||||||
|
// - UpdateClusterLayout: query format changed
|
||||||
|
// - ApplyCusterLayout: response format changed
|
||||||
|
|
||||||
|
// Key endpoints
|
||||||
|
router_v0::Endpoint::ListKeys => Ok(Self::ListKeys),
|
||||||
|
router_v0::Endpoint::CreateKey => Ok(Self::CreateKey),
|
||||||
|
router_v0::Endpoint::GetKeyInfo { id, search } => Ok(Self::GetKeyInfo {
|
||||||
|
id,
|
||||||
|
search,
|
||||||
|
show_secret_key: Some("true".into()),
|
||||||
|
}),
|
||||||
|
router_v0::Endpoint::DeleteKey { id } => Ok(Self::DeleteKey { id }),
|
||||||
|
// - UpdateKey: response format changed (secret key no longer returned)
|
||||||
|
|
||||||
|
// Bucket endpoints
|
||||||
|
router_v0::Endpoint::GetBucketInfo { id, global_alias } => {
|
||||||
|
Ok(Self::GetBucketInfo { id, global_alias })
|
||||||
|
}
|
||||||
|
router_v0::Endpoint::ListBuckets => Ok(Self::ListBuckets),
|
||||||
|
router_v0::Endpoint::CreateBucket => Ok(Self::CreateBucket),
|
||||||
|
router_v0::Endpoint::DeleteBucket { id } => Ok(Self::DeleteBucket { id }),
|
||||||
|
router_v0::Endpoint::UpdateBucket { id } => Ok(Self::UpdateBucket { id }),
|
||||||
|
|
||||||
|
// Bucket-key permissions
|
||||||
|
router_v0::Endpoint::BucketAllowKey => Ok(Self::BucketAllowKey),
|
||||||
|
router_v0::Endpoint::BucketDenyKey => Ok(Self::BucketDenyKey),
|
||||||
|
|
||||||
|
// Bucket alias endpoints
|
||||||
|
router_v0::Endpoint::GlobalAliasBucket { id, alias } => {
|
||||||
|
Ok(Self::GlobalAliasBucket { id, alias })
|
||||||
|
}
|
||||||
|
router_v0::Endpoint::GlobalUnaliasBucket { id, alias } => {
|
||||||
|
Ok(Self::GlobalUnaliasBucket { id, alias })
|
||||||
|
}
|
||||||
|
router_v0::Endpoint::LocalAliasBucket {
|
||||||
|
id,
|
||||||
|
access_key_id,
|
||||||
|
alias,
|
||||||
|
} => Ok(Self::LocalAliasBucket {
|
||||||
|
id,
|
||||||
|
access_key_id,
|
||||||
|
alias,
|
||||||
|
}),
|
||||||
|
router_v0::Endpoint::LocalUnaliasBucket {
|
||||||
|
id,
|
||||||
|
access_key_id,
|
||||||
|
alias,
|
||||||
|
} => Ok(Self::LocalUnaliasBucket {
|
||||||
|
id,
|
||||||
|
access_key_id,
|
||||||
|
alias,
|
||||||
|
}),
|
||||||
|
|
||||||
|
// For endpoints that have different body content syntax, issue
|
||||||
|
// deprecation warning
|
||||||
|
_ => Err(Error::bad_request(format!(
|
||||||
|
"v0/ endpoint is no longer supported: {}",
|
||||||
|
v0_endpoint.name()
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Get the kind of authorization which is required to perform the operation.
|
||||||
|
pub fn authorization_type(&self) -> Authorization {
|
||||||
|
match self {
|
||||||
|
Self::Health => Authorization::None,
|
||||||
|
Self::CheckDomain => Authorization::None,
|
||||||
|
Self::Metrics => Authorization::MetricsToken,
|
||||||
|
_ => Authorization::AdminToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateQueryParameters! {
|
||||||
|
keywords: [],
|
||||||
|
fields: [
|
||||||
|
"format" => format,
|
||||||
|
"id" => id,
|
||||||
|
"search" => search,
|
||||||
|
"globalAlias" => global_alias,
|
||||||
|
"alias" => alias,
|
||||||
|
"accessKeyId" => access_key_id,
|
||||||
|
"showSecretKey" => show_secret_key
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::net::SocketAddr;
|
use std::fs::{self, Permissions};
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -11,6 +12,10 @@ use hyper::service::{make_service_fn, service_fn};
|
|||||||
use hyper::{Body, Request, Response, Server};
|
use hyper::{Body, Request, Response, Server};
|
||||||
use hyper::{HeaderMap, StatusCode};
|
use hyper::{HeaderMap, StatusCode};
|
||||||
|
|
||||||
|
use hyperlocal::UnixServerExt;
|
||||||
|
|
||||||
|
use tokio::net::UnixStream;
|
||||||
|
|
||||||
use opentelemetry::{
|
use opentelemetry::{
|
||||||
global,
|
global,
|
||||||
metrics::{Counter, ValueRecorder},
|
metrics::{Counter, ValueRecorder},
|
||||||
@@ -21,6 +26,7 @@ use opentelemetry::{
|
|||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
use garage_util::forwarded_headers;
|
use garage_util::forwarded_headers;
|
||||||
use garage_util::metrics::{gen_trace_id, RecordDuration};
|
use garage_util::metrics::{gen_trace_id, RecordDuration};
|
||||||
|
use garage_util::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
pub(crate) trait ApiEndpoint: Send + Sync + 'static {
|
pub(crate) trait ApiEndpoint: Send + Sync + 'static {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
@@ -91,10 +97,11 @@ impl<A: ApiHandler> ApiServer<A> {
|
|||||||
|
|
||||||
pub async fn run_server(
|
pub async fn run_server(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
bind_addr: SocketAddr,
|
bind_addr: UnixOrTCPSocketAddress,
|
||||||
|
unix_bind_addr_mode: Option<u32>,
|
||||||
shutdown_signal: impl Future<Output = ()>,
|
shutdown_signal: impl Future<Output = ()>,
|
||||||
) -> Result<(), GarageError> {
|
) -> Result<(), GarageError> {
|
||||||
let service = make_service_fn(|conn: &AddrStream| {
|
let tcp_service = make_service_fn(|conn: &AddrStream| {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
|
||||||
let client_addr = conn.remote_addr();
|
let client_addr = conn.remote_addr();
|
||||||
@@ -102,28 +109,63 @@ impl<A: ApiHandler> ApiServer<A> {
|
|||||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||||
let this = this.clone();
|
let this = this.clone();
|
||||||
|
|
||||||
this.handler(req, client_addr)
|
this.handler(req, client_addr.to_string())
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = Server::bind(&bind_addr).serve(service);
|
let unix_service = make_service_fn(|_: &UnixStream| {
|
||||||
|
let this = self.clone();
|
||||||
|
|
||||||
|
let path = bind_addr.to_string();
|
||||||
|
async move {
|
||||||
|
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||||
|
let this = this.clone();
|
||||||
|
|
||||||
|
this.handler(req, path.clone())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
|
||||||
info!(
|
info!(
|
||||||
"{} API server listening on http://{}",
|
"{} API server listening on {}",
|
||||||
A::API_NAME_DISPLAY,
|
A::API_NAME_DISPLAY,
|
||||||
bind_addr
|
bind_addr
|
||||||
);
|
);
|
||||||
|
|
||||||
graceful.await?;
|
match bind_addr {
|
||||||
|
UnixOrTCPSocketAddress::TCPSocket(addr) => {
|
||||||
|
Server::bind(&addr)
|
||||||
|
.serve(tcp_service)
|
||||||
|
.with_graceful_shutdown(shutdown_signal)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
UnixOrTCPSocketAddress::UnixSocket(ref path) => {
|
||||||
|
if path.exists() {
|
||||||
|
fs::remove_file(path)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let bound = Server::bind_unix(path)?;
|
||||||
|
|
||||||
|
fs::set_permissions(
|
||||||
|
path,
|
||||||
|
Permissions::from_mode(unix_bind_addr_mode.unwrap_or(0o222)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
bound
|
||||||
|
.serve(unix_service)
|
||||||
|
.with_graceful_shutdown(shutdown_signal)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handler(
|
async fn handler(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
addr: SocketAddr,
|
addr: String,
|
||||||
) -> Result<Response<Body>, GarageError> {
|
) -> Result<Response<Body>, GarageError> {
|
||||||
let uri = req.uri().clone();
|
let uri = req.uri().clone();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -9,6 +8,7 @@ use hyper::{Body, Method, Request, Response};
|
|||||||
use opentelemetry::{trace::SpanRef, KeyValue};
|
use opentelemetry::{trace::SpanRef, KeyValue};
|
||||||
|
|
||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
|
use garage_util::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
|
||||||
@@ -37,12 +37,12 @@ pub(crate) struct K2VApiEndpoint {
|
|||||||
impl K2VApiServer {
|
impl K2VApiServer {
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
garage: Arc<Garage>,
|
garage: Arc<Garage>,
|
||||||
bind_addr: SocketAddr,
|
bind_addr: UnixOrTCPSocketAddress,
|
||||||
s3_region: String,
|
s3_region: String,
|
||||||
shutdown_signal: impl Future<Output = ()>,
|
shutdown_signal: impl Future<Output = ()>,
|
||||||
) -> Result<(), GarageError> {
|
) -> Result<(), GarageError> {
|
||||||
ApiServer::new(s3_region, K2VApiServer { garage })
|
ApiServer::new(s3_region, K2VApiServer { garage })
|
||||||
.run_server(bind_addr, shutdown_signal)
|
.run_server(bind_addr, None, shutdown_signal)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -10,6 +9,7 @@ use hyper::{Body, Request, Response};
|
|||||||
use opentelemetry::{trace::SpanRef, KeyValue};
|
use opentelemetry::{trace::SpanRef, KeyValue};
|
||||||
|
|
||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
|
use garage_util::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
use garage_model::key_table::Key;
|
use garage_model::key_table::Key;
|
||||||
@@ -46,12 +46,12 @@ pub(crate) struct S3ApiEndpoint {
|
|||||||
impl S3ApiServer {
|
impl S3ApiServer {
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
garage: Arc<Garage>,
|
garage: Arc<Garage>,
|
||||||
addr: SocketAddr,
|
addr: UnixOrTCPSocketAddress,
|
||||||
s3_region: String,
|
s3_region: String,
|
||||||
shutdown_signal: impl Future<Output = ()>,
|
shutdown_signal: impl Future<Output = ()>,
|
||||||
) -> Result<(), GarageError> {
|
) -> Result<(), GarageError> {
|
||||||
ApiServer::new(s3_region, S3ApiServer { garage })
|
ApiServer::new(s3_region, S3ApiServer { garage })
|
||||||
.run_server(addr, shutdown_signal)
|
.run_server(addr, None, shutdown_signal)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_block"
|
name = "garage_block"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
+1
-6
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_db"
|
name = "garage_db"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
@@ -11,11 +11,6 @@ readme = "../../README.md"
|
|||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "convert"
|
|
||||||
path = "bin/convert.rs"
|
|
||||||
required-features = ["cli"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
err-derive = "0.3"
|
err-derive = "0.3"
|
||||||
hexdump = "0.1"
|
hexdump = "0.1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage"
|
name = "garage"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
@@ -1,39 +1,30 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use garage_db::*;
|
use garage_db::*;
|
||||||
|
|
||||||
use clap::Parser;
|
|
||||||
|
|
||||||
/// K2V command line interface
|
/// K2V command line interface
|
||||||
#[derive(Parser, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
#[clap(author, version, about, long_about = None)]
|
pub struct ConvertDbOpt {
|
||||||
struct Args {
|
/// Input database path (not the same as metadata_dir, see
|
||||||
/// Input DB path
|
/// https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db-engine-since-v0-8-0)
|
||||||
#[clap(short = 'i')]
|
#[structopt(short = "i")]
|
||||||
input_path: PathBuf,
|
input_path: PathBuf,
|
||||||
/// Input DB engine
|
/// Input database engine (sled, lmdb or sqlite; limited by db engines
|
||||||
#[clap(short = 'a')]
|
/// enabled in this build)
|
||||||
|
#[structopt(short = "a")]
|
||||||
input_engine: String,
|
input_engine: String,
|
||||||
|
|
||||||
/// Output DB path
|
/// Output database path
|
||||||
#[clap(short = 'o')]
|
#[structopt(short = "o")]
|
||||||
output_path: PathBuf,
|
output_path: PathBuf,
|
||||||
/// Output DB engine
|
/// Output database engine
|
||||||
#[clap(short = 'b')]
|
#[structopt(short = "b")]
|
||||||
output_engine: String,
|
output_engine: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
pub(crate) fn do_conversion(args: ConvertDbOpt) -> Result<()> {
|
||||||
let args = Args::parse();
|
|
||||||
pretty_env_logger::init();
|
|
||||||
|
|
||||||
match do_conversion(args) {
|
|
||||||
Ok(()) => println!("Success!"),
|
|
||||||
Err(e) => eprintln!("Error: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_conversion(args: Args) -> Result<()> {
|
|
||||||
let input = open_db(args.input_path, args.input_engine)?;
|
let input = open_db(args.input_path, args.input_engine)?;
|
||||||
let output = open_db(args.output_path, args.output_engine)?;
|
let output = open_db(args.output_path, args.output_engine)?;
|
||||||
output.import(&input)?;
|
output.import(&input)?;
|
||||||
@@ -42,16 +33,19 @@ fn do_conversion(args: Args) -> Result<()> {
|
|||||||
|
|
||||||
fn open_db(path: PathBuf, engine: String) -> Result<Db> {
|
fn open_db(path: PathBuf, engine: String) -> Result<Db> {
|
||||||
match engine.as_str() {
|
match engine.as_str() {
|
||||||
|
#[cfg(feature = "sled")]
|
||||||
"sled" => {
|
"sled" => {
|
||||||
let db = sled_adapter::sled::Config::default().path(&path).open()?;
|
let db = sled_adapter::sled::Config::default().path(&path).open()?;
|
||||||
Ok(sled_adapter::SledDb::init(db))
|
Ok(sled_adapter::SledDb::init(db))
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
"sqlite" | "sqlite3" | "rusqlite" => {
|
"sqlite" | "sqlite3" | "rusqlite" => {
|
||||||
let db = sqlite_adapter::rusqlite::Connection::open(&path)?;
|
let db = sqlite_adapter::rusqlite::Connection::open(&path)?;
|
||||||
db.pragma_update(None, "journal_mode", &"WAL")?;
|
db.pragma_update(None, "journal_mode", &"WAL")?;
|
||||||
db.pragma_update(None, "synchronous", &"NORMAL")?;
|
db.pragma_update(None, "synchronous", &"NORMAL")?;
|
||||||
Ok(sqlite_adapter::SqliteDb::init(db))
|
Ok(sqlite_adapter::SqliteDb::init(db))
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "lmdb")]
|
||||||
"lmdb" | "heed" => {
|
"lmdb" | "heed" => {
|
||||||
std::fs::create_dir_all(&path).map_err(|e| {
|
std::fs::create_dir_all(&path).map_err(|e| {
|
||||||
Error(format!("Unable to create LMDB data directory: {}", e).into())
|
Error(format!("Unable to create LMDB data directory: {}", e).into())
|
||||||
@@ -63,11 +57,13 @@ fn open_db(path: PathBuf, engine: String) -> Result<Db> {
|
|||||||
env_builder.max_dbs(100);
|
env_builder.max_dbs(100);
|
||||||
env_builder.map_size(map_size);
|
env_builder.map_size(map_size);
|
||||||
unsafe {
|
unsafe {
|
||||||
env_builder.flag(heed::flags::Flags::MdbNoMetaSync);
|
env_builder.flag(lmdb_adapter::heed::flags::Flags::MdbNoMetaSync);
|
||||||
}
|
}
|
||||||
let db = env_builder.open(&path)?;
|
let db = env_builder.open(&path)?;
|
||||||
Ok(lmdb_adapter::LmdbDb::init(db))
|
Ok(lmdb_adapter::LmdbDb::init(db))
|
||||||
}
|
}
|
||||||
e => Err(Error(format!("Invalid DB engine: {}", e).into())),
|
e => Err(Error(
|
||||||
|
format!("Invalid or unsupported DB engine: {}", e).into(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@ pub(crate) mod layout;
|
|||||||
pub(crate) mod structs;
|
pub(crate) mod structs;
|
||||||
pub(crate) mod util;
|
pub(crate) mod util;
|
||||||
|
|
||||||
|
pub(crate) mod convert_db;
|
||||||
|
|
||||||
pub(crate) use cmd::*;
|
pub(crate) use cmd::*;
|
||||||
pub(crate) use init::*;
|
pub(crate) use init::*;
|
||||||
pub(crate) use layout::*;
|
pub(crate) use layout::*;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use structopt::StructOpt;
|
|||||||
|
|
||||||
use garage_util::version::garage_version;
|
use garage_util::version::garage_version;
|
||||||
|
|
||||||
|
use crate::cli::convert_db;
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Run Garage server
|
/// Run Garage server
|
||||||
@@ -54,6 +56,10 @@ pub enum Command {
|
|||||||
/// Low-level debug operations on data blocks
|
/// Low-level debug operations on data blocks
|
||||||
#[structopt(name = "block", version = garage_version())]
|
#[structopt(name = "block", version = garage_version())]
|
||||||
Block(BlockOperation),
|
Block(BlockOperation),
|
||||||
|
|
||||||
|
/// Convert metadata db between database engine formats
|
||||||
|
#[structopt(name = "convert-db", version = garage_version())]
|
||||||
|
ConvertDb(convert_db::ConvertDbOpt),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
@@ -453,7 +459,7 @@ pub enum RepairWhat {
|
|||||||
/// Do a full sync of metadata tables
|
/// Do a full sync of metadata tables
|
||||||
#[structopt(name = "tables", version = garage_version())]
|
#[structopt(name = "tables", version = garage_version())]
|
||||||
Tables,
|
Tables,
|
||||||
/// Repair (resync/rebalance) the set of stored blocks
|
/// Repair (resync/rebalance) the set of stored blocks in the cluster
|
||||||
#[structopt(name = "blocks", version = garage_version())]
|
#[structopt(name = "blocks", version = garage_version())]
|
||||||
Blocks,
|
Blocks,
|
||||||
/// Repropagate object deletions to the version table
|
/// Repropagate object deletions to the version table
|
||||||
@@ -471,7 +477,7 @@ pub enum RepairWhat {
|
|||||||
#[structopt(subcommand)]
|
#[structopt(subcommand)]
|
||||||
cmd: ScrubCmd,
|
cmd: ScrubCmd,
|
||||||
},
|
},
|
||||||
/// Rebalance data blocks among storage locations
|
/// Rebalance data blocks among HDDs on individual nodes
|
||||||
#[structopt(name = "rebalance", version = garage_version())]
|
#[structopt(name = "rebalance", version = garage_version())]
|
||||||
Rebalance,
|
Rebalance,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,6 +176,9 @@ async fn main() {
|
|||||||
Command::OfflineRepair(repair_opt) => {
|
Command::OfflineRepair(repair_opt) => {
|
||||||
repair::offline::offline_repair(opt.config_file, opt.secrets, repair_opt).await
|
repair::offline::offline_repair(opt.config_file, opt.secrets, repair_opt).await
|
||||||
}
|
}
|
||||||
|
Command::ConvertDb(conv_opt) => {
|
||||||
|
cli::convert_db::do_conversion(conv_opt).map_err(From::from)
|
||||||
|
}
|
||||||
Command::Node(NodeOperation::NodeId(node_id_opt)) => {
|
Command::Node(NodeOperation::NodeId(node_id_opt)) => {
|
||||||
node_id_command(opt.config_file, node_id_opt.quiet)
|
node_id_command(opt.config_file, node_id_opt.quiet)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
|||||||
"S3 API",
|
"S3 API",
|
||||||
tokio::spawn(S3ApiServer::run(
|
tokio::spawn(S3ApiServer::run(
|
||||||
garage.clone(),
|
garage.clone(),
|
||||||
*s3_bind_addr,
|
s3_bind_addr.clone(),
|
||||||
config.s3_api.s3_region.clone(),
|
config.s3_api.s3_region.clone(),
|
||||||
wait_from(watch_cancel.clone()),
|
wait_from(watch_cancel.clone()),
|
||||||
)),
|
)),
|
||||||
@@ -94,7 +94,7 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
|||||||
"K2V API",
|
"K2V API",
|
||||||
tokio::spawn(K2VApiServer::run(
|
tokio::spawn(K2VApiServer::run(
|
||||||
garage.clone(),
|
garage.clone(),
|
||||||
config.k2v_api.as_ref().unwrap().api_bind_addr,
|
config.k2v_api.as_ref().unwrap().api_bind_addr.clone(),
|
||||||
config.s3_api.s3_region.clone(),
|
config.s3_api.s3_region.clone(),
|
||||||
wait_from(watch_cancel.clone()),
|
wait_from(watch_cancel.clone()),
|
||||||
)),
|
)),
|
||||||
@@ -110,7 +110,7 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
|||||||
"Web",
|
"Web",
|
||||||
tokio::spawn(WebServer::run(
|
tokio::spawn(WebServer::run(
|
||||||
garage.clone(),
|
garage.clone(),
|
||||||
web_config.bind_addr,
|
web_config.bind_addr.clone(),
|
||||||
web_config.root_domain.clone(),
|
web_config.root_domain.clone(),
|
||||||
wait_from(watch_cancel.clone()),
|
wait_from(watch_cancel.clone()),
|
||||||
)),
|
)),
|
||||||
@@ -121,7 +121,9 @@ pub async fn run_server(config_file: PathBuf, secrets: Secrets) -> Result<(), Er
|
|||||||
info!("Launching Admin API server...");
|
info!("Launching Admin API server...");
|
||||||
servers.push((
|
servers.push((
|
||||||
"Admin",
|
"Admin",
|
||||||
tokio::spawn(admin_server.run(*admin_bind_addr, wait_from(watch_cancel.clone()))),
|
tokio::spawn(
|
||||||
|
admin_server.run(admin_bind_addr.clone(), wait_from(watch_cancel.clone())),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_model"
|
name = "garage_model"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_rpc"
|
name = "garage_rpc"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_table"
|
name = "garage_table"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_util"
|
name = "garage_util"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
|||||||
+5
-4
@@ -7,6 +7,7 @@ use std::path::PathBuf;
|
|||||||
use serde::{de, Deserialize};
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use crate::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
/// Represent the whole configuration
|
/// Represent the whole configuration
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
@@ -129,7 +130,7 @@ pub struct DataDir {
|
|||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct S3ApiConfig {
|
pub struct S3ApiConfig {
|
||||||
/// Address and port to bind for api serving
|
/// Address and port to bind for api serving
|
||||||
pub api_bind_addr: Option<SocketAddr>,
|
pub api_bind_addr: Option<UnixOrTCPSocketAddress>,
|
||||||
/// S3 region to use
|
/// S3 region to use
|
||||||
pub s3_region: String,
|
pub s3_region: String,
|
||||||
/// Suffix to remove from domain name to find bucket. If None,
|
/// Suffix to remove from domain name to find bucket. If None,
|
||||||
@@ -141,14 +142,14 @@ pub struct S3ApiConfig {
|
|||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct K2VApiConfig {
|
pub struct K2VApiConfig {
|
||||||
/// Address and port to bind for api serving
|
/// Address and port to bind for api serving
|
||||||
pub api_bind_addr: SocketAddr,
|
pub api_bind_addr: UnixOrTCPSocketAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration for serving files as normal web server
|
/// Configuration for serving files as normal web server
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct WebConfig {
|
pub struct WebConfig {
|
||||||
/// Address and port to bind for web serving
|
/// Address and port to bind for web serving
|
||||||
pub bind_addr: SocketAddr,
|
pub bind_addr: UnixOrTCPSocketAddress,
|
||||||
/// Suffix to remove from domain name to find bucket
|
/// Suffix to remove from domain name to find bucket
|
||||||
pub root_domain: String,
|
pub root_domain: String,
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,7 @@ pub struct WebConfig {
|
|||||||
#[derive(Deserialize, Debug, Clone, Default)]
|
#[derive(Deserialize, Debug, Clone, Default)]
|
||||||
pub struct AdminConfig {
|
pub struct AdminConfig {
|
||||||
/// Address and port to bind for admin API serving
|
/// Address and port to bind for admin API serving
|
||||||
pub api_bind_addr: Option<SocketAddr>,
|
pub api_bind_addr: Option<UnixOrTCPSocketAddress>,
|
||||||
|
|
||||||
/// Bearer token to use to scrape metrics
|
/// Bearer token to use to scrape metrics
|
||||||
pub metrics_token: Option<String>,
|
pub metrics_token: Option<String>,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub mod forwarded_headers;
|
|||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
pub mod migrate;
|
pub mod migrate;
|
||||||
pub mod persister;
|
pub mod persister;
|
||||||
|
pub mod socket_address;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod tranquilizer;
|
pub mod tranquilizer;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde::de::Error;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum UnixOrTCPSocketAddress {
|
||||||
|
TCPSocket(SocketAddr),
|
||||||
|
UnixSocket(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for UnixOrTCPSocketAddress {
|
||||||
|
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
UnixOrTCPSocketAddress::TCPSocket(address) => write!(formatter, "http://{}", address),
|
||||||
|
UnixOrTCPSocketAddress::UnixSocket(path) => {
|
||||||
|
write!(formatter, "http+unix://{}", path.to_string_lossy())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for UnixOrTCPSocketAddress {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let string = String::deserialize(deserializer)?;
|
||||||
|
let string = string.as_str();
|
||||||
|
|
||||||
|
if string.starts_with("/") {
|
||||||
|
Ok(UnixOrTCPSocketAddress::UnixSocket(
|
||||||
|
PathBuf::from_str(string).map_err(Error::custom)?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(UnixOrTCPSocketAddress::TCPSocket(
|
||||||
|
SocketAddr::from_str(string).map_err(Error::custom)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "garage_web"
|
name = "garage_web"
|
||||||
version = "0.8.4"
|
version = "0.9.0"
|
||||||
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
|
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
@@ -27,5 +27,8 @@ futures = "0.3"
|
|||||||
|
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
||||||
|
hyperlocal = { version = "0.8.0", default-features = false, features = ["server"] }
|
||||||
|
|
||||||
|
tokio = { version = "1.0", default-features = false, features = ["net"] }
|
||||||
|
|
||||||
opentelemetry = "0.17"
|
opentelemetry = "0.17"
|
||||||
|
|||||||
+49
-9
@@ -1,4 +1,6 @@
|
|||||||
use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
use std::fs::{self, Permissions};
|
||||||
|
use std::os::unix::prelude::PermissionsExt;
|
||||||
|
use std::{convert::Infallible, sync::Arc};
|
||||||
|
|
||||||
use futures::future::Future;
|
use futures::future::Future;
|
||||||
|
|
||||||
@@ -9,6 +11,10 @@ use hyper::{
|
|||||||
Body, Method, Request, Response, Server, StatusCode,
|
Body, Method, Request, Response, Server, StatusCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use hyperlocal::UnixServerExt;
|
||||||
|
|
||||||
|
use tokio::net::UnixStream;
|
||||||
|
|
||||||
use opentelemetry::{
|
use opentelemetry::{
|
||||||
global,
|
global,
|
||||||
metrics::{Counter, ValueRecorder},
|
metrics::{Counter, ValueRecorder},
|
||||||
@@ -32,6 +38,7 @@ use garage_util::data::Uuid;
|
|||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
use garage_util::forwarded_headers;
|
use garage_util::forwarded_headers;
|
||||||
use garage_util::metrics::{gen_trace_id, RecordDuration};
|
use garage_util::metrics::{gen_trace_id, RecordDuration};
|
||||||
|
use garage_util::socket_address::UnixOrTCPSocketAddress;
|
||||||
|
|
||||||
struct WebMetrics {
|
struct WebMetrics {
|
||||||
request_counter: Counter<u64>,
|
request_counter: Counter<u64>,
|
||||||
@@ -69,7 +76,7 @@ impl WebServer {
|
|||||||
/// Run a web server
|
/// Run a web server
|
||||||
pub async fn run(
|
pub async fn run(
|
||||||
garage: Arc<Garage>,
|
garage: Arc<Garage>,
|
||||||
addr: SocketAddr,
|
addr: UnixOrTCPSocketAddress,
|
||||||
root_domain: String,
|
root_domain: String,
|
||||||
shutdown_signal: impl Future<Output = ()>,
|
shutdown_signal: impl Future<Output = ()>,
|
||||||
) -> Result<(), GarageError> {
|
) -> Result<(), GarageError> {
|
||||||
@@ -80,7 +87,7 @@ impl WebServer {
|
|||||||
root_domain,
|
root_domain,
|
||||||
});
|
});
|
||||||
|
|
||||||
let service = make_service_fn(|conn: &AddrStream| {
|
let tcp_service = make_service_fn(|conn: &AddrStream| {
|
||||||
let web_server = web_server.clone();
|
let web_server = web_server.clone();
|
||||||
|
|
||||||
let client_addr = conn.remote_addr();
|
let client_addr = conn.remote_addr();
|
||||||
@@ -88,23 +95,56 @@ impl WebServer {
|
|||||||
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
||||||
let web_server = web_server.clone();
|
let web_server = web_server.clone();
|
||||||
|
|
||||||
web_server.handle_request(req, client_addr)
|
web_server.handle_request(req, client_addr.to_string())
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = Server::bind(&addr).serve(service);
|
let unix_service = make_service_fn(|_: &UnixStream| {
|
||||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
let web_server = web_server.clone();
|
||||||
info!("Web server listening on http://{}", addr);
|
|
||||||
|
let path = addr.to_string();
|
||||||
|
async move {
|
||||||
|
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
||||||
|
let web_server = web_server.clone();
|
||||||
|
|
||||||
|
web_server.handle_request(req, path.clone())
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
info!("Web server listening on {}", addr);
|
||||||
|
|
||||||
|
match addr {
|
||||||
|
UnixOrTCPSocketAddress::TCPSocket(addr) => {
|
||||||
|
Server::bind(&addr)
|
||||||
|
.serve(tcp_service)
|
||||||
|
.with_graceful_shutdown(shutdown_signal)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
UnixOrTCPSocketAddress::UnixSocket(ref path) => {
|
||||||
|
if path.exists() {
|
||||||
|
fs::remove_file(path)?
|
||||||
|
}
|
||||||
|
|
||||||
|
let bound = Server::bind_unix(path)?;
|
||||||
|
|
||||||
|
fs::set_permissions(path, Permissions::from_mode(0o222))?;
|
||||||
|
|
||||||
|
bound
|
||||||
|
.serve(unix_service)
|
||||||
|
.with_graceful_shutdown(shutdown_signal)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
graceful.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_request(
|
async fn handle_request(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
addr: SocketAddr,
|
addr: String,
|
||||||
) -> Result<Response<Body>, Infallible> {
|
) -> Result<Response<Body>, Infallible> {
|
||||||
if let Ok(forwarded_for_ip_addr) =
|
if let Ok(forwarded_for_ip_addr) =
|
||||||
forwarded_headers::handle_forwarded_for_headers(req.headers())
|
forwarded_headers::handle_forwarded_for_headers(req.headers())
|
||||||
|
|||||||
Reference in New Issue
Block a user