I am new to Ansible and my play looks like this:
- name: "Spark Submit Command"
shell: "{{ sparkCommand }}"
register: spark_output
- debug: msg="{{ spark_output.stdout }}"
I have around 60 lines in my spark_output.stdout and getting the output as below:
ok: [DHADLX110] => {
"msg": "Line1\nLine2\nLine3...........Line.."
Is it possible to print these line by line or in a proper dialog box? Something similar to below format:
Line1
Line2
.
.
.
Line60
When you register command output, Ansible will give you stdout and stdout_lines.
If you change your debug task to:
- debug:
var: spark_output
You will see that it also returns stdout_lines. So instead of spark_output.stdout use:
- debug:
msg: "{{ spark_output.stdout_lines }}"
When executing a playbook to run a command in a remote host and pass the output using shell, getting below error.
fatal: [master1]: FAILED! => {} MSG: template error while templating
string: unexpected char u'a' at 4. String:
{{54aa7fda16833bff8358b6bd1157df2d9caa26b2}}
Below is my playbook content
- name: 'Play1'
hosts: master
tasks:
- name: 'Execute command'
shell: ''sh generate_ticket.sh" #command to generate ticket
register: shell_output
- name: 'debug shell_output'
debug:
var="{{ shell_output.stdout | from_yaml }}"
When I try the same with msg and don't try to filter then the output is printed without any error. However I prefer to use var as it suits best for my further requirements. If the ticket number is a different string I do not face any issues. Please see below:
Output:
ok: [master1] => {}
MSG:
54aa7fda16833bff8358b6bd1157df2d9caa26b2
Playbook :
- name: 'Play1'
hosts: master
tasks:
- name: 'Execute command'
shell: ''sh generate_ticket.sh" #command to generate ticket
register: shell_output
- name: 'debug shell_output'
debug: msg="{{ shell_output.stdout | from_yaml }}"
It seems to work when I put single quotes around shell_output.stdout
var="{{ 'shell_output.stdout' | from_yaml}}"
Let me know if anybody has a better fix than this.
use !unsafe
enter link description here
I need to replace all the / by \ in a string stored in a variable.
I'm just trying to do it a simple as possible to test it with a debug, but no matter how I try it I dont get the expected result of just replacing character to character. I think it's probably just a single/double quote problem or maybe the \ needs to be escaped in a certain way I don't know.
vars:
- SecGroup: '/stuff/foo/thing'
tasks:
- name: Display modified var
debug:
msg: "{{ SecGroup | replace('/','\') }}"
Expected output : \stuff\foo\thing
Output with differents tries :
- name: Display modified var
debug:
msg: "{{ SecGroup | replace('/','\') }}"
TASK [Display modified var]
ok: [localhost] => {
"msg": "stufffoothing"
}
- name: Display modified var
debug:
msg: "{{ SecGroup | replace('/','\\') }}"
TASK [Display modified var]
fatal: [localhost]: FAILED! => {"msg": "Unexpected failure during module execution."}
- name: Display modified var
debug:
msg: "{{ SecGroup | replace('/','\\\') }}"
TASK [Display modified var]
fatal: [localhost]: FAILED! => {"msg": "Unexpected failure during module execution."}
- name: Display modified var
debug:
msg: "{{ SecGroup | replace('/','\\\\') }}"
TASK [Display modified var]
ok: [localhost] => {
"msg": "\\\\stuff\\\\foo\\\\thing"
}
I also tried to revert the quotes :
- name: Display modified var
debug:
msg: '{{ SecGroup | replace("/","\") }}'
TASK [Display modified var]
fatal: [localhost]: FAILED! => {"msg": "Unexpected failure during module execution."}
I can't explain the output of this one
- name: Display modified var
debug:
msg: '{{ SecGroup | replace("/","\\") }}'
TASK [Display modified var]
ok: [localhost] => {
"msg": "\\\\stuff\\\\foo\\\\thing"
}
I think you've stumbled upon an edge case that involves the interaction between YAML escaping and Python escaping. The only way I was able to get it to work was introducing a guard character -- something to ensure that the \ isn't the last character in the expression, which we then remove with a subsequent replace() filter. Here I'm using a semicolon (;), but you could use anything that you're certain won't be in your SecGroup string. Note that your choice of quotes is significant; quoting the entire string with single quotes inhibits YAML escaping:
- name: With guard character
debug:
msg: '{{ SecGroup | replace("/","\;") | replace(";", "") }}'
Outputs:
TASK [With guard character] *******************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "\\stuff\\foo\\thing"
}
Which is exactly what you want (remembering that a single \ is encoded as \\ in JSON output).
Regarding this:
- name: Display modified var
debug:
msg: '{{ SecGroup | replace("/","\\") }}'
TASK [Display modified var]
ok: [localhost] => {
"msg": "\\\\stuff\\\\foo\\\\thing"
}
You are successfully replacing / with two backslashes, \\. Since a backslash must be encoded as \\ in JSON output, a double backslash will end up represented as \\\\, so this:
"msg": "\\\\stuff\\\\foo\\\\thing"
Means you actually have the string:
\\stuff\\foo\\thing
I wanted to add an alternative solution:
If you're familiar with Python, you can just write a custom filter module and avoid multiple layers of escaping. E.g., if you were to create filter_plugins/reslash.py with the following content:
#!/usr/bin/python
def filter_reslash(val):
return val.replace('/', '\\')
class FilterModule(object):
filter_map = {
'reslash': filter_reslash
}
def filters(self):
return self.filter_map
You could then write your playbook like this:
---
- hosts: localhost
gather_facts: false
vars:
- SecGroup: '/stuff/foo/thing'
tasks:
- debug:
msg: "{{ SecGroup | reslash }}"
That's arguably a cleaner solution.
The solution by #larsks didn't entirely work for me as described. I needed to escape the backslash with double slashes \ plus the guard character in order for it to work in the Ansible Playbook.
This works: replace('/','\\;') | replace(';', '')
Another easy solution is to leave escaping backslash to ansible itself. This is how i would have done.
- set_fact:
replacer: '\'
- name: With guard character
debug:
msg: '{{ SecGroup | replace("/",replacer)}}'
Same workaround if you want replace 1 backslash with double backslash on a windows path.
- hosts: localhost
gather_facts: False
vars:
- iis_manager_logdir: 'C:\inetpub\logs\manager-logs'
tasks:
- set_fact:
iis_mng_logs: "{{ iis_manager_logdir | regex_replace('\\\\', '\\\\;') | regex_replace(';', '\\\\') }}"
- name: Original path
debug:
msg: "{{ iis_manager_logdir }}"
- name: New path
debug:
msg: "{{ iis_mng_logs }}"
Thanks to the #larsks's answer i've managed to replace backslashes in ansible string variable value without intermediate replace. It's possible by supplying into regex_replace expression a regex quantifier {1} between last backslash and closing quote.
For example, expression like {{ install_path | regex_replace('\\\\{1}', '/') }} replaces all occurences of backslash \ to forward slash /. It was used to replace Windows path delimiters with Unix-like ones:
- name: install libs
win_shell: "pip install --no-index --find-links \"file://{{ install_path | regex_replace('\\\\{1}', '/') }}/libs\" attrs requests"
become: true
For what its worth, after countless struggles, this is what has worked for me without any workarounds:
Forward to Back Slash
ForwardtoBackSlash: "{{ 'c:/test' | regex_replace('\\\/', '\\\\') }}"
output:
c:\test
Single Slash to Double Slash
SingleSlashtoDoble: "{{ 'C:\test\logs\logfile.txt'| regex_replace('\\\\', '\\\\\\\\') }}"
Output:
C:\\test\\logs\\logfile.txt
I hope it helps someone.
So I need to take a particular part of my debug msg that I have in my playbook that goes like
---
- name: extract
shell: grep "ScriptAlias /.*/" /etc/httpd/conf/httpd.conf
register: st
- debug:
msg: "{{ st.stdout_lines | map('trim') | list }}"
and that playbook prints out when ran
ok: [52.61.71.178] => {
"msg": [
"ScriptAlias /cgi-bin/ \"/var/www/cgi-bin/\""
]
}
So what I need to do is put that msg "ScriptAlias /cgi-bin/ \"/var/www/cgi-bin/\""in an array and extract the last element in that which is the "/var/www/cgi-bin/"
What is the best approach in extracting the last element in my msg to where it can get only the "/var/www/cgi-bin/"?
Try as below. Only added regex_replace (Answer From Valdimir) to get exactly what you want.
- hosts: localhost
vars:
lines:
- "ScriptAlias /cgi-bin/ \"/var/www/cgi-bin/\""
tasks:
- debug:
msg: "{{ item.split(' ')[2] | regex_replace('\"', '') }}"
loop: "{{ lines }}"
Output should be exactly as ::
"msg": "/var/www/cgi-bin/"
The split method works fine. Output is abridged.
> ansible-playbook split_test.yml
"msg": "\"/var/www/cgi-bin/\""
split_test.yml
- hosts: localhost
vars:
lines:
- "ScriptAlias /cgi-bin/ \"/var/www/cgi-bin/\""
tasks:
- debug:
msg: "{{ item.split(' ')[2] }}"
loop: "{{ lines }}"
I have a python script which is returning / print two lists.
test.py
def getHosts():
Pool1=[x.x.x.x, x.x.x.x]
Pool2=[x.x.x.x, x.x.x.x]
Print pool1,pool2
Return pool1,pool2
getHosts()
My playbook looks like:
-task:
name: get the hosts
command: /test.py
register: result
Now, is it possible to fetch out the pool1 and pool2 seperately from the registered variable result ? If yes, please show me an example.
Any help or suggestions will be highly appreciated.
Produce JSON and feed it to Ansible. It will automatically create an appropriate data structure:
---
- hosts: localhost
gather_facts: no
connection: local
tasks:
- command: 'echo { \"Pool1\": \"[x.x.x.x, x.x.x.x]\", \"Pool2\": \"[x.x.x.x, x.x.x.x]\" }'
register: my_output
- set_fact:
my_variable: "{{ my_output.stdout | from_json }}"
- debug:
msg: "Pool1 is {{ my_variable.Pool1 }} and Pool2 is {{ my_variable.Pool2 }}"
Result:
ok: [localhost] => {
"msg": "Pool1 is [x.x.x.x, x.x.x.x] and Pool2 is [x.x.x.x, x.x.x.x]"
}
Depending on how you later use the variable, you might/might not need to from_json filter (see this).