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

cli.mddocs/

Command Line Interface

CLI tool for processing Python files containing Terraform configurations and generating JSON output files compatible with Terraform tooling. The CLI automatically discovers and executes Python files with Terraform configurations, compiling them to standard Terraform JSON format.

Capabilities

CLI Command

Command line interface for processing Terraform Python configurations and generating JSON output.

terraformpy [options]

# Basic usage - process all *.tf.py files in current directory
terraformpy

# The CLI will:
# 1. Discover all *.tf.py files in the current directory
# 2. Execute each file to register Terraform objects
# 3. Compile registered objects to dictionary
# 4. Convert to JSON and write output to main.tf.json
# 5. Reset the registry for next run

Main Function

Python entry point for the CLI functionality, can be called programmatically or used as a script.

def main():
    """
    Main CLI entry point function.

    This function implements the terraformpy CLI logic:
    - Argument parsing and option handling
    - File discovery and processing
    - JSON compilation and output generation
    - Error handling and user feedback

    Can be called directly or used via the console script:
    - Console script: terraformpy (installed via pip)
    - Direct call: python -c "from terraformpy.cli import main; main()"
    - Direct call: python -c "from terraformpy.cli import main; main()"
    """

Usage Examples

Basic CLI Usage

# Create Terraform Python files
cat > infrastructure.tf.py << 'EOF'
from terraformpy import Resource, Variable, Output, Provider

# Configure AWS provider
Provider('aws', region='us-west-2')

# Define variables
instance_type = Variable('instance_type', default='t3.micro')

# Create resources
web_server = Resource('aws_instance', 'web_server',
    instance_type=instance_type,  # Variable used directly
    ami='ami-0c55b159cbfafe1d0',
    tags={'Name': 'WebServer'}
)

# Define outputs
Output('instance_id', value=web_server.id)
Output('public_ip', value=web_server.public_ip)
EOF

# Generate Terraform JSON
terraformpy

# Result: main.tf.json created with complete Terraform configuration
cat main.tf.json

Multiple Configuration Files

# Project structure:
# .
# ├── network.tf.py      <- VPC and networking
# ├── compute.tf.py      <- EC2 instances
# ├── database.tf.py     <- RDS instances
# └── outputs.tf.py      <- Global outputs

# network.tf.py
cat > network.tf.py << 'EOF'
from terraformpy import Resource, Variable

# VPC
vpc = Resource('aws_vpc', 'main',
    cidr_block='10.0.0.0/16',
    enable_dns_hostnames=True,
    enable_dns_support=True,
    tags={'Name': 'main-vpc'}
)

# Subnets
public_subnet = Resource('aws_subnet', 'public',
    vpc_id=vpc.id,
    cidr_block='10.0.1.0/24',
    availability_zone='us-west-2a',
    map_public_ip_on_launch=True,
    tags={'Name': 'public-subnet'}
)

private_subnet = Resource('aws_subnet', 'private',
    vpc_id=vpc.id,
    cidr_block='10.0.2.0/24',
    availability_zone='us-west-2b',
    tags={'Name': 'private-subnet'}
)
EOF

# compute.tf.py
cat > compute.tf.py << 'EOF'
from terraformpy import Resource, Data

# Reference networking resources from network.tf.py
vpc = '${aws_vpc.main.id}'
public_subnet = '${aws_subnet.public.id}'

# Web server
web_server = Resource('aws_instance', 'web',
    instance_type='t3.micro',
    ami='ami-0c55b159cbfafe1d0',
    subnet_id=public_subnet,
    vpc_security_group_ids=['${aws_security_group.web.id}'],
    tags={'Name': 'WebServer'}
)

# Security group
web_sg = Resource('aws_security_group', 'web',
    name='web-security-group',
    description='Security group for web server',
    vpc_id=vpc,
    ingress=[
        {
            'from_port': 80,
            'to_port': 80,
            'protocol': 'tcp',
            'cidr_blocks': ['0.0.0.0/0']
        },
        {
            'from_port': 443,
            'to_port': 443,
            'protocol': 'tcp',
            'cidr_blocks': ['0.0.0.0/0']
        }
    ]
)
EOF

# Process all files
terraformpy

# All configurations combined in main.tf.json

Using with Terraform Workflow

# 1. Create Python configuration
cat > app.tf.py << 'EOF'
from terraformpy import *

Provider('aws', region='us-west-2')

# Application infrastructure
app_server = Resource('aws_instance', 'app',
    instance_type='t3.small',
    ami='ami-0c55b159cbfafe1d0'
)

Output('app_server_ip', value=app_server.public_ip)
EOF

# 2. Generate Terraform JSON
terraformpy
ls -la main.tf.json

# 3. Use with Terraform commands
terraform init
terraform plan -var-file="production.tfvars"
terraform apply

# 4. Modify Python and regenerate
echo "app_server.tags = {'Environment': 'production'}" >> app.tf.py
terraformpy

# 5. Apply changes
terraform plan
terraform apply

Integration with CI/CD

# .github/workflows/terraform.yml
name: Terraform Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'

      - name: Install Terraformpy
        run: pip install terraformpy

      - name: Generate Terraform JSON
        run: terraformpy

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        run: terraform plan

      - name: Terraform Apply
        if: github.ref == 'refs/heads/main'
        run: terraform apply -auto-approve

Development and Testing

# test_infrastructure.py
import unittest
from terraformpy import *
from terraformpy.cli import main
import json
import tempfile
import os

class TestInfrastructure(unittest.TestCase):
    def setUp(self):
        """Reset registry before each test."""
        reset()

    def test_web_server_configuration(self):
        """Test web server resource creation."""
        # Create resources
        web_server = Resource('aws_instance', 'web',
            instance_type='t3.micro',
            ami='ami-12345678'
        )

        # Compile and verify
        config = json.loads(compile())
        self.assertIn('resource', config)
        self.assertIn('aws_instance', config['resource'])
        self.assertEqual(
            config['resource']['aws_instance']['web']['instance_type'],
            't3.micro'
        )

    def test_cli_processing(self):
        """Test CLI file processing."""
        with tempfile.TemporaryDirectory() as temp_dir:
            # Create test file
            test_file = os.path.join(temp_dir, 'test.tf.py')
            with open(test_file, 'w') as f:
                f.write('''
from terraformpy import Resource
Resource('aws_instance', 'test', instance_type='t3.micro')
                ''')

            # Change to temp directory and run CLI
            original_cwd = os.getcwd()
            try:
                os.chdir(temp_dir)
                main()

                # Verify output file exists
                self.assertTrue(os.path.exists('main.tf.json'))

                # Verify content
                with open('main.tf.json', 'r') as f:
                    config = json.load(f)
                    self.assertIn('resource', config)
            finally:
                os.chdir(original_cwd)

if __name__ == '__main__':
    unittest.main()

Advanced CLI Usage Patterns

# build_infrastructure.py - Custom build script
from terraformpy.cli import main
from terraformpy import reset
import os
import json

def build_environment(env_name):
    """Build infrastructure for specific environment."""
    print(f"Building {env_name} environment...")

    # Set environment variable for configuration
    os.environ['ENVIRONMENT'] = env_name

    # Clear any existing state
    reset()

    # Run CLI to process .tf.py files
    main()

    # Verify output
    if os.path.exists('main.tf.json'):
        with open('main.tf.json', 'r') as f:
            config = json.load(f)
            resources = len(config.get('resource', {}))
            print(f"Generated {resources} resource types for {env_name}")
            return True
    return False

# Build for multiple environments
environments = ['development', 'staging', 'production']
for env in environments:
    if build_environment(env):
        # Rename output for environment
        os.rename('main.tf.json', f'{env}.tf.json')
        print(f"Saved {env}.tf.json")

Best Practices

File Organization

# Recommended project structure
terraform/
├── *.tf.py              # Terraform Python files
├── main.tf.json         # Generated output (gitignore this)
├── variables.tf         # Terraform variables (optional)
├── terraform.tfvars     # Variable values
└── modules/
    └── custom/
        ├── *.tf.py
        └── main.tf.json

Version Control

# .gitignore
main.tf.json          # Generated file - don't commit
*.pyc                 # Python bytecode
__pycache__/          # Python cache directories
.terraform/           # Terraform working directory
*.tfstate             # Terraform state files
*.tfstate.backup

Error Handling

# Check CLI exit status
terraformpy
if [ $? -ne 0 ]; then
    echo "Terraformpy compilation failed"
    exit 1
fi

# Validate generated JSON
terraform validate

# Use with error handling in scripts
set -e  # Exit on error
terraformpy
terraform plan -detailed-exitcode

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