api & web unix sockets working
This commit is contained in:
parent
54e02b4c3b
commit
972426cee1
7 changed files with 164 additions and 59 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -711,6 +711,7 @@ dependencies = [
|
|||
"http-range",
|
||||
"httpdate 0.3.2",
|
||||
"hyper",
|
||||
"hyperlocal",
|
||||
"idna",
|
||||
"log",
|
||||
"md-5",
|
||||
|
@ -934,6 +935,7 @@ dependencies = [
|
|||
"garage_util 0.6.0",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyperlocal",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
@ -1156,6 +1158,19 @@ dependencies = [
|
|||
"webpki",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
|
|
24
Cargo.nix
24
Cargo.nix
|
@ -1026,6 +1026,7 @@ in
|
|||
http_range = rustPackages."registry+https://github.com/rust-lang/crates.io-index".http-range."0.1.4" { inherit profileName; };
|
||||
httpdate = rustPackages."registry+https://github.com/rust-lang/crates.io-index".httpdate."0.3.2" { inherit profileName; };
|
||||
hyper = rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.13" { inherit profileName; };
|
||||
hyperlocal = rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyperlocal."0.8.0" { inherit profileName; };
|
||||
idna = rustPackages."registry+https://github.com/rust-lang/crates.io-index".idna."0.2.3" { inherit profileName; };
|
||||
log = rustPackages."registry+https://github.com/rust-lang/crates.io-index".log."0.4.14" { inherit profileName; };
|
||||
md5 = rustPackages."registry+https://github.com/rust-lang/crates.io-index".md-5."0.9.1" { inherit profileName; };
|
||||
|
@ -1551,6 +1552,25 @@ 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 [
|
||||
[ "client" ]
|
||||
[ "default" ]
|
||||
[ "server" ]
|
||||
];
|
||||
dependencies = {
|
||||
futures_util = rustPackages."registry+https://github.com/rust-lang/crates.io-index".futures-util."0.3.17" { inherit profileName; };
|
||||
hex = rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { inherit profileName; };
|
||||
hyper = rustPackages."registry+https://github.com/rust-lang/crates.io-index".hyper."0.14.13" { inherit profileName; };
|
||||
pin_project = rustPackages."registry+https://github.com/rust-lang/crates.io-index".pin-project."1.0.8" { inherit profileName; };
|
||||
tokio = rustPackages."registry+https://github.com/rust-lang/crates.io-index".tokio."1.12.0" { inherit profileName; };
|
||||
};
|
||||
});
|
||||
|
||||
"registry+https://github.com/rust-lang/crates.io-index".idna."0.2.3" = overridableMkRustCrate (profileName: rec {
|
||||
name = "idna";
|
||||
version = "0.2.3";
|
||||
|
@ -2334,7 +2354,7 @@ in
|
|||
];
|
||||
dependencies = {
|
||||
${ if hostPlatform.parsed.kernel.name == "android" || hostPlatform.parsed.kernel.name == "linux" then "libc" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.115" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.kernel.name == "dragonfly" || hostPlatform.parsed.kernel.name == "freebsd" || hostPlatform.parsed.kernel.name == "illumos" || hostPlatform.parsed.kernel.name == "netbsd" || hostPlatform.parsed.kernel.name == "openbsd" || hostPlatform.parsed.kernel.name == "solaris" || hostPlatform.parsed.kernel.name == "android" || hostPlatform.parsed.kernel.name == "linux" then "once_cell" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".once_cell."1.8.0" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.kernel.name == "android" || hostPlatform.parsed.kernel.name == "linux" || hostPlatform.parsed.kernel.name == "dragonfly" || hostPlatform.parsed.kernel.name == "freebsd" || hostPlatform.parsed.kernel.name == "illumos" || hostPlatform.parsed.kernel.name == "netbsd" || hostPlatform.parsed.kernel.name == "openbsd" || hostPlatform.parsed.kernel.name == "solaris" then "once_cell" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".once_cell."1.8.0" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.cpu.name == "i686" || hostPlatform.parsed.cpu.name == "x86_64" || (hostPlatform.parsed.cpu.name == "aarch64" || hostPlatform.parsed.cpu.name == "armv6l" || hostPlatform.parsed.cpu.name == "armv7l") && (hostPlatform.parsed.kernel.name == "android" || hostPlatform.parsed.kernel.name == "fuchsia" || hostPlatform.parsed.kernel.name == "linux") then "spin" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".spin."0.5.2" { inherit profileName; };
|
||||
untrusted = rustPackages."registry+https://github.com/rust-lang/crates.io-index".untrusted."0.7.1" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.cpu.name == "wasm32" && hostPlatform.parsed.vendor.name == "unknown" && hostPlatform.parsed.kernel.name == "unknown" && hostPlatform.parsed.abi.name == "" then "web_sys" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".web-sys."0.3.56" { inherit profileName; };
|
||||
|
@ -2704,7 +2724,7 @@ in
|
|||
];
|
||||
dependencies = {
|
||||
bitflags = rustPackages."registry+https://github.com/rust-lang/crates.io-index".bitflags."1.3.2" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.kernel.name == "linux" || hostPlatform.parsed.kernel.name == "android" then "libc" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.115" { inherit profileName; };
|
||||
${ if hostPlatform.parsed.kernel.name == "android" || hostPlatform.parsed.kernel.name == "linux" then "libc" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".libc."0.2.115" { inherit profileName; };
|
||||
${ if !(hostPlatform.parsed.kernel.name == "linux" || hostPlatform.parsed.kernel.name == "android") then "parking_lot" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".parking_lot."0.11.2" { inherit profileName; };
|
||||
${ if !(hostPlatform.parsed.kernel.name == "linux" || hostPlatform.parsed.kernel.name == "android") then "parking_lot_core" else null } = rustPackages."registry+https://github.com/rust-lang/crates.io-index".parking_lot_core."0.8.5" { inherit profileName; };
|
||||
static_init_macro = buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".static_init_macro."1.0.2" { profileName = "__noProfile"; };
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "garage_api"
|
||||
version = "0.6.0"
|
||||
authors = ["Alex Auvolat <alex@adnab.me>"]
|
||||
description = "S3 API server crate for the Garage object store"
|
||||
edition = "2018"
|
||||
license = "AGPL-3.0"
|
||||
description = "S3 API server crate for the Garage object store"
|
||||
repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
|
||||
name = "garage_api"
|
||||
readme = "../../README.md"
|
||||
repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
|
||||
version = "0.6.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
@ -14,9 +14,9 @@ path = "lib.rs"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
garage_model = { version = "0.6.0", path = "../model" }
|
||||
garage_table = { version = "0.6.0", path = "../table" }
|
||||
garage_util = { version = "0.6.0", path = "../util" }
|
||||
garage_model = {version = "0.6.0", path = "../model"}
|
||||
garage_table = {version = "0.6.0", path = "../table"}
|
||||
garage_util = {version = "0.6.0", path = "../util"}
|
||||
|
||||
base64 = "0.13"
|
||||
bytes = "1.0"
|
||||
|
@ -34,18 +34,19 @@ sha2 = "0.9"
|
|||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
pin-project = "1.0"
|
||||
tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
|
||||
tokio = {version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"]}
|
||||
|
||||
form_urlencoded = "1.0.0"
|
||||
http = "0.2"
|
||||
httpdate = "0.3"
|
||||
http-range = "0.1"
|
||||
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
||||
httpdate = "0.3"
|
||||
hyper = {version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"]}
|
||||
hyperlocal = "0.8"
|
||||
multer = "2.0"
|
||||
percent-encoding = "2.1.0"
|
||||
quick-xml = {version = "0.21", features = ["serialize"]}
|
||||
roxmltree = "0.14"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde = {version = "1.0", features = ["derive"]}
|
||||
serde_bytes = "0.11"
|
||||
serde_json = "1.0"
|
||||
quick-xml = { version = "0.21", features = [ "serialize" ] }
|
||||
url = "2.1"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use futures::future::Future;
|
||||
use hyper::header;
|
||||
|
@ -7,6 +7,8 @@ use hyper::server::conn::AddrStream;
|
|||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Method, Request, Response, Server};
|
||||
|
||||
use hyperlocal::UnixServerExt;
|
||||
|
||||
use garage_util::data::*;
|
||||
use garage_util::error::Error as GarageError;
|
||||
|
||||
|
@ -35,32 +37,57 @@ pub async fn run_api_server(
|
|||
garage: Arc<Garage>,
|
||||
shutdown_signal: impl Future<Output = ()>,
|
||||
) -> Result<(), GarageError> {
|
||||
let addr = &garage.config.s3_api.api_bind_addr;
|
||||
let socket_path = &garage.config.s3_api.api_unix_socket;
|
||||
if socket_path.is_empty() {
|
||||
let addr = &garage.config.s3_api.api_bind_addr;
|
||||
|
||||
let service = make_service_fn(|conn: &AddrStream| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = conn.remote_addr();
|
||||
async move {
|
||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handler(garage, req, client_addr)
|
||||
}))
|
||||
let service = make_service_fn(|conn: &AddrStream| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = conn.remote_addr().to_string();
|
||||
async move {
|
||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handler(garage, req, client_addr.clone())
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
let server = Server::bind(addr).serve(service);
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
|
||||
info!("API server listening on http://{}", addr);
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
let path = Path::new(socket_path);
|
||||
if path.exists() {
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
});
|
||||
let service = make_service_fn(|_conn| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = String::from("unix");
|
||||
async move {
|
||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handler(garage, req, client_addr.clone())
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
let server = Server::bind(addr).serve(service);
|
||||
let listener = Server::bind_unix(path)?;
|
||||
let server = listener.serve(service);
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
info!("API server listening on http://{}", addr);
|
||||
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
info!("API server listening on {}", socket_path);
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn handler(
|
||||
garage: Arc<Garage>,
|
||||
req: Request<Body>,
|
||||
addr: SocketAddr,
|
||||
addr: String,
|
||||
) -> Result<Response<Body>, GarageError> {
|
||||
let uri = req.uri().clone();
|
||||
info!("{} {} {}", addr, req.method(), uri);
|
||||
|
|
|
@ -37,6 +37,10 @@ pub struct Config {
|
|||
)]
|
||||
pub compression_level: Option<i32>,
|
||||
|
||||
/// Path to unix socket
|
||||
#[serde(default = "default_unix_socket")]
|
||||
pub rpc_unix_socket: String,
|
||||
|
||||
/// RPC secret key: 32 bytes hex encoded
|
||||
pub rpc_secret: String,
|
||||
|
||||
|
@ -71,6 +75,9 @@ pub struct Config {
|
|||
/// Configuration for S3 api
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct ApiConfig {
|
||||
/// Path to unix socket
|
||||
#[serde(default = "default_unix_socket")]
|
||||
pub api_unix_socket: String,
|
||||
/// Address and port to bind for api serving
|
||||
pub api_bind_addr: SocketAddr,
|
||||
/// S3 region to use
|
||||
|
@ -83,6 +90,9 @@ pub struct ApiConfig {
|
|||
/// Configuration for serving files as normal web server
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
pub struct WebConfig {
|
||||
/// Path to unix socket
|
||||
#[serde(default = "default_unix_socket")]
|
||||
pub web_unix_socket: String,
|
||||
/// Address and port to bind for web serving
|
||||
pub bind_addr: SocketAddr,
|
||||
/// Suffix to remove from domain name to find bucket
|
||||
|
@ -98,6 +108,9 @@ fn default_sled_flush_every_ms() -> u64 {
|
|||
fn default_block_size() -> usize {
|
||||
1048576
|
||||
}
|
||||
fn default_unix_socket() -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
/// Read and parse configuration
|
||||
pub fn read_config(config_file: PathBuf) -> Result<Config, Error> {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "garage_web"
|
||||
version = "0.6.0"
|
||||
authors = ["Alex Auvolat <alex@adnab.me>", "Quentin Dufour <quentin@dufour.io>"]
|
||||
description = "S3-like website endpoint crate for the Garage object store"
|
||||
edition = "2018"
|
||||
license = "AGPL-3.0"
|
||||
description = "S3-like website endpoint crate for the Garage object store"
|
||||
repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
|
||||
name = "garage_web"
|
||||
readme = "../../README.md"
|
||||
repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
|
||||
version = "0.6.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
@ -14,10 +14,10 @@ path = "lib.rs"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
garage_api = { version = "0.6.0", path = "../api" }
|
||||
garage_model = { version = "0.6.0", path = "../model" }
|
||||
garage_util = { version = "0.6.0", path = "../util" }
|
||||
garage_table = { version = "0.6.0", path = "../table" }
|
||||
garage_api = {version = "0.6.0", path = "../api"}
|
||||
garage_model = {version = "0.6.0", path = "../model"}
|
||||
garage_table = {version = "0.6.0", path = "../table"}
|
||||
garage_util = {version = "0.6.0", path = "../util"}
|
||||
|
||||
err-derive = "0.3"
|
||||
log = "0.4"
|
||||
|
@ -26,4 +26,5 @@ percent-encoding = "2.1.0"
|
|||
futures = "0.3"
|
||||
|
||||
http = "0.2"
|
||||
hyper = { version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"] }
|
||||
hyper = {version = "0.14", features = ["server", "http1", "runtime", "tcp", "stream"]}
|
||||
hyperlocal = "0.8"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, convert::Infallible, net::SocketAddr, sync::Arc};
|
||||
use std::{borrow::Cow, convert::Infallible, fs, path::Path, sync::Arc};
|
||||
|
||||
use futures::future::Future;
|
||||
|
||||
|
@ -9,6 +9,8 @@ use hyper::{
|
|||
Body, Method, Request, Response, Server,
|
||||
};
|
||||
|
||||
use hyperlocal::UnixServerExt;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
use garage_api::error::{Error as ApiError, OkOrBadRequest, OkOrInternalError};
|
||||
|
@ -26,31 +28,57 @@ pub async fn run_web_server(
|
|||
garage: Arc<Garage>,
|
||||
shutdown_signal: impl Future<Output = ()>,
|
||||
) -> Result<(), GarageError> {
|
||||
let addr = &garage.config.s3_web.bind_addr;
|
||||
let socket_path = &garage.config.s3_web.web_unix_socket;
|
||||
if socket_path.is_empty() {
|
||||
let addr = &garage.config.s3_web.bind_addr;
|
||||
|
||||
let service = make_service_fn(|conn: &AddrStream| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = conn.remote_addr();
|
||||
async move {
|
||||
Ok::<_, Error>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handle_request(garage, req, client_addr)
|
||||
}))
|
||||
let service = make_service_fn(|conn: &AddrStream| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = conn.remote_addr().to_string();
|
||||
async move {
|
||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handler(garage, req, client_addr.clone())
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
let server = Server::bind(addr).serve(service);
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
|
||||
info!("Web server listening on http://{}", addr);
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
let path = Path::new(socket_path);
|
||||
if path.exists() {
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
});
|
||||
let service = make_service_fn(|_conn| {
|
||||
let garage = garage.clone();
|
||||
let client_addr = String::from("unix");
|
||||
async move {
|
||||
Ok::<_, GarageError>(service_fn(move |req: Request<Body>| {
|
||||
let garage = garage.clone();
|
||||
handler(garage, req, client_addr.clone())
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
let server = Server::bind(addr).serve(service);
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
info!("Web server listening on http://{}", addr);
|
||||
let listener = Server::bind_unix(path)?;
|
||||
let server = listener.serve(service);
|
||||
let graceful = server.with_graceful_shutdown(shutdown_signal);
|
||||
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
info!("Web server listening on {}", socket_path);
|
||||
graceful.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_request(
|
||||
async fn handler(
|
||||
garage: Arc<Garage>,
|
||||
req: Request<Body>,
|
||||
addr: SocketAddr,
|
||||
addr: String,
|
||||
) -> Result<Response<Body>, Infallible> {
|
||||
info!("{} {} {}", addr, req.method(), req.uri());
|
||||
match serve_file(garage, &req).await {
|
||||
|
|
Loading…
Reference in a new issue