Fix CNAME acceptance test content pointer types

This commit is contained in:
beatz174-bit
2026-04-28 08:31:45 +10:00
parent bfe283af77
commit 088f180e41
7 changed files with 189 additions and 86 deletions
+36 -37
View File
@@ -1,57 +1,56 @@
# Live Safe DNS Record Example
This example is an **opt-in live test** for writable Dynu provider functionality.
It creates exactly one disposable DNS `A` record under a user-supplied Dynu root domain,
then you remove it with `terraform destroy`.
This example is an **opt-in live test** for writable Dynu provider functionality. It creates real Dynu DNS records and is designed for disposable, test-owned hostnames only.
## Safety model
## What this creates
- Creates a **new disposable subdomain** using configurable `test_prefix` and `test_suffix` values.
- Hostname format is:
- `<test_prefix>-<test_suffix>.<dynu_root_domain>`
- Creates exactly one record:
- `A` record, default content `1.1.1.1`, default TTL `300`.
- Does **not** import, update, replace, or delete existing production hostnames/records.
- `terraform destroy` removes only the disposable record in this state.
Using a single suffix (`test_suffix`), this example creates five DNS record scenarios under `dynu_root_domain`:
1. `A` record with IPv4 content (`codex-a-<suffix>.<root_domain>`)
2. `AAAA` record with IPv6 content (`codex-aaaa-<suffix>.<root_domain>`)
3. `CNAME` record (`codex-cname-<suffix>.<root_domain>`)
4. **Blank `A` record** with no content/IP (`codex-blank-a-<suffix>.<root_domain>`)
5. **Blank `AAAA` record** with no content/IP (`codex-blank-aaaa-<suffix>.<root_domain>`)
> [!WARNING]
> Do not repurpose this example to target existing production subdomains.
> Always provide only a root Dynu-managed domain (for example, `example.com`) via
> `dynu_root_domain`.
> Do not use a suffix that overlaps important existing hostnames. This example is intended only for disposable test records that you can safely destroy.
## Prerequisites
- Local provider binary and Terraform `dev_overrides` set up for `dynu/dynu`.
- `DYNU_API_KEY` exported (or set `dynu_api_key` in `terraform.tfvars`).
- A Dynu-managed root domain you control.
- Local provider binary + Terraform `dev_overrides` for `dynu/dynu`
- `DYNU_API_KEY` exported, or `dynu_api_key` set in `terraform.tfvars`
- A Dynu-managed root domain you control
## Workflow
This example intentionally uses only the `dynu/dynu` provider (no `hashicorp/random`).
If you want per-run uniqueness, pass `test_suffix` explicitly.
## Configure
```bash
go build -o terraform-provider-dynu
cd examples/live_safe_dns_record
cp terraform.tfvars.example terraform.tfvars
# edit terraform.tfvars and set dynu_root_domain (and optionally test_suffix)
terraform validate
TEST_SUFFIX="$(date +%s)"
terraform plan -var="test_suffix=${TEST_SUFFIX}"
terraform apply -var="test_suffix=${TEST_SUFFIX}"
```
After apply, inspect outputs to confirm the disposable hostname and record ID,
then clean up using the **same** suffix value:
Edit `terraform.tfvars` and set at least:
- `dynu_root_domain`
- `test_suffix` (use a unique value per run)
Optional overrides include `test_ipv4`, `test_ipv6`, and `test_cname_target`.
## Run
```bash
terraform destroy -var="test_suffix=${TEST_SUFFIX}"
terraform init
terraform validate
terraform plan
terraform apply
terraform destroy
```
## Cleanup guidance
## Notes
- Always run `terraform destroy` after testing.
- If apply is interrupted or partially succeeds, rerun `terraform destroy` from this same
directory with the same `terraform.tfvars`, CLI vars, and state files.
- If re-running without destroying first, Terraform may keep state for the previous
disposable record until it is destroyed.
- `terraform apply` should create all five record scenarios.
- `terraform destroy` should remove all five records created by this state.
- If you need to target a single scenario, resources are explicitly named:
- `dynu_dns_record.a_ipv4`
- `dynu_dns_record.aaaa_ipv6`
- `dynu_dns_record.cname`
- `dynu_dns_record.blank_a`
- `dynu_dns_record.blank_aaaa`
+43 -13
View File
@@ -1,24 +1,54 @@
terraform {
required_providers {
dynu = {
source = "dynu/dynu"
}
}
}
# Local development note:
# Keep source as "dynu/dynu" and use ~/.terraformrc dev_overrides to point to
# your local terraform-provider-dynu binary during provider development.
provider "dynu" {
api_key = var.dynu_api_key
}
locals {
disposable_label = "${var.test_prefix}-${var.test_suffix}"
disposable_hostname = "${local.disposable_label}.${var.dynu_root_domain}"
hostname_a_ipv4 = "codex-a-${var.test_suffix}.${var.dynu_root_domain}"
hostname_aaaa_ipv6 = "codex-aaaa-${var.test_suffix}.${var.dynu_root_domain}"
hostname_cname = "codex-cname-${var.test_suffix}.${var.dynu_root_domain}"
hostname_blank_a = "codex-blank-a-${var.test_suffix}.${var.dynu_root_domain}"
hostname_blank_aaaa = "codex-blank-aaaa-${var.test_suffix}.${var.dynu_root_domain}"
}
resource "dynu_dns_record" "safe_live_test" {
hostname = local.disposable_hostname
resource "dynu_dns_record" "a_ipv4" {
hostname = local.hostname_a_ipv4
record_type = "A"
content = var.test_ip
content = var.test_ipv4
ttl = var.test_ttl
state = true
}
resource "dynu_dns_record" "aaaa_ipv6" {
hostname = local.hostname_aaaa_ipv6
record_type = "AAAA"
content = var.test_ipv6
ttl = var.test_ttl
state = true
}
resource "dynu_dns_record" "cname" {
hostname = local.hostname_cname
record_type = "CNAME"
content = var.test_cname_target
ttl = var.test_ttl
state = true
}
# Deliberate blank A record scenario: A type with no content/IP value.
resource "dynu_dns_record" "blank_a" {
hostname = local.hostname_blank_a
record_type = "A"
ttl = var.test_ttl
state = true
}
# Deliberate blank AAAA record scenario: AAAA type with no content/IP value.
resource "dynu_dns_record" "blank_aaaa" {
hostname = local.hostname_blank_aaaa
record_type = "AAAA"
ttl = var.test_ttl
state = true
}
+42 -14
View File
@@ -1,19 +1,47 @@
output "disposable_hostname" {
description = "Disposable hostname created by this run."
value = local.disposable_hostname
output "record_hostnames" {
description = "Disposable hostnames created for each live-safe DNS scenario."
value = {
a_ipv4 = dynu_dns_record.a_ipv4.hostname
aaaa_ipv6 = dynu_dns_record.aaaa_ipv6.hostname
cname = dynu_dns_record.cname.hostname
blank_a = dynu_dns_record.blank_a.hostname
blank_aaaa = dynu_dns_record.blank_aaaa.hostname
}
}
output "disposable_record_id" {
description = "Dynu DNS record ID in domain_id/record_id format for the disposable record."
value = dynu_dns_record.safe_live_test.id
output "record_ids" {
description = "Dynu record IDs (domain_id/record_id) for each scenario."
value = {
a_ipv4 = dynu_dns_record.a_ipv4.id
aaaa_ipv6 = dynu_dns_record.aaaa_ipv6.id
cname = dynu_dns_record.cname.id
blank_a = dynu_dns_record.blank_a.id
blank_aaaa = dynu_dns_record.blank_aaaa.id
}
}
output "root_domain" {
description = "Dynu root domain used for this live-safe test."
value = var.dynu_root_domain
}
output "cleanup_reminder" {
description = "Reminder to destroy the disposable record after verification."
value = "Run terraform destroy in this same directory/state to remove only this disposable record."
output "record_values" {
description = "Record type/content summary for each scenario; blank records intentionally omit content."
value = {
a_ipv4 = {
type = dynu_dns_record.a_ipv4.record_type
content = dynu_dns_record.a_ipv4.content
}
aaaa_ipv6 = {
type = dynu_dns_record.aaaa_ipv6.record_type
content = dynu_dns_record.aaaa_ipv6.content
}
cname = {
type = dynu_dns_record.cname.record_type
content = dynu_dns_record.cname.content
}
blank_a = {
type = dynu_dns_record.blank_a.record_type
content = dynu_dns_record.blank_a.content
}
blank_aaaa = {
type = dynu_dns_record.blank_aaaa.record_type
content = dynu_dns_record.blank_aaaa.content
}
}
}
@@ -1,14 +1,16 @@
# Required: use only a Dynu-managed root domain/zone that you control.
# Do NOT put an existing full production hostname here.
# Optional if DYNU_API_KEY is exported in your shell.
# dynu_api_key = "REPLACE_ME"
# Required: a Dynu-managed root domain/zone that you control.
# Do NOT put an existing production hostname here.
dynu_root_domain = "example.com"
# Optional naming for disposable hostname labels.
# Final hostname format: <test_prefix>-<test_suffix>.<dynu_root_domain>
test_prefix = "tfacc"
# Set to a unique value per run so records are clearly disposable.
test_suffix = "manual"
# Optional: documentation/test IP for disposable A record content.
test_ip = "1.1.1.1"
# Safe documentation values for live test scenarios.
test_ipv4 = "192.0.2.123"
test_ipv6 = "2001:db8::123"
test_cname_target = "example.com"
# Optional TTL for disposable A record.
test_ttl = 300
+43 -12
View File
@@ -1,35 +1,66 @@
variable "dynu_api_key" {
description = "Dynu API key. Leave null to use DYNU_API_KEY from the environment."
description = "Dynu API key. Leave null to use DYNU_API_KEY from environment."
type = string
default = null
sensitive = true
}
variable "dynu_root_domain" {
description = "Dynu-managed root domain for creating a disposable live test subdomain (for example: example.com)."
description = "Dynu-managed root domain used to create disposable live test records (for example: example.com)."
type = string
}
variable "test_prefix" {
description = "Prefix for the disposable test hostname label."
type = string
default = "tfacc"
validation {
condition = trimspace(var.dynu_root_domain) != ""
error_message = "dynu_root_domain must be a non-empty Dynu-managed root domain."
}
}
variable "test_suffix" {
description = "Suffix for disposable hostname uniqueness (set explicitly per run if needed)."
description = "Suffix used to make this run's disposable record hostnames unique."
type = string
default = "manual"
validation {
condition = trimspace(var.test_suffix) != ""
error_message = "test_suffix must be non-empty."
}
}
variable "test_ip" {
description = "IPv4 value for the disposable A record. Dynu rejects reserved documentation ranges (for example 198.51.100.0/24), so this default uses a public resolver address."
variable "test_ipv4" {
description = "IPv4 value for the disposable A record scenario."
type = string
default = "1.1.1.1"
default = "192.0.2.123"
validation {
condition = trimspace(var.test_ipv4) != ""
error_message = "test_ipv4 must be non-empty for the A record scenario."
}
}
variable "test_ipv6" {
description = "IPv6 value for the disposable AAAA record scenario."
type = string
default = "2001:db8::123"
validation {
condition = trimspace(var.test_ipv6) != ""
error_message = "test_ipv6 must be non-empty for the AAAA record scenario."
}
}
variable "test_cname_target" {
description = "CNAME target for the disposable CNAME record scenario."
type = string
default = "example.com"
validation {
condition = trimspace(var.test_cname_target) != ""
error_message = "test_cname_target must be non-empty for the CNAME scenario."
}
}
variable "test_ttl" {
description = "TTL in seconds for the disposable DNS record."
description = "TTL in seconds for disposable DNS records."
type = number
default = 300
}
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.5.0"
required_providers {
dynu = {
source = "dynu/dynu"
}
}
}