Ansible remove \ and brackets from output - debugging

I am trying to print out the kubernetes version and client version with Ansible however the output comes with slashes and how can I remove the brackets for a more cleaner output?
- name: Kubernetes version
run_once: true
changed_when: False
shell: |
kubectl version
delegate_to: localhost
register: kubernetes_version
Output:
name: Output
run_once: true
delegate_to: localhost
debug:
msg: "{{ kubernetes_version.stdout_lines }}"
output:
ok: [localhost] => {
"msg": [
"Client Version: version.Info{Major:\"1\", Minor:\"18\", GitVersion:\"v1.18.4\", GitCommit:\"e0fccafd69541e3750d460ba0f9743\", GitTreeState:\"clean\", BuildDate:\"2020-04-16T11:44:03Z\", GoVersion:\"
go1.13.9\", Compiler:\"gc\", Platform:\"linux/amd64\"}",
"Server Version: version.Info{Major:\"1\", Minor:\"18\", GitVersion:\"v1.18.4\", GitCommit:\"e0fccafd69541e3750d460ba0f9743\", GitTreeState:\"clean\", BuildDate:\"2020-04-16T11:35:47Z\", GoVersion:\"
go1.13.9\", Compiler:\"gc\", Platform:\"linux/amd64\"}"
]
}

I'm replacing my original answer, because I was forgetting that
kubectl version can produce JSON output for us, which makes this
much easier.
By taking the output of kubectl version -o json and passing it
through the from_json filter, we can create an Ansible dictionary
variable from the result.
Then we can use a debug task to print out keys from this variable,
and I think you'll get something closer to what you want.
This playbook:
- hosts: localhost
gather_facts: false
tasks:
- name: run kubectl version
command: kubectl version -o json
register: kv_raw
- set_fact:
kv: "{{ kv_raw.stdout | from_json }}"
- debug:
msg:
- "{{ kv.clientVersion }}"
- "{{ kv.serverVersion }}"
Will produce output like this:
PLAY [localhost] ********************************************************************************************
TASK [run kubectl version] **********************************************************************************
changed: [localhost]
TASK [set_fact] *********************************************************************************************
ok: [localhost]
TASK [debug] ************************************************************************************************
ok: [localhost] => {
"msg": [
{
"buildDate": "2020-11-14T01:08:04Z",
"compiler": "gc",
"gitCommit": "6082e941e6d62f3a0c6ca8ba52927100948b1d0d",
"gitTreeState": "clean",
"gitVersion": "v1.18.2-0-g52c56ce",
"goVersion": "go1.13.15",
"major": "1",
"minor": "18",
"platform": "linux/amd64"
},
{
"buildDate": "2020-10-25T05:12:54Z",
"compiler": "gc",
"gitCommit": "45b9524",
"gitTreeState": "clean",
"gitVersion": "v1.18.3+45b9524",
"goVersion": "go1.13.4",
"major": "1",
"minor": "18+",
"platform": "linux/amd64"
}
]
}
PLAY RECAP **************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

Register command output as 2 separate variables

I have an Ansible playbook that runs a script over my remote machines.
The script finds log files, determine the application the log file came from (so it would know the destination directory), and uploads the files back to the Ansible server (using scp).
Just because it worth mentioning - there are 2 different playbooks, one for Windows servers, using a PowerShell script, and the other is for Linux servers, using a bash script.
I would like to eliminate the scp part for those scripts, and instead using the fetch module in my playbooks. But I'm facing a problem with that - my scripts generates 2 variables for each application on each server:
the log file, full path.
the destination directory in the Ansible server (determined by the servers name and the application name).
My current playbook looks like that (this is the Windows one):
---
- hosts: <WindowsHosts>
gather_facts: no
tasks:
- name: Find and Copy Windows Applications Logs
script: fetchwinFindLogs.ps1 {{ server_partition }} {{days}} {{ansibleSRV_Port}} {{ansibleSRV_IP}}
register: result
- debug:
var: result
# - fetch: src={{ result }} dest={{ result }}
# with_items: "{{ result.stdout_lines }}"
The output:
PLAY [<WinHost>] *********************************************************************************************************************************************************************************************
TASK [Find and Copy Windows Applications Logs] ***************************************************************************************************************************************************************
changed: [<WinHost>]
TASK [debug] *************************************************************************************************************************************************************************************************
ok: [<WinHost>] => {
"result": {
"changed": true,
"failed": false,
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/\r\nC:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/\r\nC:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/\r\nC:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/\r\n",
"stdout_lines": [
"C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/",
"C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/",
"C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/",
"C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
}
PLAY RECAP ***************************************************************************************************************************************************************************************************
<WinHost> : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
How do I use the 2 separate values gotten from the script, so the fetch module would know to direct each log file from each application to the correct directory in my Ansible server?
This includes, of course, looping over every 2 values, so it would direct the correct log to the correct destination directory (since, again, the first value will always be the full path log, and the second would be the destination directory, for each application separately).
There is possibly plenty of ways to achieve this.
Here are two of them:
Using the extended loop variables and a when condition, you could skip every other item with a when and a modulo % and get the item along with the ansible_loop.nextitem.
Here is an example for that:
- hosts: all
gather_facts: no
tasks:
- debug:
msg:
- "src: {{ item  }}"
- "dest: {{ ansible_loop.nextitem }}"
loop: "{{ result.stdout_lines }}"
when: ansible_loop.index % 2 == 1
loop_control:
extended: yes
vars:
result:
stdout_lines:
- "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
- "C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
- "C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
- "C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
This yields the recap:
PLAY [all] ********************************************************************************************************
TASK [debug] ******************************************************************************************************
ok: [localhost] => (item=C:\<Maindir>\<App1>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/)
ok: [localhost] => (item=C:\<Maindir>\<App2>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/)
ok: [localhost] => (item=C:\<Maindir>\<App3>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/)
ok: [localhost] => (item=C:\<Maindir>\<App4>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/)
PLAY RECAP ********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Another idea would be to use Python array slicing to separate odd from even elements and Ansible zip filter.
This would be the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg:
- "src: {{ item.0 }}"
- "dest: {{ item.1 }}"
loop: "{{ result.stdout_lines[::2] | zip(result.stdout_lines[1::2]) | list }}"
vars:
result:
stdout_lines:
- "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
- "C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
- "C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
- "C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
This yields the recap:
PLAY [all] ********************************************************************************************************
TASK [debug] ******************************************************************************************************
ok: [localhost] => (item=['C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
PLAY RECAP ********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
When I would have a slight preference for the second approach, I could understand it could be less readable for people not used to Python's array slicing.

Split debug variable output into two separate variables in ansible

I am using below code snippet where image details would be printed:
- set_fact:
image_name: "{{ load.results|map(attribute='stdout_lines')|list }}"
- debug:
var: image_name
Output:
TASK [set_fact] ***************************************************************************************************************************************************************************
ok: [xx.xx.xx.xx]
TASK [debug] ******************************************************************************************************************************************************************************
ok: [xx.xx.xx.xx] => {
"image_name": [
[
"Loaded image(s): localhost/cim:v1.5"
],
[
"Loaded image(s): localhost/cim:v1.8"
]
]
}
Is there a way I can store the image name and tag in two separate variables under set_fact itself or in any other form so I can reuse those 2 variables for the next task?
You can use a regex_findall filter in order to achieve this.
The regex used here is (\S*):(\S+). if needed, more explanation on it can be found here
Given the playbook:
- hosts: all
gather_facts: no
vars:
load:
results:
- stdout_lines:
- "Loaded image(s): localhost/cim:v1.5"
- stdout_lines:
- "Loaded image(s): localhost/cim:v1.8"
tasks:
- set_fact:
images: "{{ images | default([]) + item | regex_findall('(\\S*):(\\S+)') }}"
loop: "{{ load.results | map(attribute='stdout_lines') | flatten }}"
- debug:
msg: "This image repository is `{{ item.0 }}` and its tag is `{{ item.1 }}`"
loop: "{{ images }}"
This yields the recap:
PLAY [all] *********************************************************************************************************
TASK [set_fact] ****************************************************************************************************
ok: [localhost] => (item=Loaded image(s): localhost/cim:v1.5)
ok: [localhost] => (item=Loaded image(s): localhost/cim:v1.8)
TASK [debug] *******************************************************************************************************
ok: [localhost] => (item=['localhost/cim', 'v1.5']) => {
"msg": "This image repository is `localhost/cim` and its tag is `v1.5`"
}
ok: [localhost] => (item=['localhost/cim', 'v1.8']) => {
"msg": "This image repository is `localhost/cim` and its tag is `v1.8`"
}
PLAY RECAP *********************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Ansible filter list of dict when dict value is another list

I have a use case to filter "waf" IP alone from below yml input (zone: site9.poc.acd.xyz.in.) which is passed as Ansible parameter in my task. I don't want to loop though the list of dns_records but instead use selectattr/ map or json_query to fetch it.
Tried below option which works but looking for better one line option if any.
#Test task:
- set_fact:
zone: "{{ (myzone.dns_records|selectattr('zone','equalto','site9.poc.acd.xyz.in.')) | first }}"
- set_fact:
wafip: "{{ zone.a | selectattr('name','equalto','waf') | map(attribute='ip') |first}}"
- debug:
var: "{{ wafip }}"
#Output:
ok: [localhost] => {
"msg": "\"172.13.12.11\"\n"
}
# site.yml
myzone:
dns_records:
- zone: 78.100.in-addr.arpa.
- zone: 92.23.172.in-addr.arpa.
- zone: site9.poc.acd.xyz.in.
a:
- name: aproxy
ip: 10.8.2.12
- name: bproxy
ip: 10.8.2.108
- name: sssd
ip: 10.8.2.109
- name: waf
ip: 172.13.12.11
Here is a possible solution using a singlejson_query
---
- hosts: localhost
gather_facts: false
vars:
# Same as your above var declaration.
myzone: {"dns_records": [{"zone": "78.100.in-addr.arpa."}, {"zone": "92.23.172.in-addr.arpa."}, {"zone": "site9.poc.acd.xyz.in.", "a": [{"name": "aproxy", "ip": "10.8.2.12"}, {"name": "bproxy", "ip": "10.8.2.108"}, {"name": "sssd", "ip": "10.8.2.109"}, {"name": "waf", "ip": "172.13.12.11"}]}]}
# Pass target data as vars for possible future changes...
target_zone: site9.poc.acd.xyz.in.
target_name: waf
tasks:
- name: "Show {{ target_name }} ip for {{ target_zone }}"
vars:
query: "[?zone=='{{ target_zone }}'].a[] | [?name=='{{ target_name }}'].ip[] | [0]"
debug:
msg: "{{ myzone.dns_records | json_query(query) }}"
Result:
PLAY [localhost] *******************************************************************************************************************************************************
TASK [Show waf ip for site9.poc.acd.xyz.in.] ***************************************************************************************************************************
ok: [localhost] => {
"msg": "172.13.12.11"
}
PLAY RECAP *************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

ansible: create a list from comma separated string

I want to create a list from comma separated string to pass to loop in ansible, sometime variable can have only one value also
var1=test1,test2 and it can be var1=test1 also
here is my code
- name: Separate facts
set_fact: groups="{{ var1.split(',') }}"
- name: delete
gcp_compute_instance_group:
name: "{{ item }}"
zone: xxx
project: xxx
auth_kind: serviceaccount
service_account_file: xxx
state: absent
loop: "{{ groups }}"
this doesn't work, how can i achieve my requirement
your filter is correct, you do get a list variable. please see below PB and output:
---
- hosts: localhost
gather_facts: false
vars:
var1: test1,test2
var2: test3
tasks:
- name: Create the list
set_fact:
list_var1: "{{ var1.split(',') }}"
list_var2: "{{ var2.split(',') }}"
- debug:
var: list_var1
- debug:
var: list_var2
result:
[is#orangehat-29 temp]$ ansible-playbook test.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] ***********************************************************************************************************************************************************************************************************************
TASK [Create the list] *****************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"list_var1": [
"test1",
"test2"
]
}
TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"list_var2": [
"test3"
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[is#orangehat-29 temp]$

Ansible playbook to get all private Ip of my AWS environments

I'm running a scan against all the instances on my AWS using Ansible pLaybook . I need to get their Private IP and list them
I have tried to use json query to filter the Json format. The format output look like this..............
ok: [localhost] => {
"msg": [
{
"private_dns_name": "ip-10.89.3.12.ec2.internal",
"private_ip_address": "10.89.3.12",
"public_dns_name": "",
"public_ip_address": null,
},
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: Gather EC2 remote facts.
ec2_remote_facts:
region: "{{ region | default('us-east-1') }}"
filters:
instance-state-name: running
register: ec2_remote_facts
- set_fact:
msg: "{{ ec2_remote_facts | json_query('results[*].instances[*].private_ip_address') }} "
- debug: var=msg
I expect the output to be list of private_IP only
I tried with "ec2_instance_facts" as below :
- hosts: localhost
connection: local
gather_facts: yes
tasks:
- name: Gather EC2 remote facts.
ec2_instance_facts:
filters:
availability-zone: ap-south-1b
register: ec2_instance_facts
- set_fact:
msg: "{{ ec2_instance_facts | json_query('instances[*].private_ip_address') }} "
- debug: var=msg
and below is the output :
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Gather EC2 remote facts.] ***********************************************************************************************************************************************************************************
ok: [localhost]
TASK [set_fact] ***************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"172.31.6.87"
]
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Which is correct as per EC2 instance I had created.

Resources