When/where does the data aws_availability_zones is initialised or injected? - terraform

I am reading the terraform code here https://github.com/linuxacademy/content-terraform/blob/master/course/terraform-aws/networking/main.tf and here are the code I don't quite understand.
data "aws_availability_zones" "available" {}
....
resource "aws_subnet" "tf_public_subnet" {
count = 2
vpc_id = "${aws_vpc.tf_vpc.id}"
cidr_block = "${var.public_cidrs[count.index]}"
map_public_ip_on_launch = true
availability_zone = "${data.aws_availability_zones.available.names[count.index]}"
tags {
Name = "tf_public_${count.index + 1}"
}
}
I don't understand when the data.aws_availability_zones is populated.

data.aws_availability_zones is data source, different from resource (the next code you pasted)
Please go through this url terraform data source to understand how data sources work
If you don't understand how data.aws_availability_zones works, go through this url Data Source: aws_availability_zones
So from its Attributes Reference, we know it will help to get current account's availability zones.
zone_ids - A list of the Availability Zone IDs available to the account.
Its attribute name is alias of zone_ids, their outputs are same.

Related

how can i get a list of azure vm ids in terraform and then read them back one value at a time?

I need to get a list of all VM ids in an Azure subscription using Terraform then read them back one by one and feed one id at a time to a module to perform some tasks on it, how can i do this?
You can use the feature multiple instances of the data source to get the list of all the VM ids. See the data source azurerm_virtual_machine, it requires the name and the resource group name. So if the VMs in the same group, you just need to create a list variable for all the VM names, then the data block will be like this:
variable "vm_names" {
type = list(string)
default = [
...
]
}
data "azurerm_virtual_machine" "example" {
count = length(var.vm_names)
name = element(var.vm_names, count.index)
resource_group_name = var.resource_group_name
}
output "vm_ids" {
value = data.azurerm_virtual_machine.example.*.id
}
The output is all the VM ids.

Passing multiple values to a variable in Terraform

I have a question about passing multiple values to a variable in Terraform. I can't find the answer anywhere and I am not sure if this is even possible. In our environment when we create AWS resources such VPC and add a tag name to it like project-environment-VPC e.g. cvs-production-VPC. How would I do the same when I am trying to create the resource using Terraform? I tried the below approach and it didn't work:
resource "aws_vpc" "main" {
cidr_block = var.aws_cidr
instance_tenancy = "default"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = ${var.project}-${var.environment}-${"VPC"}
}
}
If it is not possible - perhaps there is a workaround? Thanks in advance for any replies.
The current Name tag value causes Invalid Character error using Terraform 0.14.6.
Change the Name tag value as below to resolve the issue.
Name = "${var.project}-${var.environment}-${"VPC"}"

Creating two VMs in the same resource group without Terraform wanting to destoy the first one

I'm trying to deploy two virtual machines within the same resource group to our Azure platform with Terraform. After successfully creating the first one Terraform then wants to destroy the first one to create the second one after I've changed the second VM name and Azure tag.
I've been following the Terraform guide: https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html
resource "azurerm_virtual_machine" "main" {
location = "${var.location}"
name = "${var.vm_name}"
network_interface_ids = ["${azurerm_network_interface.main.id}"]
resource_group_name = "${var.resourcegroup_vm}"
vm_size = "${var.vm_size}"
tags {
application = "${var.tag}"
}
I expected Terraform to just create the second VM after changing its variable name and tag. Not wanting to destory the first one because of the name and tag change.
Terraform is based on HCL (Hashicorp Configuration Language), which is the format *.tf files are written in. It is a declarative language (as opposed to imperative), which means that you describe the desired state you want your infrastructure to be and Terraform will figure out what changes are needed to take it to that point.
If you first create an instance and then change its name you are telling Terraform that you no longer want your instance to have the old name but the new one.
To deploy a number of instances you can use the count attribute. You could then use interpolation to get names and tags based in the counter, something similar to this:
resource "azurerm_virtual_machine" "main" {
location = "${var.location}"
name = "${var.vm_name}-${count.index + 1}"
network_interface_ids = ["${azurerm_network_interface.main.id}"]
resource_group_name = "${var.resourcegroup_vm}"
vm_size = "${var.vm_size}"
tags {
application = "${var.tag}-${count.index + 1}"
}
count = 2
}
Note the attached -${count.index + 1} to name and the application tag.

Terraform retrieve CIDR/Prefix from existing VNETs/subnets

In Terraform, I want to create a route table for an existing subnet. To achieve the desired end result, I need to pull the CIDR/Prefix for the VNET. The VNET CIDR value is not known beforehand, the only values I know before launch is the VNET's name and Resource Group.
I would like to take the VNET CIDR/Prefix and insert it as a destination in the route table.
data "azurerm_virtual_network" "vnet" {
name = "${var.vnet_name}"
resource_group_name = "${var.vnet_rg}"
}
module "routetable" {
source = "modules/routetable"
route_table_name = "${var.route_table_name}"
resource_group_name =
"${data.azurerm_resource_group.vnet.name}"
location = "eastus"
route_prefixes = ["0.0.0.0/0", "${EXISTING_VNET_CIDR_HERE}"]
route_nexthop_types = ["VirtualAppliance", "VirtualAppliance"]
route_names = ["route1", "route2"]
}
just use data you are getting from the vnet:
${data.azurerm_virtual_network.vnet.address_spaces}
the only issue - assress_spaces is an array (i think its called list in terraforms terms).

Terraform List of Maps

I currently have a single resource defined for
aws_ebs_volume & aws_volume_attachment
I use a count based on a variable to determine how many devices I want to created followed by a count on the attachment:
data_volumes = ["50"]
data_device = ["xvde"]
resource "aws_ebs_volume" "datavolumes" {
count = "${length(var.data_volumes)}"
size = "${var.data_volumes[count.index]}"
tags = "${var.instance_tags}"
encrypted = "true"
availability_zone = "us-east-2b"
kms_key_id = "${var.kms_key}"
}
resource "aws_volume_attachment" "attachvolumes" {
count = "${length(var.data_volumes)}"
device_name = "${var.data_device[count.index]}"
volume_id = "${aws_ebs_volume.datavolumes.*.id[count.index]}"
instance_id = "${aws_instance.general.id}"
}
I'm struggling with finding a way to assign unique tags to each of these volumes that get created, as you can see I'm using a static list of "instance_tags" for each of the volumes but I'd like to have unique tags applied to each of the volumes. I'm trying to avoid having to specify a resource/volume but might be easiest at this point.
Hoping someone can help me understand if its possible and an example of what it looks like.
I think I found an approach that works for what I'm trying to accomplish:
resource "aws_ebs_volume" "datavolumes" {
count = "${length(var.data_volumes)}"
size = "${var.data_volumes[count.index]}"
tags = "${merge(
var.instance_tags,
map(
"DriveLetter", "${var.data_letters[count.index]}",
"DriveLabel", "${var.data_labels[count.index]}"
)
)}"
data_volumes = ["50","50","50"]
data_device = ["xvde","xvdf","xvdg"]
data_letters = ["E:", "F:", "G:"]
data_labels = ["Data", "Logs", "TempDB"]
This gives me unique EBS volumes with Unique tag properties for each volumes and maintains my single resource

Resources