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.
Function Categories
Section titled “Function Categories”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.
Function Syntax
Section titled “Function Syntax”Functions are called by name with comma-separated arguments in parentheses:
# Simple function callupper("hello") # Returns "HELLO"
# Function with multiple argumentsjoin(", ", ["apple", "banana", "cherry"]) # Returns "apple, banana, cherry"
# Nested function callsupper(trim(" hello world ")) # Returns "HELLO WORLD"
Using Functions in Resources
Section titled “Using Functions in Resources”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 }}
Type Conversions
Section titled “Type Conversions”HCL automatically converts between compatible types, but you can use functions for explicit conversions:
# String to numberlocal { port = parseint(var.port_string, 10)}
# Number to stringlocal { message = "Port: ${tostring(local.port)}"}
# JSON encoding/decodinglocal { config_json = jsonencode({ name = "lab" enabled = true })
parsed_config = jsondecode(local.config_json)}
Common Patterns
Section titled “Common Patterns”Dynamic Resource Naming
Section titled “Dynamic Resource Naming”resource "container" "web" { count = 3
image { name = "app:latest" }
container_name = format("web-%02d", count.index + 1) # web-01, web-02, web-03}
Conditional Values
Section titled “Conditional Values”resource "container" "app" { image { name = var.use_alpine ? "app:alpine" : "app:ubuntu" }
environment = { LOG_LEVEL = upper(coalesce(var.log_level, "info")) # Default to "INFO" }}
List Operations
Section titled “List Operations”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 )}
Best Practices
Section titled “Best Practices”-
Use Descriptive Variable Names: Make function usage clear
local {normalized_username = lower(replace(var.email, "@", "-"))} -
Handle Edge Cases: Consider empty values and errors
local {safe_port = coalesce(var.custom_port, "8080")trimmed_input = trimspace(var.user_input)} -
Prefer Built-in Functions: Use standard functions over complex expressions
# Goodlocal {items = split(",", var.csv_list)}# Avoid complex regex when simpler functions work -
Document Complex Expressions: Add comments for clarity
local {# Extract username from email by taking everything before @username = element(split("@", var.email), 0)}