From a778d4ce612984678377dd090100ab405ded4c6c Mon Sep 17 00:00:00 2001 From: Novikov Sergey Date: Mon, 29 Nov 2021 11:35:50 +0100 Subject: [PATCH] Add records (#1) * Add simple records * Move iteration over records to locals * Fix fmt * Add collection submodule * Use collection submodule for the same name/type * Add examples --- Makefile | 8 +-- README.md | 68 +++++++++++++++++---- data.tf | 3 + examples/records/README.md | 82 ++++++++++++++++++++++++++ examples/records/main.tf | 67 +++++++++++++++++++++ examples/records/outputs.tf | 4 ++ examples/records/variables.tf | 10 ++++ main.tf | 22 +++++++ modules/record_collection/README.md | 47 +++++++++++++++ modules/record_collection/main.tf | 13 ++++ modules/record_collection/outputs.tf | 4 ++ modules/record_collection/variables.tf | 31 ++++++++++ modules/record_collection/versions.tf | 9 +++ outputs.tf | 9 +++ providers.tf | 3 + variables.tf | 28 +++++++++ versions.tf | 6 ++ 17 files changed, 397 insertions(+), 17 deletions(-) create mode 100644 data.tf create mode 100644 examples/records/README.md create mode 100644 examples/records/main.tf create mode 100644 examples/records/outputs.tf create mode 100644 examples/records/variables.tf create mode 100644 main.tf create mode 100644 modules/record_collection/README.md create mode 100644 modules/record_collection/main.tf create mode 100644 modules/record_collection/outputs.tf create mode 100644 modules/record_collection/variables.tf create mode 100644 modules/record_collection/versions.tf create mode 100644 outputs.tf create mode 100644 providers.tf create mode 100644 variables.tf diff --git a/Makefile b/Makefile index 5835317..a425945 100644 --- a/Makefile +++ b/Makefile @@ -79,14 +79,12 @@ test: _pull-tf echo "------------------------------------------------------------"; \ if docker run $$(tty -s && echo "-it" || echo) --rm -v "$(CURRENT_DIR):/t" --workdir "$${DOCKER_PATH}" hashicorp/terraform:$(TF_VERSION) \ init \ - -verify-plugins=true \ -lock=false \ - -upgrade=true \ + -upgrade \ -reconfigure \ -input=false \ - -get-plugins=true \ - -get=true \ - .; then \ + -get=true; \ + then \ echo "OK"; \ else \ echo "Failed"; \ diff --git a/README.md b/README.md index 5d94599..0dd0e2c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ -# terraform-module-template -Template for Terraform modules - - +# terraform-cloudflare-records + +Terraform module to create set of DNS records in Cloudflare Hosted Zone. + +[![lint](https://github.com/flaconi/terraform-cloudflare-records/workflows/lint/badge.svg)](https://github.com/flaconi/terraform-cloudflare-records/actions?query=workflow%3Alint) +[![test](https://github.com/flaconi/terraform-cloudflare-records/workflows/test/badge.svg)](https://github.com/flaconi/terraform-cloudflare-records/actions?query=workflow%3Atest) +[![Tag](https://img.shields.io/github/tag/flaconi/terraform-cloudflare-records.svg)](https://github.com/flaconi/terraform-cloudflare-records/releases) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) @@ -16,7 +15,9 @@ Template for Terraform modules ## Providers -No providers. +| Name | Version | +|------|---------| +| [cloudflare](#provider\_cloudflare) | ~> 3.2 | @@ -26,24 +27,67 @@ No providers. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | ~> 1.0 | +| [cloudflare](#requirement\_cloudflare) | ~> 3.2 | ## Required Inputs -No required inputs. +The following input variables are required: + +### [api\_token](#input\_api\_token) + +Description: The Cloudflare API token. + +Type: `string` + +### [domain](#input\_domain) + +Description: Cloudflare domain name to create + +Type: `string` ## Optional Inputs -No optional inputs. +The following input variables are optional (have default values): + +### [records](#input\_records) + +Description: List of names to create + +Type: + +```hcl +list(object({ + name = string + value = string + type = string + ttl = number + proxied = bool + priority = number + })) +``` + +Default: `[]` + +### [allow\_overwrite](#input\_allow\_overwrite) + +Description: Allow override existing records + +Type: `bool` + +Default: `false` ## Outputs -No outputs. +| Name | Description | +|------|-------------| +| [records](#output\_records) | Cloudflare Zone DNS Records | +| [zone\_id](#output\_zone\_id) | Cloudflare Zone ID | diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..c14a3a9 --- /dev/null +++ b/data.tf @@ -0,0 +1,3 @@ +data "cloudflare_zone" "this" { + name = var.domain +} diff --git a/examples/records/README.md b/examples/records/README.md new file mode 100644 index 0000000..ff3d440 --- /dev/null +++ b/examples/records/README.md @@ -0,0 +1,82 @@ +# Example + +This example will create multiple DNS records. + +Output for `example.com`: + +```hcl +records = { + "A_mytestdomain.example.com" = { + "4.4.4.4" = { + "created" = "2021-11-26T15:36:09.973899Z" + "id" = "90bc69d4b5e5bb5c7a58858d7156cf36" + } + "8.8.8.8" = { + "created" = "2021-11-26T15:36:09.764104Z" + "id" = "03aae5145060e77dfc903e4a41ad7f4d" + } + } + "CNAME_myproxieddomain.example.com" = { + "example.com" = { + "created" = "2021-11-26T15:36:10.544251Z" + "id" = "20cfad416b4dcd3fdbb16d3d8e7ce2d3" + } + } + "MX_mymaildomain.example.com" = { + "mail1.mx.maildomainexample.com" = { + "created" = "2021-11-26T15:36:10.323258Z" + "id" = "61cc65ae9845eeb5d0a253f03cac2acd" + } + "mail2.mx.maildomainexample.com" = { + "created" = "2021-11-26T15:36:10.189034Z" + "id" = "e16fd484fa77f12049af5e8c66958626" + } + } + "NS_mynsdomain.example.com" = { + "ns1.mytestdns.com" = { + "created" = "2021-11-26T15:36:11.447047Z" + "id" = "b2ba6ade689541d5afff586bdacbfd5f" + } + "ns2.mytestdns.com" = { + "created" = "2021-11-26T15:36:11.126715Z" + "id" = "8df957fd25f7a2212fcae8ba00cd6b39" + } + } +} +``` + + +## Requirements + +No requirements. + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [records](#module\_records) | ./../../ | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_token](#input\_api\_token) | The Cloudflare API token. | `string` | n/a | yes | +| [domain](#input\_domain) | Cloudflare domain name to create | `string` | `"example.com"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [records](#output\_records) | Cloudflare Zone DNS Records | + + + +Copyright (c) 2021 **[Flaconi GmbH](https://github.com/flaconi)** diff --git a/examples/records/main.tf b/examples/records/main.tf new file mode 100644 index 0000000..1f7abf0 --- /dev/null +++ b/examples/records/main.tf @@ -0,0 +1,67 @@ +locals { + records = [ + { + name = "myproxieddomain" + value = "example.com" + type = "CNAME" + ttl = 1 + proxied = true + priority = null + }, + { + name = "mytestdomain" + value = "8.8.8.8" + type = "A" + ttl = 600 + proxied = false + priority = null + }, + { + name = "mytestdomain" + value = "4.4.4.4" + type = "A" + ttl = 600 + proxied = false + priority = null + }, + { + name = "mymaildomain" + value = "mail1.mx.maildomainexample.com" + type = "MX" + ttl = 300 + proxied = false + priority = 10 + }, + { + name = "mymaildomain" + value = "mail2.mx.maildomainexample.com" + type = "MX" + ttl = 300 + proxied = false + priority = 20 + }, + { + name = "mynsdomain" + value = "ns1.mytestdns.com" + type = "NS" + ttl = 300 + proxied = false + priority = null + }, + { + name = "mynsdomain" + value = "ns2.mytestdns.com" + type = "NS" + ttl = 300 + proxied = false + priority = null + }, + ] +} + +module "records" { + source = "./../../" + api_token = var.api_token + domain = var.domain + records = local.records +} diff --git a/examples/records/outputs.tf b/examples/records/outputs.tf new file mode 100644 index 0000000..00b6f99 --- /dev/null +++ b/examples/records/outputs.tf @@ -0,0 +1,4 @@ +output "records" { + description = "Cloudflare Zone DNS Records" + value = module.records.records +} diff --git a/examples/records/variables.tf b/examples/records/variables.tf new file mode 100644 index 0000000..59baa16 --- /dev/null +++ b/examples/records/variables.tf @@ -0,0 +1,10 @@ +variable "api_token" { + description = "The Cloudflare API token." + type = string +} + +variable "domain" { + description = "Cloudflare domain name to create" + type = string + default = "example.com" +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..c08f5a5 --- /dev/null +++ b/main.tf @@ -0,0 +1,22 @@ +locals { + # Grouping records by type and name + collections = { for r in var.records : "${r.type}_${r.name}.${var.domain}" => r... } +} + +module "records" { + source = "./modules/record_collection" + for_each = local.collections + + zone_id = data.cloudflare_zone.this.id + name = each.value[0].name + type = each.value[0].type + values = [for r in each.value : + { + value = r.value + ttl = r.ttl + proxied = r.proxied + priority = r.priority + } + ] + allow_overwrite = var.allow_overwrite +} diff --git a/modules/record_collection/README.md b/modules/record_collection/README.md new file mode 100644 index 0000000..b55aed4 --- /dev/null +++ b/modules/record_collection/README.md @@ -0,0 +1,47 @@ +# Submodule record_collection + +Terraform submodule to create a list of Cloudflare DNS records grouped by type and name. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | ~> 1.0 | +| [cloudflare](#requirement\_cloudflare) | ~> 3.2 | + +## Providers + +| Name | Version | +|------|---------| +| [cloudflare](#provider\_cloudflare) | ~> 3.2 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [cloudflare_record.this](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/record) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [zone\_id](#input\_zone\_id) | Cloudflare Hosted Zone ID | `string` | n/a | yes | +| [name](#input\_name) | Cloudflare Hosted Zone Record Name | `string` | n/a | yes | +| [type](#input\_type) | Cloudflare Hosted Zone Record Type | `string` | n/a | yes | +| [values](#input\_values) | List of values to create |
list(object({
value = string
ttl = number
proxied = bool
priority = number
}))
| `[]` | no | +| [allow\_overwrite](#input\_allow\_overwrite) | Allow override existing records | `bool` | `false` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [values](#output\_values) | Cloudflare Zone DNS Records | + + + +Copyright (c) 2021 **[Flaconi GmbH](https://github.com/flaconi)** diff --git a/modules/record_collection/main.tf b/modules/record_collection/main.tf new file mode 100644 index 0000000..2786473 --- /dev/null +++ b/modules/record_collection/main.tf @@ -0,0 +1,13 @@ +resource "cloudflare_record" "this" { + count = length(var.values) + + zone_id = var.zone_id + type = var.type + name = var.name + value = var.values[count.index].value + ttl = var.values[count.index].ttl + proxied = var.values[count.index].proxied + priority = var.values[count.index].priority + + allow_overwrite = var.allow_overwrite +} diff --git a/modules/record_collection/outputs.tf b/modules/record_collection/outputs.tf new file mode 100644 index 0000000..8ec17b5 --- /dev/null +++ b/modules/record_collection/outputs.tf @@ -0,0 +1,4 @@ +output "values" { + description = "Cloudflare Zone DNS Records" + value = { for v in cloudflare_record.this : v.value => { id = v.id, created = v.created_on } } +} diff --git a/modules/record_collection/variables.tf b/modules/record_collection/variables.tf new file mode 100644 index 0000000..521344f --- /dev/null +++ b/modules/record_collection/variables.tf @@ -0,0 +1,31 @@ +variable "zone_id" { + description = "Cloudflare Hosted Zone ID" + type = string +} + +variable "name" { + description = "Cloudflare Hosted Zone Record Name" + type = string +} + +variable "type" { + description = "Cloudflare Hosted Zone Record Type" + type = string +} + +variable "values" { + description = "List of values to create" + type = list(object({ + value = string + ttl = number + proxied = bool + priority = number + })) + default = [] +} + +variable "allow_overwrite" { + description = "Allow override existing records" + type = bool + default = false +} diff --git a/modules/record_collection/versions.tf b/modules/record_collection/versions.tf new file mode 100644 index 0000000..3bb791a --- /dev/null +++ b/modules/record_collection/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 3.2" + } + } + required_version = "~> 1.0" +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..956dbba --- /dev/null +++ b/outputs.tf @@ -0,0 +1,9 @@ +output "zone_id" { + description = "Cloudflare Zone ID" + value = data.cloudflare_zone.this.id +} + +output "records" { + description = "Cloudflare Zone DNS Records" + value = { for k, v in local.collections : k => module.records[k].values } +} diff --git a/providers.tf b/providers.tf new file mode 100644 index 0000000..16ff320 --- /dev/null +++ b/providers.tf @@ -0,0 +1,3 @@ +provider "cloudflare" { + api_token = var.api_token +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..a21102d --- /dev/null +++ b/variables.tf @@ -0,0 +1,28 @@ +variable "api_token" { + description = "The Cloudflare API token." + type = string +} + +variable "domain" { + description = "Cloudflare domain name to create" + type = string +} + +variable "records" { + description = "List of names to create" + type = list(object({ + name = string + value = string + type = string + ttl = number + proxied = bool + priority = number + })) + default = [] +} + +variable "allow_overwrite" { + description = "Allow override existing records" + type = bool + default = false +} diff --git a/versions.tf b/versions.tf index ab789a3..3bb791a 100644 --- a/versions.tf +++ b/versions.tf @@ -1,3 +1,9 @@ terraform { + required_providers { + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 3.2" + } + } required_version = "~> 1.0" }