OutputValues icon
WorkingDirectory icon
Script icon
AnsibleCLI icon

Render Kestra-Templated Ansible Playbooks Before Execution

Two-stage Ansible pattern with Kestra: download playbooks containing Kestra expressions, render them with runtime outputs, then run the result.

Categories
Infrastructure

Sometimes the playbook itself needs Kestra data: an IP produced by a provisioning task, a message from an upstream API call, a secret-derived value. This blueprint demonstrates the two-stage pattern that makes it work. Stage one downloads (or, here, generates) inventories and playbooks that contain unrendered Kestra expressions, protected by {% raw %} markers. Stage two loops over every downloaded file, renders the expressions with live execution context using render(read(...)), writes the results back to the same relative paths, and runs the rendered playbook with the Ansible CLI.

How it works

  1. The dummy_values task (io.kestra.plugin.core.output.OutputValues) produces the runtime data to inject; in real use this is any upstream task output.
  2. The setup task (io.kestra.plugin.core.flow.WorkingDirectory) simulates a Git checkout: shell scripts create ansible_inventory/inventory.ini and ansible_playbooks/playbook.yml, where the playbook references {{ outputs.dummy_values.values.message }} wrapped in {% raw %} so it survives the first pass unrendered. Everything is exported via outputFiles: ansible_*/**.
  3. The render_and_run task opens a fresh WorkingDirectory. Its render_all_files script (io.kestra.plugin.scripts.shell.Script) iterates outputs.setup.outputFiles with a Pebble {% for %} loop, recreates each directory, and writes {{ render(read(entry.value)) }}: the file content with all Kestra expressions now evaluated.
  4. The ansible_run_playbook task (io.kestra.plugin.ansible.cli.AnsibleCLI) runs the rendered playbook inside cytopia/ansible:latest-tools, printing the injected message.

What you get

  • A generic render-then-run pipeline for any templated configuration files, not just Ansible.
  • The {% raw %} escape pattern that lets you commit Kestra expressions inside Git-managed files.
  • A file-loop technique (outputs.<task>.outputFiles + render(read(...))) reusable for Terraform vars, Helm values, or config bundles.
  • Containerized Ansible execution with no worker-side installation.

Who it's for

  • Teams storing Ansible content in Git that must be parameterized with execution data.
  • Platform engineers building reusable automation where playbooks are written once and templated per run.
  • Anyone migrating from Jinja2-only templating toward orchestrator-driven rendering.

Why orchestrate this with Kestra

Ansible's own templating cannot see your orchestrator's state: task outputs, KV values, secrets, execution metadata. Kestra's Pebble engine can, and this pattern applies it to whole directories of files at runtime. Combined with WorkingDirectory for shared filesystems and outputFiles for passing artifacts between isolated stages, you get late-bound configuration without maintaining a custom rendering script per repository.

Prerequisites

  • Docker available to the Kestra worker for the Ansible container image.
  • For real use, a Git repository of templated inventories and playbooks (swap the setup scripts for io.kestra.plugin.git.Clone).

Secrets

  • None required for the demo. Add Git credentials (for example GITHUB_ACCESS_TOKEN) when cloning private repositories, and reference secrets inside templated files with {{ secret('NAME') }}.

Quick start

  1. Execute the flow as-is: it runs against localhost inside the container and prints the templated message.
  2. Replace the setup shell scripts with a Clone of your templated repository.
  3. Wrap any Kestra expressions in your committed files with {% raw %}...{% endraw %}.
  4. Point the final ansible-playbook command at your real inventory and playbook paths.

How to extend

  • Render Terraform .tfvars, Helm values, or Kubernetes manifests the same way.
  • Add a validation step (ansible-lint, yamllint) between rendering and execution.
  • Pass rendered files onward with outputFiles for multi-stage pipelines.
  • Fan out the render-and-run stage per environment with io.kestra.plugin.core.flow.ForEach.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.