diff --git a/hertzner/README.md b/hertzner/README.md new file mode 100644 index 00000000..cc5aec78 --- /dev/null +++ b/hertzner/README.md @@ -0,0 +1,174 @@ +# Hetzner Cloud CAF - tinycaf + +Hetzner Cloud Adoption Framework modules for tinycaf. This is a parallel implementation to the Azure CAF modules in `src/`, fully independent and isolated. + +## Why separate from `src/`? + +`src/` is reserved for Azure CAF resources. The Hetzner implementation lives under `hertzner/` to maintain clean separation between cloud providers while sharing the same CAF philosophy and patterns. + +## Architecture + +``` +hertzner/ +├── _provider.tf # hcloud provider configuration +├── _variables.tf # Core variables (token, global_settings, landingzone) +├── _variables.resources.tf # Resource type variable declarations +├── _locals.tf # Global settings merge +├── _outputs.tf # All module outputs +├── *.tf # Root composition files (one per resource group) +├── modules/ # Reusable CAF modules +│ ├── network/ +│ ├── server/ +│ ├── firewall/ +│ ├── load_balancer/ +│ └── ... +└── examples/ # Example .tfvars files +``` + +## Provider Authentication + +Set the Hetzner Cloud API token via environment variable: + +```bash +export HCLOUD_TOKEN="your-api-token" +``` + +Or pass it explicitly: + +```hcl +hcloud_token = "your-api-token" +``` + +## Supported Modules + +### Networking +| Module | Resource | Labels | +|--------|----------|--------| +| `network` | `hcloud_network` | Yes | +| `network_subnet` | `hcloud_network_subnet` | No | +| `network_route` | `hcloud_network_route` | No | + +### Compute +| Module | Resource | Labels | +|--------|----------|--------| +| `server` | `hcloud_server` | Yes | +| `server_network` | `hcloud_server_network` | No | +| `placement_group` | `hcloud_placement_group` | Yes | + +### Storage +| Module | Resource | Labels | +|--------|----------|--------| +| `volume` | `hcloud_volume` | Yes | +| `volume_attachment` | `hcloud_volume_attachment` | No | +| `snapshot` | `hcloud_snapshot` | Yes | +| `storage_box` | `hcloud_storage_box` | Yes | +| `storage_box_snapshot` | `hcloud_storage_box_snapshot` | Yes | +| `storage_box_subaccount` | `hcloud_storage_box_subaccount` | Yes | + +### Security +| Module | Resource | Labels | +|--------|----------|--------| +| `firewall` | `hcloud_firewall` | Yes | +| `firewall_attachment` | `hcloud_firewall_attachment` | No | +| `ssh_key` | `hcloud_ssh_key` | Yes | + +### IP Management +| Module | Resource | Labels | +|--------|----------|--------| +| `primary_ip` | `hcloud_primary_ip` | Yes | +| `floating_ip` | `hcloud_floating_ip` | Yes | +| `floating_ip_assignment` | `hcloud_floating_ip_assignment` | No | +| `rdns` | `hcloud_rdns` | No | + +### Load Balancing +| Module | Resource | Labels | +|--------|----------|--------| +| `load_balancer` | `hcloud_load_balancer` | Yes | +| `load_balancer_service` | `hcloud_load_balancer_service` | No | +| `load_balancer_target` | `hcloud_load_balancer_target` | No | +| `load_balancer_network` | `hcloud_load_balancer_network` | No | + +### Certificates +| Module | Resource | Labels | +|--------|----------|--------| +| `managed_certificate` | `hcloud_managed_certificate` | Yes | +| `uploaded_certificate` | `hcloud_uploaded_certificate` | Yes | + +### DNS +| Module | Resource | Labels | +|--------|----------|--------| +| `zone` | `hcloud_zone` | Yes | +| `zone_record` | `hcloud_zone_record` | No | +| `zone_rrset` | `hcloud_zone_rrset` | Yes | + +## Usage + +Deploy using tfvars files (same as Azure CAF): + +```bash +terraform init +terraform plan -var-file=examples/complete-foundation.tfvars +terraform apply -var-file=examples/complete-foundation.tfvars +``` + +## Labels Strategy + +Labels are merged in two layers: +1. **Global labels** from `global_settings.labels` +2. **Resource-specific labels** from each resource's `labels` field + +Resource-specific labels override global labels for the same key. + +## Cross-Module References + +Resources reference each other using `_ref` keys: + +```hcl +network_subnets = { + subnet_web = { + network_ref = "net_main" # references networks.net_main + type = "cloud" + ip_range = "10.0.1.0/24" + network_zone = "eu-central" + } +} +``` + +For cross-landing-zone references, use `_lz_key`: + +```hcl +network_subnets = { + subnet_web = { + network_ref = "net_main" + network_lz_key = "other_landingzone" + # ... + } +} +``` + +## Key Differences from Azure CAF + +| Aspect | Azure CAF (`src/`) | Hetzner CAF (`hertzner/`) | +|--------|-------------------|--------------------------| +| Provider | azurerm, azapi | hcloud | +| Auth | OIDC (client_id, tenant_id) | API token (HCLOUD_TOKEN) | +| Resource grouping | Resource groups | None (flat per-project) | +| Metadata | Tags | Labels | +| Tag inheritance | Global → RG → resource | Global → resource | +| Regions | Azure regions | Hetzner locations (fsn1, nbg1, hel1, ash, hil, sin) | + +## Not Included and Why + +| Provider Resource | Reason | +|-------------------|--------| +| `hcloud_certificate` | Deprecated alias for `hcloud_uploaded_certificate` | +| `hcloud_server_poweroff` | Imperative action resource, not declarative infrastructure | +| `hcloud_server_poweron` | Imperative action resource, not declarative infrastructure | +| `hcloud_server_reboot` | Imperative action resource, not declarative infrastructure | +| `hcloud_server_reset` | Imperative action resource, not declarative infrastructure | + +## Known Limitations + +- No remote state pattern implemented yet (can be added following the Azure CAF pattern with `module.remote_states`) +- Landing zone cross-references work within the same state; multi-state references require the remote state pattern +- Provider version pinned to 1.60.1; update in `_provider.tf` as needed diff --git a/hertzner/_locals.tf b/hertzner/_locals.tf new file mode 100644 index 00000000..ad430ed6 --- /dev/null +++ b/hertzner/_locals.tf @@ -0,0 +1,3 @@ +locals { + global_settings = var.global_settings +} diff --git a/hertzner/_outputs.tf b/hertzner/_outputs.tf new file mode 100644 index 00000000..60196007 --- /dev/null +++ b/hertzner/_outputs.tf @@ -0,0 +1,114 @@ +output "networks" { + value = module.networks +} + +output "network_subnets" { + value = module.network_subnets +} + +output "network_routes" { + value = module.network_routes +} + +output "servers" { + value = module.servers +} + +output "server_networks" { + value = module.server_networks +} + +output "volumes" { + value = module.volumes +} + +output "volume_attachments" { + value = module.volume_attachments +} + +output "firewalls" { + value = module.firewalls +} + +output "firewall_attachments" { + value = module.firewall_attachments +} + +output "ssh_keys" { + value = module.ssh_keys +} + +output "placement_groups" { + value = module.placement_groups +} + +output "primary_ips" { + value = module.primary_ips +} + +output "rdns_records" { + value = module.rdns_records +} + +output "floating_ips" { + value = module.floating_ips +} + +output "floating_ip_assignments" { + value = module.floating_ip_assignments +} + +output "load_balancers" { + value = module.load_balancers +} + +output "load_balancer_services" { + value = module.load_balancer_services +} + +output "load_balancer_targets" { + value = module.load_balancer_targets +} + +output "load_balancer_networks" { + value = module.load_balancer_networks +} + +output "managed_certificates" { + value = module.managed_certificates +} + +output "uploaded_certificates" { + value = module.uploaded_certificates + sensitive = true +} + +output "snapshots" { + value = module.snapshots +} + +output "storage_boxes" { + value = module.storage_boxes + sensitive = true +} + +output "storage_box_snapshots" { + value = module.storage_box_snapshots +} + +output "storage_box_subaccounts" { + value = module.storage_box_subaccounts + sensitive = true +} + +output "zones" { + value = module.zones +} + +output "zone_records" { + value = module.zone_records +} + +output "zone_rrsets" { + value = module.zone_rrsets +} diff --git a/hertzner/_provider.tf b/hertzner/_provider.tf new file mode 100644 index 00000000..dff48261 --- /dev/null +++ b/hertzner/_provider.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + version = "1.60.1" + } + } +} + +provider "hcloud" { + token = var.hcloud_token +} diff --git a/hertzner/_variables.resources.tf b/hertzner/_variables.resources.tf new file mode 100644 index 00000000..01e61146 --- /dev/null +++ b/hertzner/_variables.resources.tf @@ -0,0 +1,55 @@ +variable "networks" { default = {} } + +variable "network_subnets" { default = {} } + +variable "network_routes" { default = {} } + +variable "servers" { default = {} } + +variable "server_networks" { default = {} } + +variable "volumes" { default = {} } + +variable "volume_attachments" { default = {} } + +variable "firewalls" { default = {} } + +variable "firewall_attachments" { default = {} } + +variable "ssh_keys" { default = {} } + +variable "placement_groups" { default = {} } + +variable "primary_ips" { default = {} } + +variable "rdns_records" { default = {} } + +variable "floating_ips" { default = {} } + +variable "floating_ip_assignments" { default = {} } + +variable "load_balancers" { default = {} } + +variable "load_balancer_services" { default = {} } + +variable "load_balancer_targets" { default = {} } + +variable "load_balancer_networks" { default = {} } + +variable "managed_certificates" { default = {} } + +variable "uploaded_certificates" { default = {} } + +variable "snapshots" { default = {} } + +variable "storage_boxes" { default = {} } + +variable "storage_box_snapshots" { default = {} } + +variable "storage_box_subaccounts" { default = {} } + +variable "zones" { default = {} } + +variable "zone_records" { default = {} } + +variable "zone_rrsets" { default = {} } diff --git a/hertzner/_variables.tf b/hertzner/_variables.tf new file mode 100644 index 00000000..edaf5041 --- /dev/null +++ b/hertzner/_variables.tf @@ -0,0 +1,28 @@ +variable "hcloud_token" { + description = "Hetzner Cloud API token. Can also be set via HCLOUD_TOKEN env var." + type = string + sensitive = true + default = null +} + +variable "global_settings" { + description = "Global settings for tinycaf Hetzner CAF" + type = object({ + labels = optional(map(string), {}) + }) + + default = { + labels = {} + } +} + +variable "landingzone" { + description = "Landing zone metadata and tfstate dependencies" + type = object({ + backend_type = string + key = string + tfstates = optional(map(object({ + tfstate = string + }))) + }) +} diff --git a/hertzner/certificates.tf b/hertzner/certificates.tf new file mode 100644 index 00000000..7ca14793 --- /dev/null +++ b/hertzner/certificates.tf @@ -0,0 +1,21 @@ +module "managed_certificates" { + source = "./modules/managed_certificate" + for_each = var.managed_certificates + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "uploaded_certificates" { + source = "./modules/uploaded_certificate" + for_each = var.uploaded_certificates + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/dns.tf b/hertzner/dns.tf new file mode 100644 index 00000000..96ed7801 --- /dev/null +++ b/hertzner/dns.tf @@ -0,0 +1,44 @@ +module "zones" { + source = "./modules/zone" + for_each = var.zones + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "zone_records" { + source = "./modules/zone_record" + for_each = var.zone_records + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + zones = module.zones + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "zone_rrsets" { + source = "./modules/zone_rrset" + for_each = var.zone_rrsets + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + zones = module.zones + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/examples/complete-foundation.tfvars b/hertzner/examples/complete-foundation.tfvars new file mode 100644 index 00000000..7753bb8e --- /dev/null +++ b/hertzner/examples/complete-foundation.tfvars @@ -0,0 +1,254 @@ +# Complete Hetzner Cloud Foundation +# Demonstrates a realistic minimal landing zone deployment + +global_settings = { + labels = { + environment = "production" + managed_by = "terraform" + project = "tinycaf" + } +} + +# --- Networking --- + +networks = { + net_main = { + name = "net-production" + ip_range = "10.0.0.0/16" + } +} + +network_subnets = { + subnet_web = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.1.0/24" + network_zone = "eu-central" + } + subnet_app = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.2.0/24" + network_zone = "eu-central" + } + subnet_db = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.3.0/24" + network_zone = "eu-central" + } +} + +# --- Security --- + +ssh_keys = { + key_deploy = { + name = "deploy-key" + public_key = "ssh-rsa AAAAB3... deploy@infra" + } +} + +firewalls = { + fw_web = { + name = "fw-web" + labels = { + role = "web" + } + rules = { + allow_ssh = { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = ["10.0.0.0/16"] + description = "Allow SSH from private network" + } + allow_http = { + direction = "in" + protocol = "tcp" + port = "80" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTP" + } + allow_https = { + direction = "in" + protocol = "tcp" + port = "443" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTPS" + } + } + } + fw_internal = { + name = "fw-internal" + labels = { + role = "internal" + } + rules = { + allow_ssh = { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = ["10.0.0.0/16"] + description = "Allow SSH from private network" + } + allow_internal = { + direction = "in" + protocol = "tcp" + port = "1-65535" + source_ips = ["10.0.0.0/16"] + description = "Allow all TCP from private network" + } + } + } +} + +# --- Compute --- + +placement_groups = { + pg_web = { + name = "pg-web-spread" + type = "spread" + } +} + +servers = { + srv_web_01 = { + name = "web-01" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["deploy-key"] + labels = { + role = "web" + } + placement_group_ref = "pg_web" + firewall_ids_ref = ["fw_web"] + public_net = { + ipv4_enabled = true + ipv6_enabled = true + } + networks = { + main = { + network_ref = "net_main" + ip = "10.0.1.10" + } + } + } + srv_web_02 = { + name = "web-02" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["deploy-key"] + labels = { + role = "web" + } + placement_group_ref = "pg_web" + firewall_ids_ref = ["fw_web"] + public_net = { + ipv4_enabled = true + ipv6_enabled = true + } + networks = { + main = { + network_ref = "net_main" + ip = "10.0.1.11" + } + } + } + srv_app_01 = { + name = "app-01" + server_type = "cx32" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["deploy-key"] + labels = { + role = "app" + } + firewall_ids_ref = ["fw_internal"] + public_net = { + ipv4_enabled = false + ipv6_enabled = false + } + networks = { + main = { + network_ref = "net_main" + ip = "10.0.2.10" + } + } + } +} + +# --- Storage --- + +volumes = { + vol_app_data = { + name = "vol-app-data" + size = 50 + server_ref = "srv_app_01" + format = "ext4" + automount = true + labels = { + role = "app-data" + } + } +} + +# --- Load Balancing --- + +load_balancers = { + lb_web = { + name = "lb-web" + load_balancer_type = "lb11" + location = "fsn1" + algorithm = { + type = "round_robin" + } + labels = { + role = "web" + } + } +} + +load_balancer_services = { + lbs_http = { + load_balancer_ref = "lb_web" + protocol = "http" + listen_port = 80 + destination_port = 80 + health_check = { + protocol = "http" + port = 80 + interval = 15 + timeout = 10 + retries = 3 + http = { + path = "/health" + status_codes = ["2??", "3??"] + } + } + } +} + +load_balancer_targets = { + lbt_web_01 = { + load_balancer_ref = "lb_web" + type = "server" + server_ref = "srv_web_01" + use_private_ip = true + } + lbt_web_02 = { + load_balancer_ref = "lb_web" + type = "server" + server_ref = "srv_web_02" + use_private_ip = true + } +} + +load_balancer_networks = { + lbn_web = { + load_balancer_ref = "lb_web" + network_ref = "net_main" + ip = "10.0.1.100" + } +} diff --git a/hertzner/examples/firewall-basic.tfvars b/hertzner/examples/firewall-basic.tfvars new file mode 100644 index 00000000..c6d83712 --- /dev/null +++ b/hertzner/examples/firewall-basic.tfvars @@ -0,0 +1,37 @@ +firewalls = { + fw_web = { + name = "fw-web" + labels = { + role = "web" + } + rules = { + allow_ssh = { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow SSH" + } + allow_http = { + direction = "in" + protocol = "tcp" + port = "80" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTP" + } + allow_https = { + direction = "in" + protocol = "tcp" + port = "443" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTPS" + } + allow_icmp = { + direction = "in" + protocol = "icmp" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow ICMP" + } + } + } +} diff --git a/hertzner/examples/load-balancer-basic.tfvars b/hertzner/examples/load-balancer-basic.tfvars new file mode 100644 index 00000000..3b8ecb15 --- /dev/null +++ b/hertzner/examples/load-balancer-basic.tfvars @@ -0,0 +1,52 @@ +load_balancers = { + lb_web = { + name = "lb-web" + load_balancer_type = "lb11" + location = "fsn1" + algorithm = { + type = "round_robin" + } + labels = { + role = "web" + } + } +} + +load_balancer_services = { + lbs_http = { + load_balancer_ref = "lb_web" + protocol = "http" + listen_port = 80 + destination_port = 80 + health_check = { + protocol = "http" + port = 80 + interval = 15 + timeout = 10 + retries = 3 + http = { + path = "/health" + status_codes = ["2??", "3??"] + } + } + } +} + +load_balancer_targets = { + lbt_web_01 = { + load_balancer_ref = "lb_web" + type = "server" + server_ref = "srv_web_01" + use_private_ip = true + } +} + +# pre-requisites +servers = { + srv_web_01 = { + name = "web-01" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + } +} diff --git a/hertzner/examples/network-basic.tfvars b/hertzner/examples/network-basic.tfvars new file mode 100644 index 00000000..0a63ede6 --- /dev/null +++ b/hertzner/examples/network-basic.tfvars @@ -0,0 +1,32 @@ +networks = { + net_main = { + name = "network-main" + ip_range = "10.0.0.0/16" + labels = { + environment = "dev" + } + } +} + +network_subnets = { + subnet_servers = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.1.0/24" + network_zone = "eu-central" + } + subnet_lb = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.2.0/24" + network_zone = "eu-central" + } +} + +network_routes = { + route_vpn = { + network_ref = "net_main" + destination = "10.100.0.0/16" + gateway = "10.0.1.1" + } +} diff --git a/hertzner/examples/server-basic.tfvars b/hertzner/examples/server-basic.tfvars new file mode 100644 index 00000000..a35e92a6 --- /dev/null +++ b/hertzner/examples/server-basic.tfvars @@ -0,0 +1,24 @@ +servers = { + srv_web_01 = { + name = "web-01" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["deploy-key"] + labels = { + role = "web" + environment = "dev" + } + public_net = { + ipv4_enabled = true + ipv6_enabled = true + } + } +} + +ssh_keys = { + key_deploy = { + name = "deploy-key" + public_key = "ssh-rsa AAAAB3... user@host" + } +} diff --git a/hertzner/examples/server-private-network.tfvars b/hertzner/examples/server-private-network.tfvars new file mode 100644 index 00000000..e66987ac --- /dev/null +++ b/hertzner/examples/server-private-network.tfvars @@ -0,0 +1,45 @@ +networks = { + net_main = { + name = "network-main" + ip_range = "10.0.0.0/16" + } +} + +network_subnets = { + subnet_servers = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.1.0/24" + network_zone = "eu-central" + } +} + +servers = { + srv_app_01 = { + name = "app-01" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["deploy-key"] + labels = { + role = "app" + } + public_net = { + ipv4_enabled = false + ipv6_enabled = false + } + networks = { + main = { + network_ref = "net_main" + ip = "10.0.1.10" + } + } + } +} + +ssh_keys = { + key_deploy = { + name = "deploy-key" + public_key = "ssh-rsa AAAAB3... user@host" + } +} diff --git a/hertzner/firewalls.tf b/hertzner/firewalls.tf new file mode 100644 index 00000000..cc34d3dd --- /dev/null +++ b/hertzner/firewalls.tf @@ -0,0 +1,28 @@ +module "firewalls" { + source = "./modules/firewall" + for_each = var.firewalls + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "firewall_attachments" { + source = "./modules/firewall_attachment" + for_each = var.firewall_attachments + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + firewalls = module.firewalls + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/ips.tf b/hertzner/ips.tf new file mode 100644 index 00000000..e7aec9ac --- /dev/null +++ b/hertzner/ips.tf @@ -0,0 +1,59 @@ +module "primary_ips" { + source = "./modules/primary_ip" + for_each = var.primary_ips + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "floating_ips" { + source = "./modules/floating_ip" + for_each = var.floating_ips + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "floating_ip_assignments" { + source = "./modules/floating_ip_assignment" + for_each = var.floating_ip_assignments + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + floating_ips = module.floating_ips + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "rdns_records" { + source = "./modules/rdns" + for_each = var.rdns_records + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + servers = module.servers + primary_ips = module.primary_ips + floating_ips = module.floating_ips + load_balancers = module.load_balancers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/load_balancers.tf b/hertzner/load_balancers.tf new file mode 100644 index 00000000..700f04ac --- /dev/null +++ b/hertzner/load_balancers.tf @@ -0,0 +1,64 @@ +module "load_balancers" { + source = "./modules/load_balancer" + for_each = var.load_balancers + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "load_balancer_services" { + source = "./modules/load_balancer_service" + for_each = var.load_balancer_services + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + load_balancers = module.load_balancers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "load_balancer_targets" { + source = "./modules/load_balancer_target" + for_each = var.load_balancer_targets + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + load_balancers = module.load_balancers + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "load_balancer_networks" { + source = "./modules/load_balancer_network" + for_each = var.load_balancer_networks + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + load_balancers = module.load_balancers + networks = module.networks + network_subnets = module.network_subnets + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/modules/firewall/README.md b/hertzner/modules/firewall/README.md new file mode 100644 index 00000000..90ff6cc1 --- /dev/null +++ b/hertzner/modules/firewall/README.md @@ -0,0 +1,45 @@ +# Firewall Module + +Manages an hcloud_firewall resource. + +## Usage + +```hcl +firewalls = { + fw_web = { + name = "fw-web" + rules = { + allow_ssh = { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow SSH" + } + allow_http = { + direction = "in" + protocol = "tcp" + port = "80" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTP" + } + allow_https = { + direction = "in" + protocol = "tcp" + port = "443" + source_ips = ["0.0.0.0/0", "::/0"] + description = "Allow HTTPS" + } + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Firewall name | Yes | +| labels | Key-value label pairs | No | +| rules | Map of firewall rules | No | +| apply_to | Map of targets to apply firewall to | No | diff --git a/hertzner/modules/firewall/_locals.tf b/hertzner/modules/firewall/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/firewall/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/firewall/_outputs.tf b/hertzner/modules/firewall/_outputs.tf new file mode 100644 index 00000000..570aff53 --- /dev/null +++ b/hertzner/modules/firewall/_outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = hcloud_firewall.main.id +} + +output "name" { + value = hcloud_firewall.main.name +} + +output "labels" { + value = hcloud_firewall.main.labels +} + +output "rule" { + value = hcloud_firewall.main.rule +} + +output "apply_to" { + value = hcloud_firewall.main.apply_to +} diff --git a/hertzner/modules/firewall/_provider.tf b/hertzner/modules/firewall/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/firewall/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/firewall/_variables.tf b/hertzner/modules/firewall/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/firewall/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/firewall/main.tf b/hertzner/modules/firewall/main.tf new file mode 100644 index 00000000..d5c394e5 --- /dev/null +++ b/hertzner/modules/firewall/main.tf @@ -0,0 +1,24 @@ +resource "hcloud_firewall" "main" { + name = var.settings.name + labels = local.labels + + dynamic "rule" { + for_each = try(var.settings.rules, {}) + content { + direction = rule.value.direction + protocol = rule.value.protocol + port = try(rule.value.port, null) + source_ips = try(rule.value.source_ips, null) + destination_ips = try(rule.value.destination_ips, null) + description = try(rule.value.description, null) + } + } + + dynamic "apply_to" { + for_each = try(var.settings.apply_to, {}) + content { + label_selector = try(apply_to.value.label_selector, null) + server = try(apply_to.value.server, null) + } + } +} diff --git a/hertzner/modules/firewall_attachment/README.md b/hertzner/modules/firewall_attachment/README.md new file mode 100644 index 00000000..6f2a7ab1 --- /dev/null +++ b/hertzner/modules/firewall_attachment/README.md @@ -0,0 +1,22 @@ +# Firewall Attachment Module + +Manages an hcloud_firewall_attachment resource. + +## Usage + +```hcl +firewall_attachments = { + fwa_web = { + firewall_ref = "fw_web" + server_ids_ref = ["srv_web_01", "srv_web_02"] + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| firewall_ref | Reference key to the firewall | Yes | +| server_ids_ref | List of server reference keys | No | +| label_selectors | List of label selectors | No | diff --git a/hertzner/modules/firewall_attachment/_locals.tf b/hertzner/modules/firewall_attachment/_locals.tf new file mode 100644 index 00000000..eb9bd417 --- /dev/null +++ b/hertzner/modules/firewall_attachment/_locals.tf @@ -0,0 +1,12 @@ +locals { + firewall_id = var.resources[ + try(var.settings.firewall_lz_key, var.client_config.landingzone_key) + ].firewalls[var.settings.firewall_ref].id + + server_ids = try([ + for ref in var.settings.server_ids_ref : + var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[ref].id + ], null) +} diff --git a/hertzner/modules/firewall_attachment/_outputs.tf b/hertzner/modules/firewall_attachment/_outputs.tf new file mode 100644 index 00000000..827cbba9 --- /dev/null +++ b/hertzner/modules/firewall_attachment/_outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = hcloud_firewall_attachment.main.id +} + +output "firewall_id" { + value = hcloud_firewall_attachment.main.firewall_id +} + +output "server_ids" { + value = hcloud_firewall_attachment.main.server_ids +} + +output "label_selectors" { + value = hcloud_firewall_attachment.main.label_selectors +} diff --git a/hertzner/modules/firewall_attachment/_provider.tf b/hertzner/modules/firewall_attachment/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/firewall_attachment/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/firewall_attachment/_variables.tf b/hertzner/modules/firewall_attachment/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/firewall_attachment/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/firewall_attachment/main.tf b/hertzner/modules/firewall_attachment/main.tf new file mode 100644 index 00000000..8fbfd946 --- /dev/null +++ b/hertzner/modules/firewall_attachment/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_firewall_attachment" "main" { + firewall_id = local.firewall_id + server_ids = try(local.server_ids, null) + label_selectors = try(var.settings.label_selectors, null) +} diff --git a/hertzner/modules/floating_ip/README.md b/hertzner/modules/floating_ip/README.md new file mode 100644 index 00000000..8291eae1 --- /dev/null +++ b/hertzner/modules/floating_ip/README.md @@ -0,0 +1,27 @@ +# Floating IP Module + +Manages an hcloud_floating_ip resource. + +## Usage + +```hcl +floating_ips = { + fip_web = { + name = "floating-ip-web" + type = "ipv4" + home_location = "fsn1" + description = "Web frontend floating IP" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| type | IP type: ipv4 or ipv6 | Yes | +| name | Floating IP name | No | +| description | Description | No | +| home_location | Home location | No | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | diff --git a/hertzner/modules/floating_ip/_locals.tf b/hertzner/modules/floating_ip/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/floating_ip/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/floating_ip/_outputs.tf b/hertzner/modules/floating_ip/_outputs.tf new file mode 100644 index 00000000..536533e9 --- /dev/null +++ b/hertzner/modules/floating_ip/_outputs.tf @@ -0,0 +1,23 @@ +output "id" { + value = hcloud_floating_ip.main.id +} + +output "name" { + value = hcloud_floating_ip.main.name +} + +output "type" { + value = hcloud_floating_ip.main.type +} + +output "ip_address" { + value = hcloud_floating_ip.main.ip_address +} + +output "home_location" { + value = hcloud_floating_ip.main.home_location +} + +output "labels" { + value = hcloud_floating_ip.main.labels +} diff --git a/hertzner/modules/floating_ip/_provider.tf b/hertzner/modules/floating_ip/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/floating_ip/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/floating_ip/_variables.tf b/hertzner/modules/floating_ip/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/floating_ip/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/floating_ip/main.tf b/hertzner/modules/floating_ip/main.tf new file mode 100644 index 00000000..4af22023 --- /dev/null +++ b/hertzner/modules/floating_ip/main.tf @@ -0,0 +1,11 @@ +resource "hcloud_floating_ip" "main" { + type = var.settings.type + + name = try(var.settings.name, null) + description = try(var.settings.description, null) + home_location = try(var.settings.home_location, null) + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) +} diff --git a/hertzner/modules/floating_ip_assignment/README.md b/hertzner/modules/floating_ip_assignment/README.md new file mode 100644 index 00000000..c996b18e --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/README.md @@ -0,0 +1,23 @@ +# Floating IP Assignment Module + +Manages an hcloud_floating_ip_assignment resource. + +## Usage + +```hcl +floating_ip_assignments = { + fipa_web = { + floating_ip_ref = "fip_web" + server_ref = "srv_web_01" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| floating_ip_ref | Reference key to the floating IP | Yes | +| server_ref | Reference key to the server | Yes | +| floating_ip_lz_key | Landing zone key for floating IP | No | +| server_lz_key | Landing zone key for server | No | diff --git a/hertzner/modules/floating_ip_assignment/_locals.tf b/hertzner/modules/floating_ip_assignment/_locals.tf new file mode 100644 index 00000000..d5bfaa77 --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/_locals.tf @@ -0,0 +1,9 @@ +locals { + floating_ip_id = var.resources[ + try(var.settings.floating_ip_lz_key, var.client_config.landingzone_key) + ].floating_ips[var.settings.floating_ip_ref].id + + server_id = var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id +} diff --git a/hertzner/modules/floating_ip_assignment/_outputs.tf b/hertzner/modules/floating_ip_assignment/_outputs.tf new file mode 100644 index 00000000..05193ac0 --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/_outputs.tf @@ -0,0 +1,11 @@ +output "id" { + value = hcloud_floating_ip_assignment.main.id +} + +output "floating_ip_id" { + value = hcloud_floating_ip_assignment.main.floating_ip_id +} + +output "server_id" { + value = hcloud_floating_ip_assignment.main.server_id +} diff --git a/hertzner/modules/floating_ip_assignment/_provider.tf b/hertzner/modules/floating_ip_assignment/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/floating_ip_assignment/_variables.tf b/hertzner/modules/floating_ip_assignment/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/floating_ip_assignment/main.tf b/hertzner/modules/floating_ip_assignment/main.tf new file mode 100644 index 00000000..2b669a23 --- /dev/null +++ b/hertzner/modules/floating_ip_assignment/main.tf @@ -0,0 +1,4 @@ +resource "hcloud_floating_ip_assignment" "main" { + floating_ip_id = local.floating_ip_id + server_id = local.server_id +} diff --git a/hertzner/modules/load_balancer/README.md b/hertzner/modules/load_balancer/README.md new file mode 100644 index 00000000..4a3a4570 --- /dev/null +++ b/hertzner/modules/load_balancer/README.md @@ -0,0 +1,30 @@ +# Load Balancer Module + +Manages an hcloud_load_balancer resource. + +## Usage + +```hcl +load_balancers = { + lb_web = { + name = "lb-web" + load_balancer_type = "lb11" + location = "fsn1" + algorithm = { + type = "round_robin" + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Load balancer name | Yes | +| load_balancer_type | Load balancer type (e.g. lb11) | Yes | +| location | Location (required if no network_zone) | No | +| network_zone | Network zone (required if no location) | No | +| algorithm | Algorithm configuration block | No | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | diff --git a/hertzner/modules/load_balancer/_locals.tf b/hertzner/modules/load_balancer/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/load_balancer/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/load_balancer/_outputs.tf b/hertzner/modules/load_balancer/_outputs.tf new file mode 100644 index 00000000..5ae7adb6 --- /dev/null +++ b/hertzner/modules/load_balancer/_outputs.tf @@ -0,0 +1,35 @@ +output "id" { + value = hcloud_load_balancer.main.id +} + +output "name" { + value = hcloud_load_balancer.main.name +} + +output "load_balancer_type" { + value = hcloud_load_balancer.main.load_balancer_type +} + +output "location" { + value = hcloud_load_balancer.main.location +} + +output "ipv4" { + value = hcloud_load_balancer.main.ipv4 +} + +output "ipv6" { + value = hcloud_load_balancer.main.ipv6 +} + +output "labels" { + value = hcloud_load_balancer.main.labels +} + +output "network_id" { + value = hcloud_load_balancer.main.network_id +} + +output "network_ip" { + value = hcloud_load_balancer.main.network_ip +} diff --git a/hertzner/modules/load_balancer/_provider.tf b/hertzner/modules/load_balancer/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/load_balancer/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/load_balancer/_variables.tf b/hertzner/modules/load_balancer/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/load_balancer/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/load_balancer/main.tf b/hertzner/modules/load_balancer/main.tf new file mode 100644 index 00000000..4d556f2a --- /dev/null +++ b/hertzner/modules/load_balancer/main.tf @@ -0,0 +1,18 @@ +resource "hcloud_load_balancer" "main" { + name = var.settings.name + load_balancer_type = var.settings.load_balancer_type + + location = try(var.settings.location, null) + network_zone = try(var.settings.network_zone, null) + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) + + dynamic "algorithm" { + for_each = can(var.settings.algorithm) ? [1] : [] + content { + type = try(var.settings.algorithm.type, "round_robin") + } + } +} diff --git a/hertzner/modules/load_balancer_network/README.md b/hertzner/modules/load_balancer_network/README.md new file mode 100644 index 00000000..e7a81502 --- /dev/null +++ b/hertzner/modules/load_balancer_network/README.md @@ -0,0 +1,25 @@ +# Load Balancer Network Module + +Manages an hcloud_load_balancer_network resource. + +## Usage + +```hcl +load_balancer_networks = { + lbn_web = { + load_balancer_ref = "lb_web" + network_ref = "net_main" + ip = "10.0.1.100" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| load_balancer_ref | Reference key to the load balancer | Yes | +| network_ref | Reference key to the network | No | +| subnet_ref | Reference key to the subnet | No | +| ip | IP address to assign | No | +| enable_public_interface | Enable public interface (default: true) | No | diff --git a/hertzner/modules/load_balancer_network/_locals.tf b/hertzner/modules/load_balancer_network/_locals.tf new file mode 100644 index 00000000..1d718a7a --- /dev/null +++ b/hertzner/modules/load_balancer_network/_locals.tf @@ -0,0 +1,19 @@ +locals { + load_balancer_id = var.resources[ + try(var.settings.load_balancer_lz_key, var.client_config.landingzone_key) + ].load_balancers[var.settings.load_balancer_ref].id + + network_id = try( + var.resources[ + try(var.settings.network_lz_key, var.client_config.landingzone_key) + ].networks[var.settings.network_ref].id, + null + ) + + subnet_id = try( + var.resources[ + try(var.settings.subnet_lz_key, var.client_config.landingzone_key) + ].network_subnets[var.settings.subnet_ref].id, + null + ) +} diff --git a/hertzner/modules/load_balancer_network/_outputs.tf b/hertzner/modules/load_balancer_network/_outputs.tf new file mode 100644 index 00000000..dbe9909b --- /dev/null +++ b/hertzner/modules/load_balancer_network/_outputs.tf @@ -0,0 +1,7 @@ +output "id" { + value = hcloud_load_balancer_network.main.id +} + +output "load_balancer_id" { + value = hcloud_load_balancer_network.main.load_balancer_id +} diff --git a/hertzner/modules/load_balancer_network/_provider.tf b/hertzner/modules/load_balancer_network/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/load_balancer_network/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/load_balancer_network/_variables.tf b/hertzner/modules/load_balancer_network/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/load_balancer_network/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/load_balancer_network/main.tf b/hertzner/modules/load_balancer_network/main.tf new file mode 100644 index 00000000..820cdc42 --- /dev/null +++ b/hertzner/modules/load_balancer_network/main.tf @@ -0,0 +1,7 @@ +resource "hcloud_load_balancer_network" "main" { + load_balancer_id = local.load_balancer_id + network_id = try(local.network_id, null) + subnet_id = try(local.subnet_id, null) + ip = try(var.settings.ip, null) + enable_public_interface = try(var.settings.enable_public_interface, true) +} diff --git a/hertzner/modules/load_balancer_service/README.md b/hertzner/modules/load_balancer_service/README.md new file mode 100644 index 00000000..acd0ebc6 --- /dev/null +++ b/hertzner/modules/load_balancer_service/README.md @@ -0,0 +1,36 @@ +# Load Balancer Service Module + +Manages an hcloud_load_balancer_service resource. + +## Usage + +```hcl +load_balancer_services = { + lbs_http = { + load_balancer_ref = "lb_web" + protocol = "http" + listen_port = 80 + destination_port = 80 + health_check = { + protocol = "http" + port = 80 + http = { + path = "/health" + status_codes = ["2??", "3??"] + } + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| load_balancer_ref | Reference key to the load balancer | Yes | +| protocol | Protocol: http, https, or tcp | Yes | +| listen_port | Listen port | No | +| destination_port | Destination port | No | +| proxyprotocol | Enable proxy protocol | No | +| http | HTTP configuration block | No | +| health_check | Health check configuration block | No | diff --git a/hertzner/modules/load_balancer_service/_locals.tf b/hertzner/modules/load_balancer_service/_locals.tf new file mode 100644 index 00000000..ffc39783 --- /dev/null +++ b/hertzner/modules/load_balancer_service/_locals.tf @@ -0,0 +1,5 @@ +locals { + load_balancer_id = var.resources[ + try(var.settings.load_balancer_lz_key, var.client_config.landingzone_key) + ].load_balancers[var.settings.load_balancer_ref].id +} diff --git a/hertzner/modules/load_balancer_service/_outputs.tf b/hertzner/modules/load_balancer_service/_outputs.tf new file mode 100644 index 00000000..3ec636af --- /dev/null +++ b/hertzner/modules/load_balancer_service/_outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = hcloud_load_balancer_service.main.id +} + +output "load_balancer_id" { + value = hcloud_load_balancer_service.main.load_balancer_id +} + +output "protocol" { + value = hcloud_load_balancer_service.main.protocol +} + +output "listen_port" { + value = hcloud_load_balancer_service.main.listen_port +} + +output "destination_port" { + value = hcloud_load_balancer_service.main.destination_port +} diff --git a/hertzner/modules/load_balancer_service/_provider.tf b/hertzner/modules/load_balancer_service/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/load_balancer_service/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/load_balancer_service/_variables.tf b/hertzner/modules/load_balancer_service/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/load_balancer_service/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/load_balancer_service/main.tf b/hertzner/modules/load_balancer_service/main.tf new file mode 100644 index 00000000..b265a531 --- /dev/null +++ b/hertzner/modules/load_balancer_service/main.tf @@ -0,0 +1,41 @@ +resource "hcloud_load_balancer_service" "main" { + load_balancer_id = local.load_balancer_id + protocol = var.settings.protocol + + listen_port = try(var.settings.listen_port, null) + destination_port = try(var.settings.destination_port, null) + proxyprotocol = try(var.settings.proxyprotocol, null) + + dynamic "http" { + for_each = can(var.settings.http) ? [1] : [] + content { + sticky_sessions = try(var.settings.http.sticky_sessions, null) + cookie_name = try(var.settings.http.cookie_name, null) + cookie_lifetime = try(var.settings.http.cookie_lifetime, null) + certificates = try(var.settings.http.certificates, null) + redirect_http = try(var.settings.http.redirect_http, null) + } + } + + dynamic "health_check" { + for_each = can(var.settings.health_check) ? [1] : [] + content { + protocol = var.settings.health_check.protocol + port = var.settings.health_check.port + interval = try(var.settings.health_check.interval, null) + timeout = try(var.settings.health_check.timeout, null) + retries = try(var.settings.health_check.retries, null) + + dynamic "http" { + for_each = can(var.settings.health_check.http) ? [1] : [] + content { + domain = try(var.settings.health_check.http.domain, null) + path = try(var.settings.health_check.http.path, null) + response = try(var.settings.health_check.http.response, null) + tls = try(var.settings.health_check.http.tls, null) + status_codes = try(var.settings.health_check.http.status_codes, null) + } + } + } + } +} diff --git a/hertzner/modules/load_balancer_target/README.md b/hertzner/modules/load_balancer_target/README.md new file mode 100644 index 00000000..4dd1ccf2 --- /dev/null +++ b/hertzner/modules/load_balancer_target/README.md @@ -0,0 +1,27 @@ +# Load Balancer Target Module + +Manages an hcloud_load_balancer_target resource. + +## Usage + +```hcl +load_balancer_targets = { + lbt_web_01 = { + load_balancer_ref = "lb_web" + type = "server" + server_ref = "srv_web_01" + use_private_ip = true + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| load_balancer_ref | Reference key to the load balancer | Yes | +| type | Target type: server, label_selector, or ip | Yes | +| server_ref | Server reference key (if type=server) | No | +| label_selector | Label selector (if type=label_selector) | No | +| ip | IP address (if type=ip) | No | +| use_private_ip | Use private IP for the target | No | diff --git a/hertzner/modules/load_balancer_target/_locals.tf b/hertzner/modules/load_balancer_target/_locals.tf new file mode 100644 index 00000000..ae9ce50f --- /dev/null +++ b/hertzner/modules/load_balancer_target/_locals.tf @@ -0,0 +1,12 @@ +locals { + load_balancer_id = var.resources[ + try(var.settings.load_balancer_lz_key, var.client_config.landingzone_key) + ].load_balancers[var.settings.load_balancer_ref].id + + server_id = try( + var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id, + null + ) +} diff --git a/hertzner/modules/load_balancer_target/_outputs.tf b/hertzner/modules/load_balancer_target/_outputs.tf new file mode 100644 index 00000000..25c6eaf4 --- /dev/null +++ b/hertzner/modules/load_balancer_target/_outputs.tf @@ -0,0 +1,19 @@ +output "type" { + value = hcloud_load_balancer_target.main.type +} + +output "load_balancer_id" { + value = hcloud_load_balancer_target.main.load_balancer_id +} + +output "server_id" { + value = hcloud_load_balancer_target.main.server_id +} + +output "label_selector" { + value = hcloud_load_balancer_target.main.label_selector +} + +output "use_private_ip" { + value = hcloud_load_balancer_target.main.use_private_ip +} diff --git a/hertzner/modules/load_balancer_target/_provider.tf b/hertzner/modules/load_balancer_target/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/load_balancer_target/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/load_balancer_target/_variables.tf b/hertzner/modules/load_balancer_target/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/load_balancer_target/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/load_balancer_target/main.tf b/hertzner/modules/load_balancer_target/main.tf new file mode 100644 index 00000000..11d05468 --- /dev/null +++ b/hertzner/modules/load_balancer_target/main.tf @@ -0,0 +1,9 @@ +resource "hcloud_load_balancer_target" "main" { + type = var.settings.type + load_balancer_id = local.load_balancer_id + + server_id = try(local.server_id, null) + label_selector = try(var.settings.label_selector, null) + ip = try(var.settings.ip, null) + use_private_ip = try(var.settings.use_private_ip, null) +} diff --git a/hertzner/modules/managed_certificate/README.md b/hertzner/modules/managed_certificate/README.md new file mode 100644 index 00000000..473bd3b5 --- /dev/null +++ b/hertzner/modules/managed_certificate/README.md @@ -0,0 +1,22 @@ +# Managed Certificate Module + +Manages an hcloud_managed_certificate resource (Let's Encrypt). + +## Usage + +```hcl +managed_certificates = { + cert_web = { + name = "cert-web" + domain_names = ["example.com", "www.example.com"] + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Certificate name | Yes | +| domain_names | List of domain names | Yes | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/managed_certificate/_locals.tf b/hertzner/modules/managed_certificate/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/managed_certificate/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/managed_certificate/_outputs.tf b/hertzner/modules/managed_certificate/_outputs.tf new file mode 100644 index 00000000..e293c395 --- /dev/null +++ b/hertzner/modules/managed_certificate/_outputs.tf @@ -0,0 +1,35 @@ +output "id" { + value = hcloud_managed_certificate.main.id +} + +output "name" { + value = hcloud_managed_certificate.main.name +} + +output "domain_names" { + value = hcloud_managed_certificate.main.domain_names +} + +output "certificate" { + value = hcloud_managed_certificate.main.certificate +} + +output "fingerprint" { + value = hcloud_managed_certificate.main.fingerprint +} + +output "created" { + value = hcloud_managed_certificate.main.created +} + +output "not_valid_before" { + value = hcloud_managed_certificate.main.not_valid_before +} + +output "not_valid_after" { + value = hcloud_managed_certificate.main.not_valid_after +} + +output "labels" { + value = hcloud_managed_certificate.main.labels +} diff --git a/hertzner/modules/managed_certificate/_provider.tf b/hertzner/modules/managed_certificate/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/managed_certificate/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/managed_certificate/_variables.tf b/hertzner/modules/managed_certificate/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/managed_certificate/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/managed_certificate/main.tf b/hertzner/modules/managed_certificate/main.tf new file mode 100644 index 00000000..dd1c70f5 --- /dev/null +++ b/hertzner/modules/managed_certificate/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_managed_certificate" "main" { + name = var.settings.name + domain_names = var.settings.domain_names + labels = local.labels +} diff --git a/hertzner/modules/network/README.md b/hertzner/modules/network/README.md new file mode 100644 index 00000000..2617bc1b --- /dev/null +++ b/hertzner/modules/network/README.md @@ -0,0 +1,25 @@ +# Network Module + +Manages an hcloud_network resource. + +## Usage + +```hcl +networks = { + net_main = { + name = "network-main" + ip_range = "10.0.0.0/16" + labels = { environment = "production" } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Network name | Yes | +| ip_range | IP range in CIDR notation | Yes | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | +| expose_routes_to_vswitch | Expose routes to vSwitch | No | diff --git a/hertzner/modules/network/_locals.tf b/hertzner/modules/network/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/network/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/network/_outputs.tf b/hertzner/modules/network/_outputs.tf new file mode 100644 index 00000000..a48811fa --- /dev/null +++ b/hertzner/modules/network/_outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = hcloud_network.main.id +} + +output "name" { + value = hcloud_network.main.name +} + +output "ip_range" { + value = hcloud_network.main.ip_range +} + +output "labels" { + value = hcloud_network.main.labels +} diff --git a/hertzner/modules/network/_provider.tf b/hertzner/modules/network/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/network/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/network/_variables.tf b/hertzner/modules/network/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/network/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/network/main.tf b/hertzner/modules/network/main.tf new file mode 100644 index 00000000..dca56e53 --- /dev/null +++ b/hertzner/modules/network/main.tf @@ -0,0 +1,9 @@ +resource "hcloud_network" "main" { + name = var.settings.name + ip_range = var.settings.ip_range + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) + expose_routes_to_vswitch = try(var.settings.expose_routes_to_vswitch, false) +} diff --git a/hertzner/modules/network_route/README.md b/hertzner/modules/network_route/README.md new file mode 100644 index 00000000..1150ea10 --- /dev/null +++ b/hertzner/modules/network_route/README.md @@ -0,0 +1,24 @@ +# Network Route Module + +Manages an hcloud_network_route resource. + +## Usage + +```hcl +network_routes = { + route_default = { + network_ref = "net_main" + destination = "10.100.1.0/24" + gateway = "10.0.1.1" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| network_ref | Reference key to the parent network | Yes | +| destination | Destination network in CIDR notation | Yes | +| gateway | Gateway IP address | Yes | +| network_lz_key | Landing zone key for network (defaults to current) | No | diff --git a/hertzner/modules/network_route/_locals.tf b/hertzner/modules/network_route/_locals.tf new file mode 100644 index 00000000..f150ed6b --- /dev/null +++ b/hertzner/modules/network_route/_locals.tf @@ -0,0 +1,5 @@ +locals { + network_id = var.resources[ + try(var.settings.network_lz_key, var.client_config.landingzone_key) + ].networks[var.settings.network_ref].id +} diff --git a/hertzner/modules/network_route/_outputs.tf b/hertzner/modules/network_route/_outputs.tf new file mode 100644 index 00000000..91c459c6 --- /dev/null +++ b/hertzner/modules/network_route/_outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = hcloud_network_route.main.id +} + +output "network_id" { + value = hcloud_network_route.main.network_id +} + +output "destination" { + value = hcloud_network_route.main.destination +} + +output "gateway" { + value = hcloud_network_route.main.gateway +} diff --git a/hertzner/modules/network_route/_provider.tf b/hertzner/modules/network_route/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/network_route/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/network_route/_variables.tf b/hertzner/modules/network_route/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/network_route/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/network_route/main.tf b/hertzner/modules/network_route/main.tf new file mode 100644 index 00000000..2215178d --- /dev/null +++ b/hertzner/modules/network_route/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_network_route" "main" { + network_id = local.network_id + destination = var.settings.destination + gateway = var.settings.gateway +} diff --git a/hertzner/modules/network_subnet/README.md b/hertzner/modules/network_subnet/README.md new file mode 100644 index 00000000..5efec587 --- /dev/null +++ b/hertzner/modules/network_subnet/README.md @@ -0,0 +1,27 @@ +# Network Subnet Module + +Manages an hcloud_network_subnet resource. + +## Usage + +```hcl +network_subnets = { + subnet_main = { + network_ref = "net_main" + type = "cloud" + ip_range = "10.0.1.0/24" + network_zone = "eu-central" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| network_ref | Reference key to the parent network | Yes | +| type | Subnet type: server, cloud, or vswitch | Yes | +| ip_range | IP range in CIDR notation | Yes | +| network_zone | Network zone (e.g. eu-central) | Yes | +| vswitch_id | vSwitch ID (required if type is vswitch) | No | +| network_lz_key | Landing zone key for network (defaults to current) | No | diff --git a/hertzner/modules/network_subnet/_locals.tf b/hertzner/modules/network_subnet/_locals.tf new file mode 100644 index 00000000..f150ed6b --- /dev/null +++ b/hertzner/modules/network_subnet/_locals.tf @@ -0,0 +1,5 @@ +locals { + network_id = var.resources[ + try(var.settings.network_lz_key, var.client_config.landingzone_key) + ].networks[var.settings.network_ref].id +} diff --git a/hertzner/modules/network_subnet/_outputs.tf b/hertzner/modules/network_subnet/_outputs.tf new file mode 100644 index 00000000..290ab4e0 --- /dev/null +++ b/hertzner/modules/network_subnet/_outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = hcloud_network_subnet.main.id +} + +output "network_id" { + value = hcloud_network_subnet.main.network_id +} + +output "type" { + value = hcloud_network_subnet.main.type +} + +output "ip_range" { + value = hcloud_network_subnet.main.ip_range +} + +output "network_zone" { + value = hcloud_network_subnet.main.network_zone +} diff --git a/hertzner/modules/network_subnet/_provider.tf b/hertzner/modules/network_subnet/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/network_subnet/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/network_subnet/_variables.tf b/hertzner/modules/network_subnet/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/network_subnet/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/network_subnet/main.tf b/hertzner/modules/network_subnet/main.tf new file mode 100644 index 00000000..c8513f97 --- /dev/null +++ b/hertzner/modules/network_subnet/main.tf @@ -0,0 +1,8 @@ +resource "hcloud_network_subnet" "main" { + network_id = local.network_id + type = var.settings.type + ip_range = var.settings.ip_range + network_zone = var.settings.network_zone + + vswitch_id = try(var.settings.vswitch_id, null) +} diff --git a/hertzner/modules/placement_group/README.md b/hertzner/modules/placement_group/README.md new file mode 100644 index 00000000..8a9d5dbc --- /dev/null +++ b/hertzner/modules/placement_group/README.md @@ -0,0 +1,22 @@ +# Placement Group Module + +Manages an hcloud_placement_group resource. + +## Usage + +```hcl +placement_groups = { + pg_web = { + name = "pg-web-spread" + type = "spread" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Placement group name | Yes | +| type | Placement group type (default: spread) | No | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/placement_group/_locals.tf b/hertzner/modules/placement_group/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/placement_group/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/placement_group/_outputs.tf b/hertzner/modules/placement_group/_outputs.tf new file mode 100644 index 00000000..8047c28b --- /dev/null +++ b/hertzner/modules/placement_group/_outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = hcloud_placement_group.main.id +} + +output "name" { + value = hcloud_placement_group.main.name +} + +output "type" { + value = hcloud_placement_group.main.type +} + +output "labels" { + value = hcloud_placement_group.main.labels +} diff --git a/hertzner/modules/placement_group/_provider.tf b/hertzner/modules/placement_group/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/placement_group/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/placement_group/_variables.tf b/hertzner/modules/placement_group/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/placement_group/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/placement_group/main.tf b/hertzner/modules/placement_group/main.tf new file mode 100644 index 00000000..8c25737e --- /dev/null +++ b/hertzner/modules/placement_group/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_placement_group" "main" { + name = var.settings.name + type = try(var.settings.type, "spread") + labels = local.labels +} diff --git a/hertzner/modules/primary_ip/README.md b/hertzner/modules/primary_ip/README.md new file mode 100644 index 00000000..20c61e02 --- /dev/null +++ b/hertzner/modules/primary_ip/README.md @@ -0,0 +1,30 @@ +# Primary IP Module + +Manages an hcloud_primary_ip resource. + +## Usage + +```hcl +primary_ips = { + pip_web = { + name = "primary-ip-web" + type = "ipv4" + assignee_type = "server" + auto_delete = false + location = "fsn1" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Primary IP name | Yes | +| type | IP type: ipv4 or ipv6 | Yes | +| assignee_type | Assignee type (default: server) | No | +| auto_delete | Auto delete when unassigned | No | +| location | Location name | No | +| datacenter | Datacenter name (deprecated, use location) | No | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | diff --git a/hertzner/modules/primary_ip/_locals.tf b/hertzner/modules/primary_ip/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/primary_ip/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/primary_ip/_outputs.tf b/hertzner/modules/primary_ip/_outputs.tf new file mode 100644 index 00000000..73efba3e --- /dev/null +++ b/hertzner/modules/primary_ip/_outputs.tf @@ -0,0 +1,27 @@ +output "id" { + value = hcloud_primary_ip.main.id +} + +output "name" { + value = hcloud_primary_ip.main.name +} + +output "type" { + value = hcloud_primary_ip.main.type +} + +output "ip_address" { + value = hcloud_primary_ip.main.ip_address +} + +output "location" { + value = hcloud_primary_ip.main.location +} + +output "assignee_type" { + value = hcloud_primary_ip.main.assignee_type +} + +output "labels" { + value = hcloud_primary_ip.main.labels +} diff --git a/hertzner/modules/primary_ip/_provider.tf b/hertzner/modules/primary_ip/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/primary_ip/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/primary_ip/_variables.tf b/hertzner/modules/primary_ip/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/primary_ip/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/primary_ip/main.tf b/hertzner/modules/primary_ip/main.tf new file mode 100644 index 00000000..794b9e13 --- /dev/null +++ b/hertzner/modules/primary_ip/main.tf @@ -0,0 +1,13 @@ +resource "hcloud_primary_ip" "main" { + name = var.settings.name + type = var.settings.type + assignee_type = try(var.settings.assignee_type, "server") + auto_delete = try(var.settings.auto_delete, false) + + datacenter = try(var.settings.datacenter, null) + location = try(var.settings.location, null) + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) +} diff --git a/hertzner/modules/rdns/README.md b/hertzner/modules/rdns/README.md new file mode 100644 index 00000000..fadafe66 --- /dev/null +++ b/hertzner/modules/rdns/README.md @@ -0,0 +1,26 @@ +# Reverse DNS Module + +Manages an hcloud_rdns resource. + +## Usage + +```hcl +rdns_records = { + rdns_web = { + dns_ptr = "web.example.com" + ip_address = "1.2.3.4" + server_ref = "srv_web_01" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| dns_ptr | DNS pointer (hostname) | Yes | +| ip_address | IP address for rDNS | Yes | +| server_ref | Reference to server (mutually exclusive with others) | No | +| primary_ip_ref | Reference to primary IP | No | +| floating_ip_ref | Reference to floating IP | No | +| load_balancer_ref | Reference to load balancer | No | diff --git a/hertzner/modules/rdns/_locals.tf b/hertzner/modules/rdns/_locals.tf new file mode 100644 index 00000000..9cfdb988 --- /dev/null +++ b/hertzner/modules/rdns/_locals.tf @@ -0,0 +1,29 @@ +locals { + server_id = try( + var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id, + null + ) + + primary_ip_id = try( + var.resources[ + try(var.settings.primary_ip_lz_key, var.client_config.landingzone_key) + ].primary_ips[var.settings.primary_ip_ref].id, + null + ) + + floating_ip_id = try( + var.resources[ + try(var.settings.floating_ip_lz_key, var.client_config.landingzone_key) + ].floating_ips[var.settings.floating_ip_ref].id, + null + ) + + load_balancer_id = try( + var.resources[ + try(var.settings.load_balancer_lz_key, var.client_config.landingzone_key) + ].load_balancers[var.settings.load_balancer_ref].id, + null + ) +} diff --git a/hertzner/modules/rdns/_outputs.tf b/hertzner/modules/rdns/_outputs.tf new file mode 100644 index 00000000..b41cebc1 --- /dev/null +++ b/hertzner/modules/rdns/_outputs.tf @@ -0,0 +1,11 @@ +output "id" { + value = hcloud_rdns.main.id +} + +output "dns_ptr" { + value = hcloud_rdns.main.dns_ptr +} + +output "ip_address" { + value = hcloud_rdns.main.ip_address +} diff --git a/hertzner/modules/rdns/_provider.tf b/hertzner/modules/rdns/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/rdns/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/rdns/_variables.tf b/hertzner/modules/rdns/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/rdns/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/rdns/main.tf b/hertzner/modules/rdns/main.tf new file mode 100644 index 00000000..a37d7c8f --- /dev/null +++ b/hertzner/modules/rdns/main.tf @@ -0,0 +1,9 @@ +resource "hcloud_rdns" "main" { + dns_ptr = var.settings.dns_ptr + ip_address = var.settings.ip_address + + server_id = try(local.server_id, null) + primary_ip_id = try(local.primary_ip_id, null) + floating_ip_id = try(local.floating_ip_id, null) + load_balancer_id = try(local.load_balancer_id, null) +} diff --git a/hertzner/modules/server/README.md b/hertzner/modules/server/README.md new file mode 100644 index 00000000..facd25f8 --- /dev/null +++ b/hertzner/modules/server/README.md @@ -0,0 +1,49 @@ +# Server Module + +Manages an hcloud_server resource. + +## Usage + +```hcl +servers = { + srv_web_01 = { + name = "web-01" + server_type = "cx22" + image = "ubuntu-24.04" + location = "fsn1" + ssh_keys = ["my-ssh-key"] + labels = { role = "web" } + + public_net = { + ipv4_enabled = true + ipv6_enabled = true + } + + networks = { + net_main = { + network_ref = "net_main" + ip = "10.0.1.10" + } + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Server name | Yes | +| server_type | Server type (e.g. cx22, cx32) | Yes | +| image | Image name or ID | Yes | +| location | Location name | No | +| ssh_keys | List of SSH key names/IDs | No | +| user_data | Cloud-Init user data | No | +| labels | Key-value label pairs | No | +| backups | Enable backups | No | +| firewall_ids_ref | List of firewall reference keys | No | +| placement_group_ref | Placement group reference key | No | +| public_net | Public network configuration block | No | +| networks | Map of network attachments | No | +| delete_protection | Enable delete protection | No | +| rebuild_protection | Enable rebuild protection | No | diff --git a/hertzner/modules/server/_locals.tf b/hertzner/modules/server/_locals.tf new file mode 100644 index 00000000..8b964e19 --- /dev/null +++ b/hertzner/modules/server/_locals.tf @@ -0,0 +1,34 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + firewall_ids = try([ + for ref in var.settings.firewall_ids_ref : + var.resources[ + try(var.settings.firewall_lz_key, var.client_config.landingzone_key) + ].firewalls[ref].id + ], null) + + placement_group_id = try( + var.resources[ + try(var.settings.placement_group_lz_key, var.client_config.landingzone_key) + ].placement_groups[var.settings.placement_group_ref].id, + null + ) + + public_net_ipv4 = try( + var.resources[ + try(var.settings.public_net.ipv4_lz_key, var.client_config.landingzone_key) + ].primary_ips[var.settings.public_net.ipv4_ref].id, + null + ) + + public_net_ipv6 = try( + var.resources[ + try(var.settings.public_net.ipv6_lz_key, var.client_config.landingzone_key) + ].primary_ips[var.settings.public_net.ipv6_ref].id, + null + ) +} diff --git a/hertzner/modules/server/_outputs.tf b/hertzner/modules/server/_outputs.tf new file mode 100644 index 00000000..e8dc5b27 --- /dev/null +++ b/hertzner/modules/server/_outputs.tf @@ -0,0 +1,43 @@ +output "id" { + value = hcloud_server.main.id +} + +output "name" { + value = hcloud_server.main.name +} + +output "server_type" { + value = hcloud_server.main.server_type +} + +output "image" { + value = hcloud_server.main.image +} + +output "location" { + value = hcloud_server.main.location +} + +output "ipv4_address" { + value = hcloud_server.main.ipv4_address +} + +output "ipv6_address" { + value = hcloud_server.main.ipv6_address +} + +output "status" { + value = hcloud_server.main.status +} + +output "labels" { + value = hcloud_server.main.labels +} + +output "placement_group_id" { + value = hcloud_server.main.placement_group_id +} + +output "primary_disk_size" { + value = hcloud_server.main.primary_disk_size +} diff --git a/hertzner/modules/server/_provider.tf b/hertzner/modules/server/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/server/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/server/_variables.tf b/hertzner/modules/server/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/server/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/server/main.tf b/hertzner/modules/server/main.tf new file mode 100644 index 00000000..da63594b --- /dev/null +++ b/hertzner/modules/server/main.tf @@ -0,0 +1,44 @@ +resource "hcloud_server" "main" { + name = var.settings.name + server_type = var.settings.server_type + image = try(var.settings.image, null) + location = try(var.settings.location, null) + + user_data = try(var.settings.user_data, null) + ssh_keys = try(var.settings.ssh_keys, null) + + labels = local.labels + + backups = try(var.settings.backups, false) + keep_disk = try(var.settings.keep_disk, false) + iso = try(var.settings.iso, null) + rescue = try(var.settings.rescue, null) + firewall_ids = try(local.firewall_ids, null) + placement_group_id = try(local.placement_group_id, null) + delete_protection = try(var.settings.delete_protection, false) + rebuild_protection = try(var.settings.rebuild_protection, false) + allow_deprecated_images = try(var.settings.allow_deprecated_images, false) + shutdown_before_deletion = try(var.settings.shutdown_before_deletion, false) + ignore_remote_firewall_ids = try(var.settings.ignore_remote_firewall_ids, false) + + dynamic "public_net" { + for_each = can(var.settings.public_net) ? [1] : [] + content { + ipv4_enabled = try(var.settings.public_net.ipv4_enabled, true) + ipv6_enabled = try(var.settings.public_net.ipv6_enabled, true) + ipv4 = try(local.public_net_ipv4, null) + ipv6 = try(local.public_net_ipv6, null) + } + } + + dynamic "network" { + for_each = try(var.settings.networks, {}) + content { + network_id = var.resources[ + try(network.value.network_lz_key, var.client_config.landingzone_key) + ].networks[network.value.network_ref].id + ip = try(network.value.ip, null) + alias_ips = try(network.value.alias_ips, null) + } + } +} diff --git a/hertzner/modules/server_network/README.md b/hertzner/modules/server_network/README.md new file mode 100644 index 00000000..16c11f98 --- /dev/null +++ b/hertzner/modules/server_network/README.md @@ -0,0 +1,25 @@ +# Server Network Module + +Manages an hcloud_server_network resource. + +## Usage + +```hcl +server_networks = { + srvnet_web_main = { + server_ref = "srv_web_01" + network_ref = "net_main" + ip = "10.0.1.10" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| server_ref | Reference key to the server | Yes | +| network_ref | Reference key to the network | No | +| subnet_ref | Reference key to the subnet | No | +| ip | IP address to assign | No | +| alias_ips | Set of alias IPs | No | diff --git a/hertzner/modules/server_network/_locals.tf b/hertzner/modules/server_network/_locals.tf new file mode 100644 index 00000000..705e31e6 --- /dev/null +++ b/hertzner/modules/server_network/_locals.tf @@ -0,0 +1,19 @@ +locals { + server_id = var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id + + network_id = try( + var.resources[ + try(var.settings.network_lz_key, var.client_config.landingzone_key) + ].networks[var.settings.network_ref].id, + null + ) + + subnet_id = try( + var.resources[ + try(var.settings.subnet_lz_key, var.client_config.landingzone_key) + ].network_subnets[var.settings.subnet_ref].id, + null + ) +} diff --git a/hertzner/modules/server_network/_outputs.tf b/hertzner/modules/server_network/_outputs.tf new file mode 100644 index 00000000..177e29c3 --- /dev/null +++ b/hertzner/modules/server_network/_outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = hcloud_server_network.main.id +} + +output "server_id" { + value = hcloud_server_network.main.server_id +} + +output "network_id" { + value = hcloud_server_network.main.network_id +} + +output "ip" { + value = hcloud_server_network.main.ip +} + +output "mac_address" { + value = hcloud_server_network.main.mac_address +} diff --git a/hertzner/modules/server_network/_provider.tf b/hertzner/modules/server_network/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/server_network/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/server_network/_variables.tf b/hertzner/modules/server_network/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/server_network/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/server_network/main.tf b/hertzner/modules/server_network/main.tf new file mode 100644 index 00000000..d93ba117 --- /dev/null +++ b/hertzner/modules/server_network/main.tf @@ -0,0 +1,7 @@ +resource "hcloud_server_network" "main" { + server_id = local.server_id + network_id = try(local.network_id, null) + subnet_id = try(local.subnet_id, null) + ip = try(var.settings.ip, null) + alias_ips = try(var.settings.alias_ips, null) +} diff --git a/hertzner/modules/snapshot/README.md b/hertzner/modules/snapshot/README.md new file mode 100644 index 00000000..4688d31e --- /dev/null +++ b/hertzner/modules/snapshot/README.md @@ -0,0 +1,22 @@ +# Snapshot Module + +Manages an hcloud_snapshot resource. + +## Usage + +```hcl +snapshots = { + snap_web_01 = { + server_ref = "srv_web_01" + description = "Pre-upgrade snapshot" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| server_ref | Reference key to the server | Yes | +| description | Snapshot description | No | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/snapshot/_locals.tf b/hertzner/modules/snapshot/_locals.tf new file mode 100644 index 00000000..163cd352 --- /dev/null +++ b/hertzner/modules/snapshot/_locals.tf @@ -0,0 +1,10 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + server_id = var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id +} diff --git a/hertzner/modules/snapshot/_outputs.tf b/hertzner/modules/snapshot/_outputs.tf new file mode 100644 index 00000000..3722d289 --- /dev/null +++ b/hertzner/modules/snapshot/_outputs.tf @@ -0,0 +1,15 @@ +output "id" { + value = hcloud_snapshot.main.id +} + +output "server_id" { + value = hcloud_snapshot.main.server_id +} + +output "description" { + value = hcloud_snapshot.main.description +} + +output "labels" { + value = hcloud_snapshot.main.labels +} diff --git a/hertzner/modules/snapshot/_provider.tf b/hertzner/modules/snapshot/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/snapshot/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/snapshot/_variables.tf b/hertzner/modules/snapshot/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/snapshot/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/snapshot/main.tf b/hertzner/modules/snapshot/main.tf new file mode 100644 index 00000000..c1fb17b9 --- /dev/null +++ b/hertzner/modules/snapshot/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_snapshot" "main" { + server_id = local.server_id + description = try(var.settings.description, null) + labels = local.labels +} diff --git a/hertzner/modules/ssh_key/README.md b/hertzner/modules/ssh_key/README.md new file mode 100644 index 00000000..43d3dbe8 --- /dev/null +++ b/hertzner/modules/ssh_key/README.md @@ -0,0 +1,22 @@ +# SSH Key Module + +Manages an hcloud_ssh_key resource. + +## Usage + +```hcl +ssh_keys = { + key_deploy = { + name = "deploy-key" + public_key = file("~/.ssh/id_rsa.pub") + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | SSH key name | Yes | +| public_key | Public key content | Yes | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/ssh_key/_locals.tf b/hertzner/modules/ssh_key/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/ssh_key/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/ssh_key/_outputs.tf b/hertzner/modules/ssh_key/_outputs.tf new file mode 100644 index 00000000..bbc1b137 --- /dev/null +++ b/hertzner/modules/ssh_key/_outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = hcloud_ssh_key.main.id +} + +output "name" { + value = hcloud_ssh_key.main.name +} + +output "public_key" { + value = hcloud_ssh_key.main.public_key +} + +output "fingerprint" { + value = hcloud_ssh_key.main.fingerprint +} + +output "labels" { + value = hcloud_ssh_key.main.labels +} diff --git a/hertzner/modules/ssh_key/_provider.tf b/hertzner/modules/ssh_key/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/ssh_key/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/ssh_key/_variables.tf b/hertzner/modules/ssh_key/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/ssh_key/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/ssh_key/main.tf b/hertzner/modules/ssh_key/main.tf new file mode 100644 index 00000000..b897966a --- /dev/null +++ b/hertzner/modules/ssh_key/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_ssh_key" "main" { + name = var.settings.name + public_key = var.settings.public_key + labels = local.labels +} diff --git a/hertzner/modules/storage_box/README.md b/hertzner/modules/storage_box/README.md new file mode 100644 index 00000000..f071b155 --- /dev/null +++ b/hertzner/modules/storage_box/README.md @@ -0,0 +1,33 @@ +# Storage Box Module + +Manages an hcloud_storage_box resource. + +## Usage + +```hcl +storage_boxes = { + sb_backup = { + name = "backup-storage" + location = "fsn1" + storage_box_type = "storagebox-10" + password = "secure-password" + access_settings = { + ssh_enabled = true + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Storage box name | Yes | +| location | Location | Yes | +| storage_box_type | Storage box type | Yes | +| password | Password (sensitive) | Yes | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | +| ssh_keys | Set of SSH public keys | No | +| access_settings | Access settings block | No | +| snapshot_plan | Snapshot plan configuration | No | diff --git a/hertzner/modules/storage_box/_locals.tf b/hertzner/modules/storage_box/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/storage_box/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/storage_box/_outputs.tf b/hertzner/modules/storage_box/_outputs.tf new file mode 100644 index 00000000..e4458208 --- /dev/null +++ b/hertzner/modules/storage_box/_outputs.tf @@ -0,0 +1,36 @@ +output "id" { + value = hcloud_storage_box.main.id +} + +output "name" { + value = hcloud_storage_box.main.name +} + +output "location" { + value = hcloud_storage_box.main.location +} + +output "storage_box_type" { + value = hcloud_storage_box.main.storage_box_type +} + +output "server" { + value = hcloud_storage_box.main.server +} + +output "system" { + value = hcloud_storage_box.main.system +} + +output "username" { + value = hcloud_storage_box.main.username +} + +output "labels" { + value = hcloud_storage_box.main.labels +} + +output "password" { + value = hcloud_storage_box.main.password + sensitive = true +} diff --git a/hertzner/modules/storage_box/_provider.tf b/hertzner/modules/storage_box/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/storage_box/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/storage_box/_variables.tf b/hertzner/modules/storage_box/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/storage_box/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/storage_box/main.tf b/hertzner/modules/storage_box/main.tf new file mode 100644 index 00000000..7506f710 --- /dev/null +++ b/hertzner/modules/storage_box/main.tf @@ -0,0 +1,27 @@ +resource "hcloud_storage_box" "main" { + name = var.settings.name + location = var.settings.location + storage_box_type = var.settings.storage_box_type + password = var.settings.password + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) + ssh_keys = try(var.settings.ssh_keys, null) + + access_settings = can(var.settings.access_settings) ? { + reachable_externally = try(var.settings.access_settings.reachable_externally, null) + samba_enabled = try(var.settings.access_settings.samba_enabled, null) + ssh_enabled = try(var.settings.access_settings.ssh_enabled, null) + webdav_enabled = try(var.settings.access_settings.webdav_enabled, null) + zfs_enabled = try(var.settings.access_settings.zfs_enabled, null) + } : null + + snapshot_plan = can(var.settings.snapshot_plan) ? { + hour = var.settings.snapshot_plan.hour + max_snapshots = var.settings.snapshot_plan.max_snapshots + minute = var.settings.snapshot_plan.minute + day_of_month = try(var.settings.snapshot_plan.day_of_month, null) + day_of_week = try(var.settings.snapshot_plan.day_of_week, null) + } : null +} diff --git a/hertzner/modules/storage_box_snapshot/README.md b/hertzner/modules/storage_box_snapshot/README.md new file mode 100644 index 00000000..ef89dcb3 --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/README.md @@ -0,0 +1,22 @@ +# Storage Box Snapshot Module + +Manages an hcloud_storage_box_snapshot resource. + +## Usage + +```hcl +storage_box_snapshots = { + sbs_backup = { + storage_box_ref = "sb_backup" + description = "Weekly snapshot" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| storage_box_ref | Reference key to the storage box | Yes | +| description | Snapshot description | No | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/storage_box_snapshot/_locals.tf b/hertzner/modules/storage_box_snapshot/_locals.tf new file mode 100644 index 00000000..a39724f0 --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/_locals.tf @@ -0,0 +1,10 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + storage_box_id = var.resources[ + try(var.settings.storage_box_lz_key, var.client_config.landingzone_key) + ].storage_boxes[var.settings.storage_box_ref].id +} diff --git a/hertzner/modules/storage_box_snapshot/_outputs.tf b/hertzner/modules/storage_box_snapshot/_outputs.tf new file mode 100644 index 00000000..72fc036a --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/_outputs.tf @@ -0,0 +1,23 @@ +output "id" { + value = hcloud_storage_box_snapshot.main.id +} + +output "storage_box_id" { + value = hcloud_storage_box_snapshot.main.storage_box_id +} + +output "description" { + value = hcloud_storage_box_snapshot.main.description +} + +output "is_automatic" { + value = hcloud_storage_box_snapshot.main.is_automatic +} + +output "name" { + value = hcloud_storage_box_snapshot.main.name +} + +output "labels" { + value = hcloud_storage_box_snapshot.main.labels +} diff --git a/hertzner/modules/storage_box_snapshot/_provider.tf b/hertzner/modules/storage_box_snapshot/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/storage_box_snapshot/_variables.tf b/hertzner/modules/storage_box_snapshot/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/storage_box_snapshot/main.tf b/hertzner/modules/storage_box_snapshot/main.tf new file mode 100644 index 00000000..bdbd389d --- /dev/null +++ b/hertzner/modules/storage_box_snapshot/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_storage_box_snapshot" "main" { + storage_box_id = local.storage_box_id + description = try(var.settings.description, null) + labels = local.labels +} diff --git a/hertzner/modules/storage_box_subaccount/README.md b/hertzner/modules/storage_box_subaccount/README.md new file mode 100644 index 00000000..6715999d --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/README.md @@ -0,0 +1,32 @@ +# Storage Box Subaccount Module + +Manages an hcloud_storage_box_subaccount resource. + +## Usage + +```hcl +storage_box_subaccounts = { + sbsa_app = { + storage_box_ref = "sb_backup" + home_directory = "/app-backups" + password = "secure-password" + name = "app-backup-user" + access_settings = { + ssh_enabled = true + readonly = false + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| storage_box_ref | Reference key to the storage box | Yes | +| home_directory | Home directory path | Yes | +| password | Password (sensitive) | Yes | +| name | Subaccount name | No | +| description | Description | No | +| labels | Key-value label pairs | No | +| access_settings | Access settings block | No | diff --git a/hertzner/modules/storage_box_subaccount/_locals.tf b/hertzner/modules/storage_box_subaccount/_locals.tf new file mode 100644 index 00000000..a39724f0 --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/_locals.tf @@ -0,0 +1,10 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + storage_box_id = var.resources[ + try(var.settings.storage_box_lz_key, var.client_config.landingzone_key) + ].storage_boxes[var.settings.storage_box_ref].id +} diff --git a/hertzner/modules/storage_box_subaccount/_outputs.tf b/hertzner/modules/storage_box_subaccount/_outputs.tf new file mode 100644 index 00000000..d41405b5 --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/_outputs.tf @@ -0,0 +1,28 @@ +output "id" { + value = hcloud_storage_box_subaccount.main.id +} + +output "storage_box_id" { + value = hcloud_storage_box_subaccount.main.storage_box_id +} + +output "name" { + value = hcloud_storage_box_subaccount.main.name +} + +output "server" { + value = hcloud_storage_box_subaccount.main.server +} + +output "username" { + value = hcloud_storage_box_subaccount.main.username +} + +output "labels" { + value = hcloud_storage_box_subaccount.main.labels +} + +output "password" { + value = hcloud_storage_box_subaccount.main.password + sensitive = true +} diff --git a/hertzner/modules/storage_box_subaccount/_provider.tf b/hertzner/modules/storage_box_subaccount/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/storage_box_subaccount/_variables.tf b/hertzner/modules/storage_box_subaccount/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/storage_box_subaccount/main.tf b/hertzner/modules/storage_box_subaccount/main.tf new file mode 100644 index 00000000..92676489 --- /dev/null +++ b/hertzner/modules/storage_box_subaccount/main.tf @@ -0,0 +1,17 @@ +resource "hcloud_storage_box_subaccount" "main" { + storage_box_id = local.storage_box_id + home_directory = var.settings.home_directory + password = var.settings.password + + name = try(var.settings.name, null) + description = try(var.settings.description, null) + labels = local.labels + + access_settings = can(var.settings.access_settings) ? { + reachable_externally = try(var.settings.access_settings.reachable_externally, null) + readonly = try(var.settings.access_settings.readonly, null) + samba_enabled = try(var.settings.access_settings.samba_enabled, null) + ssh_enabled = try(var.settings.access_settings.ssh_enabled, null) + webdav_enabled = try(var.settings.access_settings.webdav_enabled, null) + } : null +} diff --git a/hertzner/modules/uploaded_certificate/README.md b/hertzner/modules/uploaded_certificate/README.md new file mode 100644 index 00000000..9270437c --- /dev/null +++ b/hertzner/modules/uploaded_certificate/README.md @@ -0,0 +1,24 @@ +# Uploaded Certificate Module + +Manages an hcloud_uploaded_certificate resource. + +## Usage + +```hcl +uploaded_certificates = { + cert_custom = { + name = "cert-custom" + private_key = file("certs/private.key") + certificate = file("certs/cert.pem") + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Certificate name | Yes | +| private_key | Private key PEM content (sensitive) | Yes | +| certificate | Certificate PEM content | Yes | +| labels | Key-value label pairs | No | diff --git a/hertzner/modules/uploaded_certificate/_locals.tf b/hertzner/modules/uploaded_certificate/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/uploaded_certificate/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/uploaded_certificate/_outputs.tf b/hertzner/modules/uploaded_certificate/_outputs.tf new file mode 100644 index 00000000..8ae9a0d7 --- /dev/null +++ b/hertzner/modules/uploaded_certificate/_outputs.tf @@ -0,0 +1,36 @@ +output "id" { + value = hcloud_uploaded_certificate.main.id +} + +output "name" { + value = hcloud_uploaded_certificate.main.name +} + +output "certificate" { + value = hcloud_uploaded_certificate.main.certificate + sensitive = true +} + +output "domain_names" { + value = hcloud_uploaded_certificate.main.domain_names +} + +output "fingerprint" { + value = hcloud_uploaded_certificate.main.fingerprint +} + +output "created" { + value = hcloud_uploaded_certificate.main.created +} + +output "not_valid_before" { + value = hcloud_uploaded_certificate.main.not_valid_before +} + +output "not_valid_after" { + value = hcloud_uploaded_certificate.main.not_valid_after +} + +output "labels" { + value = hcloud_uploaded_certificate.main.labels +} diff --git a/hertzner/modules/uploaded_certificate/_provider.tf b/hertzner/modules/uploaded_certificate/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/uploaded_certificate/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/uploaded_certificate/_variables.tf b/hertzner/modules/uploaded_certificate/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/uploaded_certificate/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/uploaded_certificate/main.tf b/hertzner/modules/uploaded_certificate/main.tf new file mode 100644 index 00000000..13043c78 --- /dev/null +++ b/hertzner/modules/uploaded_certificate/main.tf @@ -0,0 +1,6 @@ +resource "hcloud_uploaded_certificate" "main" { + name = var.settings.name + private_key = var.settings.private_key + certificate = var.settings.certificate + labels = local.labels +} diff --git a/hertzner/modules/volume/README.md b/hertzner/modules/volume/README.md new file mode 100644 index 00000000..d3654bfa --- /dev/null +++ b/hertzner/modules/volume/README.md @@ -0,0 +1,29 @@ +# Volume Module + +Manages an hcloud_volume resource. + +## Usage + +```hcl +volumes = { + vol_data = { + name = "vol-data-01" + size = 50 + location = "fsn1" + format = "ext4" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Volume name | Yes | +| size | Volume size in GB | Yes | +| location | Location (conflicts with server_ref) | No | +| server_ref | Server reference key (conflicts with location) | No | +| automount | Auto-mount on server (requires server_ref) | No | +| format | Filesystem format: ext4 or xfs | No | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | diff --git a/hertzner/modules/volume/_locals.tf b/hertzner/modules/volume/_locals.tf new file mode 100644 index 00000000..cd864dad --- /dev/null +++ b/hertzner/modules/volume/_locals.tf @@ -0,0 +1,13 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + server_id = try( + var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id, + null + ) +} diff --git a/hertzner/modules/volume/_outputs.tf b/hertzner/modules/volume/_outputs.tf new file mode 100644 index 00000000..25ecc97c --- /dev/null +++ b/hertzner/modules/volume/_outputs.tf @@ -0,0 +1,27 @@ +output "id" { + value = hcloud_volume.main.id +} + +output "name" { + value = hcloud_volume.main.name +} + +output "size" { + value = hcloud_volume.main.size +} + +output "location" { + value = hcloud_volume.main.location +} + +output "server_id" { + value = hcloud_volume.main.server_id +} + +output "linux_device" { + value = hcloud_volume.main.linux_device +} + +output "labels" { + value = hcloud_volume.main.labels +} diff --git a/hertzner/modules/volume/_provider.tf b/hertzner/modules/volume/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/volume/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/volume/_variables.tf b/hertzner/modules/volume/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/volume/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/volume/main.tf b/hertzner/modules/volume/main.tf new file mode 100644 index 00000000..2a239d5b --- /dev/null +++ b/hertzner/modules/volume/main.tf @@ -0,0 +1,13 @@ +resource "hcloud_volume" "main" { + name = var.settings.name + size = var.settings.size + location = try(var.settings.location, null) + + server_id = try(local.server_id, null) + automount = try(var.settings.automount, null) + format = try(var.settings.format, null) + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) +} diff --git a/hertzner/modules/volume_attachment/README.md b/hertzner/modules/volume_attachment/README.md new file mode 100644 index 00000000..8c718aca --- /dev/null +++ b/hertzner/modules/volume_attachment/README.md @@ -0,0 +1,23 @@ +# Volume Attachment Module + +Manages an hcloud_volume_attachment resource. + +## Usage + +```hcl +volume_attachments = { + va_data = { + volume_ref = "vol_data" + server_ref = "srv_web_01" + automount = true + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| volume_ref | Reference key to the volume | Yes | +| server_ref | Reference key to the server | Yes | +| automount | Auto-mount the volume | No | diff --git a/hertzner/modules/volume_attachment/_locals.tf b/hertzner/modules/volume_attachment/_locals.tf new file mode 100644 index 00000000..e8e3c69f --- /dev/null +++ b/hertzner/modules/volume_attachment/_locals.tf @@ -0,0 +1,9 @@ +locals { + volume_id = var.resources[ + try(var.settings.volume_lz_key, var.client_config.landingzone_key) + ].volumes[var.settings.volume_ref].id + + server_id = var.resources[ + try(var.settings.server_lz_key, var.client_config.landingzone_key) + ].servers[var.settings.server_ref].id +} diff --git a/hertzner/modules/volume_attachment/_outputs.tf b/hertzner/modules/volume_attachment/_outputs.tf new file mode 100644 index 00000000..0f06681e --- /dev/null +++ b/hertzner/modules/volume_attachment/_outputs.tf @@ -0,0 +1,11 @@ +output "id" { + value = hcloud_volume_attachment.main.id +} + +output "volume_id" { + value = hcloud_volume_attachment.main.volume_id +} + +output "server_id" { + value = hcloud_volume_attachment.main.server_id +} diff --git a/hertzner/modules/volume_attachment/_provider.tf b/hertzner/modules/volume_attachment/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/volume_attachment/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/volume_attachment/_variables.tf b/hertzner/modules/volume_attachment/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/volume_attachment/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/volume_attachment/main.tf b/hertzner/modules/volume_attachment/main.tf new file mode 100644 index 00000000..45a247f5 --- /dev/null +++ b/hertzner/modules/volume_attachment/main.tf @@ -0,0 +1,5 @@ +resource "hcloud_volume_attachment" "main" { + volume_id = local.volume_id + server_id = local.server_id + automount = try(var.settings.automount, null) +} diff --git a/hertzner/modules/zone/README.md b/hertzner/modules/zone/README.md new file mode 100644 index 00000000..2238813f --- /dev/null +++ b/hertzner/modules/zone/README.md @@ -0,0 +1,26 @@ +# DNS Zone Module + +Manages an hcloud_zone resource. + +## Usage + +```hcl +zones = { + zone_example = { + name = "example.com" + mode = "primary" + ttl = 3600 + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| name | Zone name (domain) | Yes | +| mode | Zone mode | Yes | +| ttl | Default TTL | No | +| labels | Key-value label pairs | No | +| delete_protection | Enable delete protection | No | +| primary_nameservers | Map of primary nameserver configurations | No | diff --git a/hertzner/modules/zone/_locals.tf b/hertzner/modules/zone/_locals.tf new file mode 100644 index 00000000..91109f20 --- /dev/null +++ b/hertzner/modules/zone/_locals.tf @@ -0,0 +1,6 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) +} diff --git a/hertzner/modules/zone/_outputs.tf b/hertzner/modules/zone/_outputs.tf new file mode 100644 index 00000000..9deb1857 --- /dev/null +++ b/hertzner/modules/zone/_outputs.tf @@ -0,0 +1,23 @@ +output "id" { + value = hcloud_zone.main.id +} + +output "name" { + value = hcloud_zone.main.name +} + +output "mode" { + value = hcloud_zone.main.mode +} + +output "ttl" { + value = hcloud_zone.main.ttl +} + +output "registrar" { + value = hcloud_zone.main.registrar +} + +output "labels" { + value = hcloud_zone.main.labels +} diff --git a/hertzner/modules/zone/_provider.tf b/hertzner/modules/zone/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/zone/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/zone/_variables.tf b/hertzner/modules/zone/_variables.tf new file mode 100644 index 00000000..bad3402f --- /dev/null +++ b/hertzner/modules/zone/_variables.tf @@ -0,0 +1,14 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/zone/main.tf b/hertzner/modules/zone/main.tf new file mode 100644 index 00000000..df704919 --- /dev/null +++ b/hertzner/modules/zone/main.tf @@ -0,0 +1,18 @@ +resource "hcloud_zone" "main" { + name = var.settings.name + mode = var.settings.mode + ttl = try(var.settings.ttl, null) + + labels = local.labels + + delete_protection = try(var.settings.delete_protection, false) + + primary_nameservers = can(var.settings.primary_nameservers) ? [ + for ns in var.settings.primary_nameservers : { + address = ns.address + port = try(ns.port, null) + tsig_algorithm = try(ns.tsig_algorithm, null) + tsig_key = try(ns.tsig_key, null) + } + ] : null +} diff --git a/hertzner/modules/zone_record/README.md b/hertzner/modules/zone_record/README.md new file mode 100644 index 00000000..16ca3a45 --- /dev/null +++ b/hertzner/modules/zone_record/README.md @@ -0,0 +1,26 @@ +# DNS Zone Record Module + +Manages an hcloud_zone_record resource. Use hcloud_zone_rrset where possible instead. + +## Usage + +```hcl +zone_records = { + rec_www = { + zone_ref = "zone_example" + name = "www" + type = "A" + value = "1.2.3.4" + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| zone_ref | Reference key to the DNS zone | Yes | +| name | Record name | Yes | +| type | Record type (A, AAAA, CNAME, etc.) | Yes | +| value | Record value | Yes | +| comment | Record comment | No | diff --git a/hertzner/modules/zone_record/_locals.tf b/hertzner/modules/zone_record/_locals.tf new file mode 100644 index 00000000..88dd580e --- /dev/null +++ b/hertzner/modules/zone_record/_locals.tf @@ -0,0 +1,5 @@ +locals { + zone_id = var.resources[ + try(var.settings.zone_lz_key, var.client_config.landingzone_key) + ].zones[var.settings.zone_ref].id +} diff --git a/hertzner/modules/zone_record/_outputs.tf b/hertzner/modules/zone_record/_outputs.tf new file mode 100644 index 00000000..d5d1fdf8 --- /dev/null +++ b/hertzner/modules/zone_record/_outputs.tf @@ -0,0 +1,15 @@ +output "zone" { + value = hcloud_zone_record.main.zone +} + +output "name" { + value = hcloud_zone_record.main.name +} + +output "type" { + value = hcloud_zone_record.main.type +} + +output "value" { + value = hcloud_zone_record.main.value +} diff --git a/hertzner/modules/zone_record/_provider.tf b/hertzner/modules/zone_record/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/zone_record/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/zone_record/_variables.tf b/hertzner/modules/zone_record/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/zone_record/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/zone_record/main.tf b/hertzner/modules/zone_record/main.tf new file mode 100644 index 00000000..c89c16f6 --- /dev/null +++ b/hertzner/modules/zone_record/main.tf @@ -0,0 +1,7 @@ +resource "hcloud_zone_record" "main" { + zone = local.zone_id + name = var.settings.name + type = var.settings.type + value = var.settings.value + comment = try(var.settings.comment, null) +} diff --git a/hertzner/modules/zone_rrset/README.md b/hertzner/modules/zone_rrset/README.md new file mode 100644 index 00000000..c0dce261 --- /dev/null +++ b/hertzner/modules/zone_rrset/README.md @@ -0,0 +1,37 @@ +# DNS Zone Record Set Module + +Manages an hcloud_zone_rrset resource (preferred over zone_record). + +## Usage + +```hcl +zone_rrsets = { + rrset_www = { + zone_ref = "zone_example" + name = "www" + type = "A" + ttl = 300 + records = { + primary = { + value = "1.2.3.4" + } + secondary = { + value = "5.6.7.8" + comment = "Failover IP" + } + } + } +} +``` + +## Inputs + +| Name | Description | Required | +|------|-------------|----------| +| zone_ref | Reference key to the DNS zone | Yes | +| name | Record name | Yes | +| type | Record type (A, AAAA, CNAME, etc.) | Yes | +| records | Map of record values | Yes | +| ttl | TTL in seconds | No | +| labels | Key-value label pairs | No | +| change_protection | Enable change protection | No | diff --git a/hertzner/modules/zone_rrset/_locals.tf b/hertzner/modules/zone_rrset/_locals.tf new file mode 100644 index 00000000..48f1b31f --- /dev/null +++ b/hertzner/modules/zone_rrset/_locals.tf @@ -0,0 +1,10 @@ +locals { + labels = merge( + try(var.global_settings.labels, {}), + try(var.settings.labels, {}) + ) + + zone_id = var.resources[ + try(var.settings.zone_lz_key, var.client_config.landingzone_key) + ].zones[var.settings.zone_ref].id +} diff --git a/hertzner/modules/zone_rrset/_outputs.tf b/hertzner/modules/zone_rrset/_outputs.tf new file mode 100644 index 00000000..45ac80aa --- /dev/null +++ b/hertzner/modules/zone_rrset/_outputs.tf @@ -0,0 +1,23 @@ +output "id" { + value = hcloud_zone_rrset.main.id +} + +output "zone" { + value = hcloud_zone_rrset.main.zone +} + +output "name" { + value = hcloud_zone_rrset.main.name +} + +output "type" { + value = hcloud_zone_rrset.main.type +} + +output "ttl" { + value = hcloud_zone_rrset.main.ttl +} + +output "labels" { + value = hcloud_zone_rrset.main.labels +} diff --git a/hertzner/modules/zone_rrset/_provider.tf b/hertzner/modules/zone_rrset/_provider.tf new file mode 100644 index 00000000..4914c45b --- /dev/null +++ b/hertzner/modules/zone_rrset/_provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + hcloud = { + source = "hetznercloud/hcloud" + } + } +} diff --git a/hertzner/modules/zone_rrset/_variables.tf b/hertzner/modules/zone_rrset/_variables.tf new file mode 100644 index 00000000..bb7a9d86 --- /dev/null +++ b/hertzner/modules/zone_rrset/_variables.tf @@ -0,0 +1,18 @@ +variable "global_settings" { + description = "Global settings for tinycaf" +} + +variable "settings" { + description = "All the configuration for this resource" +} + +variable "resources" { + description = "All required resources" +} + +variable "client_config" { + description = "Client config such as current landingzone key" + type = object({ + landingzone_key = string + }) +} diff --git a/hertzner/modules/zone_rrset/main.tf b/hertzner/modules/zone_rrset/main.tf new file mode 100644 index 00000000..2a51231c --- /dev/null +++ b/hertzner/modules/zone_rrset/main.tf @@ -0,0 +1,17 @@ +resource "hcloud_zone_rrset" "main" { + zone = local.zone_id + name = var.settings.name + type = var.settings.type + ttl = try(var.settings.ttl, null) + + labels = local.labels + + change_protection = try(var.settings.change_protection, false) + + records = [ + for r in var.settings.records : { + value = r.value + comment = try(r.comment, null) + } + ] +} diff --git a/hertzner/networks.tf b/hertzner/networks.tf new file mode 100644 index 00000000..55c10ea9 --- /dev/null +++ b/hertzner/networks.tf @@ -0,0 +1,44 @@ +module "networks" { + source = "./modules/network" + for_each = var.networks + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "network_subnets" { + source = "./modules/network_subnet" + for_each = var.network_subnets + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + networks = module.networks + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "network_routes" { + source = "./modules/network_route" + for_each = var.network_routes + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + networks = module.networks + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/placement_groups.tf b/hertzner/placement_groups.tf new file mode 100644 index 00000000..23a99f6c --- /dev/null +++ b/hertzner/placement_groups.tf @@ -0,0 +1,10 @@ +module "placement_groups" { + source = "./modules/placement_group" + for_each = var.placement_groups + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/servers.tf b/hertzner/servers.tf new file mode 100644 index 00000000..fe823492 --- /dev/null +++ b/hertzner/servers.tf @@ -0,0 +1,38 @@ +module "servers" { + source = "./modules/server" + for_each = var.servers + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + networks = module.networks + firewalls = module.firewalls + placement_groups = module.placement_groups + primary_ips = module.primary_ips + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "server_networks" { + source = "./modules/server_network" + for_each = var.server_networks + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + servers = module.servers + networks = module.networks + network_subnets = module.network_subnets + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/snapshots.tf b/hertzner/snapshots.tf new file mode 100644 index 00000000..698fe7e3 --- /dev/null +++ b/hertzner/snapshots.tf @@ -0,0 +1,16 @@ +module "snapshots" { + source = "./modules/snapshot" + for_each = var.snapshots + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/ssh_keys.tf b/hertzner/ssh_keys.tf new file mode 100644 index 00000000..8222941c --- /dev/null +++ b/hertzner/ssh_keys.tf @@ -0,0 +1,10 @@ +module "ssh_keys" { + source = "./modules/ssh_key" + for_each = var.ssh_keys + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/storage_boxes.tf b/hertzner/storage_boxes.tf new file mode 100644 index 00000000..d3e17b25 --- /dev/null +++ b/hertzner/storage_boxes.tf @@ -0,0 +1,44 @@ +module "storage_boxes" { + source = "./modules/storage_box" + for_each = var.storage_boxes + + settings = each.value + global_settings = local.global_settings + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "storage_box_snapshots" { + source = "./modules/storage_box_snapshot" + for_each = var.storage_box_snapshots + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + storage_boxes = module.storage_boxes + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "storage_box_subaccounts" { + source = "./modules/storage_box_subaccount" + for_each = var.storage_box_subaccounts + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + storage_boxes = module.storage_boxes + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} diff --git a/hertzner/volumes.tf b/hertzner/volumes.tf new file mode 100644 index 00000000..d7487ede --- /dev/null +++ b/hertzner/volumes.tf @@ -0,0 +1,34 @@ +module "volumes" { + source = "./modules/volume" + for_each = var.volumes + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +} + +module "volume_attachments" { + source = "./modules/volume_attachment" + for_each = var.volume_attachments + + settings = each.value + global_settings = local.global_settings + + resources = { + (var.landingzone.key) = { + volumes = module.volumes + servers = module.servers + } + } + client_config = { + landingzone_key = var.landingzone.key + } +}