Chapter 1

Prerequisites

Prerequisites

Tools

In this section, we will cover the tools we commonly use. This ecosystem is ever-growing and it is not an exhaustive list. These are simply the tools we use, that add value to our interactions with Terraform and we felt were worth passing along. Get started here

Types

One of the biggest obstacles we have encountered when mentoring folks new to Terraform is they will pass the incorrect type to Terraform. It has been our experience that there is value in understanding what type Terraform is expecting you to pass to it. The docs often fall short here. Having an awareness of the types Terraform supports, and how to find out what type the Resource or Data Source is expecting is what we cover in this section. We feel with this knowledge and awareness will create a better experience and hopefully a less frustrating experience. Get started here.

Subsections of Prerequisites

Tools

  • tfenv

    • We don’t recommend installing Terraform globally rather, we are big fans of tfenv.
    • We also recommend you use a .terraform-version file in your project’s root.
    • This is useful when you’re testing TF upgrades. Though this is less of a problem today with HashiCorp’s v1.x Compatiability Promises if you’re lucky enough to be using Terraform 1.x.x
  • pre-commit-terraform

    • Your uses case may be different than ours, see here for available hooks.

    • For what it’s worth, most of our projects have terraform_fmt, terraform_lint and terraform_validate.

    • Some projects also require terraform_tfsec, terrascan and terraform_docs

      • I have a .terraform-docs.yml configuration like so:
      settings:
        html: false
        anchor: false
      formatter: "markdown table"
      
  • If you use Visual Studio Code, the Terraform Plugin is highly recommended.

Types

It has been our experience, the best way to understand Terrarform is to be aware of Types. Types are common in other lanuages, so if you’ve used Ruby, Python, NodeJS, etc. you may already be familiar with types. If you’re not, here are the types defined by Terraform.

Source Code?!

We’re strong believers that no one should ever have to look at the source code to figure something out. But, we have found ourselves having to eventually look at the source code to figure out what a Resource or a Data Source is expecting. The source code presented here is not meant to teach you Golang or the internals of Terraform. The intent is to create an awareness of what these types may look like so if or when you see them again when you’re trying to figure something out, you’re not staring at it really really confused.

Additional Resources

Subsections of Types

Null

null

A value that represents absence or omission. Setting an arugment’s value to null, Terraform will act as though you had completely omitted it. It will use the argument’s default value if it has one, or raise an error if the argument is mandatory.

Example

References

Map

Map

A map is represented as a key/value pair.

Example Resource

The Terraform Resource digitalocean_loadbalancer (truncated for brevity)

...
forwarding_rule {
  entry_port     = 80
  entry_protocol = "http"

  target_port     = 80
  target_protocol = "http"
}
...

The keys entry_port, entry_protocol, target_port and target_protocol above and their respective values, 80, and http.

Source Code

The corresponding source code

"forwarding_rule": {
  Type:     schema.TypeSet,
  Required: true,
  MinItems: 1,
  Elem: &schema.Resource{
   Schema: map[string]*schema.Schema{
    "entry_protocol": {
  Type:     schema.TypeString,
  Required: true,
  ValidateFunc: validation.StringInSlice([]string{
   "http",
   "https",
   "http2",
   "http3",
   "tcp",
   "udp",
  }, false),
    },
    "entry_port": {
  Type:         schema.TypeInt,
  Required:     true,
  ValidateFunc: validation.IntBetween(1, 65535),
    },
    "target_protocol": {
  Type:     schema.TypeString,
  Required: true,
  ValidateFunc: validation.StringInSlice([]string{
   "http",
   "https",
   "http2",
   "tcp",
   "udp",
  }, false),
    },
    "target_port": {
  Type:         schema.TypeInt,
  Required:     true,
  ValidateFunc: validation.IntBetween(1, 65535),
    },
    "certificate_id": {
  Type:         schema.TypeString,
  Optional:     true,
  ValidateFunc: validation.NoZeroValues,
    },
    "tls_passthrough": {
  Type:     schema.TypeBool,
  Optional: true,
  Default:  false,
    },
   },
  },
  Set: hashForwardingRules,
  },

References

Bool

bool

Can either be true or false. A bool value can be used in conditional logic.

Example

digitalocean_droplet

...
backups = true
...

The source

   "backups": {
        Type:     schema.TypeBool,
        Optional: true,
        Default:  false,
   },

References

List

List

A list or tuple is a squence of values (e.g ipAddr = ["192.168.1.1", "192.168.1.2"]). Lists are zero-indexed, so elements can be selected with this syntax ipAddr[0].

Example Resource

The Terraform Resource digitalocean_spaces_bucket

...
  cors_rule {
    allowed_headers = ["*"]
    allowed_methods = ["PUT", "POST", "DELETE"]
    allowed_origins = ["https://www.example.com"]
    max_age_seconds = 3000
  }
...

Source Code

The corresponding source code.

   "cors_rule": {
        Type:        schema.TypeList,
        Optional:    true,
        Description: "A container holding a list of elements describing allowed methods for a specific origin.",
        Elem: &schema.Resource{
         Schema: map[string]*schema.Schema{
          "allowed_methods": {
           Type:        schema.TypeList,
           Required:    true,
           Description: "A list of HTTP methods (e.g. GET) which are allowed from the specified origin.",
           Elem:        &schema.Schema{Type: schema.TypeString},
          },
          "allowed_origins": {
           Type:        schema.TypeList,
           Required:    true,
           Description: "A list of hosts from which requests using the specified methods are allowed. A host may contain one wildcard (e.g. http://*.example.com).",
           Elem:        &schema.Schema{Type: schema.TypeString},
          },
          "allowed_headers": {
           Type:        schema.TypeList,
           Optional:    true,
           Description: "A list of headers that will be included in the CORS preflight request's Access-Control-Request-Headers. A header may contain one wildcard (e.g. x-amz-*).",
           Elem:        &schema.Schema{Type: schema.TypeString},
          },
          "max_age_seconds": {
           Type:     schema.TypeInt,
           Optional: true,
          },
         },
        },
   },

References

Terraform Docs

Number

Number

Example

The Terraform Resource aws_ecs_service.

...
  load_balancer {
    target_group_arn = aws_lb_target_group.foo.arn
    container_name   = "mongo"
    container_port   = 8080
  }

Source Code

The corresponding source code.

      "container_port": {
           Type:         schema.TypeInt,
           Required:     true,
           ValidateFunc: validation.IntBetween(0, 65536),
      },

References

Strings

Strings

Example Resource

The Terraform Resource aws_ecs_service

resource "aws_ecs_service" "mongo" {
  name            = "mongodb"
  cluster         = aws_ecs_cluster.foo.id
...

Source Code

The corresponding source code.

   "name": {
    Type:     schema.TypeString,
    Required: true,
    ForceNew: true,
   },

Example

References