I was given a task to verify some routing entries for all Linux server and here is how I did it using an Ansible playbook
--- - hosts: Linux serial: 1 tasks: - name: Check first command: /sbin/ip route list xxx.xxx.xxx.xxx/24 register: result changed_when: false - debug: msg="{{result.stdout}}" - name: Check second command: /sbin/ip route list xxx.xxx.xxx.xxx/24 register: result changed_when: false - debug: msg="{{result.stdout}}"
You can see I have to repeat same task for each routing entry and I believe I should be able to avoid this. I tried use with_items
loop but got following error message
One or more undefined variables: 'dict object' has no attribute 'stdout'
is there a way to register variable for each command and loop over them one by one ?
No, this is not possible. Ansible (as of current version 2.4) does not allow to register partial output of the module (or several different parts of it). You can register only full result and extract parts of it in the tasks to follow.
In Ansible, you can run any shell command on your Ansible hosts, the hosts you will be configuring with Ansible. These shell commands may have outputs. By default, the output is ignored. If you want to store the output in a variable and use it later, then you can use the Ansible register module.
Ansible registers are used when you want to capture the output of a task to a variable. You can then use the value of these registers for different scenarios like a conditional statement, logging etc. The variables will contain the value returned by the task. The common return values are documented in Ansible docs.
Starting in Ansible 1.6.1, the results registered with multiple items are stored in result.results
as an array. So you can use result.results[0].stdout
and so on.
Testing playbook:
--- - hosts: localhost gather_facts: no tasks: - command: "echo {{item}}" register: result with_items: [1, 2] - debug: var: result
Result:
$ ansible-playbook -i localhost, test.yml PLAY [localhost] ************************************************************** TASK: [command echo {{item}}] ************************************************* changed: [localhost] => (item=1) changed: [localhost] => (item=2) TASK: [debug ] **************************************************************** ok: [localhost] => { "var": { "result": { "changed": true, "msg": "All items completed", "results": [ { "changed": true, "cmd": [ "echo", "1" ], "delta": "0:00:00.002502", "end": "2015-08-07 16:44:08.901313", "invocation": { "module_args": "echo 1", "module_name": "command" }, "item": 1, "rc": 0, "start": "2015-08-07 16:44:08.898811", "stderr": "", "stdout": "1", "stdout_lines": [ "1" ], "warnings": [] }, { "changed": true, "cmd": [ "echo", "2" ], "delta": "0:00:00.002516", "end": "2015-08-07 16:44:09.038458", "invocation": { "module_args": "echo 2", "module_name": "command" }, "item": 2, "rc": 0, "start": "2015-08-07 16:44:09.035942", "stderr": "", "stdout": "2", "stdout_lines": [ "2" ], "warnings": [] } ] } } } PLAY RECAP ******************************************************************** localhost : ok=2 changed=1 unreachable=0 failed=0
A slightly different situation, which took a while to figure out. If you want to use the results of multiple items, but for changed_when
, then the register variable will not have a var.results! Instead, changed_when
, is evaluated for each item, and you can just directly use the register var.
Simple example, which will result in changed: false:
- action: command echo {{item}} register: out changed_when: "'z' in out.stdout" with_items: - hello - foo - bye
Another example:
- name: Create fulltext index for faster text searches. mysql_db: name={{SO_database}} state=import target=/tmp/fulltext-{{item.tableName}}-{{item.columnName}}.sql with_items: - {tableName: Posts, columnName: Title} - {tableName: Posts, columnName: Body} - {tableName: Posts, columnName: Tags} - {tableName: Comments, columnName: Text} register: createfulltextcmd changed_when: createindexcmd.msg.find('already exists') == -1
Finally, when you do want to loop through results in other contexts, it does seem a bit tricky to programmatically access the index as that is not exposed. I did find this one example that might be promising:
- name: add hosts to known_hosts shell: 'ssh-keyscan -H {{item.host}}>> /home/testuser/known_hosts' with_items: - { index: 0, host: testhost1.test.dom } - { index: 1, host: testhost2.test.dom } - { index: 2, host: 192.168.202.100 } when: ssh_known_hosts.results[{{item.index}}].rc == 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With