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.
|
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
|
## Output shaping expectations
|
||||||
|
|
||||||
When adding Terraform outputs for documentation/tooling:
|
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.
|
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
|
### Ansible bootstrap decisions
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,21 @@ Use for existing Proxmox VMs and metadata reconciliation.
|
|||||||
5. Keep lifecycle ignore rules narrow and explicit.
|
5. Keep lifecycle ignore rules narrow and explicit.
|
||||||
6. Iterate per VM until plan stabilizes.
|
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 workflow
|
||||||
|
|
||||||
Physical host metadata currently lives in Proxmox Terraform locals/outputs and is used as documentation inventory context.
|
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.
|
- Physical host metadata represented in Terraform locals/outputs.
|
||||||
- Select Docker container mirror resources for documentation-oriented tracking.
|
- Select Docker container mirror resources for documentation-oriented tracking.
|
||||||
- Outputs that can support documentation and later downstream tooling.
|
- Outputs that can support documentation and later downstream tooling.
|
||||||
|
- Dynu DNS domain/record import and documentation inventory.
|
||||||
|
|
||||||
## What Terraform is not used for (today)
|
## What Terraform is not used for (today)
|
||||||
|
|
||||||
- Replacing `services-up.sh` / Compose for day-to-day app runtime orchestration.
|
- Replacing `services-up.sh` / Compose for day-to-day app runtime orchestration.
|
||||||
- Broad, immediate greenfield provisioning of the whole stack.
|
- Broad, immediate greenfield provisioning of the whole stack.
|
||||||
- Casual `apply` operations across all infrastructure.
|
- Casual `apply` operations across all infrastructure.
|
||||||
|
- Replacing Dynu as DNS authority.
|
||||||
|
- Blindly recreating production DNS records without import/reconciliation.
|
||||||
|
|
||||||
## Directory map
|
## Directory map
|
||||||
|
|
||||||
- `proxmox/` — imported/reconciled VM resources and host metadata outputs.
|
- `proxmox/` — imported/reconciled VM resources and host metadata outputs.
|
||||||
- `docker/` — selective Docker container import/mirror resources.
|
- `docker/` — selective Docker container import/mirror resources.
|
||||||
|
- `dynu/` — Dynu DNS brownfield import/reconciliation and DNS documentation outputs.
|
||||||
- `bootstrap/` — backend/provider bootstrap scaffolding.
|
- `bootstrap/` — backend/provider bootstrap scaffolding.
|
||||||
- `modules/` — placeholder module directories for future stable abstractions.
|
- `modules/` — placeholder module directories for future stable abstractions.
|
||||||
- `scripts/reconcile_from_plan.sh` — helper to convert generated plan config into reviewable draft files.
|
- `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