Skip to content

Commit c2b108d

Browse files
committed
feat: implement instance name parameterization and enhance template cleanup
- Update E2E tests to use 'torrust-tracker-vm' instead of 'torrust-vm' - Fix template caching issue by adding templates directory cleanup - Update OpenTofu template default instance name to 'torrust-tracker-vm' - Add template system architecture documentation focusing on double indirection pattern - Create user guide for template customization explaining current limitations - Enhance preflight cleanup to ensure proper test isolation between runs This change verifies that instance names are properly parameterized through the template system and addresses template caching issues that prevented proper E2E test isolation.
1 parent c869488 commit c2b108d

File tree

5 files changed

+263
-2
lines changed

5 files changed

+263
-2
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Template System Architecture
2+
3+
Technical documentation for contributors working with the template rendering system.
4+
5+
## 🏗️ System Overview
6+
7+
The template system uses a **double indirection** approach to provide flexible infrastructure deployment while maintaining portability and customizability.
8+
9+
## 📦 Double Indirection Pattern
10+
11+
The system operates through two levels of indirection to balance portability with flexibility:
12+
13+
### Level 1: Embedded → External Extraction
14+
15+
1. **Source**: Templates are compiled into the binary as embedded resources
16+
2. **Extraction**: On first use, templates are extracted to an external directory (e.g., `data/templates`)
17+
3. **Benefit**: Enables single binary deployment while allowing runtime customization
18+
19+
### Level 2: Template → Build Directory Rendering
20+
21+
1. **Source**: Templates are read from the external directory
22+
2. **Processing**: Templates are processed (static copy or dynamic rendering with variables)
23+
3. **Output**: Final configuration files are written to the build directory
24+
4. **Benefit**: Separates template definitions from runtime-generated configurations
25+
26+
## 🔄 Template Flow
27+
28+
```text
29+
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
30+
│ Embedded │ │ External │ │ Build │
31+
│ Templates │───▶│ Templates │───▶│ Directory │
32+
│ (in binary) │ │ (data/templates) │ │ (build/) │
33+
└─────────────────┘ └──────────────────┘ └─────────────────┘
34+
│ │ │
35+
Compile Time Runtime Extraction Runtime Rendering
36+
```
37+
38+
## 🎯 Template Types
39+
40+
### Static Templates
41+
42+
- **Processing**: Direct file copy from templates to build directory
43+
- **Examples**: Infrastructure definitions, playbooks
44+
- **Use Case**: Configuration files that don't need variable substitution
45+
46+
### Dynamic Templates (Tera)
47+
48+
- **Processing**: Variable substitution using Tera templating engine
49+
- **File Suffix**: `.tera` extension (e.g., `variables.tfvars.tera`)
50+
- **Use Case**: Configuration files requiring runtime parameters
51+
52+
## 🔧 Key Components
53+
54+
### Template Manager
55+
56+
- Handles the embedded → external extraction process
57+
- Manages template source selection (embedded vs external directory)
58+
- Coordinates template availability and caching
59+
60+
### Template Renderers
61+
62+
- **OpenTofu Renderer**: Processes infrastructure templates
63+
- **Ansible Renderer**: Processes configuration management templates
64+
- Handle the template → build directory rendering process
65+
66+
### Template Engine
67+
68+
- Tera-based templating for dynamic content
69+
- Variable context resolution
70+
- Template syntax validation and error handling
71+
72+
## ⚠️ Important Behaviors
73+
74+
### Template Persistence
75+
76+
- Once extracted, external templates persist between runs
77+
- Templates are **not** automatically refreshed from embedded sources
78+
- This enables template customization but can cause confusion during development
79+
80+
### E2E Test Isolation
81+
82+
- E2E tests clean the templates directory before each run
83+
- This ensures fresh embedded template extraction for consistent test results
84+
- Production deployments may use persistent template directories
85+
86+
## 🎯 Design Goals
87+
88+
### Portability
89+
90+
- Single binary contains all necessary templates
91+
- No external dependencies for basic deployment
92+
93+
### Flexibility
94+
95+
- External templates can be customized without recompilation
96+
- Support for both static and dynamic template processing
97+
- CLI option to specify custom template directories
98+
99+
### Test Isolation
100+
101+
- Template cleanup ensures consistent test environments
102+
- Separation of template sources from generated configurations
103+
104+
## 📋 Beta Status Notice
105+
106+
This system is currently in beta. The implementation details, APIs, and internal structure may change significantly. This document focuses on the core architectural concept rather than specific implementation details that are likely to evolve.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Template System Overview
2+
3+
This document explains how the template system works in the Torrust Tracker Deploy tool.
4+
5+
## 📋 Overview
6+
7+
The deployment tool uses templates to generate configuration files for infrastructure provisioning (OpenTofu) and software configuration (Ansible). Currently, templates are embedded in the binary for production use.
8+
9+
## 🗂️ Template Structure
10+
11+
Templates are organized in the following structure:
12+
13+
```text
14+
templates/
15+
├── ansible/ # Ansible playbooks and inventory templates
16+
│ ├── inventory.yml.tera
17+
│ ├── install-docker.yml
18+
│ └── ...
19+
└── tofu/ # OpenTofu infrastructure templates
20+
└── lxd/ # LXD provider templates
21+
├── main.tf
22+
├── variables.tfvars.tera
23+
└── cloud-init.yml.tera
24+
```
25+
26+
## 🚀 Current Template System
27+
28+
### Embedded Templates (Production)
29+
30+
- Templates are embedded in the binary during compilation
31+
- No external files required for deployment
32+
- Provides consistent, tested deployment configurations
33+
- Templates are automatically extracted to build directory during deployment
34+
35+
## 🎛️ Template Types
36+
37+
### Static Templates
38+
39+
- Files copied as-is to the build directory
40+
- Examples: `main.tf`, `install-docker.yml`
41+
- No variable substitution
42+
43+
### Dynamic Templates (`.tera` extension)
44+
45+
- Use Tera templating engine for variable substitution
46+
- Examples: `variables.tfvars.tera`, `inventory.yml.tera`
47+
- Support runtime variables like `{{ instance_name }}`
48+
49+
## � Template Variables
50+
51+
Common variables available in templates:
52+
53+
| Variable | Description | Example |
54+
| --------------------- | ----------------- | -------------------- |
55+
| `instance_name` | VM/container name | `torrust-tracker-vm` |
56+
| `ansible_host` | Target server IP | `10.140.190.11` |
57+
| `ssh_pub_key_content` | SSH public key | `ssh-rsa AAAA...` |
58+
59+
## 🔄 Template Processing Flow
60+
61+
1. **Template Loading**: Load embedded templates from binary
62+
2. **Extraction**: Copy templates to build directory
63+
3. **Variable Resolution**: Render `.tera` templates with runtime values
64+
4. **Deployment**: Use generated files for infrastructure provisioning
65+
66+
## ⚠️ Important Notes
67+
68+
- Templates are currently embedded and cannot be customized in production deployments
69+
- All template modifications require recompilation of the binary
70+
- Templates are tested as part of the CI/CD pipeline to ensure reliability
71+
72+
## 🛠️ Development & Testing
73+
74+
For development and testing purposes only, the system supports external template directories through the `--templates-dir` CLI argument. This is used internally for:
75+
76+
- E2E testing with fresh template states
77+
- Development and debugging of template rendering
78+
- Template validation during CI/CD
79+
80+
**Note**: This functionality is not available in production builds and is reserved for development and testing workflows.

src/bin/e2e_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub async fn main() -> Result<()> {
8686

8787
// Instance name for the test environment - not user configurable for now
8888
let instance_name =
89-
InstanceName::new("torrust-vm".to_string()).expect("Valid hardcoded instance name");
89+
InstanceName::new("torrust-tracker-vm".to_string()).expect("Valid hardcoded instance name");
9090

9191
let env = TestEnvironment::new(cli.keep, cli.templates_dir, instance_name)?;
9292

src/e2e/tasks/preflight_cleanup.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ pub fn cleanup_lingering_resources(env: &TestEnvironment) -> Result<(), Prefligh
8686
// Clean the build directory to ensure fresh template state for E2E tests
8787
cleanup_build_directory(env)?;
8888

89+
// Clean the templates directory to ensure fresh embedded template extraction for E2E tests
90+
cleanup_templates_directory(env)?;
91+
8992
// Clean any existing OpenTofu infrastructure from previous test runs
9093
cleanup_opentofu_infrastructure(env)?;
9194

@@ -171,6 +174,78 @@ fn cleanup_build_directory(env: &TestEnvironment) -> Result<(), PreflightCleanup
171174
}
172175
}
173176

177+
/// Cleans the templates directory to ensure fresh embedded template extraction for E2E tests
178+
///
179+
/// This function removes the templates directory if it exists, ensuring that
180+
/// E2E tests start with fresh embedded templates and don't use stale cached template files.
181+
/// This is critical for testing template changes and instance name parameterization.
182+
///
183+
/// # Safety
184+
///
185+
/// This function is only intended for E2E test environments and should never
186+
/// be called in production code paths. It's designed to provide test isolation
187+
/// by ensuring fresh template extraction for each test run.
188+
///
189+
/// # Arguments
190+
///
191+
/// * `env` - The test environment containing configuration paths
192+
///
193+
/// # Returns
194+
///
195+
/// Returns `Ok(())` if cleanup succeeds or if the templates directory doesn't exist.
196+
///
197+
/// # Errors
198+
///
199+
/// Returns a `PreflightCleanupError::ResourceConflicts` error if the templates directory
200+
/// cannot be removed due to permission issues or file locks.
201+
fn cleanup_templates_directory(env: &TestEnvironment) -> Result<(), PreflightCleanupError> {
202+
let templates_dir = std::path::Path::new(&env.config.templates_dir);
203+
204+
if !templates_dir.exists() {
205+
info!(
206+
operation = "templates_directory_cleanup",
207+
status = "clean",
208+
path = %templates_dir.display(),
209+
"Templates directory doesn't exist, skipping cleanup"
210+
);
211+
return Ok(());
212+
}
213+
214+
info!(
215+
operation = "templates_directory_cleanup",
216+
path = %templates_dir.display(),
217+
"Cleaning templates directory to ensure fresh embedded template extraction"
218+
);
219+
220+
match std::fs::remove_dir_all(templates_dir) {
221+
Ok(()) => {
222+
info!(
223+
operation = "templates_directory_cleanup",
224+
status = "success",
225+
path = %templates_dir.display(),
226+
"Templates directory cleaned successfully"
227+
);
228+
Ok(())
229+
}
230+
Err(e) => {
231+
warn!(
232+
operation = "templates_directory_cleanup",
233+
status = "failed",
234+
path = %templates_dir.display(),
235+
error = %e,
236+
"Failed to clean templates directory"
237+
);
238+
Err(PreflightCleanupError::ResourceConflicts {
239+
details: format!(
240+
"Failed to clean templates directory '{}': {}",
241+
templates_dir.display(),
242+
e
243+
),
244+
})
245+
}
246+
}
247+
}
248+
174249
/// Cleans any existing `OpenTofu` infrastructure from previous test runs
175250
///
176251
/// This function attempts to destroy `OpenTofu` infrastructure that might remain from

templates/tofu/lxd/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ provider "lxd" {
1717
variable "instance_name" {
1818
description = "Name of the LXD instance"
1919
type = string
20-
default = "torrust-vm"
20+
default = "torrust-tracker-vm"
2121
}
2222

2323
variable "image" {

0 commit comments

Comments
 (0)