Implement ConnectClusterNodes

This commit is contained in:
Alex 2022-05-17 18:43:47 +02:00
parent 440a577563
commit 70383b4363
Signed by untrusted user: lx
GPG key ID: 0E496D15096376BE
5 changed files with 74 additions and 4 deletions

View file

@ -94,6 +94,36 @@ Example response body:
}
```
### ConnectClusterNodes `POST /v0/connect`
Instructs this Garage node to connect to other Garage nodes at specified addresses.
Example request body:
```json
[
"ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f@10.0.0.11:3901",
"4a6ae5a1d0d33bf895f5bb4f0a418b7dc94c47c0dd2eb108d1158f3c8f60b0ff@10.0.0.12:3901"
]
```
The format of the string for a node to connect to is: `<node ID>@<ip address>:<port>`, same as in the `garage node connect` CLI call.
Example response:
```json
[
{
"success": true,
"error": null,
},
{
"success": false,
"error": "Handshake error",
}
]
```
### GetClusterLayout `GET /v0/layout`
Returns the cluster's current layout in JSON, including:

View file

@ -124,6 +124,7 @@ impl ApiHandler for AdminApiServer {
Endpoint::Options => self.handle_options(&req),
Endpoint::Metrics => self.handle_metrics(),
Endpoint::GetClusterStatus => handle_get_cluster_status(&self.garage).await,
Endpoint::ConnectClusterNodes => handle_connect_cluster_nodes(&self.garage, req).await,
// Layout
Endpoint::GetClusterLayout => handle_get_cluster_layout(&self.garage).await,
Endpoint::UpdateClusterLayout => handle_update_cluster_layout(&self.garage, req).await,

View file

@ -45,6 +45,33 @@ pub async fn handle_get_cluster_status(garage: &Arc<Garage>) -> Result<Response<
.body(Body::from(resp_json))?)
}
pub async fn handle_connect_cluster_nodes(
garage: &Arc<Garage>,
req: Request<Body>,
) -> Result<Response<Body>, Error> {
let req = parse_json_body::<Vec<String>>(req).await?;
let res = futures::future::join_all(req.iter().map(|node| garage.system.connect(node)))
.await
.into_iter()
.map(|r| match r {
Ok(()) => ConnectClusterNodesResponse {
success: true,
error: None,
},
Err(e) => ConnectClusterNodesResponse {
success: false,
error: Some(format!("{}", e)),
},
})
.collect::<Vec<_>>();
let resp_json = serde_json::to_string_pretty(&res).map_err(GarageError::from)?;
Ok(Response::builder()
.status(StatusCode::OK)
.body(Body::from(resp_json))?)
}
pub async fn handle_get_cluster_layout(garage: &Arc<Garage>) -> Result<Response<Body>, Error> {
let res = get_cluster_layout(garage);
let resp_json = serde_json::to_string_pretty(&res).map_err(GarageError::from)?;
@ -84,6 +111,12 @@ struct GetClusterStatusResponse {
layout: GetClusterLayoutResponse,
}
#[derive(Serialize)]
struct ConnectClusterNodesResponse {
success: bool,
error: Option<String>,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct GetClusterLayoutResponse {

View file

@ -18,6 +18,7 @@ pub enum Endpoint {
Options,
Metrics,
GetClusterStatus,
ConnectClusterNodes,
// Layout
GetClusterLayout,
UpdateClusterLayout,
@ -91,6 +92,7 @@ impl Endpoint {
OPTIONS _ => Options,
GET "/metrics" => Metrics,
GET "/v0/status" => GetClusterStatus,
POST "/v0/connect" => ConnectClusterNodes,
// Layout endpoints
GET "/v0/layout" => GetClusterLayout,
POST "/v0/layout" => UpdateClusterLayout,

View file

@ -383,11 +383,15 @@ impl System {
}
}
}
if errors.len() == 1 {
return Err(Error::Message(errors[0].1.to_string()));
} else {
return Err(Error::Message(format!(
"Could not connect to specified peers. Errors: {:?}",
errors
)));
}
}
// ---- INTERNALS ----