Add API access key admin endpoints
This commit is contained in:
parent
bb6ec9ebd9
commit
f97a7845e9
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
|
version number, which MUST be 1 + the value of the currently
|
||||||
existing layout in the cluster.
|
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::UpdateClusterLayout => handle_update_cluster_layout(&self.garage, req).await,
|
||||||
Endpoint::ApplyClusterLayout => handle_apply_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,
|
Endpoint::RevertClusterLayout => handle_revert_cluster_layout(&self.garage, req).await,
|
||||||
/*
|
|
||||||
_ => Err(Error::NotImplemented(format!(
|
_ => Err(Error::NotImplemented(format!(
|
||||||
"Admin endpoint {} not implemented yet",
|
"Admin endpoint {} not implemented yet",
|
||||||
endpoint.name()
|
endpoint.name()
|
||||||
))),
|
))),
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::error::*;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use hyper::{Method, Request};
|
use hyper::{Method, Request};
|
||||||
|
|
||||||
use crate::router_macros::router_match;
|
use crate::error::*;
|
||||||
|
use crate::router_macros::*;
|
||||||
|
|
||||||
pub enum Authorization {
|
pub enum Authorization {
|
||||||
MetricsToken,
|
MetricsToken,
|
||||||
|
@ -21,6 +22,17 @@ pub enum Endpoint {
|
||||||
UpdateClusterLayout,
|
UpdateClusterLayout,
|
||||||
ApplyClusterLayout,
|
ApplyClusterLayout,
|
||||||
RevertClusterLayout,
|
RevertClusterLayout,
|
||||||
|
ListKeys,
|
||||||
|
CreateKey,
|
||||||
|
GetKeyInfo {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
DeleteKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
UpdateKey {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
impl Endpoint {
|
impl Endpoint {
|
||||||
|
@ -28,24 +40,32 @@ impl Endpoint {
|
||||||
/// possibly extracted from the Host header.
|
/// possibly extracted from the Host header.
|
||||||
/// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets
|
/// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets
|
||||||
pub fn from_request<T>(req: &Request<T>) -> Result<Self, Error> {
|
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 mut query = QueryParameters::from_query(query.unwrap_or_default())?;
|
||||||
let res = match (req.method(), path) {
|
|
||||||
(&Method::OPTIONS, _) => Options,
|
let res = router_match!(@gen_path_parser (req.method(), path, query) [
|
||||||
(&Method::GET, "/metrics") => Metrics,
|
OPTIONS _ => Options,
|
||||||
(&Method::GET, "/status") => GetClusterStatus,
|
GET "/metrics" => Metrics,
|
||||||
(&Method::GET, "/layout") => GetClusterLayout,
|
GET "/status" => GetClusterStatus,
|
||||||
(&Method::POST, "/layout") => UpdateClusterLayout,
|
// Layout endpoints
|
||||||
(&Method::POST, "/layout/apply") => ApplyClusterLayout,
|
GET "/layout" => GetClusterLayout,
|
||||||
(&Method::POST, "/layout/revert") => RevertClusterLayout,
|
POST "/layout" => UpdateClusterLayout,
|
||||||
(m, p) => {
|
POST "/layout/apply" => ApplyClusterLayout,
|
||||||
return Err(Error::BadRequest(format!(
|
POST "/layout/revert" => RevertClusterLayout,
|
||||||
"Unknown API endpoint: {} {}",
|
// API key endpoints
|
||||||
m, p
|
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)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
@ -57,3 +77,7 @@ impl Endpoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateQueryParameters! {
|
||||||
|
"id" => id
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,29 @@ macro_rules! router_match {
|
||||||
_ => None
|
_ => 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),
|
(@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),*))?,)*],
|
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),*))?,)*]) => {{
|
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 std::borrow::Cow;
|
||||||
|
|
||||||
use hyper::header::HeaderValue;
|
use hyper::header::HeaderValue;
|
||||||
use hyper::{HeaderMap, Method, Request};
|
use hyper::{HeaderMap, Method, Request};
|
||||||
|
|
||||||
|
use crate::error::{Error, OkOrBadRequest};
|
||||||
use crate::helpers::Authorization;
|
use crate::helpers::Authorization;
|
||||||
use crate::router_macros::{generateQueryParameters, router_match};
|
use crate::router_macros::{generateQueryParameters, router_match};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue