0
# Helper Utilities
1
2
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.
3
4
## Capabilities
5
6
### Relative File Path Utilities
7
8
Functions that generate file and path references relative to the calling Python file's location, ensuring Terraform configurations work consistently across different execution contexts.
9
10
```python { .api }
11
def relative_file(filename: str, _caller_depth: int = 1) -> str:
12
"""
13
Generate a file path relative to the calling file's directory.
14
15
Parameters:
16
- filename: str - The filename or relative path to resolve
17
- _caller_depth: int, optional - How many stack frames up to look (default: 1)
18
19
Returns:
20
str - Terraform file() interpolation expression relative to caller's directory
21
22
Example:
23
# In /project/terraform/main.py
24
template_path = relative_file('templates/userdata.sh')
25
# Returns: '${file("${path.module}/templates/userdata.sh")}'
26
"""
27
28
def relative_path(path: str, _caller_depth: int = 1) -> str:
29
"""
30
Generate a directory path relative to the calling file's directory.
31
32
Parameters:
33
- path: str - The path to resolve relative to caller
34
- _caller_depth: int, optional - How many stack frames up to look (default: 1)
35
36
Returns:
37
str - Terraform path expression relative to caller's directory
38
39
Example:
40
# In /project/terraform/main.py
41
config_dir = relative_path('config')
42
# Returns: '${path.module}/config'
43
"""
44
```
45
46
## Usage Examples
47
48
### File Templates and Configuration
49
50
```python
51
from terraformpy import Resource
52
from terraformpy.helpers import relative_file
53
54
# Project structure:
55
# /project/
56
# ├── terraform/
57
# │ ├── main.py <- This file
58
# │ ├── templates/
59
# │ │ ├── userdata.sh
60
# │ │ └── nginx.conf
61
# │ └── config/
62
# │ └── app.json
63
64
# EC2 instance with user data script
65
web_server = Resource('aws_instance', 'web',
66
instance_type='t3.micro',
67
ami='ami-12345678',
68
user_data_base64='${base64encode(file("${relative_file('templates/userdata.sh')}"))}',
69
tags={'Name': 'WebServer'}
70
)
71
72
# Launch template with file reference
73
launch_template = Resource('aws_launch_template', 'app',
74
instance_type='t3.micro',
75
image_id='ami-12345678',
76
user_data='${base64encode(file("${relative_file('templates/userdata.sh')}"))}',
77
tag_specifications=[{
78
'resource_type': 'instance',
79
'tags': {'Name': 'AppServer'}
80
}]
81
)
82
```
83
84
### Container and Lambda Deployments
85
86
```python
87
from terraformpy import Resource
88
from terraformpy.helpers import relative_file, relative_path
89
90
# Lambda function with local code
91
lambda_function = Resource('aws_lambda_function', 'processor',
92
filename=relative_file('lambda/processor.zip'),
93
function_name='data-processor',
94
role='${aws_iam_role.lambda_role.arn}',
95
handler='index.handler',
96
runtime='python3.9'
97
)
98
99
# ECS task definition with template
100
ecs_task = Resource('aws_ecs_task_definition', 'app',
101
family='myapp',
102
container_definitions='${templatefile("${relative_file('templates/task-def.json')}", {
103
image_url = var.app_image_url,
104
log_group = aws_cloudwatch_log_group.app.name
105
})}',
106
requires_compatibilities=['FARGATE'],
107
cpu='256',
108
memory='512'
109
)
110
111
# Docker image build using local context
112
docker_image = Resource('docker_image', 'app',
113
name='myapp:latest',
114
build={
115
'context': relative_path('.'),
116
'dockerfile': relative_file('Dockerfile')
117
}
118
)
119
```
120
121
### Configuration Files and Secrets
122
123
```python
124
from terraformpy import Resource, Variable
125
from terraformpy.helpers import relative_file
126
127
# Application configuration
128
app_config = Variable('app_config',
129
default='${file("${relative_file('config/app.json')}")}'
130
)
131
132
# Kubernetes config map from file
133
k8s_config_map = Resource('kubernetes_config_map', 'app_config',
134
metadata={'name': 'app-config'},
135
data={
136
'config.yaml': '${file("${relative_file('config/k8s-config.yaml')}"))',
137
'logging.conf': '${file("${relative_file('config/logging.conf')}"))'
138
}
139
)
140
141
# SSL certificate from file
142
tls_cert = Resource('aws_acm_certificate', 'app',
143
certificate_body='${file("${relative_file('certs/app.crt')}"))',
144
private_key='${file("${relative_file('certs/app.key')}"))'
145
)
146
```
147
148
### Module Organization
149
150
```python
151
from terraformpy import Module
152
from terraformpy.helpers import relative_path
153
154
# Project structure:
155
# /project/
156
# ├── main.py <- This file
157
# ├── modules/
158
# │ ├── networking/
159
# │ │ ├── main.py
160
# │ │ └── variables.py
161
# │ └── compute/
162
# │ ├── main.py
163
# │ └── variables.py
164
165
# Reference local modules with relative paths
166
vpc_module = Module('vpc',
167
source=relative_path('modules/networking'),
168
cidr_block='10.0.0.0/16',
169
availability_zones=['us-west-2a', 'us-west-2b']
170
)
171
172
compute_module = Module('compute',
173
source=relative_path('modules/compute'),
174
vpc_id=vpc_module.vpc_id,
175
subnet_ids=vpc_module.private_subnet_ids
176
)
177
```
178
179
### Multi-Environment Configurations
180
181
```python
182
from terraformpy import Resource, Variable
183
from terraformpy.helpers import relative_file
184
185
# Environment-specific configuration files
186
environment = Variable('environment', default='dev')
187
188
# Load environment-specific config
189
app_config = Resource('aws_s3_object', 'app_config',
190
bucket='${aws_s3_bucket.config.bucket}',
191
key='app-config.json',
192
source=relative_file('config/${var.environment}.json'),
193
etag='${filemd5("${relative_file('config/${var.environment}.json')}")}'
194
)
195
196
# Conditional file loading based on environment
197
database_init = Resource('aws_s3_object', 'db_init',
198
bucket='${aws_s3_bucket.scripts.bucket}',
199
key='init.sql',
200
source=relative_file('sql/${var.environment == "production" ? "prod-init.sql" : "dev-init.sql"}')
201
)
202
```
203
204
### Template Processing
205
206
```python
207
from terraformpy import Resource, Data, Output
208
from terraformpy.helpers import relative_file
209
210
# Load and process template files
211
user_data = Data('template_file', 'user_data',
212
template='${file("${relative_file('templates/userdata.sh.tpl')}")}',
213
vars={
214
'app_version': '${var.app_version}',
215
'environment': '${var.environment}',
216
'region': '${data.aws_region.current.name}'
217
}
218
)
219
220
# EC2 instance using processed template
221
web_server = Resource('aws_instance', 'web',
222
instance_type='t3.micro',
223
ami='ami-12345678',
224
user_data_base64='${base64encode(data.template_file.user_data.rendered)}',
225
tags={'Name': 'WebServer'}
226
)
227
228
# Output the processed template for verification
229
Output('processed_user_data',
230
value='${data.template_file.user_data.rendered}',
231
sensitive=True
232
)
233
```
234
235
## Best Practices
236
237
### Portable Configurations
238
239
```python
240
# Good: Relative paths work regardless of execution directory
241
config_file = relative_file('config/app.json')
242
243
# Bad: Absolute paths break when moved
244
config_file = '/home/user/project/terraform/config/app.json'
245
246
# Bad: Relative paths from current directory break
247
config_file = './config/app.json' # Fails if run from different directory
248
```
249
250
### Consistent Directory Structure
251
252
```python
253
# Organize files consistently within terraform directory
254
# /project/terraform/
255
# ├── main.py
256
# ├── templates/ <- Template files
257
# ├── config/ <- Configuration files
258
# ├── scripts/ <- Shell scripts
259
# └── modules/ <- Local modules
260
261
# Use helpers to reference consistently
262
template = relative_file('templates/script.sh')
263
config = relative_file('config/settings.json')
264
module_path = relative_path('modules/networking')
265
```