Hi Ansible developers,
I’ve been wondering about something. Ansible’s syntax for module arguments is key=value parameters, all on a single line. This then needs to be parsed, and the key=value elements properly separated.
Wouldn’t it be much nicer if the module parameters were also just written in YAML syntax? For example:
- hosts: all
tasks:
- name: blah
yum:
- name: package
- state: installed
And it might even be an idea to pass the playbook through Jinja first, allowing things like:
- name: blah
yum:
{% for pkg in packages %}
- name: “{{ pkg }}”
- state: installed
{% endfor %}
We would not need the “when:” conditional, or the shlex module to split key=value pairs. This would allow taking full advantage of Jinja’s templating features.
Could this be an idea for Ansible 2.0?
Regards,
Anand
Hi Anand
You actually can (and I prefer to) write your playbooks with that kind of plain YAML syntax. e.g.
- hosts: localhost
tasks:
- name: blah
yum:
name:
- mypackage
- otherpackage
state: present
- name: blurh
copy:
src: myfile
dest: /tmp/myfile
mode: 0640
owner: me
It gets more interesting with the shell and command modules
- hosts: localhost
tasks:
- name: run this
shell: mycommand
args:
creates: /tmp/artefact
chdir: /path/to/dir
executable: /bin/bash
Thanks Tom! I didn’t realise it was already possible! So I can also use Jinja functions in a playbook to include/exclude some parameters based on facts?
Same here. Otherwise I've found sometimes I have to decide which one to
use, where to put quotes, etc. I just go 100% YAML and the INI files.
Ansible's syntax with the equal signs is more concise but I don't mind
the extra lines with YAML.
Giovanni
Hi Tom,
I just tried the syntax you suggested.
My very simple playbook is:
- hosts: myhost
tasks:
- name: install packages
yum:
name:
- screen
- tmux
state: installed
However, when I run this, I get an errors:
SUDO-SUCCESS-ziubbkxxzglhrtsmdmekoixffubflanc
Traceback (most recent call last):
File “/tmp/ansible-tmp-1422870182.84-7050423984136/yum”, line 2402, in
main()
File “/tmp/ansible-tmp-1422870182.84-7050423984136/yum”, line 832, in main
disablerepo, disable_gpg_check)
File “/tmp/ansible-tmp-1422870182.84-7050423984136/yum”, line 717, in ensure
items = pkgspec.split(‘,’)
AttributeError: ‘list’ object has no attribute ‘split’
Are you certain that plain YAML syntax works for modules?
- hosts: myhost
tasks:
- name: install packages
yum:
name: "{{ item }}"
state: latest
with_items:
- screen
- tmux
Useful reading:
http://docs.ansible.com/playbooks_loops.html
Giovanni
Hi Giovanni,
Your suggestion works. But I think what I was trying to say is that Ansible’s playbook syntax is mixed. Wouldn’t it be cool if it were pure YAML, with Jinja templating? Then it would allow something like:
- hosts: myhost
tasks:
- name: install packages
yum:
name:
- tmux
- screen
{% if ansible_distribution_major_version == ‘6’ %}
- lsof
{% endif %}
Instead of inventing ansible-specific loops, we could just use the power of Jinja templating.
As an Ansible newbie, I have struggled with understanding where it's
Ansible or Jinja2 doing the parsing. So I can surely related to that. On
the other hand, Ansible tries to be simple and the looping constructs,
IMHO, are easy to work with and have a concise syntax.
I don't have enough experience with Ansible to suggest where it should
go next.
In my so far very limited knowledge of Ansible, I would suggest
encapsulating these things in different roles (e.g. common_debian,
common_centos6, common_centos7). It seems more idiomatic in Ansible,
based on the examples I've seen so far.
Giovanni
Hi Anand
Are you sure your indenting is correct? Here’s an example from one of my role task files, known working with Ansible v1.8.2 (packages trimmed for brevity)
---
- name: Install packages (apt)
apt:
pkg:
- bash-completion
- bind9utils
- vim-nox
- zsh
state: present
when: ansible_os_family == 'Debian'
- name: Install packages (yum)
yum:
name:
- bind-utils
- byobu
- vim-enhanced
- zsh
state: present
when: ansible_os_family == 'RedHat'
Jinja templating doesn’t work in playbooks in that way. Lots of variable constructs are actually parsed with jinja2, so you can do stuff like
- set_fact:
myvar: "{% if something %}this{% else %}that{% endif %}"
As Giovanni mentioned, there are numerous looping constructs for things like task repetition. Playbooks are declarative, so it wouldn’t really be right to build them from a template.
Hello Tom,
I am certain that my syntax and indentation is correct. I have created a test role, called packages, and in the main.yml file of the tasks directory of this role, I have:
As an Ansible newbie, I have struggled with understanding where it's
Ansible or Jinja2 doing the parsing. So I can surely related to that. On
the other hand, Ansible tries to be simple and the looping constructs,
IMHO, are easy to work with and have a concise syntax.
Hi Giovanni,
My thinking is similar. Ansible playbooks are parsed in a strange way. Some
parts of it are plain YAML, whereas other parts are run through the Jinja2
templating engine. This is confusing.
I was reading Salt documentation, and saw that Salt's state files are just
plain YAML, but the entire YAML file is passed through Jinja2, so that any
loops and other variable things are done by Jinja2, and this is
conceptually neater than Ansible's current mix of Jinja2 and Ansible's own
declarative language.
Hi Tom,
Jinja templating doesn’t work in playbooks in that way. Lots of variable
constructs are actually parsed with jinja2, so you can do stuff like
- set_fact:
myvar: "{% if something %}this{% else %}that{% endif %}"
As Giovanni mentioned, there are numerous looping constructs for things
like task repetition. Playbooks are declarative, so it wouldn’t really be
right to build them from a template.
I understand this, and it is exactly what I am trying to discuss here. Why
can't one build a playbook from a template? I think plain YAML is just fine
for declarative statements. Or am I missing a use case?