Skip to main content

Differences with Ansible

Spage is compatible with Ansible's syntax, but there are some differences on both a syntax level but also runtime level.

New features

These features are available in Spage and have no equivalent in Ansible.

before/after

These task before/after keywords are available in Spage and are used to enforce a certain order of execution when running in parallel execution mode.

playbook.yaml
- name: task 1
command: echo "task 1"
after: task 3

- name: task 2
command: echo "task 2"
before: task 1

- name: task 3
command: echo "task 3"
Output
$ SPAGE_EXECUTION_MODE=parallel spage run /tmp/spage_test.yaml

TASK [task 2] (localhost) ****************************************************
changed: [localhost] =>
cmd: "echo \"task 2\""
stdout: "task 2\n"
stderr: ""


TASK [task 3] (localhost) ****************************************************
changed: [localhost] =>
cmd: "echo \"task 3\""
stdout: "task 3\n"
stderr: ""


TASK [task 1] (localhost) ****************************************************
changed: [localhost] =>
cmd: "echo \"task 1\""
stdout: "task 1\n"
stderr: ""


PLAY RECAP ****************************************************
localhost : ok=0 changed=3 failed=0 skipped=0 ignored=0

run_as

The run_as keyword is available in Spage and is used to run a task as a different user. This is equivalent to using both become and become_user together.

playbook.yaml
- name: Tell me the time
shell: echo "The time is $(date)"
run_as: root

Spage translates this to become: true and become_user: root.

Differences in behaviour

Not specifying hosts will assume localhost

If you're targeting a playbook without specifying the hosts attribute on the play, Spage will assume localhost as the target.

playbook.yaml
- name: Tell me the time
shell: echo "The time is $(date)"
register: time
Output
$ spage run playbook.yaml
TASK [Tell me the time] (localhost) ****************************************************
changed: [localhost] =>
cmd: "echo \"The time is $(date)\""

Target localhost will use connection: local by default

If you're targeting localhost in a playbook, Spage will use connection: local by default.

inventory.yaml
all:
hosts:
localhost:
Output
$ spage run playbook.yaml
TASK [Tell me the time] (localhost) ****************************************************
changed: [localhost] =>
cmd: "echo \"The time is $(date)\""

If you don't want to, you can specify spage_connection: local in your inventory:

inventory.yaml
all:
hosts:
localhost:
spage_connection: ssh

Multiple plays in a single file are not supported

Spage does not support multiple plays in a single file.

playbook.yaml
- hosts: all
tasks:
- name: Tell me the time
shell: echo "The time is $(date)"
register: time

# Only one play is allowed in a file
- hosts: all
tasks:
- name: Tell me the time
shell: echo "The time is $(date)"
register: time

Detect variable usage and require input

Spage will detect variable usage and require input for those variables.

playbook.yaml
- name: Tell me the time
shell: echo "The time is {{ time }}"
Running a playbook
$ spage generate playbook.yaml
$ cat generated_tasks.go
...
var GeneratedGraph = pkg.Graph{
RequiredInputs: []string{
"time",
},
...
$ go run generated_tasks.go
Execution failed: failed to check inventory for required inputs: required inputs [time] not found in host contexts
Error: failed to check inventory for required inputs: required inputs [time] not found in host contexts
2025-08-28T21:30:31.448+0200 ERROR Failed to run playbook {"error": "failed to check inventory for required inputs: required inputs [time] not found in host contexts"}
exit status 1