Python library and CLI tool for generating Terraform JSON configurations using full Python programming capabilities
Utility functions for working with file paths and local resources in Terraform configurations. These helpers enable relative path references that work correctly regardless of where the Python script is executed, making configurations more portable and maintainable.
Functions that generate file and path references relative to the calling Python file's location, ensuring Terraform configurations work consistently across different execution contexts.
def relative_file(filename: str, _caller_depth: int = 1) -> str:
"""
Generate a file path relative to the calling file's directory.
Parameters:
- filename: str - The filename or relative path to resolve
- _caller_depth: int, optional - How many stack frames up to look (default: 1)
Returns:
str - Terraform file() interpolation expression relative to caller's directory
Example:
# In /project/terraform/main.py
template_path = relative_file('templates/userdata.sh')
# Returns: '${file("${path.module}/templates/userdata.sh")}'
"""
def relative_path(path: str, _caller_depth: int = 1) -> str:
"""
Generate a directory path relative to the calling file's directory.
Parameters:
- path: str - The path to resolve relative to caller
- _caller_depth: int, optional - How many stack frames up to look (default: 1)
Returns:
str - Terraform path expression relative to caller's directory
Example:
# In /project/terraform/main.py
config_dir = relative_path('config')
# Returns: '${path.module}/config'
"""from terraformpy import Resource
from terraformpy.helpers import relative_file
# Project structure:
# /project/
# ├── terraform/
# │ ├── main.py <- This file
# │ ├── templates/
# │ │ ├── userdata.sh
# │ │ └── nginx.conf
# │ └── config/
# │ └── app.json
# EC2 instance with user data script
web_server = Resource('aws_instance', 'web',
instance_type='t3.micro',
ami='ami-12345678',
user_data_base64='${base64encode(file("${relative_file('templates/userdata.sh')}"))}',
tags={'Name': 'WebServer'}
)
# Launch template with file reference
launch_template = Resource('aws_launch_template', 'app',
instance_type='t3.micro',
image_id='ami-12345678',
user_data='${base64encode(file("${relative_file('templates/userdata.sh')}"))}',
tag_specifications=[{
'resource_type': 'instance',
'tags': {'Name': 'AppServer'}
}]
)from terraformpy import Resource
from terraformpy.helpers import relative_file, relative_path
# Lambda function with local code
lambda_function = Resource('aws_lambda_function', 'processor',
filename=relative_file('lambda/processor.zip'),
function_name='data-processor',
role='${aws_iam_role.lambda_role.arn}',
handler='index.handler',
runtime='python3.9'
)
# ECS task definition with template
ecs_task = Resource('aws_ecs_task_definition', 'app',
family='myapp',
container_definitions='${templatefile("${relative_file('templates/task-def.json')}", {
image_url = var.app_image_url,
log_group = aws_cloudwatch_log_group.app.name
})}',
requires_compatibilities=['FARGATE'],
cpu='256',
memory='512'
)
# Docker image build using local context
docker_image = Resource('docker_image', 'app',
name='myapp:latest',
build={
'context': relative_path('.'),
'dockerfile': relative_file('Dockerfile')
}
)from terraformpy import Resource, Variable
from terraformpy.helpers import relative_file
# Application configuration
app_config = Variable('app_config',
default='${file("${relative_file('config/app.json')}")}'
)
# Kubernetes config map from file
k8s_config_map = Resource('kubernetes_config_map', 'app_config',
metadata={'name': 'app-config'},
data={
'config.yaml': '${file("${relative_file('config/k8s-config.yaml')}"))',
'logging.conf': '${file("${relative_file('config/logging.conf')}"))'
}
)
# SSL certificate from file
tls_cert = Resource('aws_acm_certificate', 'app',
certificate_body='${file("${relative_file('certs/app.crt')}"))',
private_key='${file("${relative_file('certs/app.key')}"))'
)from terraformpy import Module
from terraformpy.helpers import relative_path
# Project structure:
# /project/
# ├── main.py <- This file
# ├── modules/
# │ ├── networking/
# │ │ ├── main.py
# │ │ └── variables.py
# │ └── compute/
# │ ├── main.py
# │ └── variables.py
# Reference local modules with relative paths
vpc_module = Module('vpc',
source=relative_path('modules/networking'),
cidr_block='10.0.0.0/16',
availability_zones=['us-west-2a', 'us-west-2b']
)
compute_module = Module('compute',
source=relative_path('modules/compute'),
vpc_id=vpc_module.vpc_id,
subnet_ids=vpc_module.private_subnet_ids
)from terraformpy import Resource, Variable
from terraformpy.helpers import relative_file
# Environment-specific configuration files
environment = Variable('environment', default='dev')
# Load environment-specific config
app_config = Resource('aws_s3_object', 'app_config',
bucket='${aws_s3_bucket.config.bucket}',
key='app-config.json',
source=relative_file('config/${var.environment}.json'),
etag='${filemd5("${relative_file('config/${var.environment}.json')}")}'
)
# Conditional file loading based on environment
database_init = Resource('aws_s3_object', 'db_init',
bucket='${aws_s3_bucket.scripts.bucket}',
key='init.sql',
source=relative_file('sql/${var.environment == "production" ? "prod-init.sql" : "dev-init.sql"}')
)from terraformpy import Resource, Data, Output
from terraformpy.helpers import relative_file
# Load and process template files
user_data = Data('template_file', 'user_data',
template='${file("${relative_file('templates/userdata.sh.tpl')}")}',
vars={
'app_version': '${var.app_version}',
'environment': '${var.environment}',
'region': '${data.aws_region.current.name}'
}
)
# EC2 instance using processed template
web_server = Resource('aws_instance', 'web',
instance_type='t3.micro',
ami='ami-12345678',
user_data_base64='${base64encode(data.template_file.user_data.rendered)}',
tags={'Name': 'WebServer'}
)
# Output the processed template for verification
Output('processed_user_data',
value='${data.template_file.user_data.rendered}',
sensitive=True
)# Good: Relative paths work regardless of execution directory
config_file = relative_file('config/app.json')
# Bad: Absolute paths break when moved
config_file = '/home/user/project/terraform/config/app.json'
# Bad: Relative paths from current directory break
config_file = './config/app.json' # Fails if run from different directory# Organize files consistently within terraform directory
# /project/terraform/
# ├── main.py
# ├── templates/ <- Template files
# ├── config/ <- Configuration files
# ├── scripts/ <- Shell scripts
# └── modules/ <- Local modules
# Use helpers to reference consistently
template = relative_file('templates/script.sh')
config = relative_file('config/settings.json')
module_path = relative_path('modules/networking')Install with Tessl CLI
npx tessl i tessl/pypi-terraformpy