torrust_tracker_deployer_lib/application/services/rendering/
grafana.rs1use std::path::PathBuf;
8use std::sync::Arc;
9
10use thiserror::Error;
11use tracing::info;
12
13use crate::domain::prometheus::PrometheusConfig;
14use crate::domain::template::TemplateManager;
15use crate::infrastructure::templating::grafana::template::renderer::{
16 GrafanaProjectGenerator, GrafanaProjectGeneratorError,
17};
18use crate::shared::Clock;
19
20#[derive(Error, Debug)]
22pub enum GrafanaTemplateRenderingServiceError {
23 #[error("Failed to render Grafana templates: {reason}")]
25 RenderingFailed {
26 reason: String,
28 },
29}
30
31impl From<GrafanaProjectGeneratorError> for GrafanaTemplateRenderingServiceError {
32 fn from(error: GrafanaProjectGeneratorError) -> Self {
33 Self::RenderingFailed {
34 reason: error.to_string(),
35 }
36 }
37}
38
39pub struct GrafanaTemplateRenderingService {
45 build_dir: PathBuf,
46 template_manager: Arc<TemplateManager>,
47 clock: Arc<dyn Clock>,
48}
49
50impl GrafanaTemplateRenderingService {
51 #[must_use]
63 pub fn from_paths(templates_dir: PathBuf, build_dir: PathBuf, clock: Arc<dyn Clock>) -> Self {
64 let template_manager = Arc::new(TemplateManager::new(templates_dir));
65
66 Self {
67 build_dir,
68 template_manager,
69 clock,
70 }
71 }
72
73 pub fn render(
91 &self,
92 grafana_configured: bool,
93 prometheus_config: Option<&PrometheusConfig>,
94 ) -> Result<Option<PathBuf>, GrafanaTemplateRenderingServiceError> {
95 if !grafana_configured {
96 info!(
97 reason = "grafana_not_configured",
98 "Skipping Grafana template rendering - not configured"
99 );
100 return Ok(None);
101 }
102
103 let Some(prometheus_config) = prometheus_config else {
104 info!(
105 reason = "prometheus_not_configured",
106 "Skipping Grafana template rendering - Prometheus datasource requires Prometheus to be configured"
107 );
108 return Ok(None);
109 };
110
111 info!(
112 templates_dir = %self.template_manager.templates_dir().display(),
113 build_dir = %self.build_dir.display(),
114 "Rendering Grafana provisioning templates"
115 );
116
117 let generator = GrafanaProjectGenerator::new(
118 &self.build_dir,
119 self.template_manager.clone(),
120 self.clock.clone(),
121 );
122
123 generator.render(prometheus_config)?;
124
125 let grafana_provisioning_dir = self.build_dir.join("storage/grafana/provisioning");
126
127 info!(
128 grafana_provisioning_dir = %grafana_provisioning_dir.display(),
129 "Grafana provisioning templates rendered successfully"
130 );
131
132 Ok(Some(grafana_provisioning_dir))
133 }
134}