Not able to read/print the csv file data - ansible

Running the below playbook and trying to print the value of that task. It fails with below error.
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'name'\n\nThe error appears to be in '/Users/srikanth.venugopalan/ansible/roles/rmi_staging/tasks/main.yml': line 9, column 4, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n register: topics\n - debug:\n ^ here\n"
The code is
- name: Login to cluster
shell: /home/srikanth/ls.sh
- name: Read the CSV file
read_csv:
path: /home/srikanth/template1.csv
register: topics
- debug:
msg: 'Name {{ topics.list.name }}'
I have tried below as well, but no luck
- name: Login to cluster
shell: /home/srikanth/ls.sh
- name: Read the CSV file
read_csv:
path: /home/srikanth/template1.csv
register: topics
- debug:
msg: 'Name {{ topics.list.1.name }}'
CSV file format as per below
name,replica,partition
test-topic,3,3
I have gone through the link https://stackoverflow.com/questions/53799730/how-to-read-csv-file-data-in-ansible-playbook-using-with-lines, but one thing dont know in the debug how it come user.username.
Please guide me.
Actual goal is to take name alone from the debug output.

Your .1.name attempt didn't work because topics.list is, like all list data structures in python, 0-indexed
You can observe the behavior for yourself, as the comments asked you to:
tasks:
- copy:
dest: ./template1.csv
content: |
name,replica,partition
test-topic,3,3
- read_csv:
path: ./template1.csv
register: topics
- debug:
var: topics
- debug:
msg: 'Name {{ topics.list.0.name }}'
emits
ok: [localhost] => {
"topics": {
"changed": false,
"dict": {},
"failed": false,
"list": [
{
"name": "test-topic",
"partition": "3",
"replica": "3"
}
]
}
}
ok: [localhost] => {
"msg": "Name test-topic"
}

Related

Nested Jinja2 dictionary valuable is disappearing

I'm using ansible and jinja2, and need to access a variable.
I have a data structure structure, and executing in a playbook:
- name: debug_1
debug:
msg: "{{ vars['structure'] }}"
Yields these results:
ok: [debug-test] => {
"msg": {
"Covo": [
{
"enabled": true
}
]
}
}
Furthermore, running
- name: debug_1
debug:
msg: "{{ vars['structure']['covo'] }}"
gives the expected result:
ok: [debug-test] => {
"msg": [
{
"enabled": true
}
]
}
However, attempting to access the enabled variable with:
- name: debug_1
debug:
msg: "{{ vars['structure']['covo']['enabled'] }}"
Will throw an error:
fatal: [debug-test]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'enabled'\n\nThe error appears to be in '/task/main.yml': line 16, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n when: vars['structure']['covo']['enabled']|default(False) == True\n - name: debug_1\n ^ here\n"}
How can I access this variable?
covo is an array, so you have to declare the index:
- name: debug_1
debug:
msg: "{{ vars['structure']['covo'][0]['enabled'] }}"

Pass a variable(value) from the JSON body to the URL in ansible

I would like to pass a particular value as an input to the URI from the JSON body. But i am getting an error as below. Please find below code and expectation is to put the netid = 12345 in the
place of netid in the URL as {{ api_uri }}/networks/12345/appliance
Error:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'rules'\n\nThe error appears to be in '/***/firewallrules.yml': line 35, column 10, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Firewall rule update\n ^ here\n"}
URI Task:
- name: Firewall rule update
uri:
method: PUT
url: "{{ api_uri }}/networks/{{ netid(from firewall.json) }}/appliance"
body: "{{ lookup('file', 'firewall.json') | from_json }}"
body_format: json
register: firewallresults
ignore_errors: yes
Firewall(JSON input to API):
{
"rules": [
{
"comment": "Test1.",
"destCidr": "x.x.x.x/24",
"srcCidr": "y.y.y.y/24",
"netid":"12345"
},
{
"comment": "Test2",
"destCidr": "a.a.a.a/24",
"srcCidr": "b.b.b.b/24",
"netid":"12345"
} ]
}
The error message reports AnsibleUnsafeText object' has no attribute 'rules' ... The error appears to be in '/***/firewallrules.yml' but I cant find anything about .rules or firewallrules.yml in your description.
In respect to the minimal information
I would like to pass a particular value as an input to the URI from the JSON body. ... need a solution to get the netid from my input JSON ... which will be used in the API URI
it seems that your URI task and URL parameter are misconstructed. I've created a debugging task to get a better understanding of the use case.
---
- hosts: localhost
become: false
gather_facts: false
vars:
BODY: "{{ lookup('file', 'firewall.json') | from_json }}"
tasks:
- name: Show BODY
debug:
msg: "{{ BODY }}"
- name: Show first 'netid' for URL
debug:
var: BODY.rules[0].netid
- name: Show all 'netid's for URL
debug:
msg: "{{ item.netid }}"
loop: "{{ BODY.rules }}"
Resulting into an output of
TASK [Show first 'netid' for URL] ***
ok: [localhost] =>
BODY.rules[0].netid: '12345'
TASK [Show all 'netid's for URL] ***
ok: [localhost] => (item={u'comment': u'Test1.', u'destCidr': u'x.x.x.x/24', u'netid': u'12345', u'srcCidr': u'y.y.y.y/24'}) =>
msg: '12345'
ok: [localhost] => (item={u'comment': u'Test2', u'destCidr': u'a.a.a.a/24', u'netid': u'12345', u'srcCidr': u'b.b.b.b/24'}) =>
msg: '12345'

Difficulty Parsing Ansible Output

[ansible 2.9.6, Ubuntu 20.04]
This seems pretty straightforward, but I keep getting an error message saying:
fatal: [192.168.254.100]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{ipv4addrs.'host[0]'}}"}
Here's my ansible playbook:
---
- hosts: nios
connection: local
vars:
nios_provider:
host: 192.x.x.x
username: xxx
password: xxx
wapi_version: "2.11.2"
tasks:
- name: Find client app server records
set_fact:
recs: "{{ lookup('nios', 'record:host', filter={'name~':'sdk' }, provider=nios_provider) }}"
- name: check return
debug:
msg: "{{ recs }}"
- name: get host name
debug:
var: ipv4addrs.'host[0]'
And here's the output:
TASK [check return] **************************************************************************************************************************************************************
ok: [192.x.x.x] => {
"msg": [
{
"_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5lYWdsZWFjY2Vzcy5zZGstZDAwMQ:sdk-d001.somename.com/default",
"ipv4addrs": [
{
"_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuY29tLmVhZ2xlYWNjZXNzLnNkay1kMDAxLjEwLjcwLjAuMS4:10.70.0.1/sdk-d001.somename.com/default",
"configure_for_dhcp": false,
"host": "sdk-d001.somename.com",
"ipv4addr": "10.70.0.1"
}
],
"name": "sdk-d001.somename.com",
"view": "default"
},
{
"_ref": "record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5lYWdsZWFjY2Vzcy5zZGstZDAwMg:sdk-d002.somename.com/default",
"ipv4addrs": [
{
"_ref": "record:host_ipv4addr/ZG5zLmhvc3RfYWRkcmVzcyQuX2RlZmF1bHQuY29tLmVhZ2xlYWNjZXNzLnNkay1kMDAyLjEwLjcwLjAuMi4:10.70.0.2/sdk-d002.somename.com/default",
"configure_for_dhcp": false,
"host": "sdk-d002.somename.com",
"ipv4addr": "10.70.0.2"
}
],
"name": "sdk-d002.somename.com",
"view": "default"
}
]
}
TASK [get host name] ***************************************************************************************************************************************************************
fatal: [192.168.254.100]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{ipv4addrs.'host[0]'}}"}
My objective is to find all of the host names beginning with (for example) "sdk". There may be 1 or several. And then I want to get the full name and ip address captured as variables. I have tried lots of different options: rec.ipv4addrs[0].host, ipv4addrs[0].host, rec.ipv4addrs[0].'host', rec.ipv4addrs[0].['host'] . . . but I cannot find the proper syntax.
This appears to be an array of dict blocks with an ipv4addrs array within it. So the first thing I tried was "ipv4addrs[0]['host']" with no joy.
Thanks in advance for the help.
You're trying to make use of a variable called ipv4addrs, but you
haven't defined any variables with that name. From the previous
debug task you apparently have a variable named recs, which is a
list of dictionaries each of which contains an ipv4addrs attribute.
If you wanted to look up the host attribute for each record in
recs, you could write something like this:
- name: get host name
debug:
var: item.ipv4addrs[0].host
loop: "{{ recs }}"
If you wanted the ipv4addrs.host value from the first record, you
could write:
- name: get host name
debug:
var: recs[0].ipv4addrs[0].host
The error you're seeing stems from the fact that the expression
ipv4addrs.'host[0]' doesn't make any sense; that's not a syntax that
Ansible supports. You can't use a string with dot-notation like that.

How to solve AnsibleUndefinedVariable in the serial mode

I am setting up a new play in my Ansible playbook that does some operations on a group of machines.
These operations require to play in serial mode 1 by 1.
My job is working well for the 1st machine but for the others one it seems that the variables are not valued.
- name: "My play"
hosts: my_hosts_group
tags: [test]
serial: 1
become: yes
become_user: root
tasks:
- shell: echo {{ MYVARIBLE.MYSOFTWARE.souche_path }} > /home/USER/test.txt
register: result
- debug: var=result
Here is my datamodel :
MYVARIBLE:
MYSOFTWARE:
souche_path: "/mybinpath/mybin"
For the 1st machine it's working well and I am getting this message :
ok: [host1] => {
"changed": false,
"result": {
"changed": true,
"cmd": "echo my_variable_value > /home/USER/test.txt",
"delta": "0:00:00.005541",
"end": "2019-04-26 16:27:09.415017",
"failed": false,
"rc": 0,
"start": "2019-04-26 16:27:09.409476",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
But fort he others one I got this one :
fatal: [host2]: FAILED! => {}
MSG:
The task includes an option with an undefined variable. The error was: 'MYVARIABLE' is undefined
The error appears to have been in '/my playbook/install.yml': line 85, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- shell: echo {{ MYVARIBLE }} > /home/USER/test.txt
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
exception type: <class 'ansible.errors.AnsibleUndefinedVariable'>
exception: 'MYVARIBLE' is undefined
I have played it in parallel mode and it's working well. So I am sure that the problem is the variable are only valued for the 1st loop.
Am I missing something ?

Ansible register result of multiple commands

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 ?
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
Posting because I can't comment yet
Relating to gameweld's answer, since Ansible 2.5 there's another way to accessing the iteration index.
From the docs:
Tracking progress through a loop with index_var
New in version 2.5.
To keep track of where you are in a loop, use the index_var directive
with loop_control. This directive specifies a variable name to contain
the current loop index:
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
This also allows you to gather results from an array and act later to the same array, taking into account the previous results
- name: Ensure directories exist
file:
path: "{{ item }}"
state: directory
loop:
- "mouse"
- "lizard"
register: reg
- name: Do something only if directory is new
debug:
msg: "New dir created with name '{{ item }}'"
loop:
- "mouse"
- "lizard"
loop_control:
index_var: index
when: reg.results[index].changed
Please note that the "mouse lizard" array should be exactly the same
If what you need is to register the output of two commands separately, use different variable names.
---
- hosts: Linux
serial: 1
tasks:
- name: Check first
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result0
changed_when: false
- debug: msg="{{result0.stdout}}"
- name: Check second
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result1
changed_when: false
- debug: msg="{{result1.stdout}}"

Resources