Removing region from Resource Group name - terraform

How would I go about removing the location code (aus) from the Resource Group creation.
from:
rg-d-lxr-aus-app1
to
rg-d-lxr-app1
I only want this to affect the only RG and not any other resources eg vnets/keyvaults etc
app1
locals.tf
locals {
full_env_code = format("%s-%s-%s", lower(var.environment_code), lower(var.deployment_code), lower(var.location_code))
}
resource_groups.tf
module "rg-app1" {
source = "git::ssh://git#ssh.dev.azure.com/*"
resource_group_name = format("rg-%s-%s", local.full_env_code, lower(var.name_suffix))
location = var.location
}
variables.tf
variable "location" {
description = "Location in which to deploy resources"
# default = "Australia Southeast"
}
variable "environment_code" {
description = "Environment code"
# default = "d"
}
variable "environment" {
description = "Environment"
# default = "d"
}
variable "deployment_code" {
description = "Deployment code"
# default = "d"
}
variable "location_code" {
description = "Location code"
# default = "d"
}
dev.tfvars
environment = "non-prod"
environment_code = "d"
deployment_code = "my org"
location_code = "aus"
location = "Australia Southeast"
name_suffix = "app1"
Output of TF Plan
Terraform will perform the following actions:
# module.rg-sharegate.azurerm_resource_group.rg will be created
+ resource "azurerm_resource_group" "rg" {
+ id = (known after apply)
+ location = "australiasoutheast"
+ name = "rg-d-lxr-aus-app1"
}
Plan: 1 to add, 0 to change, 0 to destroy.
I am thinking we need to modify the RG module and use the split command, but i'm not sure how to go about it
module "rg-app1" {
resource_group_name = format("rg-%s-%s", local.full_env_code, lower(var.name_suffix))

You can use a mixture of built-in Terraform functions to achieve what you're after.
Local Code to recreate a MRE for you:
locals {
rg_string = "rg-d-lxr-aus-app1"
// Use split by "-" to create an array so we can use contains()
is_rg = contains(split("-", local.rg_string), "rg")
final_rg_string = local.is_rg ? replace(local.rg_string, "aus-", "") : local.rg_string
not_rg_string = "blah-d-lxr-aus-app1"
is_not_rg = contains(split("-", local.not_rg_string), "rg")
final_not_rg_string = local.is_not_rg ? replace(local.not_rg_string, "aus-", "") : local.not_rg_string
}
Result using Terraform Console:
> local.is_rg
true
> local.final_rg_string
"rg-d-lxr-app1"
> local.is_not_rg
false
> local.final_not_rg_string
"blah-d-lxr-aus-app1"
Links:
https://www.terraform.io/language/functions/replace
https://www.terraform.io/language/functions/contains
https://www.terraform.io/language/functions/split
You'll likely not need to duplicate the logic but I did just for demonstrative purposes. For example you can just use your resource_group_name and create your true/false conditions. If you need more help with that please let me know.

Related

Terraform - azurerm_frontdoor_custom_https_configuration - 'the given key does not identify an element in this collection value'

this code has worked before, all I'm trying to do is add new frontend endpoints, routing rules, backend pools
I've tried only sharing the code snippets that I think are relevant but let me know if there's some key info you need missing
This one has stumped me for a couple days now and no matter what I've tried I cannot seem to make sense of the error. Its like its indexing out of the variable or searching for something that isn't there but there are something like 6 already there and now I'm adding another.
I'm worried that this front door code has not been ran in awhile and something has gotten screwed up in state. Especially given all the alerts on the accompanying TF docs for this resource - https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/frontdoor_custom_https_configuration
Its been quite awhile but the AzureRM version has gone through several updates - possibly from previous to 2.58 to now past 2.58. I guess I also don't know how to verify/look at the state file and ensure its correct - even looking at the 2.58 upgrade notes its just confusing.
Ideas?
The error
on ..\modules\frontdoor\main.tf line 129, in resource "azurerm_frontdoor_custom_https_configuration" "https_config":
129: frontend_endpoint_id = azurerm_frontdoor.main.frontend_endpoints[each.value]
|----------------
| azurerm_frontdoor.main.frontend_endpoints is map of string with 8 elements
| each.value is "www-sell-dev-contoso-com"
The given key does not identify an element in this collection value.
main.tf
provider "azurerm" {
features {}
}
terraform {
backend "azurerm" {
}
}
#the outputs.tf on this module output things like the frontdoor_endpoints
#the outputs.tf with main.tf also output similar values
module "coreInfraFrontDoor" {
source = "../modules/frontdoor"
resource_group_name = module.coreInfraResourceGroup.resource_group_name
frontdoor_name = "fd-infra-${terraform.workspace}-001"
enforce_backend_pools_certificate_name_check = lookup(var.enforce_backend_pools_certificate_name_check, terraform.workspace)
log_analytics_workspace_id = module.coreInfraLogAnalytics.log_analytics_workspace_id
tags = local.common_tags
health_probes = lookup(var.health_probes, terraform.workspace)
routing_rules = lookup(var.routing_rules, terraform.workspace)
backend_pools = lookup(var.backend_pools, terraform.workspace)
frontend_endpoints = lookup(var.frontend_endpoints, terraform.workspace)
prestage_frontend_endpoints = lookup(var.prestage_frontend_endpoints, terraform.workspace)
frontdoor_firewall_policy_name = "fdfwp${terraform.workspace}001"
frontdoor_firewall_prestage_policy_name = "fdfwp${terraform.workspace}prestage"
mode = lookup(var.mode, terraform.workspace)
ip_whitelist_enable = lookup(var.ip_whitelist_enable, terraform.workspace)
ip_whitelist = lookup(var.ip_whitelist, terraform.workspace)
key_vault_id = module.coreInfraKeyVault.id
}
module main.tf
resource "azurerm_frontdoor" "main" {
name = var.frontdoor_name
location = "global"
resource_group_name = var.resource_group_name
enforce_backend_pools_certificate_name_check = var.enforce_backend_pools_certificate_name_check
tags = var.tags
dynamic "routing_rule {#stuff is here obv}
dynamic "backend_pool {#also here}
#i think this is because there was an issue/needs to be some default value for the first endpoint?
frontend_endpoint {
name = var.frontdoor_name
host_name = "${var.frontdoor_name}.azurefd.net"
web_application_firewall_policy_link_id = azurerm_frontdoor_firewall_policy.main.id
}
#now the dynamic ones from vars
dynamic "frontend_endpoint" {
for_each = var.frontend_endpoints
content {
name = frontend_endpoint.value.name
host_name = frontend_endpoint.value.host_name
session_affinity_enabled = lookup(frontend_endpoint.value, "session_affinity_enabled", false)
web_application_firewall_policy_link_id = azurerm_frontdoor_firewall_policy.main.id
}
}
versions.tf
terraform {
required_version = "~> 0.14.7"
required_providers {
azurerm = "~>2.72.0"
}
}
variables.tf
variable "frontend_endpoints" {
type = map(any)
description = "List of frontend (custom) endpoints. This is in addition to the <frontend_name>.azurefd.net endpoint that this module creates by default."
default = {
dev = [
{
name = "dev-search-contoso-com"
host_name = "dev.search.contoso.com"
},
{
name = "dev-cool-contoso-com"
host_name = "dev.cool.contoso.com"
},
########################
#this is new below
########################
{
name = "dev-sell-contoso-com"
host_name = "dev.sell.contoso.com"
}
]
prod = [ #you get the idea ]
}

Terraform Apply Error: Code="InvalidResourceName" Message="Resource name is invalid" When creating VPN-GW Module

I'm receiving the following error when executing the Terraform Apply Command.
│ Error: Creating/Updating Virtual Network Gateway: (Name "VPN-GW-HUB-dev" / Resource Group "RG-HUB-dev"): network.VirtualNetworkGatewaysClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="InvalidResourceName" Message="Resource name is invalid. The name can be up to 80 characters long. It must begin with a word character, and it must end with a word character or with '_'. The name may contain word characters or '.', '-', '_'." Details=[]
│
│ with module.MOD-VPN-GW.azurerm_virtual_network_gateway.vpngw,
│ on Modules/10.VPN-GW/main.tf line 31, in resource "azurerm_virtual_network_gateway" "vpngw":
│ 31: resource "azurerm_virtual_network_gateway" "vpngw" {
What was I trying to do?
My Terraform code creates a complete Hub-and-Spoke infrastructure in Azure. It worked very well until I decided to modularise the VPN GW part.
My Terraform code structure is the usual format:
--Modules/{module-name}/main.tf
--main.tf
So within the {module-name} - I have a folder called:
10.VPN-GW\main.tf
What have I tried?
Well, I have tried to reformat the code, I double checked it against all other modules that worked OK. I have NO idea why this error is happening, and it has been 3 days now non stop debugging this.
The module file is here:
#------------------------------
# VPN GW MODULE FILE - ALso contains GW SUBNET
#-------------------------------
resource "azurerm_subnet" "gwSubnet" {
name = var.subnet_name
resource_group_name = var.subnet_resource_group_name
virtual_network_name = var.subnet_virtual_network_name
address_prefixes = var.subnet_address_prefixes
}
variable "subnet_name" {
type = string
}
variable "subnet_resource_group_name" {
type = string
}
variable "subnet_virtual_network_name" {
type = string
}
variable "subnet_address_prefixes" {
type = list(string)
}
output "outSubnetIDVPNGW" {
value = azurerm_subnet.gwSubnet.id
}
resource "azurerm_virtual_network_gateway" "vpngw" {
name = "${var.vpn-gw-name}"
location = "${var.vpn-gw-location}"
resource_group_name = "${var.vpngw_resource_group_name}"
type = "Vpn"
vpn_type = "RouteBased"
active_active = false
enable_bgp = false
sku = "VpnGw1"
ip_configuration {
name = "${var.ip_configuration_name}"
public_ip_address_id = "${var.ip_configuration_public_ip_address_id}"
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gwSubnet.id
}
vpn_client_configuration {
address_space = "${var.vpn_client_configuration_address_space}"
root_certificate {
name = "${var.root_certificate_name}"
public_cert_data = "${var.cert}"
}
revoked_certificate {
name = "${var.revoked_certificate_name}"
thumbprint = "${var.revoked_certificate_thumbprint}"
}
}
}
variable "vpn-gw-name" {
type = string
//default = ""
}
variable "vpn-gw-location" {
//default = ""
type = string
}
variable "vpngw_resource_group_name" {
default = ""
}
variable "ip_configuration_name" {
default = ""
}
variable "ip_configuration_public_ip_address_id" {
default = ""
}
/*
variable "ip_configuration_private_ip_address_allocation" {
//default = ""
// type = string
}
*/
variable "vpn_client_configuration_address_space" {
default = []
}
variable "root_certificate_name" {
default = ""
}
variable "cert" {
default = ""
}
variable "revoked_certificate_name" {
default = ""
}
variable "revoked_certificate_thumbprint" {
default = ""
}
variable "ip_configuration" {
type = map(string)
}
variable "vpn_client_configuration" {
type = object({
address_space = list(string)
root_certificate = map(string)
revoked_certificate = map(string)
})
}
/*
variable "revoked_certificate" {
type = map(string)
}
*/
The main.tf file -- that calls each module, is given below - (I'm only adding the snippet for the part causing the error) - i.e. creation of the VPN GW
#-----------------------------------------
# Create GW SUBNET & VPN GW
#-----------------------------------------
module "MOD-VPN-GW" {
source = "./Modules/10.VPN-GW"
subnet_name = "GatewaySubnet"
subnet_resource_group_name = "RG-HUB-${var.environmentCode}"
subnet_virtual_network_name = "VNET-HUB-${var.environmentCode}"
subnet_address_prefixes = ["10.0.1.0/27"]
vpn-gw-name = "VPN-GW-HUB-${var.environmentCode}"
vpn-gw-location = "westeurope"
vpngw_resource_group_name = "RG-HUB-${var.environmentCode}"
ip_configuration = {
name = "VNetGatewayConfig"
public_ip_address_id = "${module.MOD-VPNGW-PIP.id}"
private_ip_address_allocation = "Dynamic"
subnet_id = module.MOD-VPN-GW.outSubnetIDVPNGW
}
vpn_client_configuration = {
address_space = ["172.16.10.0/24"]
root_certificate = {
name = "dev.vpn.macos.com"
public_cert_data = data.azurerm_key_vault_certificate.akv-certificate.certificate_data_base64
}
revoked_certificate = {
name = "Verizon-Global-Root-CA"
thumbprint = "912198EEF23DCAC40939312FEE97DD560BAE49B1"
}
}
depends_on = [
module.MOD-RG-HUB, module.MOD-VNET-HUB, azurerm_linux_virtual_machine.label-vm-spoke-01
]
}
What did I search for?
I cannot seem to find this particular error code in a google search. Its not telling me that name given to my VPN GW is incorrect - its giving me the name (in the error message) and telling me that there is no name given. Which is odd. Or have I misunderstood the error message?
The terraform init command succeeds.
The terraform validate command succeeds.
The terraform plan command succeeds.
This fails when applying
There is an issue between the root module and the VPN GW module. The way that modules in Terraform work is similar to functions in other programming languages: they require certain input variables which are then replaced by the values provided to them. More about modules in [1].
To refactor this code, I would do the following in the root module:
source = "./Modules/10.VPN-GW"
subnet_name = "GatewaySubnet"
subnet_resource_group_name = "RG-HUB-${var.environmentCode}"
subnet_virtual_network_name = "VNET-HUB-${var.environmentCode}"
subnet_address_prefixes = ["10.0.1.0/27"]
vpn-gw-name = "VPN-GW-HUB-${var.environmentCode}"
vpn-gw-location = "westeurope"
vpngw_resource_group_name = "RG-HUB-${var.environmentCode}"
ip_configuration_name = "VNetGatewayConfig"
ip_configuration_public_ip_address_id = module.MOD-VPNGW-PIP.id
vpn_client_configuration_address_space = ["172.16.10.0/24"]
root_certificate_name = "dev.vpn.macos.com"
cert = data.azurerm_key_vault_certificate.akv-certificate.certificate_data_base64
revoked_certificate_name = "Verizon-Global-Root-CA"
revoked_certificate_thumbprint = "912198EEF23DCAC40939312FEE97DD560BAE49B1"
}
As you can see, the only change I did was to assign the values to variables that the VPN GW module requires. The way this works is when the module is called, it will be provided with values for the variables and it will know what to do with them. There is no need to define the same blocks in the calling (root) and called module (VPN GW). So, think of the root module as of a piece of code that invokes a function, something like:
MOD_VPN_GW(subnet_name, subnet_resource_group_name, subnet_virtual_network_name, subnet_address_prefixes, vpn-gw-name, vpn-gw-location, vpngw_resource_group_name, ip_configuration_name, ip_configuration_public_ip_address_id, vpn_client_configuration_address_space, root_certificate_name, cert, revoked_certificate_name, revoked_certificate_thumbprint)
As for your question about how the subnet_id will be accessible, that is the easy part. In the VPN GW module there is a resource block for azurerm_subnet:
resource "azurerm_subnet" "gwSubnet" {
name = var.subnet_name
resource_group_name = var.subnet_resource_group_name
virtual_network_name = var.subnet_virtual_network_name
address_prefixes = var.subnet_address_prefixes
}
One of the attributes that is provided by this resource after creation is the subnet ID [2].That means that you can assign the attribute value by referencing the resulting value using this syntax [3]:
<resource type>.<resource_name>.<attribute>
In your case that is:
azurerm_subnet.gwSubnet.id
This value is already referenced in the subnet_id argument of the azurerm_virtual_network_gateway resource:
subnet_id = azurerm_subnet.gwSubnet.id
This means it is not required as one of the input variables by the module. The good thing is that the VPN GW module will know in which order to create resource as this is an implicit dependency.
[1] https://www.terraform.io/language/modules/develop
[2] https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet#id
[3] https://www.terraform.io/language/expressions/references#references-to-resource-attributes

How to handle empty list for dynamic block

This is regarding an Azure resource, app_service, but I think it’s a more general HCL question…
You can specify IP restrictions to an app_service using a dynamic block e.g.
locals {
ip_addresses = [ "192.168.250.1" ]
}
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "West Europe"
}
resource "azurerm_app_service_plan" "example" {
name = "example-appserviceplan"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku {
tier = "Standard"
size = "S1"
}
}
resource "azurerm_app_service" "example" {
name = "example-app-service"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
site_config {
dotnet_framework_version = "v4.0"
scm_type = "LocalGit"
}
app_settings = {
"SOME_KEY" = "some-value"
}
connection_string {
name = "Database"
type = "SQLServer"
value = "Server=some-server.mydomain.com;Integrated Security=SSPI"
}
dynamic "ip_restriction" {
for_each = toset(local.ip_addresses)
content {
ip_address = each.value
}
}
}
However, to remove the restrictions you need to explicit assign ip_restriction to the empty list, i.e.
resource "azurerm_app_service" "example" {
...
ip_restriction = []
}
What I don’t see is how to do this conditionally - if I make two resources and have those conditional my app_service will be created/destroyed whereas I need it updated in place.
I'm afraid that the dynamic block does not support an empty list when using a conditional expression. Read more reference here.
After my validation, the conditional expression like for_each = var.some_variable == "" ? [] : [1] does not work when var.some_variable set to null but this could work seperately when for_each = var.some_variable and var.some_variable set to null.
So, in this case, as the answer from #rkm, you can use the for loop like this working sample for me.
variable "ip_restrictions" {
default = [
# {
# ip_address = "1.1.1.1/32"
# virtual_network_subnet_id = null
# subnet_id = null
# name = "aaa"
# priority = 110
# action = "Allow"
# },
# {
# ip_address = "2.2.2.2/32"
# virtual_network_subnet_id = null
# subnet_id = null
# name = "bbb"
# priority = 112
# action = "Allow"
# },
]
}
resource "azurerm_app_service" "example" {
name = "nn-example-app-service"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
site_config {
ip_restriction = [
for s in var.ip_restrictions :
{
ip_address = s.ip_address
virtual_network_subnet_id = s.virtual_network_subnet_id
subnet_id = s.subnet_id
name = s.name
priority = s.priority
action = s.action
}
]
}
}
This is special terraform syntax called Attributes as Blocks. Resource arguments defined using nested block syntax implicitly define a fixed collection of objects and thus in order to specify zero objects, we should explicitly set empty list. And these two forms cannot be mixed.
With that said, terraform supports an argument syntax too (even though they recommend using block syntax for simple cases for readability):
example = [
for name in var.names: {
foo = name
}
]
Just in case anyone lands here looking for how to return a blank dynamic configuration block (instead of an input parameter like the OP), you can make the iteration list used by the for_each to be blank, and use conditionals in the content to set everything to null.
For example, if you have a dynamic inline_policy for AWS iam_role and you pass your inline json with a variable name policy_documents, you can first combine them into a single json document, then set a local variable to either a blank or what was passed in:
data "aws_iam_policy_document" "combined_policy" {
source_policy_documents = var.policy_documents
}
locals {
policy_documents = length(var.policy_documents) == 0 ? [""] : [data.aws_iam_policy_document.combined_policy.json]
}
Now you can use local.policy_documents as the iterator for the dynamic block and the blank ensures the dynamic block will always generate something. To produce a blank inline_policy, you can test if the iterator is blank and set everything to null.
resource "aws_iam_role" "default" {
... #(other parameters ommitted)
dynamic "inline_policy" {
for_each = local.policy_documents
content {
name = length(inline_policy.value) == 0 ? null : "custom_inline_policy"
policy = length(inline_policy.value) == 0 ? null : inline_policy.value
}
}
}
In the case where no inline policy is passed in, the dynamic block will generate a blank inline_policy {}:
+ resource "aws_iam_role" "default" {
+ arn = (known after apply)
+ assume_role_policy = jsonencode(
{
+ Statement = [
+ {
+ Action = "sts:AssumeRole"
+ Effect = "Allow"
+ Principal = {
+ Service = "ec2.amazonaws.com"
}
+ Sid = ""
},
]
+ Version = "2012-10-17"
}
)
+ create_date = (known after apply)
+ id = (known after apply)
+ inline_policy {}
}
I discovered how important a blank inline_policy is by accident when someone manually added an inline policy in the console, but the dynamic inline_policy did not notice it when I ran a terraform plan. If there was no inline_policy to start with, then the dynamic block never runs and so terraform doesn't check it. If you force the dynamic block to run even if the inline_policy is blank, terraform will ensure it is blank and delete the manually added inline policy. (Look here and here for terraform documentation and here for a good discussion at hashicorp about blank dyanamic blocks.)

Reuse the configuration to create similar resources in Terraform

I have the below TF file, which will create a function - FirstFunction. This works perfectly.
resource "azurerm_function_app" "**firstfunction**" {
name = **var.firstfunctionname**
location = azurerm_resource_group.resourcegroupX.location
resource_group_name = azurerm_resource_group.resourcegroupX.name
app_service_plan_id = azurerm_app_service_plan.appserviceplan.id
https_only = "true"
client_affinity_enabled = "true"
app_settings = {
NS = azurerm_eventhub_namespace.eventhubns.name
Hub = azurerm_eventhub.**firsteventhub**.name
propertyX = "**firstproperty**"
LogRef = "${azurerm_storage_account.store.primary_blob_endpoint}${azurerm_storage_container.**firstlogs**.name}"
}
}
resource "azurerm_app_service_virtual_network_swift_connection" "**firstvnet**" {
app_service_id = azurerm_function_app.**firstfunction**.id
subnet_id = azurerm_subnet.snet.id
}
In the file, see the section enclosed with ****, which need to be changed to create SecondFunction, ThirdFunction and so on ...
The way i have right now is to create multiple TF files , with the same code copied and change the sections enclosed in **.
I read through the module system but understood the limitation with the module system is that I cannot refer to the other components created in the same TF root module as shown below
For e.g In the TF file, I refer to location as
location = azurerm_resource_group.resourcegroupX.location
If I do it as a module, the location should be refered to as
location = var.location_name where location_name should be defined as a variable. I cannot refer to components created with the same root module.
Can you please suggest a solution where I can create multiple components based on the similar code ? Please note that, in the above example, Im creating 2 resources in a single TF file and both of them are related.
The simplest way is that use the count property in your resources. It can help you create multiple same resources in the same code.
resource "azurerm_function_app" "myfunction" {
count = number_your_need # how many resources you want to create
name = "${var.firstfunctionname}-${count.index}"
location = azurerm_resource_group.resourcegroupX.location
resource_group_name = azurerm_resource_group.resourcegroupX.name
app_service_plan_id = azurerm_app_service_plan.appserviceplan.id
https_only = "true"
client_affinity_enabled = "true"
app_settings = {
NS = azurerm_eventhub_namespace.eventhubns.name
Hub = azurerm_eventhub.**firsteventhub**.name
propertyX = "**firstproperty**"
LogRef = "${azurerm_storage_account.store.primary_blob_endpoint}${azurerm_storage_container.**firstlogs**.name}"
}
}
resource "azurerm_app_service_virtual_network_swift_connection" "**firstvnet**" {
count = number # how many you need to create
app_service_id = element(azurerm_function_app.myfunction[*].id, count.index)
subnet_id = azurerm_subnet.snet.id
}
The same solution for the azurerm_eventhub that you need to create. For example:
resource "azurerm_eventhub" "myeventhub" {
count = number # how many you need to create
name = "${var.eventhub_name}-${count.index}"
...
}
Then you can refer it in the function app like this:
app_settings = {
NS = azurerm_eventhub_namespace.eventhubns.name
Hub = element(azurerm_eventhub.myeventhub[*].name, count.index)
propertyX = "**firstproperty**"
LogRef = "${azurerm_storage_account.store.primary_blob_endpoint}${azurerm_storage_container.**firstlogs**.name}"
}
So does all the section enclosed with ****.

Using "count" in aws_route53_record terrafrom resource

I'm starting to use (and learn) terraform, for now, I need to create multiple DO droplets and attach them to the aws route53 zone, what I'm trying to do:
My DO terraform file:
# Configure the DigitalOcean Provider
provider "digitalocean" {
token = var.do_token
}
# Create a new tag
resource "digitalocean_tag" "victor" {
name = "victor-fee1good22"
}
resource "digitalocean_droplet" "web" {
count = 2
image = var.do_config["image"]
name = "web-${count.index}"
region = var.do_config["region"]
size = var.do_config["size"]
ssh_keys = [var.public_ssh_key, var.pv_ssh_key]
tags = [digitalocean_tag.victor.name]
}
My route53 file:
provider "aws" {
version = "~> 2.0"
region = "us-east-1"
access_key = var.aws_a_key
secret_key = var.aws_s_key
}
data "aws_route53_zone" "selected" {
name = "devops.rebrain.srwx.net"
}
resource "aws_route53_record" "www" {
сount = length(digitalocean_droplet.web)
zone_id = data.aws_route53_zone.selected.zone_id
name = "web_${count.index}"
type = "A"
ttl = "300"
records = [digitalocean_droplet.web[count.index].ipv4_address]
}
But I always get The "count" object can be used only in "resource" and "data" blocks, and only
when the "count" argument is set. error, what did I wrong?
Thanks!
UPDATE:
I've resolved this one like — add сount = 2 instead of сount = length(digitalocean_droplet.web)
It works but would be better to have the dynamic variable instead of constant count. :)
you want to get number of services, that not yet created. Terraform couldn't do that.
As I think simplest way use common var with the number of droplets.
resource "digitalocean_droplet" "test" {
count = var.number_of_vps
image = "ubuntu-18-04-x64"
name = "test-1"
region = data.digitalocean_regions.available.regions[0].slug
size = "s-1vcpu-1gb"
}
resource "aws_route53_record" "test" {
count = var.number_of_vps
zone_id = data.aws_route53_zone.primary.zone_id
name = "${local.login}-${count.index}.${data.aws_route53_zone.primary.name}"
type = "A"
ttl = "300"
records = [digitalocean_droplet.test[count.index].ipv4_address]
}
This trick helped - https://github.com/hashicorp/terraform/issues/12570#issuecomment-291517239
resource "aws_route53_record" "dns" {
count = "${length(var.ips) > 0 ? length(var.domains) : 0}"
// ...
}

Resources