Skip to main content

torrust_tracker_deployer_lib/application/services/rendering/
prometheus.rs

1//! Prometheus Template Rendering Service
2//!
3//! This service is responsible for rendering Prometheus configuration templates.
4//! It's used by multiple contexts (render command, release steps) to prepare
5//! prometheus.yml configuration files.
6
7use 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::domain::tracker::TrackerConfig;
16use crate::infrastructure::templating::prometheus::{
17    PrometheusProjectGenerator, PrometheusProjectGeneratorError,
18};
19use crate::shared::Clock;
20
21/// Errors that can occur during Prometheus template rendering
22#[derive(Error, Debug)]
23pub enum PrometheusTemplateRenderingServiceError {
24    /// Template rendering failed
25    #[error("Failed to render Prometheus templates: {reason}")]
26    RenderingFailed {
27        /// Detailed reason for the failure
28        reason: String,
29    },
30}
31
32impl From<PrometheusProjectGeneratorError> for PrometheusTemplateRenderingServiceError {
33    fn from(error: PrometheusProjectGeneratorError) -> Self {
34        Self::RenderingFailed {
35            reason: error.to_string(),
36        }
37    }
38}
39
40/// Service for rendering Prometheus configuration templates
41///
42/// This service encapsulates the logic for rendering prometheus.yml configuration
43/// files. It's designed to be shared across command handlers and steps that need
44/// to prepare Prometheus configuration.
45pub struct PrometheusTemplateRenderingService {
46    build_dir: PathBuf,
47    template_manager: Arc<TemplateManager>,
48    clock: Arc<dyn Clock>,
49}
50
51impl PrometheusTemplateRenderingService {
52    /// Build a `PrometheusTemplateRenderingService` from environment paths
53    ///
54    /// # Arguments
55    ///
56    /// * `templates_dir` - Directory containing the source templates
57    /// * `build_dir` - Directory where rendered templates will be written
58    /// * `clock` - The clock for generating timestamps
59    ///
60    /// # Returns
61    ///
62    /// Returns a configured `PrometheusTemplateRenderingService` ready for template rendering
63    #[must_use]
64    pub fn from_paths(templates_dir: PathBuf, build_dir: PathBuf, clock: Arc<dyn Clock>) -> Self {
65        let template_manager = Arc::new(TemplateManager::new(templates_dir));
66
67        Self {
68            build_dir,
69            template_manager,
70            clock,
71        }
72    }
73
74    /// Render Prometheus configuration templates
75    ///
76    /// This renders the prometheus.yml configuration file to the build directory.
77    /// Returns `None` if Prometheus is not configured.
78    ///
79    /// # Arguments
80    ///
81    /// * `prometheus_config` - Prometheus configuration from user inputs (optional)
82    /// * `tracker_config` - Tracker configuration (needed for API token and port)
83    ///
84    /// # Returns
85    ///
86    /// Returns the path to the rendered Prometheus build directory, or `None` if not configured
87    ///
88    /// # Errors
89    ///
90    /// Returns `PrometheusTemplateRenderingServiceError::RenderingFailed` if template rendering fails.
91    pub fn render(
92        &self,
93        prometheus_config: Option<&PrometheusConfig>,
94        tracker_config: &TrackerConfig,
95    ) -> Result<Option<PathBuf>, PrometheusTemplateRenderingServiceError> {
96        let Some(prometheus_config) = prometheus_config else {
97            info!(
98                reason = "prometheus_not_configured",
99                "Skipping Prometheus template rendering - not configured"
100            );
101            return Ok(None);
102        };
103
104        info!(
105            templates_dir = %self.template_manager.templates_dir().display(),
106            build_dir = %self.build_dir.display(),
107            "Rendering Prometheus configuration templates"
108        );
109
110        let generator = PrometheusProjectGenerator::new(
111            &self.build_dir,
112            self.template_manager.clone(),
113            self.clock.clone(),
114        );
115
116        generator.render(prometheus_config, tracker_config)?;
117
118        let prometheus_build_dir = self.build_dir.join("storage/prometheus/etc");
119
120        info!(
121            prometheus_build_dir = %prometheus_build_dir.display(),
122            "Prometheus configuration templates rendered successfully"
123        );
124
125        Ok(Some(prometheus_build_dir))
126    }
127}