feat: Flag to validate config and queries succeeed.

This commit is contained in:
Jeremy Wall 2024-02-23 17:10:36 -05:00
parent 835c120d4b
commit 8aa41eb68c
4 changed files with 60 additions and 15 deletions

View File

@ -0,0 +1,18 @@
--- # A list of dashboards
- title: Invalid Dasbboard
graphs: # Each Dashboard can have 1 or more graphs in it.
- title: Node cpu # Graphs have titles
query_type: Range # The type of graph. Range for timeseries and Scalar for point in time
d3_tick_format: "~s" # Default tick format for the graph y axis
plots: # List of pluts to show on the graph
- source: http://heimdall:9001 # Prometheus source uri for this plot
query: 'sum by (instance)(irate(node_cpu_seconds_total{job="nodestats"}[5m])' # syntax error in query
meta: # metadata for this plot
name_format: "`${labels.instance}`" # javascript template literal to format the trace name
fill: tozeroy
#d3_tick_format: "~%" # d3 tick format override for this plot's yaxis
#named_axis: "y" # yaxis name to use for this subplots traces
span: # The span for this range query
end: now # Where the span ends. RFC3339 format with special handling for the now keyword
duration: 1d # duration of the span. Uses SI formatting for duration amounts.
step_duration: 10min # step size for the duration amounts.

View File

@ -18,8 +18,9 @@ use chrono::Duration;
use serde::Deserialize;
use serde_yaml;
use tracing::{debug, error};
use anyhow::Result;
use crate::query::{QueryConn, QueryType, PlotMeta};
use crate::query::{QueryConn, QueryType, QueryResult, PlotMeta, to_samples};
#[derive(Deserialize, Debug)]
pub struct GraphSpan {
@ -52,6 +53,21 @@ pub struct Graph {
pub d3_tick_format: Option<String>,
}
pub async fn query_data(graph: &Graph, dash: &Dashboard, query_span: Option<GraphSpan>) -> Result<Vec<QueryResult>> {
let connections = graph.get_query_connections(&dash.span, &query_span);
let mut data = Vec::new();
for conn in connections {
data.push(to_samples(
conn.get_results()
.await?
.data()
.clone(),
conn.meta,
));
}
Ok(data)
}
fn duration_from_string(duration_string: &str) -> Option<Duration> {
match parse_duration::parse(duration_string) {
Ok(d) => match Duration::from_std(d) {

View File

@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::path::PathBuf;
use anyhow;
use axum::{self, extract::State, routing::*, Router};
use clap::{self, Parser, ValueEnum};
use dashboard::{Dashboard, query_data};
use tokio::net::TcpListener;
use tower_http::trace::TraceLayer;
use tracing::{error, info};
use tracing::Level;
use tracing_subscriber::FmtSubscriber;
@ -43,6 +44,19 @@ struct Cli {
pub config: PathBuf,
#[arg(long, value_enum, default_value_t = Verbosity::INFO)]
pub verbose: Verbosity,
#[arg(long, default_value_t = false)]
pub validate: bool,
}
async fn validate(dash: &Dashboard) -> anyhow::Result<()> {
for graph in dash.graphs.iter() {
let data = query_data(graph, &dash, None).await;
if data.is_err() {
error!(err=?data, "Invalid dashboard query or queries");
}
let _ = data?;
}
return Ok(());
}
#[tokio::main]
@ -61,6 +75,14 @@ async fn main() -> anyhow::Result<()> {
.expect("setting default subscriber failed");
let config = std::sync::Arc::new(dashboard::read_dashboard_list(args.config.as_path())?);
if args.validate {
for dash in config.iter() {
validate(&dash).await?;
info!("All Queries successfully run against source");
return Ok(());
}
}
let router = Router::new()
// JSON api endpoints
.nest("/js", routes::mk_js_routes(config.clone()))

View File

@ -24,7 +24,7 @@ use axum::{
use maud::{html, Markup};
use tracing::debug;
use crate::dashboard::{Dashboard, Graph, GraphSpan};
use crate::dashboard::{Dashboard, Graph, GraphSpan, query_data};
use crate::query::{to_samples, QueryResult};
type Config = State<Arc<Vec<Dashboard>>>;
@ -54,18 +54,7 @@ pub async fn graph_query(
None
}
};
let connections = graph.get_query_connections(&dash.span, &query_span);
let mut data = Vec::new();
for conn in connections {
data.push(to_samples(
conn.get_results()
.await
.expect("Unable to get query results")
.data()
.clone(),
conn.meta,
));
}
let data = query_data(graph, dash, query_span).await.expect("Unable to get query results");
Json(data)
}