Merge pull request #57 from beatz174-bit/codex/add-dynu-dns-terraform-documentation-layer
Add Dynu Terraform brownfield DNS documentation layer
This commit is contained in:
@@ -50,6 +50,12 @@ Compose files define intended service runtime composition, networking, labels, a
|
||||
|
||||
Dynu write operations are intentionally blocked in this repository stage.
|
||||
|
||||
### 7) Terraform Dynu DNS layer
|
||||
|
||||
`infrastructure/terraform/dynu/` is the brownfield Terraform DNS mirror/reconciliation root for Dynu domain/record inventory outputs.
|
||||
|
||||
At this stage it is primarily documentation-oriented catalog output, ready for one-object-at-a-time imports.
|
||||
|
||||
## Output shaping expectations
|
||||
|
||||
When adding Terraform outputs for documentation/tooling:
|
||||
|
||||
@@ -30,6 +30,10 @@ Use Terraform when documenting/reconciling existing:
|
||||
|
||||
Do **not** treat Terraform as a full replacement for Compose operations in this repo.
|
||||
|
||||
- Dynu public DNS records remain authoritative at Dynu.
|
||||
- Terraform Dynu configuration mirrors/reconciles Dynu DNS state for documentation and controlled drift management.
|
||||
- Imported Dynu Terraform state reflects actual provider-side DNS state at import time.
|
||||
|
||||
|
||||
### Ansible bootstrap decisions
|
||||
|
||||
|
||||
@@ -43,6 +43,21 @@ Use for existing Proxmox VMs and metadata reconciliation.
|
||||
5. Keep lifecycle ignore rules narrow and explicit.
|
||||
6. Iterate per VM until plan stabilizes.
|
||||
|
||||
|
||||
## Dynu DNS workflow
|
||||
|
||||
Directory: `infrastructure/terraform/dynu/`
|
||||
|
||||
Use for existing Dynu domains and DNS records.
|
||||
|
||||
1. Add or confirm the documentation catalog entry for one hostname.
|
||||
2. Confirm the provider resource type and import ID format.
|
||||
3. Import one existing domain or DNS record at a time.
|
||||
4. Inspect state with `terraform state show`.
|
||||
5. Reconcile only stable, meaningful attributes into hand-maintained `.tf`.
|
||||
6. Keep record IDs, dynamic DNS targets, and provider-computed values out unless intentionally required.
|
||||
7. Re-run plan until intended scope is clean.
|
||||
|
||||
## Physical host metadata workflow
|
||||
|
||||
Physical host metadata currently lives in Proxmox Terraform locals/outputs and is used as documentation inventory context.
|
||||
|
||||
@@ -10,17 +10,21 @@ It does **not** replace Docker Compose as runtime deployment authority.
|
||||
- Physical host metadata represented in Terraform locals/outputs.
|
||||
- Select Docker container mirror resources for documentation-oriented tracking.
|
||||
- Outputs that can support documentation and later downstream tooling.
|
||||
- Dynu DNS domain/record import and documentation inventory.
|
||||
|
||||
## What Terraform is not used for (today)
|
||||
|
||||
- Replacing `services-up.sh` / Compose for day-to-day app runtime orchestration.
|
||||
- Broad, immediate greenfield provisioning of the whole stack.
|
||||
- Casual `apply` operations across all infrastructure.
|
||||
- Replacing Dynu as DNS authority.
|
||||
- Blindly recreating production DNS records without import/reconciliation.
|
||||
|
||||
## Directory map
|
||||
|
||||
- `proxmox/` — imported/reconciled VM resources and host metadata outputs.
|
||||
- `docker/` — selective Docker container import/mirror resources.
|
||||
- `dynu/` — Dynu DNS brownfield import/reconciliation and DNS documentation outputs.
|
||||
- `bootstrap/` — backend/provider bootstrap scaffolding.
|
||||
- `modules/` — placeholder module directories for future stable abstractions.
|
||||
- `scripts/reconcile_from_plan.sh` — helper to convert generated plan config into reviewable draft files.
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# Dynu Terraform Layer (Brownfield DNS Reconciliation)
|
||||
|
||||
This Terraform root is for **Dynu DNS brownfield import/reconciliation** and documentation outputs.
|
||||
|
||||
Dynu remains the authoritative DNS provider for existing records. Terraform here is used to mirror and reconcile existing DNS state incrementally, not to casually recreate production DNS from scratch.
|
||||
|
||||
## Provider
|
||||
|
||||
- Source: `beatz174-bit/dynu`
|
||||
- Version constraint: `>= 0.1.0`
|
||||
|
||||
Authentication is local-only and must not be committed.
|
||||
|
||||
## Credentials and auth
|
||||
|
||||
Use local `terraform.tfvars` (or environment variables if supported by the provider release you use).
|
||||
|
||||
Variables included:
|
||||
|
||||
- `dynu_api_key` (sensitive)
|
||||
- `dynu_username` (optional, sensitive)
|
||||
- `dynu_password` (optional, sensitive)
|
||||
|
||||
> Keep real values out of git and out of shared logs.
|
||||
|
||||
## Safety
|
||||
|
||||
- Do not commit `terraform.tfvars`, `.tfstate*`, or `.terraform/`.
|
||||
- Import/reconcile one domain or record at a time.
|
||||
- Treat generated config as draft input, not final truth.
|
||||
|
||||
## Safe validation commands
|
||||
|
||||
```bash
|
||||
cd infrastructure/terraform/dynu
|
||||
|
||||
terraform fmt -check -recursive
|
||||
terraform init -backend=false -input=false
|
||||
terraform validate
|
||||
```
|
||||
|
||||
## Local workflow
|
||||
|
||||
```bash
|
||||
cp terraform.tfvars.example terraform.tfvars
|
||||
$EDITOR terraform.tfvars
|
||||
terraform init
|
||||
terraform plan
|
||||
```
|
||||
|
||||
## Import workflow (placeholder examples)
|
||||
|
||||
```bash
|
||||
terraform import dynu_dns_domain.lan_ddnsgeek_com '<provider-specific-domain-import-id>'
|
||||
terraform state show dynu_dns_domain.lan_ddnsgeek_com
|
||||
terraform plan
|
||||
```
|
||||
|
||||
Or with import blocks:
|
||||
|
||||
```bash
|
||||
cp imports.tf.example imports.tf
|
||||
$EDITOR imports.tf
|
||||
terraform plan -generate-config-out=generated-dynu.tf
|
||||
```
|
||||
|
||||
Confirm exact resource types and import ID formats from the provider docs before running imports.
|
||||
@@ -0,0 +1,3 @@
|
||||
locals {
|
||||
dynu_domain = "lan.ddnsgeek.com"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Copy this file to imports.tf and adjust values after confirming the
|
||||
# published provider docs for resource type names and import ID formats.
|
||||
|
||||
# Example placeholder shape only:
|
||||
# import {
|
||||
# to = dynu_dns_domain.lan_ddnsgeek_com
|
||||
# id = "REPLACE_WITH_DYNU_DOMAIN_IMPORT_ID"
|
||||
# }
|
||||
#
|
||||
# import {
|
||||
# to = dynu_dns_record.grafana_lan_ddnsgeek_com
|
||||
# id = "REPLACE_WITH_DYNU_RECORD_IMPORT_ID"
|
||||
# }
|
||||
@@ -0,0 +1,19 @@
|
||||
output "dynu_domain" {
|
||||
description = "Primary Dynu domain represented by this Terraform root."
|
||||
value = local.dynu_domain
|
||||
}
|
||||
|
||||
output "dynu_dns_records_catalog" {
|
||||
description = "Documentation catalog of expected Dynu DNS records discovered from repo service exposure."
|
||||
value = local.dynu_dns_records_catalog
|
||||
}
|
||||
|
||||
output "dynu_dns_inventory" {
|
||||
description = "Documentation-friendly Dynu DNS inventory for export and merge into broader infrastructure docs."
|
||||
value = {
|
||||
provider = "dynu"
|
||||
domain = local.dynu_domain
|
||||
record_count = length(local.dynu_dns_records_catalog)
|
||||
records = local.dynu_dns_records_catalog
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
provider "dynu" {
|
||||
# Keep auth local-only; do not commit credentials.
|
||||
# Provider schema must be confirmed against registry docs before changing fields.
|
||||
api_key = var.dynu_api_key
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
locals {
|
||||
dynu_dns_records_catalog = {
|
||||
auth = {
|
||||
fqdn = "auth.lan.ddnsgeek.com"
|
||||
hostname = "auth"
|
||||
service = "authelia"
|
||||
source = "core/authelia/docker-compose.yml"
|
||||
purpose = "Authentication portal"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
gitea = {
|
||||
fqdn = "gitea.lan.ddnsgeek.com"
|
||||
hostname = "gitea"
|
||||
service = "gitea"
|
||||
source = "apps/gitea/docker-compose.yml"
|
||||
purpose = "Gitea service endpoint"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
gotify = {
|
||||
fqdn = "gotify.lan.ddnsgeek.com"
|
||||
hostname = "gotify"
|
||||
service = "gotify"
|
||||
source = "monitoring/gotify/docker-compose.yml"
|
||||
purpose = "Gotify notifications"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
grafana = {
|
||||
fqdn = "grafana.lan.ddnsgeek.com"
|
||||
hostname = "grafana"
|
||||
service = "grafana"
|
||||
source = "monitoring/grafana/docker-compose.yml"
|
||||
purpose = "Grafana monitoring UI"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
familytree = {
|
||||
fqdn = "familytree.lan.ddnsgeek.com"
|
||||
hostname = "familytree"
|
||||
service = "gramps"
|
||||
source = "apps/gramps/docker-compose.yml"
|
||||
purpose = "Family tree application"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
influxdb = {
|
||||
fqdn = "influxdb.lan.ddnsgeek.com"
|
||||
hostname = "influxdb"
|
||||
service = "influxdb"
|
||||
source = "monitoring/influxdb/docker-compose.yml"
|
||||
purpose = "InfluxDB metrics endpoint"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
monitor_kuma = {
|
||||
fqdn = "monitor-kuma.lan.ddnsgeek.com"
|
||||
hostname = "monitor-kuma"
|
||||
service = "uptime-kuma"
|
||||
source = "monitoring/uptime-kuma/docker-compose.yml"
|
||||
purpose = "Uptime Kuma monitoring UI"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
mtls_bridge = {
|
||||
fqdn = "mtls-bridge.lan.ddnsgeek.com"
|
||||
hostname = "mtls-bridge"
|
||||
service = "mtls-bridge"
|
||||
source = "monitoring/mtls-bridge/docker-compose.yml"
|
||||
purpose = "mTLS bridge API"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
nextcloud = {
|
||||
fqdn = "nextcloud.lan.ddnsgeek.com"
|
||||
hostname = "nextcloud"
|
||||
service = "nextcloud-webapp"
|
||||
source = "apps/nextcloud/docker-compose.yml"
|
||||
purpose = "Nextcloud service endpoint"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
node_red = {
|
||||
fqdn = "node-red.lan.ddnsgeek.com"
|
||||
hostname = "node-red"
|
||||
service = "node-red"
|
||||
source = "monitoring/node-red/docker-compose.yml"
|
||||
purpose = "Node-RED automation UI/API"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
passbolt = {
|
||||
fqdn = "passbolt.lan.ddnsgeek.com"
|
||||
hostname = "passbolt"
|
||||
service = "passbolt-webapp"
|
||||
source = "apps/passbolt/docker-compose.yml"
|
||||
purpose = "Passbolt password management"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
portainer = {
|
||||
fqdn = "portainer.lan.ddnsgeek.com"
|
||||
hostname = "portainer"
|
||||
service = "portainer"
|
||||
source = "monitoring/portainer/docker-compose.yml"
|
||||
purpose = "Portainer admin endpoint"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
prometheus = {
|
||||
fqdn = "prometheus.lan.ddnsgeek.com"
|
||||
hostname = "prometheus"
|
||||
service = "prometheus"
|
||||
source = "monitoring/prometheus/docker-compose.yml"
|
||||
purpose = "Prometheus metrics endpoint"
|
||||
record_type = null
|
||||
ttl = null
|
||||
target = null
|
||||
proxied = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Local-only credentials. Do not commit real values.
|
||||
dynu_api_key = "replace-with-dynu-api-key"
|
||||
dynu_username = null
|
||||
dynu_password = null
|
||||
@@ -0,0 +1,20 @@
|
||||
variable "dynu_api_key" {
|
||||
description = "Dynu API key/token used by the Dynu Terraform provider."
|
||||
type = string
|
||||
sensitive = true
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "dynu_username" {
|
||||
description = "Optional Dynu username, only if required by the provider."
|
||||
type = string
|
||||
sensitive = true
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "dynu_password" {
|
||||
description = "Optional Dynu password, only if required by the provider."
|
||||
type = string
|
||||
sensitive = true
|
||||
default = null
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
dynu = {
|
||||
source = "beatz174-bit/dynu"
|
||||
version = ">= 0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user