or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfiguration.mderrors.mdexecution.mdindex.mdinventory.mdmodule-utils.mdplaybook.mdplugins.mdtemplating.md

templating.mddocs/

0

# Template Engine

1

2

Ansible Core's template engine provides comprehensive Jinja2-based variable substitution, conditional logic, loops, and expression evaluation with Ansible-specific filters, tests, functions, and security controls optimized for automation workflows.

3

4

## Capabilities

5

6

### Template Engine Core

7

8

The main templating engine coordinating Jinja2 processing with Ansible-specific enhancements, variable resolution, and security controls.

9

10

```python { .api }

11

class Templar:

12

"""

13

Main templating engine with Jinja2 integration and Ansible enhancements.

14

15

Attributes:

16

- _loader: DataLoader instance

17

- _variables: Available variables

18

- environment: Jinja2 environment

19

- _fail_on_undefined: Whether to fail on undefined variables

20

- _finalized: Whether templating is finalized

21

"""

22

23

def __init__(self, loader, variables=None):

24

"""

25

Initialize templating engine.

26

27

Parameters:

28

- loader: DataLoader instance

29

- variables: Available variables dictionary

30

"""

31

32

def template(self, variable, convert_bare=False, preserve_trailing_newlines=True,

33

escape_backslashes=True, fail_on_undefined=None, overrides=None,

34

convert_data=True, static_vars=None, cache=True, disable_lookups=False):

35

"""

36

Template a variable with current context.

37

38

Parameters:

39

- variable: Variable to template (string, dict, list, etc.)

40

- convert_bare: Convert bare variables

41

- preserve_trailing_newlines: Keep trailing newlines

42

- escape_backslashes: Escape backslash characters

43

- fail_on_undefined: Fail on undefined variables

44

- overrides: Variable overrides

45

- convert_data: Convert templated data

46

- static_vars: Static variables list

47

- cache: Use template caching

48

- disable_lookups: Disable lookup plugins

49

50

Returns:

51

object: Templated result

52

"""

53

54

def is_template(self, data):

55

"""

56

Check if data contains template expressions.

57

58

Parameters:

59

- data: Data to check

60

61

Returns:

62

bool: True if data contains templates

63

"""

64

65

def set_available_variables(self, variables):

66

"""

67

Set available variables for templating.

68

69

Parameters:

70

- variables: Variables dictionary

71

"""

72

73

def get_available_variables(self):

74

"""

75

Get currently available variables.

76

77

Returns:

78

dict: Available variables

79

"""

80

```

81

82

### Jinja2 Environment

83

84

Customized Jinja2 environment with Ansible-specific filters, tests, globals, and configuration optimized for automation use cases.

85

86

```python { .api }

87

class AnsibleEnvironment:

88

"""

89

Ansible-customized Jinja2 environment with enhanced functionality.

90

91

Provides Ansible-specific filters, tests, and globals while maintaining

92

Jinja2 compatibility and adding security controls.

93

"""

94

95

def __init__(self, *args, **kwargs):

96

"""Initialize Ansible Jinja2 environment"""

97

98

def get_template(self, name, parent=None, globals=None):

99

"""

100

Get template by name with Ansible enhancements.

101

102

Parameters:

103

- name: Template name

104

- parent: Parent template

105

- globals: Template globals

106

107

Returns:

108

Template: Jinja2 template object

109

"""

110

111

class AnsibleContext:

112

"""

113

Template context with Ansible-specific variable resolution and scoping.

114

115

Manages variable inheritance, scoping, and resolution order for

116

templates while providing access to Ansible-specific data.

117

"""

118

```

119

120

### Template Filters

121

122

Ansible-specific Jinja2 filters for data transformation, formatting, and manipulation commonly needed in automation workflows.

123

124

```python { .api }

125

# String and text filters

126

def to_yaml(data, indent=2, default_flow_style=False):

127

"""

128

Convert data to YAML format.

129

130

Parameters:

131

- data: Data to convert

132

- indent: YAML indentation

133

- default_flow_style: Use flow style

134

135

Returns:

136

str: YAML representation

137

"""

138

139

def to_json(data, indent=None, sort_keys=False):

140

"""

141

Convert data to JSON format.

142

143

Parameters:

144

- data: Data to convert

145

- indent: JSON indentation

146

- sort_keys: Sort dictionary keys

147

148

Returns:

149

str: JSON representation

150

"""

151

152

def regex_replace(value, pattern, replacement, ignorecase=False, multiline=False):

153

"""

154

Replace text using regular expressions.

155

156

Parameters:

157

- value: Input string

158

- pattern: Regex pattern

159

- replacement: Replacement string

160

- ignorecase: Case insensitive matching

161

- multiline: Multiline mode

162

163

Returns:

164

str: String with replacements

165

"""

166

167

def regex_search(value, pattern, groups=None, ignorecase=False, multiline=False):

168

"""

169

Search for regex pattern in string.

170

171

Parameters:

172

- value: Input string

173

- pattern: Regex pattern

174

- groups: Groups to extract

175

- ignorecase: Case insensitive matching

176

- multiline: Multiline mode

177

178

Returns:

179

str|list: Match result or groups

180

"""

181

182

def b64encode(data):

183

"""

184

Base64 encode data.

185

186

Parameters:

187

- data: Data to encode

188

189

Returns:

190

str: Base64 encoded string

191

"""

192

193

def b64decode(data):

194

"""

195

Base64 decode data.

196

197

Parameters:

198

- data: Data to decode

199

200

Returns:

201

str: Decoded string

202

"""

203

204

# List and dictionary filters

205

def map(attribute, iterable):

206

"""

207

Extract attribute from list of objects.

208

209

Parameters:

210

- attribute: Attribute name to extract

211

- iterable: List of objects

212

213

Returns:

214

list: Extracted values

215

"""

216

217

def select(test, iterable):

218

"""

219

Filter list items by test condition.

220

221

Parameters:

222

- test: Test condition

223

- iterable: List to filter

224

225

Returns:

226

list: Filtered items

227

"""

228

229

def reject(test, iterable):

230

"""

231

Reject list items by test condition.

232

233

Parameters:

234

- test: Test condition

235

- iterable: List to filter

236

237

Returns:

238

list: Remaining items

239

"""

240

241

def combine(*dicts, recursive=False, list_merge='replace'):

242

"""

243

Combine multiple dictionaries.

244

245

Parameters:

246

- dicts: Dictionaries to combine

247

- recursive: Recursive merging

248

- list_merge: List merge strategy

249

250

Returns:

251

dict: Combined dictionary

252

"""

253

254

# Network and system filters

255

def ipaddr(value, query=''):

256

"""

257

IP address manipulation and validation.

258

259

Parameters:

260

- value: IP address or network

261

- query: Query type (network, host, etc.)

262

263

Returns:

264

str: Processed IP address

265

"""

266

267

def hash(data, hashtype='sha1'):

268

"""

269

Generate hash of data.

270

271

Parameters:

272

- data: Data to hash

273

- hashtype: Hash algorithm

274

275

Returns:

276

str: Hash digest

277

"""

278

279

def password_hash(password, hashtype='sha512', salt=None):

280

"""

281

Generate password hash.

282

283

Parameters:

284

- password: Password to hash

285

- hashtype: Hash algorithm

286

- salt: Salt value

287

288

Returns:

289

str: Password hash

290

"""

291

```

292

293

### Template Tests

294

295

Ansible-specific Jinja2 tests for conditional evaluation and data validation in templates and playbooks.

296

297

```python { .api }

298

# Type and value tests

299

def is_string(value):

300

"""Test if value is string"""

301

302

def is_number(value):

303

"""Test if value is number"""

304

305

def is_boolean(value):

306

"""Test if value is boolean"""

307

308

def is_list(value):

309

"""Test if value is list"""

310

311

def is_dict(value):

312

"""Test if value is dictionary"""

313

314

# Network tests

315

def is_ip(value):

316

"""

317

Test if value is valid IP address.

318

319

Parameters:

320

- value: Value to test

321

322

Returns:

323

bool: True if valid IP address

324

"""

325

326

def is_ipv4(value):

327

"""Test if value is IPv4 address"""

328

329

def is_ipv6(value):

330

"""Test if value is IPv6 address"""

331

332

def is_mac(value):

333

"""Test if value is MAC address"""

334

335

# Version tests

336

def version_compare(value, version, operator='==', strict=False):

337

"""

338

Compare version strings.

339

340

Parameters:

341

- value: Version to compare

342

- version: Comparison version

343

- operator: Comparison operator

344

- strict: Strict version parsing

345

346

Returns:

347

bool: Comparison result

348

"""

349

350

def version(value, version, operator='=='):

351

"""Alias for version_compare"""

352

353

# File and path tests

354

def is_file(path):

355

"""Test if path is regular file"""

356

357

def is_dir(path):

358

"""Test if path is directory"""

359

360

def is_link(path):

361

"""Test if path is symbolic link"""

362

363

def exists(path):

364

"""Test if path exists"""

365

366

# Content tests

367

def match(value, pattern, ignorecase=False, multiline=False):

368

"""Test if value matches regex pattern"""

369

370

def search(value, pattern, ignorecase=False, multiline=False):

371

"""Test if pattern found in value"""

372

373

def regex(value, pattern, ignorecase=False, multiline=False):

374

"""Test regex pattern against value"""

375

```

376

377

### Template Functions and Globals

378

379

Global functions and variables available in all template contexts providing access to Ansible-specific functionality.

380

381

```python { .api }

382

# Template functions

383

def range(start, stop=None, step=1):

384

"""Generate range of numbers"""

385

386

def lipsum(n=5, html=True, min=20, max=100):

387

"""Generate lorem ipsum text"""

388

389

def dict(items):

390

"""Create dictionary from items"""

391

392

def list(items):

393

"""Convert items to list"""

394

395

# Ansible-specific globals

396

hostvars: dict # All host variables

397

group_names: list # Groups current host belongs to

398

groups: dict # All groups and their hosts

399

inventory_hostname: str # Current hostname

400

ansible_hostname: str # Discovered hostname

401

ansible_facts: dict # Gathered facts

402

play_hosts: list # Hosts in current play

403

ansible_play_hosts: list # All play hosts

404

ansible_play_batch: list # Current batch of hosts

405

```

406

407

## Template Usage

408

409

### Variable Interpolation

410

411

```yaml

412

# Basic variable substitution

413

- name: "Install {{ package_name }}"

414

package:

415

name: "{{ package_name }}"

416

state: present

417

418

# Complex expressions

419

- name: "Setup {{ inventory_hostname }}"

420

template:

421

src: config.j2

422

dest: "/etc/{{ service_name }}/{{ inventory_hostname }}.conf"

423

vars:

424

config_file: "{{ service_name }}-{{ ansible_hostname }}.conf"

425

```

426

427

### Conditional Templates

428

429

```yaml

430

# Conditional content

431

- name: Configure service

432

template:

433

src: service.conf.j2

434

dest: /etc/service.conf

435

notify: restart service

436

437

# Template with conditionals

438

# service.conf.j2:

439

# {% if ssl_enabled %}

440

# ssl_certificate {{ ssl_cert_path }}

441

# ssl_certificate_key {{ ssl_key_path }}

442

# {% endif %}

443

#

444

# {% for port in service_ports %}

445

# listen {{ port }}

446

# {% endfor %}

447

```

448

449

### Filters in Templates

450

451

```yaml

452

# Using filters

453

- name: Display formatted data

454

debug:

455

msg: |

456

YAML: {{ my_dict | to_yaml }}

457

JSON: {{ my_dict | to_json }}

458

Base64: {{ secret_value | b64encode }}

459

460

# List processing

461

- name: Process user list

462

debug:

463

msg: "User {{ item }} has home {{ item | regex_replace('^(.+)$', '/home/\\1') }}"

464

loop: "{{ users | map('extract', hostvars, 'username') | list }}"

465

```

466

467

### Tests in Conditionals

468

469

```yaml

470

# Using tests

471

- name: Check conditions

472

debug:

473

msg: "Processing {{ item }}"

474

loop: "{{ server_list }}"

475

when:

476

- item is string

477

- item is match('^web.*')

478

- inventory_hostname is version('2.0', '>=')

479

480

# Network tests

481

- name: Configure network

482

template:

483

src: network.j2

484

dest: /etc/network/interfaces

485

when: ansible_default_ipv4.address is ip

486

```

487

488

### Complex Template Examples

489

490

```jinja2

491

{# config.j2 template #}

492

# Generated by Ansible on {{ ansible_date_time.date }}

493

# Host: {{ inventory_hostname }}

494

495

{% set server_config = {

496

'web': {'port': 80, 'workers': 4},

497

'api': {'port': 8080, 'workers': 2},

498

'db': {'port': 5432, 'workers': 1}

499

} %}

500

501

{% for service_type in groups %}

502

{% if service_type in server_config %}

503

[{{ service_type }}]

504

{% for host in groups[service_type] %}

505

{{ host }} = {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ server_config[service_type]['port'] }}

506

{% endfor %}

507

workers = {{ server_config[service_type]['workers'] }}

508

509

{% endif %}

510

{% endfor %}

511

512

# SSL Configuration

513

{% if ssl_enabled | default(false) %}

514

ssl_cert = {{ ssl_cert_path | default('/etc/ssl/certs/server.crt') }}

515

ssl_key = {{ ssl_key_path | default('/etc/ssl/private/server.key') }}

516

{% endif %}

517

518

# Environment-specific settings

519

{% if environment == 'production' %}

520

debug = false

521

log_level = warn

522

{% else %}

523

debug = true

524

log_level = debug

525

{% endif %}

526

```

527

528

## Template Security

529

530

### Trusted Templates

531

532

```python

533

# Template trust checking

534

from ansible.template import Templar

535

from ansible.errors import TemplateTrustCheckFailedError

536

537

templar = Templar(loader=loader, variables=variables)

538

539

try:

540

# This will check template trust

541

result = templar.template(untrusted_template)

542

except TemplateTrustCheckFailedError:

543

print("Template from untrusted source rejected")

544

```

545

546

### Safe Template Processing

547

548

```python

549

# Safe templating with error handling

550

from ansible.template import Templar

551

from ansible.errors import AnsibleTemplateError

552

553

templar = Templar(loader=loader, variables=variables)

554

555

try:

556

result = templar.template("{{ undefined_var }}", fail_on_undefined=True)

557

except AnsibleTemplateError as e:

558

print(f"Template error: {e}")

559

```

560

561

## Usage Examples

562

563

### Basic Templating

564

565

```python

566

from ansible.template import Templar

567

from ansible.parsing.dataloader import DataLoader

568

569

# Initialize components

570

loader = DataLoader()

571

variables = {

572

'service_name': 'nginx',

573

'port': 80,

574

'ssl_enabled': True

575

}

576

577

# Create templater

578

templar = Templar(loader=loader, variables=variables)

579

580

# Template strings

581

result = templar.template("Service {{ service_name }} on port {{ port }}")

582

print(result) # "Service nginx on port 80"

583

584

# Template with conditionals

585

template = "{% if ssl_enabled %}HTTPS{% else %}HTTP{% endif %} enabled"

586

result = templar.template(template)

587

print(result) # "HTTPS enabled"

588

```

589

590

### Advanced Templating

591

592

```python

593

# Template complex data structures

594

data = {

595

'config': {

596

'servers': [

597

{'name': 'web1', 'ip': '192.168.1.10'},

598

{'name': 'web2', 'ip': '192.168.1.11'}

599

]

600

},

601

'template_var': '{{ config.servers | map(attribute="name") | join(",") }}'

602

}

603

604

result = templar.template(data)

605

print(result['template_var']) # "web1,web2"

606

607

# Check if data needs templating

608

needs_template = templar.is_template("{{ service_name }}")

609

print(needs_template) # True

610

611

no_template = templar.is_template("static_string")

612

print(no_template) # False

613

```