0
# Command Line Interface
1
2
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.
3
4
## Capabilities
5
6
### CLI Command
7
8
Command line interface for processing Terraform Python configurations and generating JSON output.
9
10
```bash { .api }
11
terraformpy [options]
12
13
# Basic usage - process all *.tf.py files in current directory
14
terraformpy
15
16
# The CLI will:
17
# 1. Discover all *.tf.py files in the current directory
18
# 2. Execute each file to register Terraform objects
19
# 3. Compile registered objects to dictionary
20
# 4. Convert to JSON and write output to main.tf.json
21
# 5. Reset the registry for next run
22
```
23
24
### Main Function
25
26
Python entry point for the CLI functionality, can be called programmatically or used as a script.
27
28
```python { .api }
29
def main():
30
"""
31
Main CLI entry point function.
32
33
This function implements the terraformpy CLI logic:
34
- Argument parsing and option handling
35
- File discovery and processing
36
- JSON compilation and output generation
37
- Error handling and user feedback
38
39
Can be called directly or used via the console script:
40
- Console script: terraformpy (installed via pip)
41
- Direct call: python -c "from terraformpy.cli import main; main()"
42
- Direct call: python -c "from terraformpy.cli import main; main()"
43
"""
44
```
45
46
## Usage Examples
47
48
### Basic CLI Usage
49
50
```bash
51
# Create Terraform Python files
52
cat > infrastructure.tf.py << 'EOF'
53
from terraformpy import Resource, Variable, Output, Provider
54
55
# Configure AWS provider
56
Provider('aws', region='us-west-2')
57
58
# Define variables
59
instance_type = Variable('instance_type', default='t3.micro')
60
61
# Create resources
62
web_server = Resource('aws_instance', 'web_server',
63
instance_type=instance_type, # Variable used directly
64
ami='ami-0c55b159cbfafe1d0',
65
tags={'Name': 'WebServer'}
66
)
67
68
# Define outputs
69
Output('instance_id', value=web_server.id)
70
Output('public_ip', value=web_server.public_ip)
71
EOF
72
73
# Generate Terraform JSON
74
terraformpy
75
76
# Result: main.tf.json created with complete Terraform configuration
77
cat main.tf.json
78
```
79
80
### Multiple Configuration Files
81
82
```bash
83
# Project structure:
84
# .
85
# ├── network.tf.py <- VPC and networking
86
# ├── compute.tf.py <- EC2 instances
87
# ├── database.tf.py <- RDS instances
88
# └── outputs.tf.py <- Global outputs
89
90
# network.tf.py
91
cat > network.tf.py << 'EOF'
92
from terraformpy import Resource, Variable
93
94
# VPC
95
vpc = Resource('aws_vpc', 'main',
96
cidr_block='10.0.0.0/16',
97
enable_dns_hostnames=True,
98
enable_dns_support=True,
99
tags={'Name': 'main-vpc'}
100
)
101
102
# Subnets
103
public_subnet = Resource('aws_subnet', 'public',
104
vpc_id=vpc.id,
105
cidr_block='10.0.1.0/24',
106
availability_zone='us-west-2a',
107
map_public_ip_on_launch=True,
108
tags={'Name': 'public-subnet'}
109
)
110
111
private_subnet = Resource('aws_subnet', 'private',
112
vpc_id=vpc.id,
113
cidr_block='10.0.2.0/24',
114
availability_zone='us-west-2b',
115
tags={'Name': 'private-subnet'}
116
)
117
EOF
118
119
# compute.tf.py
120
cat > compute.tf.py << 'EOF'
121
from terraformpy import Resource, Data
122
123
# Reference networking resources from network.tf.py
124
vpc = '${aws_vpc.main.id}'
125
public_subnet = '${aws_subnet.public.id}'
126
127
# Web server
128
web_server = Resource('aws_instance', 'web',
129
instance_type='t3.micro',
130
ami='ami-0c55b159cbfafe1d0',
131
subnet_id=public_subnet,
132
vpc_security_group_ids=['${aws_security_group.web.id}'],
133
tags={'Name': 'WebServer'}
134
)
135
136
# Security group
137
web_sg = Resource('aws_security_group', 'web',
138
name='web-security-group',
139
description='Security group for web server',
140
vpc_id=vpc,
141
ingress=[
142
{
143
'from_port': 80,
144
'to_port': 80,
145
'protocol': 'tcp',
146
'cidr_blocks': ['0.0.0.0/0']
147
},
148
{
149
'from_port': 443,
150
'to_port': 443,
151
'protocol': 'tcp',
152
'cidr_blocks': ['0.0.0.0/0']
153
}
154
]
155
)
156
EOF
157
158
# Process all files
159
terraformpy
160
161
# All configurations combined in main.tf.json
162
```
163
164
### Using with Terraform Workflow
165
166
```bash
167
# 1. Create Python configuration
168
cat > app.tf.py << 'EOF'
169
from terraformpy import *
170
171
Provider('aws', region='us-west-2')
172
173
# Application infrastructure
174
app_server = Resource('aws_instance', 'app',
175
instance_type='t3.small',
176
ami='ami-0c55b159cbfafe1d0'
177
)
178
179
Output('app_server_ip', value=app_server.public_ip)
180
EOF
181
182
# 2. Generate Terraform JSON
183
terraformpy
184
ls -la main.tf.json
185
186
# 3. Use with Terraform commands
187
terraform init
188
terraform plan -var-file="production.tfvars"
189
terraform apply
190
191
# 4. Modify Python and regenerate
192
echo "app_server.tags = {'Environment': 'production'}" >> app.tf.py
193
terraformpy
194
195
# 5. Apply changes
196
terraform plan
197
terraform apply
198
```
199
200
### Integration with CI/CD
201
202
```yaml
203
# .github/workflows/terraform.yml
204
name: Terraform Deploy
205
206
on:
207
push:
208
branches: [main]
209
210
jobs:
211
deploy:
212
runs-on: ubuntu-latest
213
steps:
214
- uses: actions/checkout@v3
215
216
- name: Setup Python
217
uses: actions/setup-python@v4
218
with:
219
python-version: '3.9'
220
221
- name: Install Terraformpy
222
run: pip install terraformpy
223
224
- name: Generate Terraform JSON
225
run: terraformpy
226
227
- name: Setup Terraform
228
uses: hashicorp/setup-terraform@v2
229
230
- name: Terraform Init
231
run: terraform init
232
233
- name: Terraform Plan
234
run: terraform plan
235
236
- name: Terraform Apply
237
if: github.ref == 'refs/heads/main'
238
run: terraform apply -auto-approve
239
```
240
241
### Development and Testing
242
243
```python
244
# test_infrastructure.py
245
import unittest
246
from terraformpy import *
247
from terraformpy.cli import main
248
import json
249
import tempfile
250
import os
251
252
class TestInfrastructure(unittest.TestCase):
253
def setUp(self):
254
"""Reset registry before each test."""
255
reset()
256
257
def test_web_server_configuration(self):
258
"""Test web server resource creation."""
259
# Create resources
260
web_server = Resource('aws_instance', 'web',
261
instance_type='t3.micro',
262
ami='ami-12345678'
263
)
264
265
# Compile and verify
266
config = json.loads(compile())
267
self.assertIn('resource', config)
268
self.assertIn('aws_instance', config['resource'])
269
self.assertEqual(
270
config['resource']['aws_instance']['web']['instance_type'],
271
't3.micro'
272
)
273
274
def test_cli_processing(self):
275
"""Test CLI file processing."""
276
with tempfile.TemporaryDirectory() as temp_dir:
277
# Create test file
278
test_file = os.path.join(temp_dir, 'test.tf.py')
279
with open(test_file, 'w') as f:
280
f.write('''
281
from terraformpy import Resource
282
Resource('aws_instance', 'test', instance_type='t3.micro')
283
''')
284
285
# Change to temp directory and run CLI
286
original_cwd = os.getcwd()
287
try:
288
os.chdir(temp_dir)
289
main()
290
291
# Verify output file exists
292
self.assertTrue(os.path.exists('main.tf.json'))
293
294
# Verify content
295
with open('main.tf.json', 'r') as f:
296
config = json.load(f)
297
self.assertIn('resource', config)
298
finally:
299
os.chdir(original_cwd)
300
301
if __name__ == '__main__':
302
unittest.main()
303
```
304
305
### Advanced CLI Usage Patterns
306
307
```python
308
# build_infrastructure.py - Custom build script
309
from terraformpy.cli import main
310
from terraformpy import reset
311
import os
312
import json
313
314
def build_environment(env_name):
315
"""Build infrastructure for specific environment."""
316
print(f"Building {env_name} environment...")
317
318
# Set environment variable for configuration
319
os.environ['ENVIRONMENT'] = env_name
320
321
# Clear any existing state
322
reset()
323
324
# Run CLI to process .tf.py files
325
main()
326
327
# Verify output
328
if os.path.exists('main.tf.json'):
329
with open('main.tf.json', 'r') as f:
330
config = json.load(f)
331
resources = len(config.get('resource', {}))
332
print(f"Generated {resources} resource types for {env_name}")
333
return True
334
return False
335
336
# Build for multiple environments
337
environments = ['development', 'staging', 'production']
338
for env in environments:
339
if build_environment(env):
340
# Rename output for environment
341
os.rename('main.tf.json', f'{env}.tf.json')
342
print(f"Saved {env}.tf.json")
343
```
344
345
## Best Practices
346
347
### File Organization
348
349
```bash
350
# Recommended project structure
351
terraform/
352
├── *.tf.py # Terraform Python files
353
├── main.tf.json # Generated output (gitignore this)
354
├── variables.tf # Terraform variables (optional)
355
├── terraform.tfvars # Variable values
356
└── modules/
357
└── custom/
358
├── *.tf.py
359
└── main.tf.json
360
```
361
362
### Version Control
363
364
```bash
365
# .gitignore
366
main.tf.json # Generated file - don't commit
367
*.pyc # Python bytecode
368
__pycache__/ # Python cache directories
369
.terraform/ # Terraform working directory
370
*.tfstate # Terraform state files
371
*.tfstate.backup
372
```
373
374
### Error Handling
375
376
```bash
377
# Check CLI exit status
378
terraformpy
379
if [ $? -ne 0 ]; then
380
echo "Terraformpy compilation failed"
381
exit 1
382
fi
383
384
# Validate generated JSON
385
terraform validate
386
387
# Use with error handling in scripts
388
set -e # Exit on error
389
terraformpy
390
terraform plan -detailed-exitcode
391
```