0
# Resource Collections
1
2
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.
3
4
## Capabilities
5
6
### ResourceCollection Base Class
7
8
Base class for creating reusable groups of Terraform resources with parameter validation and environment-specific variants.
9
10
```python { .api }
11
class ResourceCollection(schematics.Model):
12
def __init__(self, **kwargs):
13
"""
14
Create a resource collection instance.
15
16
Parameters:
17
- **kwargs: Collection-specific parameters defined as schematics types
18
19
The constructor automatically validates parameters and calls create_resources().
20
"""
21
22
def create_resources(self):
23
"""
24
Abstract method that must be implemented by subclasses.
25
26
This method should create the Terraform resources for this collection.
27
Access collection parameters via self.parameter_name.
28
"""
29
raise NotImplementedError("Subclasses must implement create_resources()")
30
31
# Variant support
32
def __init__(self, **kwargs):
33
"""
34
Supports variant-specific parameter overrides.
35
36
Parameters ending with '_variant' are used as overrides when
37
within a matching Variant context.
38
39
Example:
40
MyCollection(count=2, production_variant={'count': 5})
41
"""
42
```
43
44
### Variant Context Manager
45
46
Context manager for environment-specific configurations that enables automatic parameter overrides based on environment context.
47
48
```python { .api }
49
class Variant:
50
def __init__(self, name: str):
51
"""
52
Create a variant context.
53
54
Parameters:
55
- name: str - Variant name (e.g., 'production', 'staging', 'development')
56
57
Example:
58
with Variant('production'):
59
# Collections instantiated here use production-specific overrides
60
pass
61
"""
62
63
def __enter__(self):
64
"""Enter variant context - subsequent collections use variant overrides."""
65
66
def __exit__(self, exc_type, exc_val, exc_tb):
67
"""Exit variant context."""
68
```
69
70
## Usage Examples
71
72
### Basic Resource Collection
73
74
```python
75
from terraformpy import ResourceCollection, Resource
76
import schematics
77
78
class WebServerStack(ResourceCollection):
79
# Define collection parameters using schematics types
80
instance_type = schematics.StringType(default='t3.micro')
81
instance_count = schematics.IntType(default=1, min_value=1)
82
environment = schematics.StringType(required=True)
83
84
def create_resources(self):
85
# Create resources using collection parameters
86
for i in range(self.instance_count):
87
Resource('aws_instance', f'web_{i}',
88
instance_type=self.instance_type,
89
ami='ami-12345678',
90
tags={
91
'Name': f'WebServer-{i}-{self.environment}',
92
'Environment': self.environment
93
}
94
)
95
96
# Instantiate the collection
97
web_stack = WebServerStack(
98
instance_count=3,
99
environment='production'
100
)
101
```
102
103
### Collection with Dependencies
104
105
```python
106
from terraformpy import ResourceCollection, Resource, Data
107
import schematics
108
109
class DatabaseStack(ResourceCollection):
110
db_instance_class = schematics.StringType(default='db.t3.micro')
111
db_name = schematics.StringType(required=True)
112
subnet_group_name = schematics.StringType(required=True)
113
114
def create_resources(self):
115
# Query existing security group
116
db_sg = Data('aws_security_group', 'db_sg',
117
filters={'tag:Name': f'{self.db_name}-db-sg'}
118
)
119
120
# Create RDS instance
121
db_instance = Resource('aws_db_instance', 'main',
122
identifier=self.db_name,
123
instance_class=self.db_instance_class,
124
engine='postgres',
125
engine_version='13.7',
126
allocated_storage=20,
127
db_name=self.db_name,
128
username='postgres',
129
manage_master_user_password=True,
130
db_subnet_group_name=self.subnet_group_name,
131
vpc_security_group_ids=[db_sg.id]
132
)
133
134
# Create parameter group
135
Resource('aws_db_parameter_group', 'main',
136
family='postgres13',
137
name=f'{self.db_name}-params',
138
parameters=[
139
{'name': 'log_connections', 'value': '1'},
140
{'name': 'log_checkpoints', 'value': '1'}
141
]
142
)
143
144
# Use the collection
145
db_stack = DatabaseStack(
146
db_name='myapp',
147
db_instance_class='db.r6g.large',
148
subnet_group_name='myapp-db-subnets'
149
)
150
```
151
152
### Environment-Specific Variants
153
154
```python
155
from terraformpy import ResourceCollection, Resource, Variant
156
import schematics
157
158
class ApplicationStack(ResourceCollection):
159
instance_type = schematics.StringType(default='t3.micro')
160
min_size = schematics.IntType(default=1)
161
max_size = schematics.IntType(default=3)
162
desired_capacity = schematics.IntType(default=2)
163
164
def create_resources(self):
165
# Auto Scaling Group
166
Resource('aws_autoscaling_group', 'app',
167
min_size=self.min_size,
168
max_size=self.max_size,
169
desired_capacity=self.desired_capacity,
170
launch_template={
171
'id': '${aws_launch_template.app.id}',
172
'version': '$Latest'
173
}
174
)
175
176
# Launch Template
177
Resource('aws_launch_template', 'app',
178
instance_type=self.instance_type,
179
image_id='ami-12345678'
180
)
181
182
# Development environment
183
with Variant('development'):
184
dev_stack = ApplicationStack(
185
instance_type='t3.micro',
186
min_size=1,
187
max_size=2,
188
desired_capacity=1,
189
# Development-specific overrides
190
development_variant={
191
'instance_type': 't3.nano', # Smaller instances in dev
192
'min_size': 0, # Allow scaling to zero
193
'desired_capacity': 0 # Start with no instances
194
}
195
)
196
197
# Production environment
198
with Variant('production'):
199
prod_stack = ApplicationStack(
200
instance_type='t3.medium',
201
min_size=2,
202
max_size=10,
203
desired_capacity=4,
204
# Production-specific overrides
205
production_variant={
206
'instance_type': 'c5.large', # More powerful instances
207
'min_size': 3, # Higher minimum
208
'max_size': 20, # Higher maximum
209
'desired_capacity': 6 # More initial capacity
210
}
211
)
212
```
213
214
### Collection Composition
215
216
```python
217
from terraformpy import ResourceCollection
218
import schematics
219
220
class NetworkingStack(ResourceCollection):
221
vpc_cidr = schematics.StringType(default='10.0.0.0/16')
222
223
def create_resources(self):
224
# VPC resources
225
Resource('aws_vpc', 'main', cidr_block=self.vpc_cidr)
226
# ... other networking resources
227
228
class SecurityStack(ResourceCollection):
229
vpc_id = schematics.StringType(required=True)
230
231
def create_resources(self):
232
# Security groups, NACLs, etc.
233
Resource('aws_security_group', 'web',
234
vpc_id=self.vpc_id,
235
# ... security group rules
236
)
237
238
class FullStack(ResourceCollection):
239
environment = schematics.StringType(required=True)
240
241
def create_resources(self):
242
# Compose multiple stacks
243
network = NetworkingStack()
244
245
# Reference network resources in security stack
246
security = SecurityStack(vpc_id='${aws_vpc.main.id}')
247
248
# Deploy complete infrastructure
249
full_stack = FullStack(environment='staging')
250
```
251
252
### Parameter Validation
253
254
```python
255
from terraformpy import ResourceCollection
256
import schematics
257
258
class ValidatedStack(ResourceCollection):
259
# String with choices
260
environment = schematics.StringType(
261
required=True,
262
choices=['dev', 'staging', 'production']
263
)
264
265
# Integer with validation
266
instance_count = schematics.IntType(
267
default=1,
268
min_value=1,
269
max_value=10
270
)
271
272
# Custom validation
273
def validate_instance_count(self, value):
274
if self.environment == 'production' and value < 2:
275
raise schematics.ValidationError(
276
'Production environment requires at least 2 instances'
277
)
278
return value
279
280
def create_resources(self):
281
for i in range(self.instance_count):
282
Resource('aws_instance', f'app_{i}',
283
instance_type='t3.micro',
284
tags={'Environment': self.environment}
285
)
286
287
# This will raise ValidationError
288
try:
289
ValidatedStack(environment='production', instance_count=1)
290
except schematics.ValidationError as e:
291
print(f"Validation failed: {e}")
292
293
# This will succeed
294
ValidatedStack(environment='production', instance_count=3)
295
```