Skip to content

Commit 6af9efc

Browse files
committed
docs: [#246] update issue documentation to reflect actual implementation details
- Add Implementation Notes section documenting key architectural decisions - Document static playbook approach vs original dynamic template plan - Explain step-level conditional execution pattern (no grafana_enabled variable) - Clarify module locations (configure_failed.rs not generic state.rs) - Document firewall pattern (Grafana public, Prometheus internal) - Update goals checklist (8 of 9 complete) - Update progress section with phase breakdown and commit history - Fix module path references throughout document
1 parent ad0b272 commit 6af9efc

File tree

1 file changed

+92
-30
lines changed

1 file changed

+92
-30
lines changed

docs/issues/246-grafana-slice-release-run-commands.md

Lines changed: 92 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,70 @@ This task adds Grafana as a metrics visualization service for the Torrust Tracke
1111

1212
## Goals
1313

14-
- [ ] Add Grafana service conditionally to docker-compose stack (only when present in environment config)
15-
- [ ] Validate that Prometheus is enabled when Grafana is requested (dependency check)
16-
- [ ] Create Grafana configuration section in environment schema
17-
- [ ] Extend environment configuration schema to include Grafana monitoring section
18-
- [ ] Configure service dependency - Grafana depends on Prometheus service
19-
- [ ] Include Grafana in generated environment templates by default (enabled by default)
20-
- [ ] Allow users to disable Grafana by removing its configuration section
21-
- [ ] Deploy and verify Grafana connects to Prometheus and displays metrics
14+
- [x] Add Grafana service conditionally to docker-compose stack (only when present in environment config)
15+
- [x] Validate that Prometheus is enabled when Grafana is requested (dependency check)
16+
- [x] Create Grafana configuration section in environment schema
17+
- [x] Extend environment configuration schema to include Grafana monitoring section
18+
- [x] Configure service dependency - Grafana depends on Prometheus service
19+
- [x] Include Grafana in generated environment templates by default (enabled by default)
20+
- [x] Allow users to disable Grafana by removing its configuration section
21+
- [x] Configure firewall to allow public access to Grafana UI (port 3100)
22+
- [ ] Deploy and verify Grafana connects to Prometheus and displays metrics (manual testing pending)
2223

2324
## Progress
2425

25-
_This section will be updated as implementation progresses._
26+
**Current Status**: Phase 3 (Testing & Verification) - E2E test configurations complete, validator implementation in progress
2627

27-
- [ ] **Phase 1**: Environment Configuration & Validation
28-
- [ ] **Phase 2**: Docker Compose Integration
29-
- [ ] **Phase 3**: Testing & Verification
30-
- [ ] **Phase 4**: Documentation
28+
**Implementation Summary**:
29+
30+
-**Phase 1**: Environment Configuration & Validation (COMPLETE)
31+
- Domain models, validation logic, error handling
32+
- 3 commits: domain layer, validation, integration
33+
-**Phase 2**: Docker Compose Integration (COMPLETE)
34+
- DockerComposeContext and EnvContext extensions
35+
- Template updates (docker-compose.yml.tera, .env.tera)
36+
- 1 commit: comprehensive Phase 2 implementation
37+
- 🔄 **Phase 3**: Testing & Verification (IN PROGRESS)
38+
- ✅ Firewall configuration complete (1 commit)
39+
- ✅ E2E test configurations created (3 configs)
40+
- ⏳ E2E validation extension (in progress)
41+
- ⏳ Manual E2E testing (pending)
42+
-**Phase 4**: Documentation (NOT STARTED)
43+
44+
**Total Commits**: 7 commits for issue #246
45+
46+
- 3 for Phase 1 (domain layer)
47+
- 1 for Phase 2 (Docker Compose integration)
48+
- 1 for Phase 3 firewall configuration
49+
- 1 for E2E test configs documentation
50+
- 1 commit message correction
51+
52+
## Implementation Notes
53+
54+
**Key Architectural Decisions Made During Implementation** (may differ from original plan):
55+
56+
1. **Static Playbook vs Dynamic Template**:
57+
58+
- **Plan**: `configure-grafana-firewall.yml.tera` (dynamic Tera template)
59+
- **Actual**: `configure-grafana-firewall.yml` (static YAML playbook)
60+
- **Rationale**: Only 2 Ansible templates are dynamic (.tera): `inventory.yml.tera` and `variables.yml.tera`. All playbooks are static and load variables via `vars_files: [variables.yml]` directive. This follows the centralized variables pattern documented in `templates/ansible/README.md`.
61+
62+
2. **Step-Level Conditional Execution**:
63+
64+
- **Plan**: Add `grafana_enabled: bool` variable to `variables.yml.tera` for task-level conditionals
65+
- **Actual**: No `grafana_enabled` variable; conditional execution happens at step level in handler
66+
- **Rationale**: Grafana has a fixed port (3100), unlike tracker which has variable ports. Simpler to check `environment.context().user_inputs.grafana.is_some()` in the configure handler than pass boolean through templates. The playbook runs unconditionally when executed; the decision to execute happens in `ConfigureCommandHandler`.
67+
68+
3. **Module Locations**:
69+
70+
- **Plan**: Generic reference to `src/domain/environment/state.rs` for enum variant
71+
- **Actual**: `src/domain/environment/state/configure_failed.rs` contains the `ConfigureStep::ConfigureGrafanaFirewall` variant
72+
- **Note**: The state module is organized into separate files per state type (configure_failed.rs, release_failed.rs, etc.)
73+
74+
4. **Firewall Pattern**:
75+
- **Prometheus**: Port 9090 is NOT exposed publicly through firewall (internal service only)
76+
- **Grafana**: Port 3100 IS exposed publicly through UFW (user-facing UI)
77+
- **Rationale**: Prometheus is an internal metrics collection service. Grafana is the user-facing visualization layer that accesses Prometheus internally.
3178

3279
## 🏗️ Architecture Requirements
3380

@@ -37,8 +84,8 @@ _This section will be updated as implementation progresses._
3784
- `src/infrastructure/templating/docker_compose/` - Docker Compose template rendering with Grafana service
3885
- `src/domain/grafana/` - Grafana configuration domain types (NEW)
3986
- `src/application/command_handlers/create/config/validation/` - Grafana-Prometheus dependency validation (NEW)
40-
- `src/application/steps/configure_grafana_firewall.rs` - Grafana firewall configuration step (NEW)
41-
- `src/domain/environment/state.rs` - Add `ConfigureGrafanaFirewall` variant to `ConfigureStep` enum (NEW)
87+
- `src/application/steps/system/configure_grafana_firewall.rs` - Grafana firewall configuration step (NEW)
88+
- `src/domain/environment/state/configure_failed.rs` - Add `ConfigureGrafanaFirewall` variant to `ConfigureStep` enum (NEW)
4289

4390
**Pattern**: Configuration-driven service selection with dependency validation
4491

@@ -239,26 +286,29 @@ fn validate_grafana_dependency(
239286

240287
**Grafana UI Port Exposure**: Port 3100 must be opened in the firewall to allow public access to the Grafana web interface.
241288

242-
**Ansible Playbook**: `templates/ansible/configure-grafana-firewall.yml` (NEW)
289+
**Ansible Playbook**: `templates/ansible/configure-grafana-firewall.yml` (NEW - static playbook, not .tera)
290+
291+
**Implementation Note**: Unlike the original plan which suggested a `.tera` dynamic template, the actual implementation uses a **static `.yml` playbook** that loads variables via `vars_files`. This follows the centralized variables pattern used by other Ansible playbooks in the project.
243292

244293
```yaml
245294
---
246295
# Configure Grafana-specific firewall rules
247-
# Opens port 3100 for Grafana UI access (conditionally, only when Grafana is enabled)
248296

249297
- name: Configure Grafana Firewall Rules
250298
hosts: all
251299
become: true
252300
vars_files:
253-
- "{{ playbook_dir }}/group_vars/all/variables.yml"
301+
- variables.yml # Loads centralized variables
302+
254303
tasks:
255304
- name: Allow Grafana UI port through firewall (port 3100)
256305
community.general.ufw:
257306
rule: allow
258307
port: "3100"
259308
proto: tcp
260309
comment: "Grafana UI"
261-
when: grafana_enabled | default(false) | bool
310+
# Note: Unconditional execution when playbook runs
311+
# Conditional execution happens at step level (don't run if Grafana disabled)
262312
notify: Reload UFW
263313

264314
handlers:
@@ -267,22 +317,32 @@ fn validate_grafana_dependency(
267317
state: reloaded
268318
```
269319
270-
**Variables in `group_vars/all/variables.yml`**:
320+
**Variables in `variables.yml.tera`**:
271321

272-
```yaml
273-
# Grafana Configuration (conditional)
274-
grafana_enabled: {{ 'true' if grafana_config else 'false' }}
275-
```
322+
**NO grafana_enabled variable needed** - The original plan included a `grafana_enabled` variable, but this was removed because:
323+
324+
1. Grafana port is fixed (3100), unlike tracker's variable ports
325+
2. Conditional execution happens at the **step level** (don't execute playbook if Grafana disabled)
326+
3. Playbook unconditionally opens port 3100 when executed - decision to run happens in configure command handler
327+
4. Simpler pattern: check `environment.context().user_inputs.grafana.is_some()` in handler
276328

277-
**Template Location**: `templates/ansible/configure-grafana-firewall.yml.tera` (uses Tera to inject variables)
329+
**Template Location**: `templates/ansible/configure-grafana-firewall.yml` (static, registered in `ProjectGenerator::copy_static_templates()`)
278330

279331
**Execution**: During `configure` command, after `ConfigureTrackerFirewall` step
280332

281333
**Conditional Behavior**:
282334

283-
- If Grafana is **enabled** in environment config → Port 3100 opened in firewall
284-
- If Grafana is **disabled** (section removed) → Playbook tasks skipped (no port opened)
285-
- If `TORRUST_TD_SKIP_FIREWALL_IN_CONTAINER=true` → Entire firewall configuration skipped
335+
- **Step-Level Conditional Execution** (actual implementation):
336+
337+
- If Grafana is **enabled** in environment config → `ConfigureGrafanaFirewallStep` executes playbook → Port 3100 opened
338+
- If Grafana is **disabled** (section absent) → Step skipped entirely (check: `environment.context().user_inputs.grafana.is_some()`)
339+
- If `TORRUST_TD_SKIP_FIREWALL_IN_CONTAINER=true` → All firewall steps skipped (including Grafana)
340+
341+
- **Rationale for Step-Level Approach**:
342+
- Grafana port is fixed (3100), unlike tracker's variable ports that need task-level conditionals
343+
- Simpler to check Grafana presence at step level than pass boolean variable through templates
344+
- Follows same pattern as Prometheus (which has no public firewall exposure at all)
345+
- Playbook unconditionally opens port 3100 when executed - clean and predictable
286346

287347
**Security Note**: This public exposure is **temporary** until HTTPS support with reverse proxy is implemented (roadmap task 6). Once a reverse proxy (like nginx) is added with HTTPS, this public port exposure will be removed, and Grafana will only be accessible through the proxy.
288348

@@ -292,10 +352,12 @@ grafana_enabled: {{ 'true' if grafana_config else 'false' }}
292352
2. Then, individual service ports are opened conditionally based on enabled services:
293353
- SSH port (always, custom or default)
294354
- Tracker ports (if tracker configured)
295-
- Prometheus port (if Prometheus enabled)
296-
- Grafana port (if Grafana enabled)
355+
- **Prometheus port**: NOT exposed (internal service, no public firewall rule)
356+
- Grafana port (if Grafana enabled) - port 3100 for UI access
297357
- Future services...
298358

359+
**Note**: Prometheus (port 9090) is intentionally NOT exposed through the firewall as it's an internal service. Only Grafana (which provides the user-facing UI) has public firewall access.
360+
299361
### Environment Configuration Schema Extensions
300362

301363
**Add to Domain Layer** (`src/domain/grafana/`):

0 commit comments

Comments
 (0)