0
# Helper Utilities
1
2
Additional utilities for user data, template conversion, and stack monitoring to enhance CloudFormation workflow integration.
3
4
## Capabilities
5
6
### UserData Helpers
7
8
Utilities for loading and processing EC2 user data scripts from files.
9
10
```python { .api }
11
def from_file(filepath: str) -> str:
12
"""
13
Load user data from file.
14
15
Args:
16
filepath: Path to user data script file
17
18
Returns:
19
str: File contents as string
20
21
Raises:
22
IOError: If file cannot be read
23
"""
24
25
def from_file_sub(filepath: str) -> str:
26
"""
27
Load user data from file with variable substitution support.
28
29
Args:
30
filepath: Path to user data script file with ${variable} placeholders
31
32
Returns:
33
str: File contents with substitution placeholders preserved
34
35
Raises:
36
IOError: If file cannot be read
37
"""
38
```
39
40
### Template Generator
41
42
Convert existing CloudFormation JSON/YAML templates to Troposphere Template objects.
43
44
```python { .api }
45
class TemplateGenerator:
46
def __init__(self):
47
"""Template conversion utility."""
48
49
def convert_template(self, template_data: dict) -> Template:
50
"""
51
Convert CloudFormation template dictionary to Troposphere Template.
52
53
Args:
54
template_data: CloudFormation template as dictionary
55
56
Returns:
57
Template: Troposphere Template object
58
59
Raises:
60
ValueError: If template format is invalid
61
"""
62
63
def convert_from_file(self, filepath: str) -> Template:
64
"""
65
Convert CloudFormation template file to Troposphere Template.
66
67
Args:
68
filepath: Path to CloudFormation template file (JSON or YAML)
69
70
Returns:
71
Template: Troposphere Template object
72
73
Raises:
74
IOError: If file cannot be read
75
ValueError: If template format is invalid
76
"""
77
```
78
79
### Stack Monitoring
80
81
Utilities for monitoring CloudFormation stack events and status.
82
83
```python { .api }
84
def get_events(stackname: str, region: str = None, aws_profile: str = None) -> List[dict]:
85
"""
86
Get CloudFormation stack events.
87
88
Args:
89
stackname: CloudFormation stack name
90
region: AWS region (uses default if not specified)
91
aws_profile: AWS profile name (uses default if not specified)
92
93
Returns:
94
List[dict]: Stack events
95
96
Raises:
97
ClientError: If stack not found or access denied
98
"""
99
100
def tail(stackname: str, region: str = None, aws_profile: str = None) -> None:
101
"""
102
Monitor CloudFormation stack events in real-time.
103
104
Args:
105
stackname: CloudFormation stack name
106
region: AWS region (uses default if not specified)
107
aws_profile: AWS profile name (uses default if not specified)
108
109
Raises:
110
ClientError: If stack not found or access denied
111
KeyboardInterrupt: If monitoring interrupted by user
112
"""
113
```
114
115
### Encoding Utilities
116
117
Utilities for encoding and data transformation.
118
119
```python { .api }
120
def encode_to_dict(obj) -> Union[Dict[str, Any], List[Any], Any]:
121
"""
122
Recursively encode objects to dictionary format.
123
124
Args:
125
obj: Object to encode (BaseAWSObject, list, dict, or primitive)
126
127
Returns:
128
Encoded object in dictionary format
129
"""
130
131
def depends_on_helper(obj) -> Union[str, List[str], Any]:
132
"""
133
Helper for processing DependsOn values.
134
135
Args:
136
obj: Dependency object (AWSObject, string, or list)
137
138
Returns:
139
Processed dependency (resource title or list of titles)
140
"""
141
```
142
143
## Usage Examples
144
145
### UserData File Loading
146
147
```python
148
from troposphere import Template, Base64
149
from troposphere.ec2 import Instance
150
from troposphere.helpers.userdata import from_file, from_file_sub
151
152
template = Template()
153
154
# Load static user data from file
155
user_data_script = from_file("/path/to/userdata.sh")
156
157
instance = template.add_resource(Instance(
158
"WebServer",
159
ImageId="ami-0abcdef1234567890",
160
InstanceType="t3.micro",
161
UserData=Base64(user_data_script)
162
))
163
164
# Load user data with substitution placeholders
165
user_data_template = from_file_sub("/path/to/userdata_template.sh")
166
167
# Use with Sub function for variable substitution
168
from troposphere import Sub, Ref
169
170
instance_with_vars = template.add_resource(Instance(
171
"AppServer",
172
ImageId="ami-0abcdef1234567890",
173
InstanceType="t3.micro",
174
UserData=Base64(Sub(user_data_template, {
175
"StackName": Ref("AWS::StackName"),
176
"Region": Ref("AWS::Region")
177
}))
178
))
179
```
180
181
Example userdata_template.sh:
182
```bash
183
#!/bin/bash
184
echo "Stack: ${StackName}" >> /var/log/stack-info.log
185
echo "Region: ${Region}" >> /var/log/stack-info.log
186
echo "Starting application..." >> /var/log/stack-info.log
187
188
# Install application
189
curl -o /tmp/app.zip https://releases.example.com/app.zip
190
unzip /tmp/app.zip -d /opt/app/
191
chmod +x /opt/app/start.sh
192
/opt/app/start.sh
193
```
194
195
### Template Conversion
196
197
```python
198
from troposphere.template_generator import TemplateGenerator
199
import json
200
201
# Convert existing CloudFormation template
202
generator = TemplateGenerator()
203
204
# From file
205
troposphere_template = generator.convert_from_file("existing-stack.json")
206
207
# From dictionary
208
with open("cloudformation-template.json", "r") as f:
209
cf_template = json.load(f)
210
211
troposphere_template = generator.convert_template(cf_template)
212
213
# Now you can modify using Troposphere
214
from troposphere.ec2 import Instance
215
216
new_instance = troposphere_template.add_resource(Instance(
217
"AdditionalInstance",
218
ImageId="ami-0abcdef1234567890",
219
InstanceType="t3.micro"
220
))
221
222
# Convert back to CloudFormation
223
updated_cf_json = troposphere_template.to_json()
224
updated_cf_yaml = troposphere_template.to_yaml()
225
```
226
227
### Stack Monitoring
228
229
```python
230
from troposphere.utils import get_events, tail
231
import time
232
233
# Get current stack events
234
try:
235
events = get_events("my-stack", region="us-east-1")
236
237
print("Recent stack events:")
238
for event in events[:10]: # Show last 10 events
239
print(f"{event['Timestamp']}: {event['LogicalResourceId']} - {event['ResourceStatus']}")
240
241
except Exception as e:
242
print(f"Error getting stack events: {e}")
243
244
# Monitor stack in real-time (blocks until interrupted)
245
print("Monitoring stack events (Ctrl+C to stop)...")
246
try:
247
tail("my-stack", region="us-east-1", aws_profile="production")
248
except KeyboardInterrupt:
249
print("Monitoring stopped")
250
```
251
252
### Custom Encoding
253
254
```python
255
from troposphere import encode_to_dict, Template, Ref
256
from troposphere.ec2 import Instance
257
258
template = Template()
259
260
instance = template.add_resource(Instance(
261
"MyInstance",
262
ImageId="ami-0abcdef1234567890",
263
InstanceType="t3.micro"
264
))
265
266
# Encode individual resource
267
instance_dict = encode_to_dict(instance)
268
print("Instance as dict:", instance_dict)
269
270
# Encode entire template
271
template_dict = encode_to_dict(template.to_dict())
272
print("Template as dict:", template_dict)
273
274
# Custom object encoding
275
class CustomObject:
276
def __init__(self, name, value):
277
self.name = name
278
self.value = value
279
280
def to_dict(self):
281
return {"Name": self.name, "Value": self.value}
282
283
custom = CustomObject("test", "value")
284
encoded_custom = encode_to_dict(custom)
285
print("Custom object:", encoded_custom)
286
```
287
288
### DependsOn Helper Usage
289
290
```python
291
from troposphere import depends_on_helper, Template
292
from troposphere.ec2 import Instance, SecurityGroup
293
294
template = Template()
295
296
# Create security group
297
sg = template.add_resource(SecurityGroup(
298
"MySecurityGroup",
299
GroupDescription="Test security group"
300
))
301
302
# Create instance
303
instance = template.add_resource(Instance(
304
"MyInstance",
305
ImageId="ami-0abcdef1234567890",
306
InstanceType="t3.micro"
307
))
308
309
# Use depends_on_helper for processing dependencies
310
# These are equivalent:
311
instance.DependsOn = depends_on_helper(sg) # Converts to "MySecurityGroup"
312
instance.DependsOn = "MySecurityGroup" # Direct string
313
314
# For multiple dependencies
315
dependencies = [sg, "SomeOtherResource"]
316
instance.DependsOn = depends_on_helper(dependencies) # Converts to ["MySecurityGroup", "SomeOtherResource"]
317
```
318
319
### Advanced UserData with Parameters
320
321
```python
322
from troposphere import Template, Parameter, Sub, Base64, Ref
323
from troposphere.ec2 import Instance
324
from troposphere.helpers.userdata import from_file_sub
325
326
template = Template()
327
328
# Parameters for user data
329
app_version = template.add_parameter(Parameter(
330
"AppVersion",
331
Type="String",
332
Default="1.0.0",
333
Description="Application version to deploy"
334
))
335
336
database_url = template.add_parameter(Parameter(
337
"DatabaseURL",
338
Type="String",
339
Description="Database connection URL"
340
))
341
342
# Load user data template
343
user_data_template = from_file_sub("scripts/app-setup.sh")
344
345
# Create instance with parameterized user data
346
instance = template.add_resource(Instance(
347
"AppServer",
348
ImageId="ami-0abcdef1234567890",
349
InstanceType="t3.micro",
350
UserData=Base64(Sub(user_data_template, {
351
"AppVersion": Ref(app_version),
352
"DatabaseURL": Ref(database_url),
353
"StackName": Ref("AWS::StackName"),
354
"Region": Ref("AWS::Region")
355
}))
356
))
357
```
358
359
Example app-setup.sh:
360
```bash
361
#!/bin/bash
362
set -e
363
364
# Log all output
365
exec > >(tee /var/log/user-data.log)
366
exec 2>&1
367
368
echo "Starting application setup..."
369
echo "Stack: ${StackName}"
370
echo "Region: ${Region}"
371
echo "App Version: ${AppVersion}"
372
373
# Set environment variables
374
export APP_VERSION="${AppVersion}"
375
export DATABASE_URL="${DatabaseURL}"
376
export STACK_NAME="${StackName}"
377
378
# Download and install application
379
cd /opt
380
wget https://releases.example.com/app-${AppVersion}.tar.gz
381
tar -xzf app-${AppVersion}.tar.gz
382
cd app-${AppVersion}
383
384
# Configure application
385
cat > config.json << EOF
386
{
387
"database_url": "${DatabaseURL}",
388
"stack_name": "${StackName}",
389
"region": "${Region}",
390
"version": "${AppVersion}"
391
}
392
EOF
393
394
# Start application
395
chmod +x start.sh
396
./start.sh
397
398
echo "Application setup completed successfully"
399
```