Skip to content

Commit 6cd06ce

Browse files
committed
Merge #109: feat: Add centralized variables template infrastructure for Ansible playbooks (#105)
e162cf1 fix: [#105] improve error mapping for context creation failures (copilot-swe-agent[bot]) b61ffea fix: [#105] remove Tera variables from comments in template (copilot-swe-agent[bot]) 57c357d fix: [#105] fix clippy warnings and formatting (copilot-swe-agent[bot]) dae5fa0 feat: [#105] integrate variables rendering into AnsibleTemplateRenderer (copilot-swe-agent[bot]) 5976b7c feat: [#105] add VariablesTemplateRenderer (copilot-swe-agent[bot]) b411b6d feat: [#105] add AnsibleVariablesTemplate wrapper (copilot-swe-agent[bot]) a033f0d feat: [#105] add AnsibleVariablesContext with validation (copilot-swe-agent[bot]) 8759e57 feat: [#105] add centralized variables template file (copilot-swe-agent[bot]) bff5db0 Initial plan (copilot-swe-agent[bot]) Pull request description: Implements the foundational infrastructure for consolidating Ansible playbook variables into a centralized `variables.yml` file, following the same pattern as OpenTofu's `variables.tfvars.tera`. ## Implementation ### Template & Context - **Template**: `templates/ansible/variables.yml.tera` - Centralized variable definitions with SSH port - **Context**: `AnsibleVariablesContext` - Validates SSH port using existing `AnsiblePort` validation ### Wrapper & Renderer - **Wrapper**: `AnsibleVariablesTemplate` - Renders template with domain `TemplateEngine` - **Renderer**: `VariablesTemplateRenderer` - Orchestrates template loading, context processing, and file output - **Integration**: Hooked into `AnsibleTemplateRenderer::render()` workflow after firewall playbook rendering ### Error Handling - Added `ContextCreationFailed` error variant for SSH port validation failures - Updated both `create_firewall_context()` and `create_variables_context()` to use semantically correct error types ## Output Generated `variables.yml` contains runtime SSH port configuration: ```yaml --- # Centralized Ansible Variables ssh_port: 22 # Future service variables can be added here when needed ``` ## Architecture Follows existing three-layer template pattern: 1. **Context Layer** - Validates input data (SSH port) 2. **Wrapper Layer** - Renders Tera template with validated context 3. **Renderer Layer** - Orchestrates file I/O and template management Future service variables (MySQL, Tracker, Prometheus, Grafana) can be added to the template without additional Rust infrastructure per service. <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>Create Variables Template Infrastructure</issue_title> > <issue_description>**Parent Epic**: #19 - Refactor Ansible Templates to Variables Pattern > > ## Overview > > Create the centralized `variables.yml.tera` template and supporting Rust infrastructure (context, wrapper, renderer) to consolidate Ansible playbook variables into a single file. This establishes the foundation for the variables pattern that will simplify future playbook additions. > > ## Goals > > - [ ] **Variables Template**: Create `templates/ansible/variables.yml.tera` with system configuration variables > - [ ] **Context Layer**: Implement `AnsibleVariablesContext` with validation > - [ ] **Wrapper Layer**: Implement `AnsibleVariablesTemplate` for rendering > - [ ] **Renderer Layer**: Implement `VariablesTemplateRenderer` for orchestration > - [ ] **Integration**: Hook into `AnsibleTemplateRenderer::render()` workflow > - [ ] **Test Coverage**: Comprehensive unit tests for all components > > ## 🏗️ Architecture Requirements > > **DDD Layer**: Infrastructure > **Module Path**: `src/infrastructure/external_tools/ansible/template/` > **Pattern**: Template Wrapper + Context + Renderer (existing pattern) > > ## Time Estimate > > **2.5 days** - Complete vertical slice including implementation, testing, and documentation > > ## Documentation > > Full implementation details: [`docs/issues/19.1-create-variables-template.md`](https://github.com/torrust/torrust-tracker-deployer/blob/copilot/configure-ufw-firewall/docs/issues/19.1-create-variables-template.md) > > ## Acceptance Criteria > > ### Template File > - [ ] `templates/ansible/variables.yml.tera` exists with SSH port variable > - [ ] Template has correct Tera syntax: `{{ ssh_port }}` > - [ ] YAML linting passes > > ### Implementation > - [ ] `AnsibleVariablesContext` with SSH port validation > - [ ] `AnsibleVariablesTemplate` wrapper implementation > - [ ] `VariablesTemplateRenderer` orchestrator > - [ ] Integration into `AnsibleTemplateRenderer` > > ### Testing > - [ ] Unit tests pass: `cargo test` > - [ ] Config tests pass: `cargo run --bin e2e-config-tests` > - [ ] Linters pass: `cargo run --bin linter all` > - [ ] `variables.yml` generated in build directory > > ### Documentation > - [ ] Rustdoc comments for all public types > - [ ] Template file includes descriptive comments > - [ ] Error types have clear descriptions > > ## Related > > - Parent Epic: #19 > - Next Task: #19.2 (depends on this task) > - [Template System Architecture](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/technical/template-system-architecture.md)</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> - Fixes #105 <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. ACKs for top commit: josecelano: ACK e162cf1 Tree-SHA512: 7dc3c0b1e16a99eb0ada7881c0f047289f2a50524a4014ced1c5bae3085edbe30a079cca8aff8ecd13481f07987ab06ad7a559ac8ee93b82c2732367bf84daba
2 parents b965259 + e162cf1 commit 6cd06ce

File tree

6 files changed

+608
-10
lines changed

6 files changed

+608
-10
lines changed

src/infrastructure/external_tools/ansible/template/renderer/mod.rs

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ use crate::infrastructure::external_tools::ansible::template::wrappers::inventor
5555

5656
pub mod firewall_playbook;
5757
pub mod inventory;
58+
pub mod variables;
5859

5960
pub use firewall_playbook::FirewallPlaybookTemplateRenderer;
6061
pub use inventory::InventoryTemplateRenderer;
62+
pub use variables::VariablesTemplateRenderer;
6163

6264
/// Errors that can occur during configuration template rendering
6365
#[derive(Error, Debug)]
@@ -129,6 +131,20 @@ pub enum ConfigurationTemplateError {
129131
#[source]
130132
source: firewall_playbook::FirewallPlaybookTemplateError,
131133
},
134+
135+
/// Failed to render variables template using collaborator
136+
#[error("Failed to render variables template: {source}")]
137+
VariablesRenderingFailed {
138+
#[source]
139+
source: variables::VariablesTemplateError,
140+
},
141+
142+
/// Failed to create context from inventory data
143+
#[error("Failed to create {context_type} context: {message}")]
144+
ContextCreationFailed {
145+
context_type: String,
146+
message: String,
147+
},
132148
}
133149

134150
/// Renders `Ansible` configuration templates to a build directory
@@ -141,6 +157,7 @@ pub struct AnsibleTemplateRenderer {
141157
template_manager: Arc<TemplateManager>,
142158
inventory_renderer: InventoryTemplateRenderer,
143159
firewall_playbook_renderer: FirewallPlaybookTemplateRenderer,
160+
variables_renderer: VariablesTemplateRenderer,
144161
}
145162

146163
impl AnsibleTemplateRenderer {
@@ -161,12 +178,14 @@ impl AnsibleTemplateRenderer {
161178
let inventory_renderer = InventoryTemplateRenderer::new(template_manager.clone());
162179
let firewall_playbook_renderer =
163180
FirewallPlaybookTemplateRenderer::new(template_manager.clone());
181+
let variables_renderer = VariablesTemplateRenderer::new(template_manager.clone());
164182

165183
Self {
166184
build_dir: build_dir.as_ref().to_path_buf(),
167185
template_manager,
168186
inventory_renderer,
169187
firewall_playbook_renderer,
188+
variables_renderer,
170189
}
171190
}
172191

@@ -219,6 +238,12 @@ impl AnsibleTemplateRenderer {
219238
|source| ConfigurationTemplateError::FirewallPlaybookRenderingFailed { source },
220239
)?;
221240

241+
// Render dynamic variables template with system configuration using collaborator
242+
let variables_context = Self::create_variables_context(inventory_context)?;
243+
self.variables_renderer
244+
.render(&variables_context, &build_ansible_dir)
245+
.map_err(|source| ConfigurationTemplateError::VariablesRenderingFailed { source })?;
246+
222247
// Copy static Ansible files (config and playbooks)
223248
self.copy_static_templates(&self.template_manager, &build_ansible_dir)
224249
.await?;
@@ -421,21 +446,50 @@ impl AnsibleTemplateRenderer {
421446

422447
// Extract SSH port from inventory context
423448
let ssh_port = AnsiblePort::new(inventory_context.ansible_port()).map_err(|e| {
424-
ConfigurationTemplateError::TemplatePathFailed {
425-
file_name: "configure-firewall.yml.tera".to_string(),
426-
source: TemplateManagerError::TemplateNotFound {
427-
relative_path: format!("Invalid SSH port: {e}"),
428-
},
449+
ConfigurationTemplateError::ContextCreationFailed {
450+
context_type: "FirewallPlaybook".to_string(),
451+
message: format!("Invalid SSH port: {e}"),
429452
}
430453
})?;
431454

432455
// Create firewall context
433456
FirewallPlaybookContext::new(ssh_port).map_err(|e| {
434-
ConfigurationTemplateError::TemplatePathFailed {
435-
file_name: "configure-firewall.yml.tera".to_string(),
436-
source: TemplateManagerError::TemplateNotFound {
437-
relative_path: format!("Failed to create firewall context: {e}"),
438-
},
457+
ConfigurationTemplateError::ContextCreationFailed {
458+
context_type: "FirewallPlaybook".to_string(),
459+
message: format!("Failed to create firewall context: {e}"),
460+
}
461+
})
462+
}
463+
464+
/// Creates an `AnsibleVariablesContext` from an `InventoryContext`
465+
///
466+
/// Extracts the SSH port from the inventory context to create
467+
/// a variables context for template rendering.
468+
///
469+
/// # Arguments
470+
///
471+
/// * `inventory_context` - The inventory context containing SSH port information
472+
///
473+
/// # Returns
474+
///
475+
/// * `Result<AnsibleVariablesContext, ConfigurationTemplateError>` - The variables context or an error
476+
///
477+
/// # Errors
478+
///
479+
/// Returns an error if the SSH port cannot be extracted or validated
480+
fn create_variables_context(
481+
inventory_context: &InventoryContext,
482+
) -> Result<
483+
crate::infrastructure::external_tools::ansible::template::wrappers::variables::AnsibleVariablesContext,
484+
ConfigurationTemplateError,
485+
>{
486+
use crate::infrastructure::external_tools::ansible::template::wrappers::variables::AnsibleVariablesContext;
487+
488+
// Extract SSH port from inventory context and create variables context
489+
AnsibleVariablesContext::new(inventory_context.ansible_port()).map_err(|e| {
490+
ConfigurationTemplateError::ContextCreationFailed {
491+
context_type: "AnsibleVariables".to_string(),
492+
message: format!("Failed to create variables context: {e}"),
439493
}
440494
})
441495
}

0 commit comments

Comments
 (0)