Skip to content

Functions Overview

Functions allow you to transform and combine values within HCL expressions. Instruqt labs support both standard HCL functions and custom functions specific to lab environments.

Functions are organized into logical categories based on their purpose:

Text manipulation, formatting, and string operations.

Mathematical operations and number formatting.

Operations on lists, maps, and sets.

Encoding and decoding data in various formats.

File operations and path manipulation.

Date formatting and time calculations.

Functions specific to Instruqt lab environments.

Functions are called by name with comma-separated arguments in parentheses:

# Simple function call
upper("hello") # Returns "HELLO"
# Function with multiple arguments
join(", ", ["apple", "banana", "cherry"]) # Returns "apple, banana, cherry"
# Nested function calls
upper(trim(" hello world ")) # Returns "HELLO WORLD"

Functions can be used in any HCL expression within your lab configuration:

resource "container" "app" {
image {
name = "nginx:${lower(var.environment)}" # Use lower() function
}
environment = {
API_KEY = base64_encode(var.api_secret) # Encode sensitive data
HOME_DIR = data("workspace") # Get lab data directory
}
}
resource "template" "config" {
source = file("./config.tmpl") # Read template file
destination = "./config.json"
variables = {
timestamp = formatdate("YYYY-MM-DD", timestamp()) # Format current time
host_ip = docker_ip() # Get Docker host IP
}
}

HCL automatically converts between compatible types, but you can use functions for explicit conversions:

# String to number
local {
port = parseint(var.port_string, 10)
}
# Number to string
local {
message = "Port: ${tostring(local.port)}"
}
# JSON encoding/decoding
local {
config_json = jsonencode({
name = "lab"
enabled = true
})
parsed_config = jsondecode(local.config_json)
}
resource "container" "web" {
count = 3
image {
name = "app:latest"
}
container_name = format("web-%02d", count.index + 1) # web-01, web-02, web-03
}
resource "container" "app" {
image {
name = var.use_alpine ? "app:alpine" : "app:ubuntu"
}
environment = {
LOG_LEVEL = upper(coalesce(var.log_level, "info")) # Default to "INFO"
}
}
variable "allowed_regions" {
default = ["us-east-1", "us-west-2", "eu-west-1"]
}
resource "aws_account" "lab" {
regions = concat(
var.allowed_regions,
["us-central-1"] # Always include us-central-1
)
}
  1. Use Descriptive Variable Names: Make function usage clear

    local {
    normalized_username = lower(replace(var.email, "@", "-"))
    }
  2. Handle Edge Cases: Consider empty values and errors

    local {
    safe_port = coalesce(var.custom_port, "8080")
    trimmed_input = trimspace(var.user_input)
    }
  3. Prefer Built-in Functions: Use standard functions over complex expressions

    # Good
    local {
    items = split(",", var.csv_list)
    }
    # Avoid complex regex when simpler functions work
  4. Document Complex Expressions: Add comments for clarity

    local {
    # Extract username from email by taking everything before @
    username = element(split("@", var.email), 0)
    }