From 4aa76f370f2a5aefa0713d8376ef0a2171560b22 Mon Sep 17 00:00:00 2001 From: Jason Rothstein Date: Wed, 12 Aug 2026 20:17:45 -0500 Subject: [PATCH] Version bump, Style guide, dns records updates optional, and input validation --- data.linode_domain.this.tf | 1 + output.domain_records.tf | 7 +++++++ output.fqdn.tf | 4 ++++ output.instance.tf | 3 ++- resource.linode_domain_record.this_ipv4.tf | 3 ++- resource.linode_domain_record.this_ipv6.tf | 3 ++- resource.linode_instance.this.tf | 10 ++++++++-- terraform.tf | 2 +- variable.authorized_keys.tf | 10 ++++++++-- variable.backups_enabled.tf | 5 +++-- variable.booted.tf | 5 +++-- variable.create_dns_record.tf | 5 +++++ variable.domain_name.tf | 10 ++++++++-- variable.host_name.tf | 10 ++++++++-- variable.image.tf | 10 ++++++++-- variable.private_ip.tf | 5 +++-- variable.region.tf | 10 ++++++++-- variable.tags.tf | 10 ++++++++-- variable.type.tf | 10 ++++++++-- variable.watchdog_enabled.tf | 5 +++-- 20 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 output.domain_records.tf create mode 100644 output.fqdn.tf create mode 100644 variable.create_dns_record.tf diff --git a/data.linode_domain.this.tf b/data.linode_domain.this.tf index 6ecc951..c5286ad 100644 --- a/data.linode_domain.this.tf +++ b/data.linode_domain.this.tf @@ -1,3 +1,4 @@ data "linode_domain" "this" { + count = var.create_dns_record ? 1 : 0 domain = var.domain_name } diff --git a/output.domain_records.tf b/output.domain_records.tf new file mode 100644 index 0000000..5724535 --- /dev/null +++ b/output.domain_records.tf @@ -0,0 +1,7 @@ +output "domain_records" { + description = "The DNS records created for the instance, if create_dns_record is true." + value = { + ipv4 = try(linode_domain_record.this_ipv4[0], null) + ipv6 = try(linode_domain_record.this_ipv6[0], null) + } +} diff --git a/output.fqdn.tf b/output.fqdn.tf new file mode 100644 index 0000000..aae0e65 --- /dev/null +++ b/output.fqdn.tf @@ -0,0 +1,4 @@ +output "fqdn" { + description = "The fully qualified domain name of the Linode instance." + value = "${var.host_name}.${var.domain_name}" +} diff --git a/output.instance.tf b/output.instance.tf index 35e6bda..a51aa1f 100644 --- a/output.instance.tf +++ b/output.instance.tf @@ -1,3 +1,4 @@ output "instance" { - value = linode_instance.this + description = "The entire linode_instance.this resource." + value = linode_instance.this } diff --git a/resource.linode_domain_record.this_ipv4.tf b/resource.linode_domain_record.this_ipv4.tf index 746d080..bd73186 100644 --- a/resource.linode_domain_record.this_ipv4.tf +++ b/resource.linode_domain_record.this_ipv4.tf @@ -1,5 +1,6 @@ resource "linode_domain_record" "this_ipv4" { - domain_id = data.linode_domain.this.id + count = var.create_dns_record ? 1 : 0 + domain_id = data.linode_domain.this[0].id name = var.host_name record_type = "A" target = linode_instance.this.ip_address diff --git a/resource.linode_domain_record.this_ipv6.tf b/resource.linode_domain_record.this_ipv6.tf index 4eeffba..35dcdfc 100644 --- a/resource.linode_domain_record.this_ipv6.tf +++ b/resource.linode_domain_record.this_ipv6.tf @@ -1,5 +1,6 @@ resource "linode_domain_record" "this_ipv6" { - domain_id = data.linode_domain.this.id + count = var.create_dns_record ? 1 : 0 + domain_id = data.linode_domain.this[0].id name = var.host_name record_type = "AAAA" target = element(split("/", linode_instance.this.ipv6), 0) diff --git a/resource.linode_instance.this.tf b/resource.linode_instance.this.tf index 1442cb7..0e43582 100644 --- a/resource.linode_instance.this.tf +++ b/resource.linode_instance.this.tf @@ -2,11 +2,17 @@ resource "linode_instance" "this" { authorized_keys = var.authorized_keys backups_enabled = var.backups_enabled booted = var.booted - label = "${var.host_name}.${var.domain_name}" image = var.image + label = "${var.host_name}.${var.domain_name}" private_ip = var.private_ip + region = var.region tags = var.tags type = var.type - region = var.region watchdog_enabled = var.watchdog_enabled + + lifecycle { + ignore_changes = [ + image, + ] + } } diff --git a/terraform.tf b/terraform.tf index 59ad07d..3c7c403 100644 --- a/terraform.tf +++ b/terraform.tf @@ -2,7 +2,7 @@ terraform { required_providers { linode = { source = "linode/linode" - version = ">= 4.2.0" + version = ">= 4.3.0" } } required_version = ">= 1.11.5" diff --git a/variable.authorized_keys.tf b/variable.authorized_keys.tf index 7a4fae1..1a215a7 100644 --- a/variable.authorized_keys.tf +++ b/variable.authorized_keys.tf @@ -1,4 +1,10 @@ variable "authorized_keys" { - default = [] - type = list(string) + default = [] + description = "A list of SSH public keys to deploy for the root user on the newly created Linode instance." + type = list(string) + + validation { + condition = alltrue([for key in var.authorized_keys : can(regex("^(ssh-rsa|ssh-ed25519|ecdsa-sha2-nistp256|ssh-dss)", key))]) || length(var.authorized_keys) == 0 + error_message = "All authorized keys must be valid SSH public keys starting with ssh-rsa, ssh-ed25519, ecdsa-sha2-nistp256, or ssh-dss." + } } diff --git a/variable.backups_enabled.tf b/variable.backups_enabled.tf index 25c8df6..e764eb3 100644 --- a/variable.backups_enabled.tf +++ b/variable.backups_enabled.tf @@ -1,4 +1,5 @@ variable "backups_enabled" { - default = true - type = bool + default = true + description = "If this field is set to true, the created Linode will automatically be enrolled in the Linode Backup service." + type = bool } diff --git a/variable.booted.tf b/variable.booted.tf index edb2cd8..ee1e02c 100644 --- a/variable.booted.tf +++ b/variable.booted.tf @@ -1,4 +1,5 @@ variable "booted" { - default = true - type = bool + default = true + description = "If true, then the instance is kept or converted into a running state." + type = bool } diff --git a/variable.create_dns_record.tf b/variable.create_dns_record.tf new file mode 100644 index 0000000..5810b63 --- /dev/null +++ b/variable.create_dns_record.tf @@ -0,0 +1,5 @@ +variable "create_dns_record" { + default = true + description = "If true, the module will look up the domain_name and create A and AAAA records for the instance." + type = bool +} diff --git a/variable.domain_name.tf b/variable.domain_name.tf index 274cfb8..e1617f2 100644 --- a/variable.domain_name.tf +++ b/variable.domain_name.tf @@ -1,4 +1,10 @@ variable "domain_name" { - default = "example.com" - type = string + default = "example.com" + description = "The domain name for the Linode instance and domain records." + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.domain_name)) + error_message = "The domain name must be a valid fully-qualified domain name (e.g., example.com)." + } } diff --git a/variable.host_name.tf b/variable.host_name.tf index 6a2e1cc..16036ec 100644 --- a/variable.host_name.tf +++ b/variable.host_name.tf @@ -1,4 +1,10 @@ variable "host_name" { - default = "hello-world" - type = string + default = "hello-world" + description = "The host name for the Linode instance." + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9-]+$", var.host_name)) + error_message = "The host name can only contain alphanumeric characters and hyphens." + } } diff --git a/variable.image.tf b/variable.image.tf index 026ca2c..6f78790 100644 --- a/variable.image.tf +++ b/variable.image.tf @@ -1,4 +1,10 @@ variable "image" { - default = "linode/fedora38" - type = string + default = "linode/fedora44" + description = "An Image ID to deploy the Disk from." + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9-]+/[a-zA-Z0-9.-]+$", var.image)) + error_message = "The image must be a valid Linode image ID (e.g., linode/fedora44)." + } } diff --git a/variable.private_ip.tf b/variable.private_ip.tf index 2577f86..566fcb4 100644 --- a/variable.private_ip.tf +++ b/variable.private_ip.tf @@ -1,4 +1,5 @@ variable "private_ip" { - default = true - type = bool + default = true + description = "If true, the created Linode will have private networking enabled." + type = bool } diff --git a/variable.region.tf b/variable.region.tf index 5f97528..b50e77f 100644 --- a/variable.region.tf +++ b/variable.region.tf @@ -1,4 +1,10 @@ variable "region" { - default = "us-central" - type = string + default = "us-central" + description = "The region where the Linode will be located." + type = string + + validation { + condition = can(regex("^[a-z]{2}-[a-z]+(-[a-z]+)?$", var.region)) + error_message = "The region must be a valid Linode region format (e.g., us-central, ap-south)." + } } diff --git a/variable.tags.tf b/variable.tags.tf index a14b03c..7add907 100644 --- a/variable.tags.tf +++ b/variable.tags.tf @@ -1,4 +1,10 @@ variable "tags" { - default = [] - type = list(string) + default = [] + description = "A list of tags applied to this object." + type = list(string) + + validation { + condition = alltrue([for t in var.tags : can(regex("^[a-zA-Z0-9-_]+$", t))]) || length(var.tags) == 0 + error_message = "Tags must only contain alphanumeric characters, hyphens, and underscores." + } } diff --git a/variable.type.tf b/variable.type.tf index 6f557e9..4ce04a4 100644 --- a/variable.type.tf +++ b/variable.type.tf @@ -1,4 +1,10 @@ variable "type" { - default = "g6-nanode-1" - type = string + default = "g6-nanode-1" + description = "The Linode type defines the pricing, CPU, disk, and RAM specs of the instance." + type = string + + validation { + condition = can(regex("^g[0-9]+-[a-zA-Z0-9-]+$", var.type)) + error_message = "The type must be a valid Linode instance type (e.g., g6-nanode-1, g6-standard-2)." + } } diff --git a/variable.watchdog_enabled.tf b/variable.watchdog_enabled.tf index a07b161..0c6c3c8 100644 --- a/variable.watchdog_enabled.tf +++ b/variable.watchdog_enabled.tf @@ -1,4 +1,5 @@ variable "watchdog_enabled" { - default = true - type = bool + default = true + description = "The watchdog, named Lassie, is a Shutdown Watchdog that monitors your Linode and will reboot it if it powers off unexpectedly." + type = bool }