Terraform Visual

rover

Object


variable "health_check" {
  type = object({
    type = string
    protocol = string
    timeout = number
  })
  default = {
    protocol = "http"
    type = "ipv4"
    timeout = 20
  }
}

# 先运行 terraform plan 或者 apply,然后再运行 terraform console 来测试
# 直接 .出属性,或者[""]
-> % terraform console                          
> var.health_check
{
  "protocol" = "http"
  "timeout" = 20
  "type" = "ipv4"
}
> var.health_check.type
"ipv4"
> var.health_check["type"]
"ipv4

Map


Basic Usage of Maps
variable "region" {
  type  = "string"
  default = "us-east-1"
}

variable "ami" {
  type = map(string)
  default = {
    "us-east-1" = "ami-123456",
    "us-west-1" = "ami-abcdef"
  }
}

locals {
  defaults = {
    instance_type = "t2.micro",
    count         = 1
  }
  overrides = {
    us-east-1 = {
      instance_type = "t2.large",
      count = 2
    }
  }
  instance_types = {
    "small" = "t2.micro",
    "large" = "t2.large"
  }
}


#
resource "aws_instance" "example" {
  ami           = var.ami[var.region]
  instance_type = "t2.micro"
}
# merging maps
# count
resource "aws_instance" "advanced_example" {
  count         = merge(local.defaults, local.overrides[var.region]).count
  ami           = var.ami[var.region]
  instance_type = merge(local.defaults, local.overrides[var.region]).instance_type
}
# Conditionals with Maps
resource "aws_instance" "conditional_example" {
  count         = var.size == "large" ? local.instance_types["large"] : local.instance_types["small"]
  ami           = var.ami[var.aws_region]
  instance_type = local.instance_types[var.size]
}
# Looping Over Maps
# for_each each.key/each.value
resource "aws_instance" "looping_example" {
  for_each      = var.ami
  ami           = each.value
  instance_type = "t2.micro"
  tags = {
    "Name" = "Instance-${each.key}"
  }
}
Map for_each
variable "map" {
  type = map(string)
  default = {
    "name" = "value"
  }
}

# terraform console
# 也可以 [""]获取值,但是一般map的key是不确定的
> var.map
tomap({
  "name" = "value"
})
> var.map["name"]
"value"
# 对于map而已,k 就是key值,v就是 value值
> {for k, v in var.map: k=>v}
{
  "name" = "value"
}
# map 也有length
> length(var.map)
1
Basic Filtering of Maps
variable "input_map" {
  default = {
    "a" = "apple",
    "b" = "banana",
    "c" = "cherry"
  }
}

# Filtering Based on Key
{for k, v in var.input_map : k => v if substr(k, 0, 1) == "a"}
{
  "a" = "apple"
}

# Filtering Based on Value
{for k, v in var.input_map : k => v if contains(["apple", "banana"], v)}
{
  "a" = "apple",
  "b" = "banana"
}

# Filtering and Transforming Map Values
{for k, v in var.input_map : k => upper(v) if substr(k, 0, 1) == "b"}
{
  "b" = "BANANA"
}

# To combine these maps into one while filtering
variable "first_map" {
  default = {
    "a" = "apple",
    "b" = "banana"
  }
}

variable "second_map" {
  default = {
    "c" = "cherry",
    "d" = "date"
  }
}

{
  {for k, v in var.first_map : k => v if substr(k, 0, 1) == "a"},
  {for k, v in var.second_map : k => v if substr(k, 0, 1) == "d"}
}
{
  "a" = "apple",
  "d" = "date"
}
Map(Object)
variable "instance_details" {
  type = map(object({
    zone     = string
    size     = string
  }))
  default = {
    "instance1" = { zone = "us-west-1a", size = "t2.micro" },
    "instance2" = { zone = "us-west-1b", size = "t2.small" }
  }
}
  • Basic Iteration with count
    shell resource "aws_instance" "example" { count = length(var.instance_details) ami = "ami-123456" instance_type = var.instance_details[keys(var.instance_details)[count.index]].size availability_zone = var.instance_details[keys(var.instance_details)[count.index]].zone } - Advanced Iteration with for_each shell resource "aws_instance" "example" { for_each = var.instance_details ami = "ami-123456" instance_type = each.value.size availability_zone = each.value.zone tags = { Name = each.key } }

Conditional Iteration

locals {
  filtered_instance_details = { for k, v in var.instance_details : k => v if v.zone == "us-west-1a" }
}

resource "aws_instance" "filtered_example" {
  for_each      = local.filtered_instance_details
  ami           = "ami-123456"
  instance_type = each.value.size
  availability_zone = each.value.zone
}

List


List(string)

> var.list-string
tolist([
  "value",
  "value1",
])

# List 都是有长度的
> length(var.list-string)
2
# 可以通过 index 取值
> var.list-string[1]
"value1"
# 不管是k还是v,都是用的v的值
> [for k,v in var.set: upper(k)]
[
  "VALUE",
  "VALUE1",
]

List(Object)

variable "iam_list" {
  type = list(object({
    name = string
    trust = string
    account = number
  }))
  default = [ 
    {
      name = "name1"
      trust = "trust1"
      account = 123
    } 
  ]
}


> var.iam_list
tolist([
  {
    "account" = 123
    "name" = "name1"
    "trust" = "trust1"
  },
])

# 对于List(object) k,v 时,k 就是 index
# k=>v 这就是转成 map 了,key是index,value就是原来 list中的object
# 与 List(map(string)) 不同的是,map的是"0"=tomap({}) 
# 而 List(object) 为 "0" = {} ,
> {for k, v in var.iam_list: k=>v}
{
  "0" = {
    "account" = 123
    "name" = "name1"
    "trust" = "trust1"
  }
}
# 单独的 v 就是里面的一个一个的 object
> [for v in var.iam_list: v]
[
  {
    "account" = 123
    "name" = "name1"
    "trust" = "trust1"
  },
]
# 只单独的 k 就是 index
> [for k,v in var.iam_list: k]
[
  0,
]
# List 的有 length
> length(var.iam_list)
1
# 可以通过 index去获取
> var.iam_list[0]
{
  "account" = 123
  "name" = "name1"
  "trust" = "trust1"
}

List(map(string))

variable "list-map" {
  type = list(map(string))
  default = [ 
    {
      "key" = "value"
      "name" = "rick"
    } 
  ]
}
# terraform console
> var.list-map
tolist([
  tomap({
    "key" = "value"
    "name" = "rick"
  }),
])
# 可以看 list 数量
> length(var.list-map)
1
# k为索引,v为值,这里的v值是map
> {for k,v in var.list-map: k=>v}
{
  "0" = tomap({
    "key" = "value"
    "name" = "rick"
  })
}

dynamic

resource "aws_security_group" "example" {
  name = "example-group"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

execute shell/bash scripts

  • Basic Execution Using null_resource

    resource "null_resource" "example" {
    provisioner "local-exec" {
    command = "echo Hello, World!"
    }
    }
    
    • Advanced Usage: Passing Variables and Output
      shell variable "greeting" { description = "Greeting to display" type = string default = "Hello, Terraform!" } resource "null_resource" "advanced_example" { provisioner "local-exec" { command = "echo ${var.greeting} > greeting.txt" environment = { GREETING = var.greeting } } }
  • Executing Scripts From Files

    resource "null_resource" "script_file" {
    provisioner "local-exec" {
    command = "bash ${path.module}/setup.sh"
    }
    }
    
    • Using remote-exec for Remote Execution
      shell resource "aws_instance" "web" { ami = "ami-a1b2c3d4" instance_type = "t2.micro" provisioner "remote-exec" { inline = [ "sudo apt-get update", "sudo apt-get install -y nginx", ] connection { type = "ssh" user = "ubuntu" private_key = file("~/mykey.pem") host = self.public_ip } } }
  • Basic File Copy with Terraform ```shell resource "aws_instance" "example" { ami = "ami-abc123" instance_type = "t2.micro"

provisioner "file" { source = "./source_file.txt" destination = "/tmp/destination_file.txt"

connection {
  type        = "ssh"
  user        = "ec2-user"
  private_key = file("~/.ssh/id_rsa")
  host        = self.public_ip
}

} }

- Advanced Folder Synchronization
```shell
resource "null_resource" "sync_folder" {
  triggers = {
    always_run = "${timestamp()}"
  }

  provisioner "local-exec" {
    command = "rsync -avz ./source_folder/ ec2-user@${aws_instance.example.public_ip}:/tmp/destination_folder"

    environment = {
      AWS_DEFAULT_REGION = var.region
    }
  }
}

Set

variable "set" {
  type = set(string)
  default = [ "value", "value", "value1" ]
}
# terraform console
> var.set
toset([
  "value",
  "value1",
])
# set 数据有length很正常
> length(var.set)
2
# 这里不管用 k,v 都是 v的值
> [for k,v in var.set: upper(k)]
[
  "VALUE",
  "VALUE1",
]