Python library and CLI tool for generating Terraform JSON configurations using full Python programming capabilities
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.
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 runPython 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()"
"""# 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# 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# 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# .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# 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()# 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")# 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# .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# 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-exitcodeInstall with Tessl CLI
npx tessl i tessl/pypi-terraformpy