From 87ebb350167b27677faaca7f3b3916fa25d8915d Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Thu, 1 Sep 2022 21:43:01 +0200 Subject: [PATCH] initial commit --- .drone.yml | 37 +++++++++++++ .gitignore | 11 ++++ .prettierignore | 1 + .renovaterc.json | 4 ++ LICENSE | 21 ++++++++ README.md | 13 +++++ data.tf | 8 +++ main.tf | 133 +++++++++++++++++++++++++++++++++++++++++++++++ outputs.tf | 9 ++++ providers.tf | 7 +++ variables.tf | 31 +++++++++++ versions.tf | 10 ++++ 12 files changed, 285 insertions(+) create mode 100644 .drone.yml create mode 100755 .gitignore create mode 100644 .prettierignore create mode 100644 .renovaterc.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 data.tf create mode 100644 main.tf create mode 100644 outputs.tf create mode 100644 providers.tf create mode 100644 variables.tf create mode 100644 versions.tf diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..c9ba5c6 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,37 @@ +--- +kind: pipeline +name: check + +platform: + os: linux + arch: amd64 + +steps: + - name: whitespace + pull: always + image: thegeeklab/alpine-tools + commands: + - git diff-tree --check $(git hash-object -t tree /dev/null) HEAD + + - name: terraform + pull: always + image: jmccann/drone-terraform:8 + settings: + actions: + - validate + tf_version: 1.2.0 + +node: + zone: mgmt + +trigger: + ref: + - refs/heads/main + - refs/tags/** + - refs/pull/** + +--- +kind: signature +hmac: ec825d5879e3dc1d26bdc619143cf2ea41d5183c2d7b892498b21103379675c2 + +... diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..bf61628 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/terraform/.terraform + +*.retry +*.tfvars +*.tfstate +.terraform.lock.hcl + +.vaultpasswd +.envrc + +/galaxy diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..ef05acb --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +.drone* diff --git a/.renovaterc.json b/.renovaterc.json new file mode 100644 index 0000000..4ac4f8d --- /dev/null +++ b/.renovaterc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>thegeeklab/renovate-presets:ansible"] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3812eb4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Robert Kaussow + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a07c341 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# hcloud-server-tf + +[![Build Status](https://drone.rknet.org/api/badges/infra/hcloud_server_tf/status.svg)](https://drone.rknet.org/infra/hcloud_server_tf) + +Terraform module to provision Hetzner Cloud servers. + +## Usage + +This [Terraform module](https://www.terraform.io/docs/language/modules/syntax.html) is used in our deployment repos to avoid duplicate resource definitions and simplify maintenance. + +## License + +This project is licensed under the MIT License - see the [LICENSE](https://github.com/ansible/galaxy/blob/main/LICENSE) file for details. diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..30f3bac --- /dev/null +++ b/data.tf @@ -0,0 +1,8 @@ +data "cloudflare_zones" "zones" { + for_each = toset(try(var.cloudflare_zones, [])) + + filter { + name = each.key + status = "active" + } +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..c449faf --- /dev/null +++ b/main.tf @@ -0,0 +1,133 @@ +locals { + zones = { + for zone in try(data.cloudflare_zones.zones, []) : zone.zones[0].name => zone.zones[0].id + } +} + +locals { + server_volumes = flatten([ + for server_key, server in var.server : [ + for volume_key, volume in try(server.volumes, []) : { + volume_name = volume.name + volume_size = volume.size + server_id = hcloud_server.server[server.name].id + } + ] + ]) +} + +locals { + server_domains = flatten([ + for server_key, server in var.server : [ + for domain_key, domain in try(server.domains, []) : { + record_id = try(domain.id, domain.name) + record_name = domain.name + record_type = domain.type + record_value = domain.value + record_ttl = try(domain.ttl, 1) + zone_id = local.zones[try(domain.zone_name, var.cloudflare_default_zone)] + } + ] + ]) +} + +resource "hcloud_placement_group" "group" { + for_each = { for key, row in var.server : row.name => row if contains(keys(row), "placement_group") } + + name = each.value.placement_group + type = "spread" +} + +resource "hcloud_server" "server" { + for_each = { for row in var.server : row.name => row } + depends_on = [hcloud_ssh_key.key] + + name = each.value.name + server_type = try(each.value.type, "cx11") + image = try(each.value.image, "rocky-9") + datacenter = try(each.value.datacenter, "fsn1-dc14") + ssh_keys = var.server_keys + backups = try(each.value.backups, true) + keep_disk = try(each.value.keep_disk, false) + placement_group_id = try(hcloud_placement_group.group[each.value.placement_group].id, null) + + lifecycle { + ignore_changes = [ssh_keys] + } + + labels = merge( + { + provisioner = "ansible" + project = var.hcloud_project + deploygroup = try(each.value.deploygroup, "1") + }, + { + for index, service in try(each.value.services, []) : "service_${index + 1}" => service + }, + { + for index, group in try(each.value.groups, []) : "group_${index + 1}" => group + }, + try(each.value.labels, {}) + ) +} + +resource "hcloud_volume" "volume" { + for_each = { for row in local.server_volumes : row.volume_name => row } + + name = each.value.volume_name + size = each.value.volume_size + server_id = each.value.server_id +} + +resource "hcloud_ssh_key" "key" { + for_each = { for row in toset(var.ssh_keys) : element(split(" ", row), 2) => row } + + name = each.key + public_key = "${element(split(" ", each.value), 0)} ${element(split(" ", each.value), 1)}" +} + +resource "hcloud_rdns" "serverv4" { + for_each = { for row in var.server : row.name => row } + + server_id = hcloud_server.server[each.value.name].id + ip_address = hcloud_server.server[each.value.name].ipv4_address + dns_ptr = "${each.value.name}.${local.zones[try(each.value.dns_zone, var.cloudflare_default_zone)]}" +} + +resource "hcloud_rdns" "serverv6" { + for_each = { for row in var.server : row.name => row } + + server_id = hcloud_server.server[each.value.name].id + ip_address = hcloud_server.server[each.value.name].ipv6_address + dns_ptr = "${each.value.name}.${local.zones[try(each.value.dns_zone, var.cloudflare_default_zone)]}" +} + +resource "cloudflare_record" "serverv4" { + for_each = { for row in var.server : row.name => row } + + zone_id = local.zones[try(each.value.dns_zone, var.cloudflare_default_zone)] + name = each.value.name + value = hcloud_server.server[each.value.name].ipv4_address + type = "A" + ttl = 1 +} + +resource "cloudflare_record" "serverv6" { + for_each = { for row in var.server : row.name => row } + + zone_id = local.zones[try(each.value.dns_zone, var.cloudflare_default_zone)] + name = each.value.name + value = hcloud_server.server[each.value.name].ipv6_address + type = "AAAA" + ttl = 1 +} + +resource "cloudflare_record" "record" { + for_each = { for row in local.server_domains : row.record_id => row } + + zone_id = each.value.zone_id + name = each.value.record_name + value = each.value.record_value + type = each.value.record_type + ttl = each.value.record_ttl +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..a8693a9 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,9 @@ +output "output" { + value = { + for server_key, server in hcloud_server.server : server_key => server + } +} + +output "zones" { + value = local.zones +} diff --git a/providers.tf b/providers.tf new file mode 100644 index 0000000..8155974 --- /dev/null +++ b/providers.tf @@ -0,0 +1,7 @@ +provider "hcloud" { + token = var.hcloud_token +} + +provider "cloudflare" { + api_token = var.cloudflare_api_token +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..025efed --- /dev/null +++ b/variables.tf @@ -0,0 +1,31 @@ +variable "hcloud_token" { + type = string +} + +variable "hcloud_project" { + type = string +} + +variable "cloudflare_api_token" { + type = string +} + +variable "cloudflare_zones" { + type = list(string) +} + +variable "server" { + default = [] +} + +variable "cloudflare_default_zone" { + type = string +} + +variable "server_keys" { + type = list(string) +} + +variable "ssh_keys" { + type = list(string) +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..a4fbcf8 --- /dev/null +++ b/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + } + hcloud = { + source = "hetznercloud/hcloud" + } + } +}