0
# Driver System
1
2
The Molecule driver system provides an extensible architecture for provisioning and managing test infrastructure across different platforms and environments. Drivers handle the creation, configuration, and destruction of test instances.
3
4
## Capabilities
5
6
### Base Driver Class
7
8
Abstract base class that all drivers must inherit from, defining the interface for infrastructure management.
9
10
```python { .api }
11
class Driver:
12
"""Base class for all drivers."""
13
14
@property
15
def name(self):
16
"""
17
Name of the driver.
18
19
Returns:
20
str: Driver name identifier
21
"""
22
23
@property
24
def login_cmd_template(self):
25
"""
26
Login command template.
27
28
Returns:
29
str: Template string for generating login commands
30
"""
31
32
@property
33
def default_ssh_connection_options(self):
34
"""
35
SSH client options.
36
37
Returns:
38
list[str]: Default SSH connection options
39
"""
40
41
@property
42
def default_safe_files(self):
43
"""
44
Generate files to be preserved.
45
46
Returns:
47
list[str]: List of files that should not be deleted
48
"""
49
50
def login_options(self, instance_name):
51
"""
52
Options used in login command.
53
54
Args:
55
instance_name (str): Name of the instance
56
57
Returns:
58
dict: Options for login command generation
59
"""
60
61
def ansible_connection_options(self, instance_name):
62
"""
63
Ansible connection options.
64
65
Args:
66
instance_name (str): Name of the instance
67
68
Returns:
69
dict: Ansible connection configuration
70
"""
71
72
def sanity_checks(self):
73
"""
74
Confirm that driver is usable.
75
76
Raises:
77
MoleculeError: If driver prerequisites are not met
78
"""
79
```
80
81
### Driver Properties and Methods
82
83
Concrete properties and methods available to all drivers for managing instances and configuration.
84
85
```python { .api }
86
class Driver:
87
@property
88
def testinfra_options(self):
89
"""
90
Testinfra specific options.
91
92
Returns:
93
dict: Configuration options for testinfra integration
94
"""
95
96
@property
97
def options(self):
98
"""
99
Driver options.
100
101
Returns:
102
dict: Driver-specific configuration options
103
"""
104
105
@property
106
def instance_config(self):
107
"""
108
Instance config file location.
109
110
Returns:
111
str: Path to instance configuration file
112
"""
113
114
@property
115
def ssh_connection_options(self):
116
"""
117
SSH connection options.
118
119
Returns:
120
list[str]: SSH connection configuration
121
"""
122
123
@property
124
def safe_files(self):
125
"""
126
Safe files list.
127
128
Returns:
129
list[str]: Files that should be preserved during cleanup
130
"""
131
132
@property
133
def delegated(self):
134
"""
135
Is the driver delegated.
136
137
Returns:
138
bool: True if driver delegates instance management
139
"""
140
141
@property
142
def managed(self):
143
"""
144
Is the driver managed.
145
146
Returns:
147
bool: True if driver manages infrastructure lifecycle
148
"""
149
150
def status(self):
151
"""
152
Collect instances state.
153
154
Returns:
155
list[Status]: List of instance status information
156
"""
157
158
def get_playbook(self, step):
159
"""
160
Return embedded playbook location.
161
162
Args:
163
step (str): Lifecycle step name
164
165
Returns:
166
str: Path to playbook file for the specified step
167
"""
168
169
def modules_dir(self):
170
"""
171
Return path to ansible modules included with driver.
172
173
Returns:
174
str: Path to driver-specific Ansible modules
175
"""
176
177
def reset(self):
178
"""Release all resources owned by molecule."""
179
180
@property
181
def required_collections(self):
182
"""
183
Return required collections dict.
184
185
Returns:
186
dict[str, str]: Required Ansible collections and their versions
187
"""
188
```
189
190
### Default Driver Implementation
191
192
The default delegated driver implementation where developers provide their own create/destroy playbooks.
193
194
```python { .api }
195
class Delegated(Driver):
196
"""
197
Default driver implementation for delegated infrastructure management.
198
199
This driver delegates instance creation and destruction to user-provided
200
Ansible playbooks, allowing maximum flexibility in infrastructure setup.
201
"""
202
203
@property
204
def name(self):
205
"""Returns 'default'."""
206
207
@property
208
def login_cmd_template(self):
209
"""Template for SSH login commands."""
210
211
def sanity_checks(self):
212
"""Validates that required playbooks exist."""
213
```
214
215
## Driver Configuration Types
216
217
Type definitions for driver configuration and options.
218
219
```python { .api }
220
class DriverOptions:
221
"""Config options for molecule drivers."""
222
ansible_connection_options: dict[str, str]
223
login_cmd_template: str
224
managed: bool
225
226
class DriverData:
227
"""Molecule driver configuration."""
228
name: str
229
provider: dict[str, Any]
230
options: DriverOptions
231
ssh_connection_options: list[str]
232
safe_files: list[str]
233
```
234
235
## Usage Examples
236
237
### Creating a Custom Driver
238
239
```python
240
from molecule.driver.base import Driver
241
from molecule.exceptions import MoleculeError
242
243
class CustomDriver(Driver):
244
def __init__(self, config=None):
245
super().__init__(config)
246
self._name = "custom"
247
248
@property
249
def name(self):
250
return self._name
251
252
@property
253
def login_cmd_template(self):
254
return "ssh {address}"
255
256
@property
257
def default_ssh_connection_options(self):
258
return ["-o", "StrictHostKeyChecking=no"]
259
260
@property
261
def default_safe_files(self):
262
return []
263
264
def login_options(self, instance_name):
265
return {"address": f"user@{instance_name}"}
266
267
def ansible_connection_options(self, instance_name):
268
return {"ansible_host": instance_name}
269
270
def sanity_checks(self):
271
# Check driver prerequisites
272
pass
273
```
274
275
### Using Drivers Programmatically
276
277
```python
278
from molecule.api import drivers
279
from molecule.config import Config
280
281
# Get available drivers
282
available_drivers = drivers()
283
default_driver = available_drivers.get("default")
284
285
if default_driver:
286
print(f"Driver: {default_driver.name}")
287
print(f"Managed: {default_driver.managed}")
288
print(f"Required collections: {default_driver.required_collections}")
289
290
# Check driver status
291
instances = default_driver.status()
292
for instance in instances:
293
print(f"Instance: {instance.instance_name}")
294
print(f"Created: {instance.created}")
295
print(f"Converged: {instance.converged}")
296
```
297
298
### Driver Configuration
299
300
```yaml
301
# molecule.yml
302
driver:
303
name: default
304
options:
305
managed: false
306
login_cmd_template: 'ssh -i {identity_file} {user}@{address}'
307
ansible_connection_options:
308
ansible_ssh_user: root
309
ansible_ssh_private_key_file: ~/.ssh/id_rsa
310
safe_files:
311
- .ssh/
312
- inventory/
313
```
314
315
## Integration Notes
316
317
- Drivers are discovered through setuptools entry points under `molecule.driver`
318
- The default driver (`delegated`) is included with Molecule
319
- Custom drivers should inherit from the `Driver` base class
320
- Driver loading failures are logged but don't prevent tool usage
321
- Drivers can specify required Ansible collections for proper functionality
322
- Instance configuration is typically stored in YAML format for persistence