CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-terraformpy

Python library and CLI tool for generating Terraform JSON configurations using full Python programming capabilities

Overview
Eval results
Files

helpers.mddocs/

Helper Utilities

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.

Capabilities

Relative File Path Utilities

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'
    """

Usage Examples

File Templates and Configuration

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'}
    }]
)

Container and Lambda Deployments

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')
    }
)

Configuration Files and Secrets

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')}"))'
)

Module Organization

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
)

Multi-Environment Configurations

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"}')
)

Template Processing

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
)

Best Practices

Portable Configurations

# 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

Consistent Directory Structure

# 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

docs

aws-hooks.md

cli.md

compilation-hooks.md

core-objects.md

helpers.md

index.md

resource-collections.md

tile.json