feat(dev) engines: "Dynamic Routing"
This commit is contained in:
parent
55270c0637
commit
6755e61163
3 changed files with 62 additions and 13 deletions
|
|
@ -5,4 +5,4 @@ CREATE TABLE secret_engines (
|
||||||
engine_type TEXT NOT NULL
|
engine_type TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO secret_engines (mount_point, engine_type) VALUES ('/kv-v2', 'kv');
|
INSERT INTO secret_engines (mount_point, engine_type) VALUES ('/kv-v2', 'kv_v2');
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,76 @@ pub mod kv;
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
extract::{Request, State},
|
extract::{Request, State},
|
||||||
http::Uri,
|
http::{StatusCode, Uri},
|
||||||
response::Response,
|
response::{IntoResponse, Response},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use tower::Service;
|
||||||
|
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DatabaseDriver;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// State to be used to store the database pool
|
||||||
|
/// and the routers for each engine
|
||||||
|
struct EngineMapperState {
|
||||||
|
pool: DatabaseDriver,
|
||||||
|
kv_v2: Router<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Secret engine router
|
||||||
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
||||||
Router::new().fallback(engine_handler).with_state(pool)
|
// State containing the pool and engine routers
|
||||||
|
let state = EngineMapperState {
|
||||||
|
pool: pool.clone(),
|
||||||
|
kv_v2: kv::kv_router(pool.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Router::new().fallback(engine_handler).with_state(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn engine_handler(State(pool): State<DatabaseDriver>, req: Request) -> Response<Body> {
|
/// Map the request to the appropriate engine and call the router
|
||||||
match map_mount_points(req.uri(), &pool).await {
|
async fn engine_handler(
|
||||||
Some((mount_path, engine_type)) => {
|
// State(pool): State<DatabaseDriver>,
|
||||||
|
State(engines): State<EngineMapperState>,
|
||||||
|
req: Request,
|
||||||
|
) -> Response<Body> {
|
||||||
|
if let Some((mount_path, engine_type)) = map_mount_points(req.uri(), &engines.pool).await {
|
||||||
info!("Found mount point {} of type {}", mount_path, engine_type);
|
info!("Found mount point {} of type {}", mount_path, engine_type);
|
||||||
todo!()
|
// Match the engine type to the appropriate router
|
||||||
|
match engine_type.as_str() {
|
||||||
|
"kv_v2" => call_router(engines.kv_v2, mount_path, req).await,
|
||||||
|
// Mount point exists but the type is unknown
|
||||||
|
_ => unknown_engine(engine_type).into_response(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, the mount path could not be found
|
||||||
|
(StatusCode::NOT_FOUND, "Mount path not found").into_response()
|
||||||
}
|
}
|
||||||
None => todo!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response::new(Body::from("Mount path:"))
|
/// Helper function to call the appropriate router with the request
|
||||||
|
async fn call_router(engine: Router<String>, mount_path: String, req: Request) -> Response {
|
||||||
|
engine
|
||||||
|
.with_state(mount_path)
|
||||||
|
.call(req)
|
||||||
|
.await
|
||||||
|
.into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HTTP error response for unknown engine types
|
||||||
|
/// Occurs when the mount path is found in the database
|
||||||
|
/// but the registered is unknown
|
||||||
|
fn unknown_engine(engine_type: String) -> (StatusCode, String) {
|
||||||
|
error!("Engine type {} not implemented", engine_type);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("Engine type {} not implemented", engine_type),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the mount path and engine type for the request,
|
||||||
|
/// if the mount path is registed at the database
|
||||||
async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, String)> {
|
async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, String)> {
|
||||||
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
|
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
|
||||||
|
|
||||||
|
|
@ -40,6 +86,7 @@ async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, S
|
||||||
.fetch_optional(pool)
|
.fetch_optional(pool)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
// Path found
|
||||||
if let Ok(Some(row)) = record {
|
if let Ok(Some(row)) = record {
|
||||||
trace!(
|
trace!(
|
||||||
"Mount path {} found with {:?} engine for route request: {}",
|
"Mount path {} found with {:?} engine for route request: {}",
|
||||||
|
|
@ -50,8 +97,10 @@ async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, S
|
||||||
|
|
||||||
return Some((mount_path_fragments.join("/"), row.engine_type));
|
return Some((mount_path_fragments.join("/"), row.engine_type));
|
||||||
} else {
|
} else {
|
||||||
|
// Shorten the mount path to find a shorter match
|
||||||
mount_path_fragments.pop();
|
mount_path_fragments.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If no mount path is found, return None
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::engines::kv::structs::KvSecret;
|
||||||
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
|
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
|
||||||
use axum::{extract::Path, routing::*, Router};
|
use axum::{extract::Path, routing::*, Router};
|
||||||
|
|
||||||
pub fn kv_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn kv_router(pool: DatabaseDriver) -> Router<String> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/:mount_path/config", get(get_config))
|
.route("/:mount_path/config", get(get_config))
|
||||||
.route("/:mount_path/config", post(post_config))
|
.route("/:mount_path/config", post(post_config))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue