I want to provision a simple terraform vpc and subnet.
I created a module and declared all the variable required in the module variable.tf
and passed wrote all the needed values through terraform.tfvars
but when I run terraform apply I get a prompt to insert a value for avail_zone
main.tf
module "myapp-subnet" {
source = "./modules/subnet"
subnet_cidr_block = var.subnet_cidr_block
avail_zone = "us-east-1a"
env_prefix = "dev"
vpc_id = aws_vpc.myapp-vpc.id
default_route_table_id = aws_vpc.myapp-vpc.default_route_table_id
}
modules/subnet/main.tf
resource "aws_subnet" "myapp-subnet-1" {
vpc_id = var.vpc_id
cidr_block = var.subnet_cidr_block
availability_zone = var.avail_zone
tags = {
Name: "${var.env_prefix}-subnet-1"
}
}
resource "aws_internet_gateway" "myapp-igw"{
vpc_id = var.vpc_id
tags = {
Name: "${var.env_prefix}-igw"
}
}
# using existing route table
resource "aws_default_route_table" "default-rtb" {
default_route_table_id = var.default_route_table_id
route{
cidr_block = "0.0.0.0/10"
gateway_id = aws_internet_gateway.myapp-igw.id
}
tags = {
Name: "${var.env_prefix}-main-rtb"
}
}
module/subnet/variables.tf
variable vpc_cidr_blocks {}
variable subnet_cidr_block {}
variable avail_zone {}
variable env_prefix{}
variable vpc_id {}
variable default_route_table_id {}
terraform.tfvars
vpc_cidr_blocks = "xxxx"
subnet_cidr_block = "xxxx"
avail_zone = "xxxxxx"
env_prefix = "dev"
myip = "xxxxxxx"
instance_type="t2.micro"
public_key_location= "/home/xxxxxxxx/.ssh/id_rsa.pub"
Related
resource "aws_subnet" "goodsubnet" {
vpc_id = "VPCID"
cidr_block = "x.x.x.x/x"
availability_zone = "xyz"
tags =
{
tagname1 = "$something"
}
}
I want the tag "tagname1" to dynamically have the value of the resource local name i.e "goodsubnet" Is there a variable I can use?
Thanks
That is not possible the way you want to do it. However, Terraform has a concept of variables, which you can use to assign values to arguments. That could be either a local value [1] or an input variable [2]. For example, an input variable definition:
variable "subnet_name_tag" {
type = string
description = "Tag name for a subnet."
}
Then, in your code you would do:
resource "aws_subnet" "goodsubnet" {
vpc_id = "VPCID"
cidr_block = "x.x.x.x/x"
availability_zone = "xyz"
tags =
{
tagname1 = var.subnet_name_tag
}
}
Alternatively, you could define a local value:
locals {
subnet_tag_name = "goodsubnet"
}
Followed by:
resource "aws_subnet" "goodsubnet" {
vpc_id = "VPCID"
cidr_block = "x.x.x.x/x"
availability_zone = "xyz"
tags =
{
tagname1 = local.subnet_name_tag
}
}
[1] https://developer.hashicorp.com/terraform/language/values/locals
[2] https://developer.hashicorp.com/terraform/language/values/variables
I am fairly new to TF and I have written some basic code. Enough to get a vpc up and running and add some subnets and deploy a simple ec2. I am starting to get to the point of wanting to use modules. I struggle with the "keeping generic" thing so I can reuse them over and over. I do not understand how values get passed into modules. For instance I have a module that deploys a vpc, within the same project I have a module that deploys a vpc endpoint. The questions becomes how do i get the value of the vpc_id created with vpc module into the vpc endpoint module? Does anyone have an example of this?
main.tf
provider "aws" {
region = var.aws_region
}
/*Module for VPC creation*/
module "vpc" {
source = "./modules/vpc"
vpc_cidr = var.vpc_cidr
environment = var.environment
tnt_public_subnets_cidr = var.tnt_public_subnets_cidr
availability_zones = var.availability_zones
}
/*Module for EC2 Webserver creation*/
module "webserver" {
source = "./modules/ec2/webserver"
count = var.instance_count
environment = var.environment
subnet_id = module.vpc.tnt_public_subnets_cidr.id
}
/*Module for VPC endpoint creation*/
module "s3-vpce"{
source = "git::https://github.com/tn-sts-cloudtn/sts-terraform-
modules.git//s3-vpce-module/modules//s3-vpce"
vpc_id = module.vpc.vpc_id
}
VPC Module TF File:
/*==== The VPC ======*/
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr
assign_generated_ipv6_cidr_block = true
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}_vpc"
Environment = var.environment
}
}
/*==== Internet Gateway for Public Subnets ======*/
/* Internet gateway for the public subnet */
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.environment}_igw"
Environment = var.environment
}
}
/* Elastic IP for NAT
resource "aws_eip" "instance_eip" {
count = 1
vpc = true
depends_on = [aws_internet_gateway.tnt_igw]
tags ={
Name = "sts_net_infra-mgmt_eip${count.index + 1}"
Environment = var.environment
}
}*/
/* Public subnet */
resource "aws_subnet" "public_subnets_cidr" {
vpc_id = aws_vpc.vpc.id
count = length(var.availability_zones)
cidr_block = var.public_subnets_cidr [count.index]
availability_zone = element(var.availability_zones, count.index)
map_public_ip_on_launch = true
tags ={
Name = "${var.environment}_mgmt_subnet_${count.index + 1}"
Environment = var.environment
}
}
/* Private subnet
resource "aws_subnet" "tnt_private_subnet" {
vpc_id = aws_vpc.tnt_vpc.id
count = length(var.tnt_private_subnets_cidr)
cidr_block = var.tnt_public_subnets_cidr [count.index]
availability_zone = element(var.availability_zones, count.index)
map_public_ip_on_launch = false
tags = {
#Name = var.environment-private-subnet
Environment = var.environment
}
*/
/* Routing table for private subnet
resource "aws_route_table" "tnt_private_rtb" {
vpc_id = aws_vpc.tnt_vpc.id
tags = {
Name = var.environment_private_route_table
Environment = var.environment
}
}*/
/* Routing table for public subnet */
resource "aws_route_table" "public_rtb" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.environment}_public_route_table"
Environment = var.environment
}
}
resource "aws_route" "public_internet_gateway" {
route_table_id = aws_route_table.public_rtb.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
/* Route table associations */
resource "aws_route_table_association" "public" {
count = length(var.public_subnets_cidr)
subnet_id = element(aws_subnet.public_subnets_cidr.*.id, count.index)
route_table_id = aws_route_table.public_rtb.id
}
So I need to output the VPC ID for the VPC endpoint, so I tried to use an output.
output.tf
output "vpc_cidr" {
value = aws_vpc.tnt_vpc.id
}
output "tnt_public_subnets_cidr"{
value = aws_subnet.tnt_public_subnets_cidr.*.id
}
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.vpc.id
}
output "vpc_arn" {
description = "The ARN of the VPC"
value = concat(aws_vpc.tnt_vpc.*.arn, [""])[0]
}
I know I am doing it incorrectly, but I am struggling to understand how outputs flow from module to module.
You can use one moule output into onether module by defining output in each module.
I'd like to use a resource name inside the resource itself to avoid string duplication and copy/paste errors.
resource "aws_instance" "bastion-euw3-infra-01" {
ami = "ami-078db6d55a16afc82"
instance_type = "t2.micro"
key_name = "sylvain"
user_data = templatefile("./scripts/cloudinit.yaml", {
hostname = "bastion-euw3-infra-01"
tailscale_authkey = var.tailscale_authkey
})
network_interface {
device_index = 0
network_interface_id = aws_network_interface.bastion-euw3-infra-01.id
}
tags = {
Name = "bastion-euw3-infra-01"
Environment = "infra"
}
lifecycle {
ignore_changes = [user_data]
}
}
Basically I'd like to replace "bastion-euw3-infra-01" inside the resource with some kind of var, e.g.:
resource "aws_instance" "bastion-euw3-infra-01" {
...
user_data = templatefile("./scripts/cloudinit.yaml", {
hostname = ___name___
tailscale_authkey = var.tailscale_authkey
})
...
tags = {
Name = ___name___
Environment = "infra"
}
...
}
Does terraform provide a way to do this ?
Here I'm trying to create one subnet per availability zone and then associate the route table with each of them.
locals {
aws_region = "${var.aws_regions[var.profile]}"
base_name = "${var.product}-${local.aws_region}"
aws_avzones = {
pro = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
dev = ["eu-west-2a", "eu-west-2b", "eu-west-2c"]
}
}
# ---
# Create VPC
resource "aws_vpc" "default" {
cidr_block = "${var.vpc_cidr_block}"
tags = {
Name = "${local.base_name}-vpc"
}
}
# ---
# Create public subnets - each in a different AZ
resource "aws_subnet" "public" {
count = "${length(local.aws_avzones[var.profile])}"
vpc_id = "${aws_vpc.default.id}"
cidr_block = "${cidrsubnet(var.vpc_cidr_block, 8, count.index)}"
availability_zone = "${element(local.aws_avzones[var.profile], count.index)}"
map_public_ip_on_launch = 1
tags = {
"Name" = "Public subnet - ${element(local.aws_avzones[var.profile], count.index)}"
}
}
# ---
# Create Internet gateway for inbound-outbound connections
resource "aws_internet_gateway" "default" {
vpc_id = "${aws_vpc.default.id}"
tags = {
"Name" = "${local.base_name}-igw"
}
}
# ---
# Create Internet gateway routes table
resource "aws_route_table" "pub" {
vpc_id = "${aws_vpc.default.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.default.id}"
}
tags = {
Name = "${local.base_name}-rtb-igw"
}
}
# ---
# Associate public subnets with the public route table
resource "aws_route_table_association" "pub" {
count = "${length(aws_subnet.public.*.id)}"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
route_table_id = "${aws_route_table.pub.id}"
}
Unfortunately terraform plan renders an error:
aws_route_table_association.pub: aws_route_table_association.pub: value of 'count' cannot be computed
Why it cannot be computed? Terraform did not complain about that when the infra. was all up and running, I discovered this error only after the destruction when attempting to to recreate the infra.
Currently my workaround is to comment out all the aws_route_table_association blocks, then terraform apply, uncomment and then finish the job. Obviously this is very far from ideal.
BTW, I also tried the explicit dependency declaration like so:
resource "aws_route_table_association" "pub" {
count = "${length(aws_subnet.public.*.id)}"
subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
route_table_id = "${aws_route_table.pub.id}"
depends_on = ["aws_subnet.public"]
}
But it didn't help.
$ terraform --version
Terraform v0.11.11
+ provider.aws v1.52.0
I'm very green to terraform; infact this is part of my training.
I'm wondering; is there a way to get terraform to store a specific value (as variable) from the previous command within the same file.
Example:
resource "aws_vpc" "TestVPC"{
cidr_block = "192.168.0.0/16"
instance_tenancy = "default"
enable_dns_hostnames="True"
tags{
Name="TestVpc"
}
}
resource "aws_subnet" "TestSubnet"{
vpc_id = "${var.aws_vpc_id}" ##This is where I'd like to populate the aws_vpc_id from the VPC creation step above.
cidr_block = "192.168.0.0/24"
map_public_ip_on_launch="True"
availability_zone = "us-east-2a"
tags{
Name="TestSubnet"
}
}
Help is greatly appreciated.
Thanks.
You can use the output from the creation of the VPC, ${aws_vpc.TestVPC.id}
Like so:
resource "aws_vpc" "TestVPC" {
cidr_block = "192.168.0.0/16"
instance_tenancy = "default"
enable_dns_hostnames = "True"
tags {
Name = "TestVpc"
}
}
resource "aws_subnet" "TestSubnet" {
vpc_id = "${aws_vpc.TestVPC.id}"
cidr_block = "192.168.0.0/24"
map_public_ip_on_launch = "True"
availability_zone = "us-east-2a"
tags {
Name = "TestSubnet"
}
}