terrafor from - create 3 server over 2 subnets using count - amazon-web-services

In terraform, I wish to create 3 servers while I'm having 2 subnets.
Creating 2 servers according to the below code will route both server and subnet ID according to the count - But what if I want 3 servers? I don't mind on which of the subnet the third server will be located.
resource "aws_instance" "consul_server" {
count = 2
ami = "ami-00ddb0e5626798373"
instance_type = t2.micro
subnet_id = var.private_subnet_id[count.index]
vpc_security_group_ids = [aws_security_group.consul_server.id]
tags = {
Name = "consul-server-${count.index + 1}-${var.project_name}"
tag_enviroment= var.tag_enviroment
project_name = var.project_name
consul_server = "true"
role = "consul-server"
}
}

Normally you would use element to wrap-around indexing:
subnet_id = element(var.private_subnet_id, count.index)

Related

How to apply different TAGs for AWS EC2 in Terraform

I have applied the code for tagging AWS ec2 instances in Terraform, when the code runs it only created singe TAG.
How can we add multiple TAGs e.g
It add Auto creation DATE.
It add Auto OS detection (like it is windows or linux)
Please see TAG detail in Screenshot
Gurus, your kind support will be highly appreciated.
I have added the following code for Tagging.
# Block for create EC2 Instance
resource "aws_instance" "ec2" {
count = var.instance_count
ami = "ami-005835d578c62050d"
instance_type = "t2.micro"
vpc_security_group_ids = [var.security_group_id]
subnet_id = var.subnet_id
key_name = var.key
**tags = {
Name = "${var.name}-${count.index + 1}"**
}
}
tags attribute accepts a map of strings and you can also use terraform functions like merge to merge default tags if available in your used case with custom resource-specific tags.
# Block for create EC2 Instance
resource "aws_instance" "ec2" {
count = var.instance_count
ami = "ami-005835d578c62050d"
instance_type = "t2.micro"
vpc_security_group_ids = [var.security_group_id]
subnet_id = var.subnet_id
key_name = var.key
tags = merge(var.default_ec2_tags,
{
Name = "${var.name}-${count.index + 1}"
}
)
}
variable "default_ec2_tags" {
type = map(string)
description = "(optional) default tags for ec2 instances"
default = {
managed_by = "terraform"
environment = "dev"
}
}
Something very specific to terraform-aws-provider and a very handy feature is default_tags which you can configure on the provider level and these tags will be applied to all resources managed by the provider.
Click to view Tutorial from hashicorp on default-tags-in-the-terraform-aws-provider
It's not possible to get the OS type tag natively as mentioned by #Marcin already in the comments.
You can add other tags by simply adding to your Tags, For example:
tags = {
Name = "${var.name}-${count.index + 1}"
CreationDate = timestamp()
OS = "Linux"
}

Terraform create multiple tags for subnets

I am trying to create VPC Module, here i am facing issue with private subnets. We have multiple resources like RDS, REDSHIFT, CASSANDRA. I want to create subnet for each of this resource in each AZ from single block of code. How ever i am unable figure out how to assign the tags in that case.
resource "aws_subnet" "packages_subnet" {
count = "${length(var.packages_subnet)}"
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${element(var.packages_subnet, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
map_public_ip_on_launch = false
tags = {
Name = "${var.env_name}-${element(var.test, count.index)}-${element(var.availability_zones, count.index)}"
}
}
this is how my vars.tf looks like
variable "test" {
type = list
default = ["rds","redshift","lambda","emr","cassandra","redis"]
}
with the above approach rds subnet is always creating in 1a.
and redshift in 1b.
module "Networking" {
source = "../modules/Networking"
packages_subnet = ["10.3.4.0/24", "10.3.5.0/24", "10.3.6.0/24", "10.3.10.0/24", "10.3.7.0/24", "10.3.8.0/24", "10.3.9.0/24", "10.3.11.0/24", "10.3.12.0/24", "10.3.13.0/24", "10.3.14.0/24", "10.3.15.0/24", "10.3.16.0/24", "10.3.17.0/24", "10.3.18.0/24"]
}

how we can use 2 diff count value in 1 resource using terraform

i have an requirement of creating multiple network interface and each containing 5 private ip depends on AWS_EIP_INSTANCE_COUNT variable . and then i need to assign 5 elastic ip to 5 private ip for each instance . how we can use assign these elastic ip to each network interface if my instance count and AWS_EIP_INSTANCE_COUNT variable has diff values ?
resource "aws_network_interface" "broker" {
count = var.AWS_INSTANCE_COUNT --> no of instances
subnet_id = data.aws_subnet.test1.id
security_groups = data.aws_security_groups.test1.ids
private_ips_count = tonumber(var.AWS_EIP_INSTANCE_COUNT) - 1 --> no of elastic ip
private_ip_list_enabled = "true"
}
resource "aws_eip" "broker-ip" {
vpc = true
count = var.AWS_EIP_INSTANCE_COUNT
network_interface = "${element(aws_network_interface.broker.*.id)}"
associate_with_private_ip = "${join(" ",aws_network_interface.broker[*].private_ip_list[count.index])}"
}

Filter out Subnet IDs based on sufficient capacity in availability zones in Terraform

I'm trying to deploy an EKS cluster and everything seems to be fine except for one!
The facade module looks like this:
module "eks" {
source = "../../../../infrastructure_modules/eks"
## EKS ##
create_eks = var.create_eks
cluster_version = var.cluster_version
cluster_name = local.cluster_name
vpc_id = data.aws_vpc.this.id
subnets = data.aws_subnet_ids.this.ids
# note: either pass worker_groups or node_groups
# this is for (EKSCTL API) unmanaged node group
worker_groups = var.worker_groups
# this is for (EKS API) managed node group
node_groups = var.node_groups
## Common tag metadata ##
env = var.env
app_name = var.app_name
tags = local.eks_tags
region = var.region
}
The VPC id is retrieved through the following block :
data "aws_vpc" "this" {
tags = {
Name = "tagName"
}
}
Which then is used to retrieve the subnet_IDs as following:
data "aws_subnet_ids" "this" {
vpc_id = data.aws_vpc.this.id
}
Nevertheless, deploying this results in error stating:
Error: error creating EKS Cluster (data-layer-eks):
UnsupportedAvailabilityZoneException: Cannot create cluster
'data-layer-eks' because us-east-1e, the targeted availability zone,
does not currently have sufficient capacity to support the cluster.
Which is a well known error, and anybody can come across this for even EC2s.
I could solve this by simply hardcoding the subnet value, but that's really undesirable and hardly maintainable.
So the question is, how can I filter out subnet_IDs based on availability zones that have sufficient capacity?
First you need to collect the subnets with all of their attributes:
data "aws_subnets" "this" {
filter {
name = "vpc-id"
values = [data.aws_vpc.this.id]
}
}
data "aws_subnet" "this" {
for_each = toset(data.aws_subnets.this.ids)
id = each.value
}
data.aws_subnet.this is now a map(object) with all of the subnets and their attributes. You can now filter by availability zone accordingly:
subnets = [for subnet in data.aws_subnet.this : subnet.id if subnet.availability_zone != "us-east-1e"]
You can also filter by truthy conditionals if that condition is easier for you:
subnets = [for subnet in data.aws_subnet.this : subnet.id if contains(["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"], subnet.availability_zone)]
It depends on your personal use case.

Trying to create 2 ASGs in one terraform file

I'm trying to create an launch configuration, ELB and 2 ASG. I guess one ELB is fine to create 2 ASG (im not sure).
So I have a launch configuration and asg code in one file calling the as module. My question is, can I create 2 ASG using a single terraform file or with file in a single repo?
Also, Please let me know if this is a good configuration.
when I tried to put two different files calling same module I get following error.
Error downloading modules: Error loading modules: module asg: duplicated. module names must be unique
My Terraform code:
auto_scaling.tf
resource "aws_launch_configuration" "launch_config" {
image_id = "${var.ec2ami_id}"
instance_type = "${var.ec2_instance_type}"
security_groups = ["${aws_security_group.*******.id}"]
key_name = "${var.keypair}"
lifecycle {
create_before_destroy = true
}
}
module "asg" {
source = ****
name = "*****"
environment = "***"
service = "****"
product = "**"
team = "****"
owner = "*****"
ami = "${var.ec2_id}"
#instance_profile = "******"
instance_type = "t2.micro"
ebs_optimized = true
key_name = "${var.keypair}"
security_group = ["${aws_security_group.****.id}"]
user_data = "${path.root}/blank_user_data.sh"
load_balancer_names = "${module.elb.elb_name}"
associate_public_ip = false
asg_instances = 2
asg_min_instances = 2
asg_max_instances = 4
root_volume_size = 250
asg_wait_for_capacity_timeout = "5m"
vpc_zone_subnets = "${module.vpc.private_subnets}"
}
###elb.tf###
module "elb" {
source = "*****"
name = "***elb"
subnet_ids = "${element(split(",",
module.vpc.private_subnets), 0)}"
security_groups = "${aws_security_group.****.id}"
s3_access_logs_bucket = "****"
}
I want to create 2 ASGs in one subnet.
You can reuse your asg module - just give both instances different resource names, e.g.:
module "asg1" {
...
}
module "asg2" {
...
}