Ansible: How to handle a list from command line input variable (--extra-vars)

Written by - 0 comments

Published on - Listed in Ansible


Ansible allows to set new or overwrite pre-defined variables with user-input on the command line, set by the --extra-vars parameter. This is also known as setting runtime variables.

But as I was looking to define a list of apt repositories to disable during the playbook run, this turned out to be a bit of a head-scratcher.

Ansible

Input variable from command line: list/array not working?

Obviously I created a test playbook for this purpose. This very simple playbook just contains one task: To display the values of the variable "disablerepo":

ck@ansible:~$ cat /tmp/test-input-list.yaml
---
- name: ANSIBLE - Testing command line input variable list
  hosts: '{{ target }}'
  tasks:

  - name: Show first disablerepo content
    debug:
      msg: "{{ disablerepo[0] }}"

The task is supposed to show the first element of the list/array of the "disablerepo" variable. This variable is defined by the user on the command line using the --extra-vars input parameter (see run time variables).

But as the playbook ran, the output was not what I was expecting:

ck@ansible:~$ ansible-playbook /tmp/test-input-list.yaml --extra-vars "target=targetserver disablerepo=['unstable*','testing*']"
TASK [Show disablerepo content 1]
******************************************************************************
ok: [targetserver] => {
    "msg": "["
}

The output showed the first character "[" instead of the first list element. This means that the disablerepo variable content was handled as string and not as list.

An attempt without the brackets resulted in a similar result:

ck@ansible:~$ ansible-playbook /tmp/test-input-list.yaml --extra-vars "target=targetserver disablerepo='unstable*,testing*'"
TASK [Show first disablerepo content] ******************************************************************************
ok: [targetserver] => {
    "msg": "u"
}

Command line input needs to be passed as JSON

According to a hint found on StackOverflow, the --extra-vars input should be formatted in JSON to successfully define a list or an array:

ck@ansible:~$ ansible-playbook /tmp/test-input-list.yaml --extra-vars '{"target":"targetserver", "disablerepo": [unstable*,testing*]}'
TASK [Show first disablerepo content] ******************************************************************************
ok: [targetserver] => {
    "msg": "unstable*"
}

The same run time variables were defined, but this time in JSON format. And this turned out to be successful - the first element of the list (unstable*) is showing up! Hurray!

The Ansible documentation for "defining variables at runtime" explains the different input methods:

Values passed in using the key=value syntax are interpreted as strings. Use the JSON format if you need to pass non-string values such as Booleans, integers, floats, lists, and so on.

Looping through the input list

The example above proofs that Ansible interpreted the (JSON formatted) disablerepo variable as list. With this we can now adjust the playbook task to loop through the list. 

Older Ansible users, like me, were used to do this with the with_items loop function:

  - name: Show full disablerepo content
    debug:
      msg: "{{ item }}"
    with_items: "{{ disablerepo }}"

This works and shows each list element in a separate msg output:

ck@ansible:~$ ansible-playbook /tmp/test-input-list.yaml --extra-vars '{"target":"targetserver", "disablerepo": [unstable*,testing*]}'
TASK [Show full disablerepo content] ******************************************************************************
ok: [targetserver] => (item=unstable*) => {
    "msg": "unstable*"
}
ok: [targetserver] => (item=testing*) => {
    "msg": "testing*"
}

But according to the Ansible loop documentation, with_items, although still working, was replaced by loop. So nowadays the loop task looks like this:

  - name: Show full disablerepo content
    debug:
      msg: "{{ item }}"
    loop: "{{ disablerepo }}"

The output is the same as before using with_items:

ck@ansible:~$ ansible-playbook /tmp/test-input-list.yaml --extra-vars '{"target":"targetserver", "disablerepo": [unstable*,testing*]}'
TASK [Show full disablerepo content] ******************************************************************************
ok: [targetserver] => (item=unstable*) => {
    "msg": "unstable*"
}
ok: [targetserver] => (item=testing*) => {
    "msg": "testing*"
}



Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder