0
# State Management
1
2
Operations for reading and managing terraform state files, including parsing state data and accessing resource information. Terraform state files contain the current state of your infrastructure and are critical for terraform's operation.
3
4
## Capabilities
5
6
### State File Reading
7
8
Read and parse terraform state files into accessible Python objects.
9
10
```python { .api }
11
def read_state_file(self, file_path: Optional[str] = None) -> None:
12
"""
13
Read and parse terraform state file.
14
15
Args:
16
file_path: Path to state file relative to working directory.
17
If None, uses instance state setting or discovers automatically.
18
19
Side Effects:
20
Updates self.tfstate property with parsed state data
21
22
State file discovery order:
23
1. Provided file_path parameter
24
2. Instance self.state setting
25
3. .terraform/terraform.tfstate (for remote backends)
26
4. terraform.tfstate (for local backends)
27
"""
28
```
29
30
Usage examples:
31
32
```python
33
# Read default state file
34
tf.read_state_file()
35
36
# Read specific state file
37
tf.read_state_file('prod.tfstate')
38
39
# Access state data after reading
40
if tf.tfstate:
41
print(f"Terraform version: {tf.tfstate.terraform_version}")
42
print(f"Serial: {tf.tfstate.serial}")
43
```
44
45
### Tfstate Class
46
47
The `Tfstate` class provides structured access to terraform state file data.
48
49
```python { .api }
50
class Tfstate:
51
def __init__(self, data: Optional[Dict[str, str]] = None):
52
"""
53
Initialize state object.
54
55
Args:
56
data: Parsed JSON data from state file
57
"""
58
59
@staticmethod
60
def load_file(file_path: str) -> Tfstate:
61
"""
62
Load state file from disk.
63
64
Args:
65
file_path: Path to terraform state file
66
67
Returns:
68
Tfstate object with parsed data, or empty Tfstate if file doesn't exist
69
"""
70
71
# Properties (dynamically set from state file data)
72
tfstate_file: Optional[str] # Path to loaded state file
73
native_data: Optional[Dict[str, str]] # Raw parsed JSON data
74
# ... all other terraform state file fields are available as attributes
75
```
76
77
Usage examples:
78
79
```python
80
from python_terraform import Tfstate
81
82
# Load state file directly
83
state = Tfstate.load_file('/path/to/terraform.tfstate')
84
85
# Check if state file exists and has data
86
if state.native_data:
87
print("State file loaded successfully")
88
89
# Access state file fields (these vary based on terraform version)
90
if hasattr(state, 'version'):
91
print(f"State format version: {state.version}")
92
if hasattr(state, 'terraform_version'):
93
print(f"Terraform version: {state.terraform_version}")
94
if hasattr(state, 'serial'):
95
print(f"Serial: {state.serial}")
96
if hasattr(state, 'lineage'):
97
print(f"Lineage: {state.lineage}")
98
99
# Access resources (structure depends on terraform version)
100
if hasattr(state, 'resources'):
101
print(f"Number of resources: {len(state.resources)}")
102
for resource in state.resources:
103
print(f"Resource: {resource.get('type', 'unknown')} - {resource.get('name', 'unknown')}")
104
else:
105
print("State file not found or empty")
106
```
107
108
### Automatic State Loading
109
110
The Terraform class automatically loads state files after successful operations.
111
112
```python
113
# State is automatically loaded after successful operations
114
tf = Terraform(working_dir='/path/to/project')
115
tf.apply()
116
117
# State is now available
118
if tf.tfstate and tf.tfstate.native_data:
119
# Access state data
120
print("Resources in state:")
121
if hasattr(tf.tfstate, 'resources'):
122
for resource in tf.tfstate.resources:
123
resource_type = resource.get('type', 'unknown')
124
resource_name = resource.get('name', 'unknown')
125
print(f" {resource_type}.{resource_name}")
126
```
127
128
## State File Formats
129
130
Terraform state files are JSON documents with version-specific schemas. The library handles different state file formats automatically:
131
132
### State File Structure (varies by version)
133
```json
134
{
135
"version": 4,
136
"terraform_version": "1.0.0",
137
"serial": 1,
138
"lineage": "uuid-here",
139
"outputs": {},
140
"resources": []
141
}
142
```
143
144
### Common State File Fields
145
146
The exact fields available depend on your terraform version, but common fields include:
147
148
- **version**: State file format version
149
- **terraform_version**: Version of terraform that created the state
150
- **serial**: Incremental counter for state changes
151
- **lineage**: UUID that identifies the state lineage
152
- **outputs**: Terraform outputs
153
- **resources**: List of managed resources
154
- **modules**: Module information (older versions)
155
156
## Working with State Data
157
158
### Accessing Resource Information
159
160
```python
161
def get_resource_by_address(tf, resource_address):
162
"""Find a resource by its terraform address."""
163
if not tf.tfstate or not tf.tfstate.native_data:
164
return None
165
166
if hasattr(tf.tfstate, 'resources'):
167
for resource in tf.tfstate.resources:
168
if resource.get('type') and resource.get('name'):
169
address = f"{resource['type']}.{resource['name']}"
170
if address == resource_address:
171
return resource
172
return None
173
174
# Usage
175
tf.apply()
176
web_instance = get_resource_by_address(tf, 'aws_instance.web')
177
if web_instance:
178
print(f"Instance ID: {web_instance.get('instances', [{}])[0].get('attributes', {}).get('id')}")
179
```
180
181
### Accessing Outputs
182
183
```python
184
def get_state_outputs(tf):
185
"""Extract outputs from state file."""
186
if not tf.tfstate or not hasattr(tf.tfstate, 'outputs'):
187
return {}
188
189
outputs = {}
190
for name, output_data in tf.tfstate.outputs.items():
191
outputs[name] = output_data.get('value')
192
return outputs
193
194
# Usage
195
tf.apply()
196
outputs = get_state_outputs(tf)
197
for name, value in outputs.items():
198
print(f"{name}: {value}")
199
```
200
201
### State File Backup and Recovery
202
203
```python
204
import shutil
205
from datetime import datetime
206
207
def backup_state_file(tf):
208
"""Create a backup of the current state file."""
209
if tf.tfstate and tf.tfstate.tfstate_file:
210
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
211
backup_path = f"{tf.tfstate.tfstate_file}.backup.{timestamp}"
212
shutil.copy2(tf.tfstate.tfstate_file, backup_path)
213
print(f"State backed up to: {backup_path}")
214
return backup_path
215
return None
216
217
# Usage
218
backup_path = backup_state_file(tf)
219
try:
220
tf.apply()
221
except TerraformCommandError:
222
print("Apply failed, state backup available at:", backup_path)
223
```
224
225
## Error Handling
226
227
State file operations can fail for various reasons:
228
229
```python
230
from python_terraform import Tfstate, TerraformCommandError
231
232
# Handle missing state files
233
try:
234
tf.read_state_file('nonexistent.tfstate')
235
except FileNotFoundError:
236
print("State file not found")
237
238
# Handle corrupted state files
239
state = Tfstate.load_file('potentially-corrupted.tfstate')
240
if not state.native_data:
241
print("State file is empty or corrupted")
242
243
# Handle state loading after failed operations
244
try:
245
tf.apply()
246
except TerraformCommandError:
247
# State may not be updated if apply failed
248
print("Apply failed, state may be inconsistent")
249
tf.read_state_file() # Explicitly reload state
250
```
251
252
## Best Practices
253
254
### State File Safety
255
- Always backup state files before major operations
256
- Use remote backends for team environments
257
- Never manually edit state files
258
- Use terraform state commands for state manipulation
259
260
### Integration with Operations
261
```python
262
# The library automatically manages state loading
263
tf = Terraform(working_dir='/path/to/project')
264
265
# State is loaded after successful operations
266
ret, out, err = tf.apply()
267
if ret == 0:
268
# tf.tfstate now contains current state
269
print("Apply successful, state updated")
270
else:
271
# State may not be updated
272
print("Apply failed, state unchanged")
273
```