how to use nest loop in ansible playbook with json register - json

I get an complex json from an rb ,and I register like this
- name: get the json
command: /abc/get_info.rb
register: JsonInfo
and the json is like this
{"a-b-c.abc.com":[["000000001","a"],["000000002","a"],["000000003","c"]],"c-d-e.abc.com":[["000000010","c"],["000000012","b"]],"c-d-m.abc.com":[["000000022","c"],["000000033","b"],["000000044","c"]]}
but what I can do is just output the json like this:
- debug: msg="{{JsonInfo}}"
and loop like this
- debug: msg="{{item.key}} and the host is{{inventory_hostname}} and value is{{item.value}}"
with_dict: "{{JsonInfo.stdout}}"
when: item.key==inventory_hostname
by the way ,the a-b-c.abc.com,c-d-e.abc.com,c-d-m.abc.com is hostname of server
but what I really want to do is to run a loop on the json first,and get the result of
"a-b-c.abc.com":[["000000001","a"],["000000002","a"],["000000003","c"]]
"c-d-e.abc.com":[["000000010","c"],["000000012","b"]]
"c-d-m.abc.com":[["000000022","c"],["000000033","b"],["000000044","c"]]
and when I got all these above ,I run another loop for each of the value of a-b-c.abc.com,c-d-e.abc.com,c-d-m.abc.com and then according to the "a","c" ,run different commmand on the a-b-c.abc.com or c-d-e.abc.com
How Can I loop those json ?

That's not possible with the available Ansible loops. You can archive this by creating your own lookup plugin.

Related

SaltStack - Unable to check if file exists on minion

I am trying to check if a particular file with some extension exists on a centos host using salt stack.
create:
cmd.run:
- name: touch /tmp/filex
{% set output = salt['cmd.run']("ls /tmp/filex") %}
output:
cmd.run:
- name: "echo {{ output }}"
Even if the file exists, I am getting the error as below:
ls: cannot access /tmp/filex: No such file or directory
I see that you already accepted an answer for this that talks about jinja being rendered first. which is true. but i wanted to add to that you don't have to use cmd.run to check the file. there is a state that is built in to salt for this.
file.exists will check for a file or directories existence in a stateful way.
One of the things about salt is you should be looking for ways to get away from cmd.run when you can.
create:
file.managed:
- name: /tmp/filex
check_file:
file.exists:
- name: /tmp/filex
- require:
- file: create
In SaltStack Jinja is evaluated before YAML. The file creation will (cmd.run) be executed after Jinja. So your Jinja variable is empty because the file isn’t created, yet.
See https://docs.saltproject.io/en/latest/topics/jinja/index.html
Jinja statements such as your set output line are evaluated when the sls file is rendered, before any of the states in it are executed. It's not seeing the file because the file hasn't been created yet.
Moving the check to the state definition should fix it:
output:
cmd.run:
- name: ls /tmp/filex
# if your underlying intent is to ensure something runs only
# once the file exists, you can enforce that here
- require:
- cmd: create

How to Parse the url data from ansible JSON output and extract the data

I am working on a AWX ansible query, I got the output from the query and the data which I need is in a URL format which is a
'dn': "uni/infra/funcprof/accportgrp-xxxxxxxxxx/rtaccBaseGrp-[uni/infra/accportprof-xxxxxxxxxxxx/hports-xxxxxx-typ-range]"
I want to extract the 'xxxx' data from the above string in ansible. I was able to do in python by splitting it with / and getting the details. Wondering how can I do that in Ansible?
with the string in a variable named mystring:
you could do something like this:
{{ mystring.split("/")[1] | lower }}

Ansible Inventory Multi-line Inventory arrays?

I'm trying to write an array in an Ansible inventory file (i.e. hosts.local) but the array seems to have to be all on one line and can't be split upon multiple:
[all:vars]
someArr=["This",
"doesn't",
"work"]
Is there any way of doing this in Ansible inventory files?
Is there any way of doing this in Ansible inventory files?
INI file doesn't support multiline. You may find some programming specific workaround but in this scenario, best is to use YAML for inventory. A sample inventory snippet:
all:
vars:
multiline: [
"This",
"is",
"multiline"
]
# Or use below style that results the same
#multiline:
# - "This"
# - "is"
# - "multiline"
hosts:
somehost:
Have a look at inventory basics for more details.

Ansible lookup a single line in a json file

I need to read an ip line from a dynamic generated json file and add it to a configuration file on the server.
At Ansible home page i found two modules which would help:
- lookup module
- fileinline module
The lookup examples however show looking up for the whole contents of a file using this phrase "{{ lookup('file', '/etc/foo.txt') }}"
How could i filter the result into reading a single line?
Does anybody know a good way to achieve this ?
You probably do want a special key from a JSON dict I guess? If it's just a random line which can not be accessed inside the JSON struct it will be hard. You would need to grep out the line in a separate task.
But let's assume you want a special value from a dict, then you can convert the JSON to an object with the from_json filter:
{{ lookup('file', '/etc/foo.txt') | from_json }}
Now if you want the value of bar from the contained data structure, something like this should work:
{{ (lookup('file', '/etc/foo.txt') | from_json).get('bar') }}

Complex stdout check in Ansible

I run a job on a remote server with Ansible. The stdout generates some output where sometimes errors show up. The error text is in the form of
#ERROR FMM0129E The following error was returned by the vSphere(TM) API: 'Cannot complete login due to an incorrect user name or password.'.
The thing is that some of these errors can safely be ignored and only these that are not in my false positive list should raise a fail.
My question is, can this be done in a pure Ansible way?
The only thing that comes to mind is the simple failed_when check which, in this case, falls short. I am thinking that these "complex" output checking should be done out of Ansible, invoking a python / shell / etc. script to help.
If you are remotely executing a shell command anyway then there's no reason why you couldn't wrap that in a shell script that returns a non 0 status code for the things you care about and then simply execute that via the script module.
example.sh
#!/bin/bash
randomInt=$[ 1 + $[ RANDOM % 10 ]]
echo $randomInt
if [ $randomInt == 1 ]; then
exit 1
else
exit 0
fi
And then use it like this in your playbook:
- name: run example.sh
script: example.sh
Ansible will automatically see any non 0 return codes as the task failing.
Instead of failed_when you could use ignore_errors: true which would get you into the position of passing the failing task and forwarding the stdout to another task. But I would not recommend this, since in my opinion a task should never ever report a failed state by intend. But if you feel this is an option for you, there even would be a way to reset the error counter so the Ansible stats at the end are correct.
- some: task
register: some_result
ignore_errors: true
- name: Reset errors after intentional fail
meta: clear_host_errors
when: some_result | failed
- another: task
check: "{{ some_result.stdout }}
when: some_result | failed
The last task then would check your stdout in a custom script or whatever you have and should report a failed state itself (return code != 0).
As far as I know the clear_host_errors feature is yet undocumented and the commit is about a month old, so I guess it will only be available in Ansible 2.0.1.
Another idea would be to wrap your task inside the script which checks the output or pipe it to that script. That obviously will only work if you run a shell command and not with any other ansible modules.
Other than those two options I don't think there is anything else available.