more complete admin API #298
5 changed files with 116 additions and 23 deletions
|
@ -209,3 +209,52 @@ Similarly to the CLI, the body must include the incremented
|
|||
version number, which MUST be 1 + the value of the currently
|
||||
existing layout in the cluster.
|
||||
|
||||
|
||||
## Access key operations
|
||||
|
||||
### ListKeys `GET /key`
|
||||
|
||||
Returns all API access keys in the cluster.
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
#TODO
|
||||
```
|
||||
|
||||
### CreateKey `POST /key`
|
||||
|
||||
Creates a new API access key.
|
||||
|
||||
Request body format:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "NameOfMyKey"
|
||||
}
|
||||
```
|
||||
|
||||
### GetKeyInfo `GET /key?id=<acces key id>`
|
||||
|
||||
Returns information about the requested API access key.
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
#TODO
|
||||
```
|
||||
|
||||
### DeleteKey `DELETE /key?id=<acces key id>`
|
||||
|
||||
Deletes an API access key.
|
||||
|
||||
### UpdateKey `POST /key?id=<acces key id>`
|
||||
|
||||
Updates information about the specified API access key.
|
||||
|
||||
Request body format:
|
||||
|
||||
```json
|
||||
#TODO
|
||||
```
|
||||
|
||||
|
|
|
@ -129,12 +129,10 @@ impl ApiHandler for AdminApiServer {
|
|||
Endpoint::UpdateClusterLayout => handle_update_cluster_layout(&self.garage, req).await,
|
||||
Endpoint::ApplyClusterLayout => handle_apply_cluster_layout(&self.garage, req).await,
|
||||
Endpoint::RevertClusterLayout => handle_revert_cluster_layout(&self.garage, req).await,
|
||||
/*
|
||||
_ => Err(Error::NotImplemented(format!(
|
||||
"Admin endpoint {} not implemented yet",
|
||||
endpoint.name()
|
||||
))),
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::error::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use hyper::{Method, Request};
|
||||
|
||||
use crate::router_macros::router_match;
|
||||
use crate::error::*;
|
||||
use crate::router_macros::*;
|
||||
|
||||
pub enum Authorization {
|
||||
MetricsToken,
|
||||
|
@ -21,6 +22,17 @@ pub enum Endpoint {
|
|||
UpdateClusterLayout,
|
||||
ApplyClusterLayout,
|
||||
RevertClusterLayout,
|
||||
ListKeys,
|
||||
CreateKey,
|
||||
GetKeyInfo {
|
||||
id: String,
|
||||
},
|
||||
DeleteKey {
|
||||
id: String,
|
||||
},
|
||||
UpdateKey {
|
||||
id: String,
|
||||
},
|
||||
}}
|
||||
|
||||
impl Endpoint {
|
||||
|
@ -28,24 +40,32 @@ impl Endpoint {
|
|||
/// 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 path = req.uri().path();
|
||||
let uri = req.uri();
|
||||
let path = uri.path();
|
||||
let query = uri.query();
|
||||
|
||||
use Endpoint::*;
|
||||
let res = match (req.method(), path) {
|
||||
(&Method::OPTIONS, _) => Options,
|
||||
(&Method::GET, "/metrics") => Metrics,
|
||||
(&Method::GET, "/status") => GetClusterStatus,
|
||||
(&Method::GET, "/layout") => GetClusterLayout,
|
||||
(&Method::POST, "/layout") => UpdateClusterLayout,
|
||||
(&Method::POST, "/layout/apply") => ApplyClusterLayout,
|
||||
(&Method::POST, "/layout/revert") => RevertClusterLayout,
|
||||
(m, p) => {
|
||||
return Err(Error::BadRequest(format!(
|
||||
"Unknown API endpoint: {} {}",
|
||||
m, p
|
||||
)))
|
||||
let mut query = QueryParameters::from_query(query.unwrap_or_default())?;
|
||||
|
||||
let res = router_match!(@gen_path_parser (req.method(), path, query) [
|
||||
OPTIONS _ => Options,
|
||||
GET "/metrics" => Metrics,
|
||||
GET "/status" => GetClusterStatus,
|
||||
// Layout endpoints
|
||||
GET "/layout" => GetClusterLayout,
|
||||
POST "/layout" => UpdateClusterLayout,
|
||||
POST "/layout/apply" => ApplyClusterLayout,
|
||||
POST "/layout/revert" => RevertClusterLayout,
|
||||
// API key endpoints
|
||||
GET "/key" if id => GetKeyInfo (query::id),
|
||||
POST "/key" if id => UpdateKey (query::id),
|
||||
POST "/key" => CreateKey,
|
||||
DELETE "/key" if id => DeleteKey (query::id),
|
||||
GET "/key" => ListKeys,
|
||||
]);
|
||||
|
||||
if let Some(message) = query.nonempty_message() {
|
||||
debug!("Unused query parameter: {}", message)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
@ -57,3 +77,7 @@ impl Endpoint {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateQueryParameters! {
|
||||
"id" => id
|
||||
}
|
||||
|
|
|
@ -23,6 +23,29 @@ macro_rules! router_match {
|
|||
_ => None
|
||||
}
|
||||
}};
|
||||
(@gen_path_parser ($method:expr, $reqpath:expr, $query:expr)
|
||||
[
|
||||
$($meth:ident $path:pat $(if $required:ident)? => $api:ident $(($($conv:ident :: $param:ident),*))?,)*
|
||||
]) => {{
|
||||
{
|
||||
use Endpoint::*;
|
||||
match ($method, $reqpath) {
|
||||
$(
|
||||
(&Method::$meth, $path) if true $(&& $query.$required.is_some())? => $api {
|
||||
$($(
|
||||
$param: router_match!(@@parse_param $query, $conv, $param),
|
||||
)*)?
|
||||
},
|
||||
)*
|
||||
(m, p) => {
|
||||
return Err(Error::BadRequest(format!(
|
||||
"Unknown API endpoint: {} {}",
|
||||
m, p
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
||||
(@gen_parser ($keyword:expr, $key:ident, $query:expr, $header:expr),
|
||||
key: [$($kw_k:ident $(if $required_k:ident)? $(header $header_k:expr)? => $api_k:ident $(($($conv_k:ident :: $param_k:ident),*))?,)*],
|
||||
no_key: [$($kw_nk:ident $(if $required_nk:ident)? $(if_header $header_nk:expr)? => $api_nk:ident $(($($conv_nk:ident :: $param_nk:ident),*))?,)*]) => {{
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::error::{Error, OkOrBadRequest};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use hyper::header::HeaderValue;
|
||||
use hyper::{HeaderMap, Method, Request};
|
||||
|
||||
use crate::error::{Error, OkOrBadRequest};
|
||||
use crate::helpers::Authorization;
|
||||
use crate::router_macros::{generateQueryParameters, router_match};
|
||||
|
||||
|
|
Loading…
Reference in a new issue