Python library and CLI tool for generating Terraform JSON configurations using full Python programming capabilities
Framework for creating reusable, parameterized groups of Terraform resources that can be instantiated with different configurations. Resource collections support environment-specific variants, inheritance patterns, and validation using the schematics library.
Base class for creating reusable groups of Terraform resources with parameter validation and environment-specific variants.
class ResourceCollection(schematics.Model):
def __init__(self, **kwargs):
"""
Create a resource collection instance.
Parameters:
- **kwargs: Collection-specific parameters defined as schematics types
The constructor automatically validates parameters and calls create_resources().
"""
def create_resources(self):
"""
Abstract method that must be implemented by subclasses.
This method should create the Terraform resources for this collection.
Access collection parameters via self.parameter_name.
"""
raise NotImplementedError("Subclasses must implement create_resources()")
# Variant support
def __init__(self, **kwargs):
"""
Supports variant-specific parameter overrides.
Parameters ending with '_variant' are used as overrides when
within a matching Variant context.
Example:
MyCollection(count=2, production_variant={'count': 5})
"""Context manager for environment-specific configurations that enables automatic parameter overrides based on environment context.
class Variant:
def __init__(self, name: str):
"""
Create a variant context.
Parameters:
- name: str - Variant name (e.g., 'production', 'staging', 'development')
Example:
with Variant('production'):
# Collections instantiated here use production-specific overrides
pass
"""
def __enter__(self):
"""Enter variant context - subsequent collections use variant overrides."""
def __exit__(self, exc_type, exc_val, exc_tb):
"""Exit variant context."""from terraformpy import ResourceCollection, Resource
import schematics
class WebServerStack(ResourceCollection):
# Define collection parameters using schematics types
instance_type = schematics.StringType(default='t3.micro')
instance_count = schematics.IntType(default=1, min_value=1)
environment = schematics.StringType(required=True)
def create_resources(self):
# Create resources using collection parameters
for i in range(self.instance_count):
Resource('aws_instance', f'web_{i}',
instance_type=self.instance_type,
ami='ami-12345678',
tags={
'Name': f'WebServer-{i}-{self.environment}',
'Environment': self.environment
}
)
# Instantiate the collection
web_stack = WebServerStack(
instance_count=3,
environment='production'
)from terraformpy import ResourceCollection, Resource, Data
import schematics
class DatabaseStack(ResourceCollection):
db_instance_class = schematics.StringType(default='db.t3.micro')
db_name = schematics.StringType(required=True)
subnet_group_name = schematics.StringType(required=True)
def create_resources(self):
# Query existing security group
db_sg = Data('aws_security_group', 'db_sg',
filters={'tag:Name': f'{self.db_name}-db-sg'}
)
# Create RDS instance
db_instance = Resource('aws_db_instance', 'main',
identifier=self.db_name,
instance_class=self.db_instance_class,
engine='postgres',
engine_version='13.7',
allocated_storage=20,
db_name=self.db_name,
username='postgres',
manage_master_user_password=True,
db_subnet_group_name=self.subnet_group_name,
vpc_security_group_ids=[db_sg.id]
)
# Create parameter group
Resource('aws_db_parameter_group', 'main',
family='postgres13',
name=f'{self.db_name}-params',
parameters=[
{'name': 'log_connections', 'value': '1'},
{'name': 'log_checkpoints', 'value': '1'}
]
)
# Use the collection
db_stack = DatabaseStack(
db_name='myapp',
db_instance_class='db.r6g.large',
subnet_group_name='myapp-db-subnets'
)from terraformpy import ResourceCollection, Resource, Variant
import schematics
class ApplicationStack(ResourceCollection):
instance_type = schematics.StringType(default='t3.micro')
min_size = schematics.IntType(default=1)
max_size = schematics.IntType(default=3)
desired_capacity = schematics.IntType(default=2)
def create_resources(self):
# Auto Scaling Group
Resource('aws_autoscaling_group', 'app',
min_size=self.min_size,
max_size=self.max_size,
desired_capacity=self.desired_capacity,
launch_template={
'id': '${aws_launch_template.app.id}',
'version': '$Latest'
}
)
# Launch Template
Resource('aws_launch_template', 'app',
instance_type=self.instance_type,
image_id='ami-12345678'
)
# Development environment
with Variant('development'):
dev_stack = ApplicationStack(
instance_type='t3.micro',
min_size=1,
max_size=2,
desired_capacity=1,
# Development-specific overrides
development_variant={
'instance_type': 't3.nano', # Smaller instances in dev
'min_size': 0, # Allow scaling to zero
'desired_capacity': 0 # Start with no instances
}
)
# Production environment
with Variant('production'):
prod_stack = ApplicationStack(
instance_type='t3.medium',
min_size=2,
max_size=10,
desired_capacity=4,
# Production-specific overrides
production_variant={
'instance_type': 'c5.large', # More powerful instances
'min_size': 3, # Higher minimum
'max_size': 20, # Higher maximum
'desired_capacity': 6 # More initial capacity
}
)from terraformpy import ResourceCollection
import schematics
class NetworkingStack(ResourceCollection):
vpc_cidr = schematics.StringType(default='10.0.0.0/16')
def create_resources(self):
# VPC resources
Resource('aws_vpc', 'main', cidr_block=self.vpc_cidr)
# ... other networking resources
class SecurityStack(ResourceCollection):
vpc_id = schematics.StringType(required=True)
def create_resources(self):
# Security groups, NACLs, etc.
Resource('aws_security_group', 'web',
vpc_id=self.vpc_id,
# ... security group rules
)
class FullStack(ResourceCollection):
environment = schematics.StringType(required=True)
def create_resources(self):
# Compose multiple stacks
network = NetworkingStack()
# Reference network resources in security stack
security = SecurityStack(vpc_id='${aws_vpc.main.id}')
# Deploy complete infrastructure
full_stack = FullStack(environment='staging')from terraformpy import ResourceCollection
import schematics
class ValidatedStack(ResourceCollection):
# String with choices
environment = schematics.StringType(
required=True,
choices=['dev', 'staging', 'production']
)
# Integer with validation
instance_count = schematics.IntType(
default=1,
min_value=1,
max_value=10
)
# Custom validation
def validate_instance_count(self, value):
if self.environment == 'production' and value < 2:
raise schematics.ValidationError(
'Production environment requires at least 2 instances'
)
return value
def create_resources(self):
for i in range(self.instance_count):
Resource('aws_instance', f'app_{i}',
instance_type='t3.micro',
tags={'Environment': self.environment}
)
# This will raise ValidationError
try:
ValidatedStack(environment='production', instance_count=1)
except schematics.ValidationError as e:
print(f"Validation failed: {e}")
# This will succeed
ValidatedStack(environment='production', instance_count=3)Install with Tessl CLI
npx tessl i tessl/pypi-terraformpy