Skip to content

Commit f20d45c

Browse files
committed
feat: [#238] add independent Prometheus template rendering in release workflow
- Create RenderPrometheusTemplatesStep for Prometheus config rendering - Add render_prometheus_templates() method to ReleaseCommandHandler - Prometheus templates rendered independently at Step 5 (after tracker, before docker-compose) - Add RenderPrometheusTemplates variant to ReleaseStep enum - Extend EnvironmentTestBuilder with with_prometheus_config() method - Export PrometheusProjectGeneratorError from prometheus module - Fix architectural issue: Each service now renders its templates independently - Docker Compose step only adds Prometheus config to context (no template rendering) This follows the architectural principle that each service should render its templates independently in the release handler. Docker Compose templates are NOT the master templates - they only define service orchestration. The environment configuration is the source of truth for which services are enabled. All tests passing (1507 tests), all linters passing.
1 parent 22790de commit f20d45c

File tree

9 files changed

+344
-9
lines changed

9 files changed

+344
-9
lines changed

docs/issues/238-prometheus-slice-release-run-commands.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ This task adds Prometheus as a metrics collection service for the Torrust Tracke
4242
- Added 12 comprehensive unit tests with full coverage
4343
- All linters passing
4444

45-
-**Phase 4**: Docker Compose Integration (commit: pending)
45+
-**Phase 4**: Docker Compose Integration (commit: 22790de)
4646

4747
- Added `prometheus_config: Option<PrometheusConfig>` field to `DockerComposeContext`
4848
- Implemented `with_prometheus()` method for context builder pattern
@@ -51,7 +51,19 @@ This task adds Prometheus as a metrics collection service for the Torrust Tracke
5151
- Added 4 comprehensive unit tests for Prometheus service rendering
5252
- All linters passing
5353

54-
-**Phase 5**: Release Command Implementation (pending)
54+
-**Phase 5**: Release Command Integration (commit: TBD)
55+
56+
- **FIXED**: Moved Prometheus template rendering from docker-compose step to independent step in release handler
57+
- Created `RenderPrometheusTemplatesStep` to render Prometheus templates
58+
- Added `render_prometheus_templates()` method to `ReleaseCommandHandler`
59+
- Prometheus templates now rendered independently at Step 5 (after tracker templates, before docker-compose)
60+
- Docker Compose step only adds Prometheus config to context (no template rendering)
61+
- Added `RenderPrometheusTemplates` variant to `ReleaseStep` enum
62+
- Extended `EnvironmentTestBuilder` with `with_prometheus_config()` method
63+
- All linters passing, all tests passing (1507 tests)
64+
- **Architectural Principle**: Each service renders its templates independently in the release handler
65+
66+
-**Phase 6**: Ansible Deployment (pending)
5567
-**Phase 6**: Ansible Playbook Integration (pending)
5668
-**Phase 7**: Testing (pending)
5769
-**Phase 8**: Documentation (pending)
@@ -85,9 +97,27 @@ This task adds Prometheus as a metrics collection service for the Torrust Tracke
8597
- [ ] Prometheus depends on tracker service (starts after tracker container starts, no health check)
8698
- [ ] Metrics API token and port read from tracker HTTP API configuration (`tracker.http_api.admin_token` and `tracker.http_api.bind_address`)
8799
- [ ] Prometheus configuration is dynamic (uses Tera templating)
100+
- [x] **Independent Template Rendering**: Each service renders its templates independently in the release handler
101+
- Prometheus templates rendered by dedicated `RenderPrometheusTemplatesStep` in release handler
102+
- Tracker templates rendered by dedicated `RenderTrackerTemplatesStep` in release handler
103+
- Docker Compose templates rendered by dedicated `RenderDockerComposeTemplatesStep` in release handler
104+
- **Rationale**: Docker Compose templates are NOT the "master" templates - they only define service orchestration
105+
- **Source of Truth**: The environment configuration determines which services are enabled
106+
- **Example**: MySQL service has docker-compose configuration but no separate config files (service-specific)
88107

89108
### Anti-Patterns to Avoid
90109

110+
- ❌ Making Prometheus mandatory for all deployments
111+
- ❌ Hardcoding API tokens in templates
112+
- ❌ Starting Prometheus before tracker is ready
113+
- ❌ Duplicating tracker endpoint configuration
114+
- ❌ Mixing metrics collection logic with other services
115+
-**Rendering service templates from within docker-compose template rendering** (CRITICAL)
116+
117+
- Docker Compose step should ONLY render docker-compose files
118+
- Each service's templates should be rendered independently in the release handler
119+
- The handler orchestrates all template rendering steps based on environment config
120+
91121
- ❌ Making Prometheus mandatory for all deployments
92122
- ❌ Hardcoding API tokens in templates
93123
- ❌ Starting Prometheus before tracker is ready

src/application/command_handlers/release/handler.rs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::adapters::ansible::AnsibleClient;
1111
use crate::application::command_handlers::common::StepResult;
1212
use crate::application::steps::{
1313
application::{CreateTrackerStorageStep, DeployTrackerConfigStep, InitTrackerDatabaseStep},
14-
rendering::RenderTrackerTemplatesStep,
14+
rendering::{RenderPrometheusTemplatesStep, RenderTrackerTemplatesStep},
1515
DeployComposeFilesStep, RenderDockerComposeTemplatesStep,
1616
};
1717
use crate::domain::environment::repository::{EnvironmentRepository, TypedEnvironmentRepository};
@@ -199,10 +199,13 @@ impl ReleaseCommandHandler {
199199
// Step 4: Deploy tracker configuration to remote
200200
self.deploy_tracker_config_to_remote(environment, &tracker_build_dir, instance_ip)?;
201201

202-
// Step 5: Render Docker Compose templates
202+
// Step 5: Render Prometheus configuration templates (if enabled)
203+
Self::render_prometheus_templates(environment)?;
204+
205+
// Step 6: Render Docker Compose templates
203206
let compose_build_dir = self.render_docker_compose_templates(environment).await?;
204207

205-
// Step 6: Deploy compose files to remote
208+
// Step 7: Deploy compose files to remote
206209
self.deploy_compose_files_to_remote(environment, &compose_build_dir, instance_ip)?;
207210

208211
let released = environment.clone().released();
@@ -308,6 +311,54 @@ impl ReleaseCommandHandler {
308311
Ok(tracker_build_dir)
309312
}
310313

314+
/// Render Prometheus configuration templates to the build directory (if enabled)
315+
///
316+
/// This step is optional and only executes if Prometheus is configured in the environment.
317+
/// If Prometheus is not configured, the step is skipped without error.
318+
///
319+
/// # Errors
320+
///
321+
/// Returns a tuple of (error, `ReleaseStep::RenderPrometheusTemplates`) if rendering fails
322+
#[allow(clippy::result_large_err)]
323+
fn render_prometheus_templates(
324+
environment: &Environment<Releasing>,
325+
) -> StepResult<(), ReleaseCommandHandlerError, ReleaseStep> {
326+
let current_step = ReleaseStep::RenderPrometheusTemplates;
327+
328+
// Check if Prometheus is configured
329+
if environment.context().user_inputs.prometheus.is_none() {
330+
info!(
331+
command = "release",
332+
step = %current_step,
333+
status = "skipped",
334+
"Prometheus not configured - skipping template rendering"
335+
);
336+
return Ok(());
337+
}
338+
339+
let template_manager = Arc::new(TemplateManager::new(environment.templates_dir()));
340+
let step = RenderPrometheusTemplatesStep::new(
341+
Arc::new(environment.clone()),
342+
template_manager,
343+
environment.build_dir().clone(),
344+
);
345+
346+
step.execute().map_err(|e| {
347+
(
348+
ReleaseCommandHandlerError::TemplateRendering(e.to_string()),
349+
current_step,
350+
)
351+
})?;
352+
353+
info!(
354+
command = "release",
355+
step = %current_step,
356+
"Prometheus configuration templates rendered successfully"
357+
);
358+
359+
Ok(())
360+
}
361+
311362
/// Deploy tracker configuration to the remote host via Ansible
312363
///
313364
/// # Arguments

src/application/steps/rendering/docker_compose_templates.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl<S> RenderDockerComposeTemplatesStep<S> {
152152

153153
// Create contexts based on database configuration
154154
let database_config = &self.environment.context().user_inputs.tracker.core.database;
155-
let (env_context, docker_compose_context) = match database_config {
155+
let (env_context, mut docker_compose_context) = match database_config {
156156
DatabaseConfig::Sqlite { .. } => {
157157
let env_context = EnvContext::new(admin_token);
158158
let docker_compose_context = DockerComposeContext::new_sqlite(ports);
@@ -189,6 +189,12 @@ impl<S> RenderDockerComposeTemplatesStep<S> {
189189
}
190190
};
191191

192+
// Add Prometheus configuration if present
193+
if let Some(prometheus_config) = &self.environment.context().user_inputs.prometheus {
194+
docker_compose_context =
195+
docker_compose_context.with_prometheus(prometheus_config.clone());
196+
}
197+
192198
let compose_build_dir = generator
193199
.render(&env_context, &docker_compose_context)
194200
.await?;

src/application/steps/rendering/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! - `opentofu_templates` - `OpenTofu` template rendering for infrastructure
1111
//! - `docker_compose_templates` - Docker Compose template rendering for deployment
1212
//! - `tracker_templates` - Tracker configuration template rendering
13+
//! - `prometheus_templates` - Prometheus configuration template rendering
1314
//!
1415
//! ## Key Features
1516
//!
@@ -24,9 +25,11 @@
2425
pub mod ansible_templates;
2526
pub mod docker_compose_templates;
2627
pub mod opentofu_templates;
28+
pub mod prometheus_templates;
2729
pub mod tracker_templates;
2830

2931
pub use ansible_templates::RenderAnsibleTemplatesStep;
3032
pub use docker_compose_templates::RenderDockerComposeTemplatesStep;
3133
pub use opentofu_templates::RenderOpenTofuTemplatesStep;
34+
pub use prometheus_templates::RenderPrometheusTemplatesStep;
3235
pub use tracker_templates::RenderTrackerTemplatesStep;

0 commit comments

Comments
 (0)