0
# Playbook Engine
1
2
Ansible Core's playbook engine provides YAML-based automation workflow execution supporting plays, tasks, handlers, roles, blocks, includes, and imports with comprehensive control flow, error handling, and variable management.
3
4
## Capabilities
5
6
### Playbook Management
7
8
The main playbook container that loads, validates, and coordinates the execution of multiple plays with shared context and variable management.
9
10
```python { .api }
11
class Playbook:
12
"""
13
Main playbook container managing plays and execution context.
14
15
Attributes:
16
- _entries: List of play entries
17
- _basedir: Base directory for relative paths
18
- _file_name: Playbook filename
19
- _loader: DataLoader instance
20
- _variable_manager: Variable manager instance
21
"""
22
23
@staticmethod
24
def load(filename, variable_manager=None, loader=None, vars=None):
25
"""
26
Load playbook from YAML file.
27
28
Parameters:
29
- filename: Path to playbook file
30
- variable_manager: Variable manager instance
31
- loader: DataLoader instance
32
- vars: Additional variables
33
34
Returns:
35
Playbook: Loaded playbook instance
36
"""
37
38
def get_plays(self):
39
"""
40
Get all plays in playbook.
41
42
Returns:
43
list: Play objects
44
"""
45
46
def get_vars(self):
47
"""
48
Get playbook-level variables.
49
50
Returns:
51
dict: Playbook variables
52
"""
53
```
54
55
### Play Management
56
57
Individual play representation containing tasks, handlers, and play-level configuration with host targeting and execution control.
58
59
```python { .api }
60
class Play:
61
"""
62
Individual play representation with tasks and configuration.
63
64
Attributes:
65
- name: Play name
66
- hosts: Target host pattern
67
- tasks: List of task objects
68
- handlers: List of handler objects
69
- vars: Play variables
70
- tags: Play tags
71
- gather_facts: Whether to gather facts
72
- remote_user: Remote user for connections
73
- become: Privilege escalation settings
74
"""
75
76
def __init__(self):
77
"""Initialize empty play"""
78
79
@staticmethod
80
def load(data, variable_manager=None, loader=None, basedir=None):
81
"""
82
Load play from data structure.
83
84
Parameters:
85
- data: Play data dictionary
86
- variable_manager: Variable manager
87
- loader: DataLoader instance
88
- basedir: Base directory for paths
89
90
Returns:
91
Play: Loaded play instance
92
"""
93
94
def get_tasks(self):
95
"""
96
Get all tasks in play including role tasks.
97
98
Returns:
99
list: Task objects
100
"""
101
102
def get_handlers(self):
103
"""
104
Get all handlers in play including role handlers.
105
106
Returns:
107
list: Handler objects
108
"""
109
110
def get_roles(self):
111
"""
112
Get all roles in play.
113
114
Returns:
115
list: Role objects
116
"""
117
118
def get_vars(self):
119
"""
120
Get play variables.
121
122
Returns:
123
dict: Play-level variables
124
"""
125
```
126
127
### Task Management
128
129
Task representation with action, parameters, conditionals, loops, and execution control supporting all Ansible modules and plugins.
130
131
```python { .api }
132
class Task:
133
"""
134
Task representation with action and execution parameters.
135
136
Attributes:
137
- action: Module or action name
138
- args: Task arguments
139
- name: Task name
140
- when: Conditional expression
141
- loop: Loop specification
142
- tags: Task tags
143
- register: Variable to register result
144
- delegate_to: Delegation target
145
- become: Privilege escalation
146
- ignore_errors: Whether to ignore failures
147
- changed_when: When to mark as changed
148
- failed_when: When to mark as failed
149
"""
150
151
def __init__(self):
152
"""Initialize empty task"""
153
154
@staticmethod
155
def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None):
156
"""
157
Load task from data structure.
158
159
Parameters:
160
- data: Task data dictionary
161
- block: Parent block object
162
- role: Parent role object
163
- task_include: Task include object
164
- variable_manager: Variable manager
165
- loader: DataLoader instance
166
167
Returns:
168
Task: Loaded task instance
169
"""
170
171
def get_vars(self):
172
"""
173
Get task variables.
174
175
Returns:
176
dict: Task-level variables
177
"""
178
179
def evaluate_conditional(self, templar, all_vars):
180
"""
181
Evaluate task conditional expression.
182
183
Parameters:
184
- templar: Templating engine
185
- all_vars: Available variables
186
187
Returns:
188
bool: Whether conditional passes
189
"""
190
```
191
192
### Block Management
193
194
Task grouping container supporting error handling, rescue, and always sections with shared conditionals and variables.
195
196
```python { .api }
197
class Block:
198
"""
199
Task block container with error handling support.
200
201
Attributes:
202
- block: List of main tasks
203
- rescue: List of rescue tasks (on failure)
204
- always: List of tasks that always run
205
- when: Block conditional
206
- tags: Block tags
207
- vars: Block variables
208
"""
209
210
def __init__(self, parent_block=None, role=None, task_include=None, use_handlers=True, implicit=False):
211
"""Initialize block container"""
212
213
@staticmethod
214
def load(data, play=None, parent_block=None, role=None, task_include=None, variable_manager=None, loader=None):
215
"""
216
Load block from data structure.
217
218
Parameters:
219
- data: Block data dictionary
220
- play: Parent play
221
- parent_block: Parent block
222
- role: Parent role
223
- task_include: Task include
224
- variable_manager: Variable manager
225
- loader: DataLoader instance
226
227
Returns:
228
Block: Loaded block instance
229
"""
230
231
def get_tasks(self):
232
"""
233
Get all tasks in block sections.
234
235
Returns:
236
list: All task objects (block + rescue + always)
237
"""
238
239
def has_tasks(self):
240
"""
241
Check if block has any tasks.
242
243
Returns:
244
bool: True if block contains tasks
245
"""
246
```
247
248
### Handler Management
249
250
Event-driven task execution triggered by notify actions with deduplication and ordered execution.
251
252
```python { .api }
253
class Handler(Task):
254
"""
255
Handler task triggered by notifications.
256
257
Inherits from Task with additional handler-specific behavior.
258
259
Attributes:
260
- listen: List of notification names to listen for
261
- _hash: Handler hash for deduplication
262
"""
263
264
def __init__(self):
265
"""Initialize handler task"""
266
267
@staticmethod
268
def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None):
269
"""
270
Load handler from data structure.
271
272
Parameters:
273
- data: Handler data dictionary
274
- block: Parent block
275
- role: Parent role
276
- task_include: Task include
277
- variable_manager: Variable manager
278
- loader: DataLoader instance
279
280
Returns:
281
Handler: Loaded handler instance
282
"""
283
```
284
285
### Role Management
286
287
Role definition and metadata management supporting role dependencies, parameters, and modular playbook organization.
288
289
```python { .api }
290
class Role:
291
"""
292
Role definition with tasks, handlers, variables, and metadata.
293
294
Attributes:
295
- _role_name: Role name
296
- _role_path: Path to role directory
297
- _role_params: Role parameters
298
- _default_vars: Default variables
299
- _role_vars: Role variables
300
- _dependencies: Role dependencies
301
- _metadata: Role metadata
302
"""
303
304
def __init__(self, play=None, from_files=None, from_include=False):
305
"""Initialize role"""
306
307
@staticmethod
308
def load(role_include, play, parent_role=None, from_files=None, from_include=False):
309
"""
310
Load role from role include specification.
311
312
Parameters:
313
- role_include: Role include specification
314
- play: Parent play
315
- parent_role: Parent role for nested roles
316
- from_files: Load from specific files
317
- from_include: Whether loaded from include
318
319
Returns:
320
Role: Loaded role instance
321
"""
322
323
def get_name(self):
324
"""
325
Get role name.
326
327
Returns:
328
str: Role name
329
"""
330
331
def get_tasks(self):
332
"""
333
Get role tasks.
334
335
Returns:
336
list: Task objects
337
"""
338
339
def get_handlers(self):
340
"""
341
Get role handlers.
342
343
Returns:
344
list: Handler objects
345
"""
346
347
def get_default_vars(self):
348
"""
349
Get role default variables.
350
351
Returns:
352
dict: Default variables
353
"""
354
355
def get_vars(self):
356
"""
357
Get role variables.
358
359
Returns:
360
dict: Role variables
361
"""
362
363
def get_dependencies(self):
364
"""
365
Get role dependencies.
366
367
Returns:
368
list: Dependency role objects
369
"""
370
```
371
372
### Include and Import Management
373
374
Dynamic and static content inclusion supporting conditional includes, variable passing, and modular playbook composition.
375
376
```python { .api }
377
class TaskInclude(Task):
378
"""
379
Task include for dynamic content inclusion.
380
381
Supports conditional includes with variable passing.
382
"""
383
384
@staticmethod
385
def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None):
386
"""Load task include from data"""
387
388
class PlaybookInclude:
389
"""
390
Playbook include for importing entire playbooks.
391
392
Supports variable passing and conditional inclusion.
393
"""
394
395
@staticmethod
396
def load(data, basedir=None, variable_manager=None, loader=None):
397
"""Load playbook include from data"""
398
```
399
400
## Playbook Structure
401
402
### Basic Playbook Format
403
404
```yaml
405
---
406
- name: Web server setup
407
hosts: webservers
408
become: yes
409
vars:
410
http_port: 80
411
server_name: "{{ inventory_hostname }}"
412
413
tasks:
414
- name: Install Apache
415
package:
416
name: apache2
417
state: present
418
notify: restart apache
419
420
- name: Copy configuration
421
template:
422
src: apache.conf.j2
423
dest: /etc/apache2/apache2.conf
424
notify: restart apache
425
426
handlers:
427
- name: restart apache
428
service:
429
name: apache2
430
state: restarted
431
```
432
433
### Advanced Features
434
435
```yaml
436
---
437
- name: Advanced playbook example
438
hosts: all
439
gather_facts: yes
440
vars:
441
app_version: "1.2.3"
442
443
tasks:
444
- name: Conditional task
445
debug:
446
msg: "Running on {{ ansible_os_family }}"
447
when: ansible_os_family == "RedHat"
448
449
- name: Loop example
450
user:
451
name: "{{ item }}"
452
state: present
453
loop:
454
- alice
455
- bob
456
- charlie
457
458
- name: Block with error handling
459
block:
460
- name: Risky operation
461
command: /bin/might-fail
462
rescue:
463
- name: Handle failure
464
debug:
465
msg: "Operation failed, continuing"
466
always:
467
- name: Cleanup
468
file:
469
path: /tmp/cleanup
470
state: absent
471
472
- name: Include tasks conditionally
473
include_tasks: database.yml
474
when: setup_database | default(false)
475
476
- name: Import role
477
import_role:
478
name: common
479
vars:
480
role_var: value
481
```
482
483
## Control Flow
484
485
### Conditionals
486
487
```yaml
488
# Simple conditional
489
- name: Task with when
490
debug:
491
msg: "Executed"
492
when: ansible_os_family == "Debian"
493
494
# Complex conditional
495
- name: Multiple conditions
496
debug:
497
msg: "Complex condition"
498
when:
499
- ansible_distribution == "Ubuntu"
500
- ansible_distribution_version is version('18.04', '>=')
501
- inventory_hostname in groups['webservers']
502
```
503
504
### Loops
505
506
```yaml
507
# Simple loop
508
- name: Create users
509
user:
510
name: "{{ item }}"
511
loop:
512
- alice
513
- bob
514
515
# Loop with dictionaries
516
- name: Create users with details
517
user:
518
name: "{{ item.name }}"
519
groups: "{{ item.groups }}"
520
loop:
521
- name: alice
522
groups: admin
523
- name: bob
524
groups: users
525
526
# Loop with conditionals
527
- name: Install packages on Debian
528
package:
529
name: "{{ item }}"
530
loop:
531
- nginx
532
- mysql-server
533
when: ansible_os_family == "Debian"
534
```
535
536
### Error Handling
537
538
```yaml
539
# Ignore errors
540
- name: Command that might fail
541
command: /bin/might-fail
542
ignore_errors: yes
543
544
# Custom failure conditions
545
- name: Check service
546
command: systemctl is-active nginx
547
register: nginx_status
548
failed_when: nginx_status.rc not in [0, 3]
549
550
# Custom change conditions
551
- name: Touch file
552
file:
553
path: /tmp/myfile
554
state: touch
555
changed_when: false
556
```
557
558
## Usage Examples
559
560
### Basic Playbook Execution
561
562
```python
563
from ansible.playbook import Playbook
564
from ansible.inventory.manager import InventoryManager
565
from ansible.parsing.dataloader import DataLoader
566
from ansible.vars.manager import VariableManager
567
568
# Initialize components
569
loader = DataLoader()
570
inventory = InventoryManager(loader=loader, sources=['inventory'])
571
variable_manager = VariableManager(loader=loader, inventory=inventory)
572
573
# Load playbook
574
pb = Playbook.load('site.yml', variable_manager=variable_manager, loader=loader)
575
576
# Get plays
577
plays = pb.get_plays()
578
for play in plays:
579
print(f"Play: {play.name}")
580
tasks = play.get_tasks()
581
for task in tasks:
582
print(f" Task: {task.name}")
583
```
584
585
### Task Manipulation
586
587
```python
588
from ansible.playbook.task import Task
589
590
# Create task programmatically
591
task_data = {
592
'name': 'Install package',
593
'package': {
594
'name': 'nginx',
595
'state': 'present'
596
},
597
'become': True,
598
'tags': ['packages']
599
}
600
601
task = Task.load(task_data, variable_manager=variable_manager, loader=loader)
602
603
# Check task properties
604
print(f"Task name: {task.name}")
605
print(f"Task action: {task.action}")
606
print(f"Task args: {task.args}")
607
```