diff --git a/server/src/handlers/http/cluster/mod.rs b/server/src/handlers/http/cluster/mod.rs index 9d07e7e31..24e045ce6 100644 --- a/server/src/handlers/http/cluster/mod.rs +++ b/server/src/handlers/http/cluster/mod.rs @@ -174,6 +174,7 @@ pub async fn fetch_daily_stats_from_ingestors( let res = reqwest::Client::new() .get(uri) + .header(header::AUTHORIZATION, &ingestor.token) .header(header::CONTENT_TYPE, "application/json") .send() .await; @@ -526,6 +527,7 @@ async fn fetch_cluster_metrics() -> Result, PostError> { let res = reqwest::Client::new() .get(uri) + .header(header::AUTHORIZATION, &ingestor.token) .header(header::CONTENT_TYPE, "application/json") .send() .await; diff --git a/server/src/handlers/http/modal/ingest_server.rs b/server/src/handlers/http/modal/ingest_server.rs index a9746fae8..c19517899 100644 --- a/server/src/handlers/http/modal/ingest_server.rs +++ b/server/src/handlers/http/modal/ingest_server.rs @@ -181,6 +181,7 @@ impl IngestServer { .service(Server::get_about_factory()) .service(Self::analytics_factory()) .service(Server::get_liveness_factory()) + .service(Server::get_metrics_webscope()) .service(Server::get_readiness_factory()), ) .service(Server::get_ingest_otel_factory()); @@ -226,7 +227,7 @@ impl IngestServer { web::resource("/info").route( web::get() .to(logstream::get_stream_info) - .authorize_for_stream(Action::GetStream), + .authorize_for_stream(Action::GetStreamInfo), ), ) .service( diff --git a/server/src/handlers/http/modal/query_server.rs b/server/src/handlers/http/modal/query_server.rs index 204d0e384..575b0748c 100644 --- a/server/src/handlers/http/modal/query_server.rs +++ b/server/src/handlers/http/modal/query_server.rs @@ -165,6 +165,7 @@ impl QueryServer { .service(Server::get_llm_webscope()) .service(Server::get_oauth_webscope(oidc_client)) .service(Server::get_user_role_webscope()) + .service(Server::get_metrics_webscope()) .service(Self::get_cluster_web_scope()), ) .service(Server::get_generated()); diff --git a/server/src/handlers/http/modal/server.rs b/server/src/handlers/http/modal/server.rs index 4eb104a01..08fd8eee2 100644 --- a/server/src/handlers/http/modal/server.rs +++ b/server/src/handlers/http/modal/server.rs @@ -180,12 +180,19 @@ impl Server { .service(Self::get_filters_webscope()) .service(Self::get_llm_webscope()) .service(Self::get_oauth_webscope(oidc_client)) - .service(Self::get_user_role_webscope()), + .service(Self::get_user_role_webscope()) + .service(Self::get_metrics_webscope()), ) .service(Self::get_ingest_otel_factory()) .service(Self::get_generated()); } + pub fn get_metrics_webscope() -> Scope { + web::scope("/metrics").service( + web::resource("").route(web::get().to(metrics::get).authorize(Action::Metrics)), + ) + } + // get the dashboards web scope pub fn get_dashboards_webscope() -> Scope { web::scope("/dashboards") @@ -312,7 +319,7 @@ impl Server { web::resource("/info").route( web::get() .to(logstream::get_stream_info) - .authorize_for_stream(Action::GetStream), + .authorize_for_stream(Action::GetStreamInfo), ), ) .service( @@ -423,8 +430,10 @@ impl Server { // get the oauth webscope pub fn get_oauth_webscope(oidc_client: Option) -> Scope { let oauth = web::scope("/o") - .service(resource("/login").route(web::get().to(oidc::login))) - .service(resource("/logout").route(web::get().to(oidc::logout))) + .service(resource("/login").route(web::get().to(oidc::login).authorize(Action::Login))) + .service( + resource("/logout").route(web::get().to(oidc::logout).authorize(Action::Login)), + ) .service(resource("/code").route(web::get().to(oidc::reply_login))); if let Some(client) = oidc_client { diff --git a/server/src/metrics/mod.rs b/server/src/metrics/mod.rs index c034e580e..b9e2bc555 100644 --- a/server/src/metrics/mod.rs +++ b/server/src/metrics/mod.rs @@ -20,7 +20,9 @@ pub mod prom_utils; pub mod storage; use crate::{handlers::http::metrics_path, stats::FullStats}; +use actix_web::Responder; use actix_web_prometheus::{PrometheusMetrics, PrometheusMetricsBuilder}; +use error::MetricsError; use once_cell::sync::Lazy; use prometheus::{HistogramOpts, HistogramVec, IntCounterVec, IntGaugeVec, Opts, Registry}; @@ -287,3 +289,42 @@ pub async fn fetch_stats_from_storage(stream_name: &str, stats: FullStats) { .with_label_values(&["data", stream_name, "parquet"]) .set(stats.lifetime_stats.storage as i64); } + +use actix_web::HttpResponse; + +pub async fn get() -> Result { + Ok(HttpResponse::Ok().body(format!("{:?}", build_metrics_handler()))) +} + +pub mod error { + + use actix_web::http::header::ContentType; + use http::StatusCode; + + #[derive(Debug, thiserror::Error)] + pub enum MetricsError { + #[error("{0}")] + Custom(String, StatusCode), + } + + impl actix_web::ResponseError for MetricsError { + fn status_code(&self) -> http::StatusCode { + match self { + Self::Custom(_, _) => StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_response(&self) -> actix_web::HttpResponse { + actix_web::HttpResponse::build(self.status_code()) + .insert_header(ContentType::plaintext()) + .body(self.to_string()) + } + } + + #[allow(dead_code)] + fn construct_custom_error() { + let error = + MetricsError::Custom("Some error".to_string(), StatusCode::INTERNAL_SERVER_ERROR); + println!("{:?}", error); + } +} diff --git a/server/src/rbac/role.rs b/server/src/rbac/role.rs index 1532c7c21..2dfb05805 100644 --- a/server/src/rbac/role.rs +++ b/server/src/rbac/role.rs @@ -24,7 +24,7 @@ pub enum Action { Query, CreateStream, ListStream, - GetStream, + GetStreamInfo, GetSchema, GetStats, DeleteStream, @@ -63,6 +63,8 @@ pub enum Action { DeleteFilter, ListCache, RemoveCache, + Login, + Metrics, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -102,7 +104,9 @@ impl RoleBuilder { self.stream.clone().unwrap(), self.tag.clone(), ), - Action::PutUser + Action::Login + | Action::Metrics + | Action::PutUser | Action::ListUser | Action::PutUserRoles | Action::GetUserRoles @@ -115,7 +119,7 @@ impl RoleBuilder { | Action::ListRole | Action::CreateStream | Action::DeleteStream - | Action::GetStream + | Action::GetStreamInfo | Action::ListStream | Action::ListCluster | Action::ListClusterMetrics @@ -201,11 +205,14 @@ pub mod model { fn editor_perm_builder() -> RoleBuilder { RoleBuilder { actions: vec![ + Action::Login, + Action::Metrics, Action::Ingest, Action::Query, Action::CreateStream, + Action::DeleteStream, Action::ListStream, - Action::GetStream, + Action::GetStreamInfo, Action::GetSchema, Action::GetStats, Action::GetRetention, @@ -217,8 +224,15 @@ pub mod model { Action::DeleteHotTierEnabled, Action::PutAlert, Action::GetAlert, - Action::GetAbout, Action::QueryLLM, + Action::CreateFilter, + Action::ListFilter, + Action::GetFilter, + Action::DeleteFilter, + Action::ListDashboard, + Action::GetDashboard, + Action::CreateDashboard, + Action::DeleteDashboard, ], stream: Some("*".to_string()), tag: None, @@ -228,17 +242,31 @@ pub mod model { fn writer_perm_builder() -> RoleBuilder { RoleBuilder { actions: vec![ - Action::Ingest, + Action::Login, Action::Query, Action::ListStream, - Action::GetStream, Action::GetSchema, Action::GetStats, - Action::GetRetention, + Action::PutRetention, Action::PutAlert, Action::GetAlert, - Action::GetAbout, + Action::GetRetention, + Action::PutHotTierEnabled, + Action::GetHotTierEnabled, + Action::DeleteHotTierEnabled, + Action::ListDashboard, + Action::GetDashboard, + Action::CreateDashboard, + Action::DeleteDashboard, + Action::Ingest, Action::QueryLLM, + Action::GetStreamInfo, + Action::GetCacheEnabled, + Action::PutCacheEnabled, + Action::GetFilter, + Action::ListFilter, + Action::CreateFilter, + Action::DeleteFilter, ], stream: None, tag: None, @@ -248,17 +276,21 @@ pub mod model { fn reader_perm_builder() -> RoleBuilder { RoleBuilder { actions: vec![ + Action::Login, Action::Query, Action::ListStream, - Action::GetStream, Action::GetSchema, Action::GetStats, - Action::GetRetention, - Action::GetAlert, - Action::GetAbout, Action::QueryLLM, - Action::ListCluster, - Action::GetHotTierEnabled, + Action::ListFilter, + Action::GetFilter, + Action::CreateFilter, + Action::DeleteFilter, + Action::ListDashboard, + Action::GetDashboard, + Action::CreateDashboard, + Action::DeleteDashboard, + Action::GetStreamInfo, ], stream: None, tag: None,