saltstack how to verify variable from jinja, result wrong from if statement - linux

I was trying to write a state to set patching status, the if statement based on a result from a cmd.run, I checked the result that it should be 'No', meaning no available patches, but my state return said otherwise.
I checked:-
# salt 'minion1' cmd.run "yum --security check-update | grep 'for security'| awk '{print \$1}'"
minion1:
No
#
My state file:-
{% set minion = salt['cmd.run']("yum --security check-update | grep 'for security'| awk '{print \$1}'") %}
{% if minion|float == 'No' %}
no_patch:
cmd.run:
- name: echo "no update"
{% else %}
patch_pls:
cmd.run:
- name: echo "Patch please"
{% endif %}
my run result:-
minion1:
----------
ID: patch_pls
Function: cmd.run
Name: echo "Patch please"
Result: True
Comment: Command "echo "Patch please"" run
Started: 12:22:10.894779
Duration: 10.047 ms
Changes:
----------
pid:
19397
retcode:
0
stderr:
stdout:
Patch please
Summary for minion1
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 10.047 ms
Been spending hours trying to figure it out but just feeling defeated and frustrated right now.
You're my last hope. Thanks in advance.

Related

Using Split and join together in Ansible template file

I want to use hostnames of a group in ansible inventory in a template bash script file.
This is my inventory:
[group_srv]
srv1.co.company
srv2.co.company
srv3.co.company
This is that I wrote in script.sh.j2
for i in '{{ groups['group_srv'][0:3].split('.')[0] | join(' ') }}' ; do
echo $i
done
This is my desired output, but I cannot use split() and join() together.
for i in 'srv1' 'srv2' 'srv3'; do
echo $i
done
Any help is appreciated.
Ansible provides a magic variable containing the short name for each server in your inventory (i.e. the first string before the first dot): inventory_hostname_short
You can access all servers vars in an other magic var: hostvars
You can use the map filter to:
extract values for a list of keys inside a dict (e.g. the relevant hosts for your group in hostvars)
select a single key in a list of dictionaries (e.g. the short inventory name in each extracted server vars).
Those two operations can actually be done at once at extraction time.
Putting it all together:
for i in '{{ groups['group_srv'] | map('extract', hostvars) | map(attribute='inventory_hostname_short') | join("' '") }}' ; do
echo $i
done
Which can be shortened as
for i in '{{ groups['group_srv'] | map('extract', hostvars, 'inventory_hostname_short') | join("' '") }}' ; do
echo $i
done
The declaration below does the job
short_0_3: "{{ groups.group_srv[0:3]|
map('split', '.')|
map('first')|
join(' ') }}"
The next option is the extraction of the variable inventory_hostname_short
short_0_3: "{{ groups.group_srv[0:3]|
map('extract', hostvars, 'inventory_hostname_short')|
join(' ') }}"
Both options give
short_0_3: srv1 srv2 srv3
Example of a complete playbook for testing
- hosts: all
gather_facts: false
vars:
short_0_3: "{{ groups.group_srv[0:3]|
map('split', '.')|
map('first')|
join(' ') }}"
tasks:
- block:
- shell: "for i in {{ short_0_3 }}; do echo $i; done"
register: out
- debug:
var: out.stdout_lines
delegate_to: localhost
run_once: true
shell> cat hosts
[group_srv]
srv1.co.company
srv2.co.company
srv3.co.company
srv4.co.company
srv5.co.company
In Jinja2 loop you can use filters.
{% if not loop.last %} {% endif %} adds a white space after every element except the last one.
for i in {% for host in groups['group_srv'] %}'{{ host.split('.')[0] }}'{% if not loop.last %} {% endif %}{% endfor %} ; do
echo $i
done
Result:
for i in 'test-001' 'test-002' ; do
echo $i
done

Output the json array of paths from bash command in github actions

I'm trying to create a github job that transforms a list of changed files to list of their directories in json format, but completely stuck with the
error shown on screenshot (line 8: Packages/test: Is a directory). Echo command at the end shows empty string.
Action step code here:
- name: Get folders
id: get-folders
run: |
echo "Changed packages: ${{ steps.filter.outputs.changed_files }}"
folders=()
for package in ${{ steps.filter.outputs.changed_files }};
do
folder="$(dirname ${package})"
folders+=("${folder}")
done
result=$("${folders[#]}" | jq -R . | jq -s)
#result=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${folders[#]}")
echo '::set-output name=FOLDERS::${result}'
- run: echo "${{ steps.get-folders.outputs.FOLDERS }}"
YOUR_BASH_ARRAY=( a b c );
jsonString="$(jq --compact-output --null-input '$ARGS.positional' --args -- "${YOUR_BASH_ARRAY[#]}")"
Result: jsonString==["a","b","c"]
Credit to pmf for calling out the answer provided by the ops' question.

When condition in ansible

I have written the following playbook and it's working fine but when I am doing the same thing with roles, when condition of the fail module is messing up. Irrespective of the values defined, when I am giving > in when, in fail module, it's skipping and when giving < , it's failing.
Please don't mind the syntax and '-' s, it's messing up here.
- hosts: localhost
vars:
vmcpu_list:
- vmcpu: 2
- vmcpu: 1
- vmcpu: 1
vcpu_value: 0
tasks:
- set_fact:
vcpu_value: "{{ vcpu_value }} + vmcpu_list[{{item}}].vmcpu"
with_sequence: start=0 end="{{ vmcpu_list | length -1 }}"
- debug:
var: "{{ vcpu_value }}"
- fail:
msg: " provided vcpu are more"
when: vcpu_value|int > 5
NOTE: Sorry earlier I have given vcpu_value|int > 5 above but it should be vcpu_value|int > 3
- fail:
msg: " provided vcpu are more"
when: vcpu_value|int > 5
you have set vcpu_value: 0
condition assessement vcpu_value < 5 it dosn't match your condition ==> ansible will skip the task
- fail:
msg: " provided vcpu are more"
when: vcpu_value|int < 5
you have set vcpu_value: 0
condition assessement vcpu_value < 5 OK ==> ansible will get execute the task
There is no problem your code works fine no strange behavior ^^

Saltstack passing character Escaping backslash and doublequotes for cronjobs Variables

I am writing a sls template in saltstack and tried to correctly write a cronjob entry but i am not able to do so cause compiler always cries about syntax problem cause it seems the escaping is not working as i thought.
i need the escaping backslashes inside the cron command too cause otherwise cronjob does not use the format charackters correctly.
this is the code in my template
{{instance}} cron-entry-for-backup-daily:
cron.present:
- user: root
- name: "{{ online_basedir }}/online_tools/db-tools.py -b {{ settings.port }} -s {{ settings.online_master }} -x {{ instance + '.domain.name' }} backup -d {{ instance }} -f {{ '/opt/onlinebackupdir/' + instance + '/' + instance + '-odoo_db-' + '`date' + '\"' + '+\%Y_\%m_\%d-\%H_\%M' + '\"' + '`' + '_daily.zip'}}"
- minute: '*'
- hour: '22'
- daymonth: '*'
- month: '*'
- dayweek: '1-6'
- identifier: {{ instance + '_dailybackup' }}
- comment: 'Installed via Salt'
the cronjob entry should look like this
* 22 * * 1-6 /opt/online/online_tools/db-tools.py -b 63000 -s xyz123 -x sub.domain.name backup -d dbname -f /opt/onlinebackupdir/dbname/dbname-odoo_db-`date "+\%Y_\%m_\%d-\%H_\%M"`_daily.zip
If i execute this on command line it work if i execute it via cron it works ....
Error message:
i cannot compile my code from the sls file expected , but
found '' in "", line 124, column 154:
... ckupdir/dbname/dbname-odoo_db-date"+\%Y_\%m_\%d-\%H_\%M"_daily.zip"
i already tried some ways but i think i am unable to solve it at the moment to much brain dead already :-( maybe someone knows a solution i also checked the jinja docs for escaping aso ... but i am helpless at the moment
tries:
'`date +\%Y_\%m_\%d-\%H_\%M`' --> error
'`date "+\%Y_\%m_\%d-\%H_\%M"`' --> error
'`date \"+\%Y_\%m_\%d-\%H_\%M\"`' --> error
'`date '+'\%Y_\%m_\%d-\%H_\%M`' --> error
'`date '+\%Y_\%m_\%d-\%H_\%M'`' --> error
'`date \"+"\%Y_\%m_\%d-\%H_\%M"\"'`' --> error
'`date' + '"' + '+\%Y_\%m_\%d-\%H_\%M' + '"' + '`' --> error
'`date' + '"' + '+\%Y_\%m_\%d-\%H_\%M' + '"' + '`' --> error
'`date +%Y_%m_%d-%H%M`' --> compiled and worked in command line but not inside crontab % needs to be escaped
in the meantime i tried this too
"{{ online_basedir }}/online_tools/db-tools.py -b {{ settings.port }} -s {{ settings.online_master_pw }} -x {{ instance + '.domainname.net' }} backup -d {{ instance }} -f {{ '/opt/onlinebackupdir/' + instance + '/' + instance + '-odoo_db-' }} + {% raw %} `date "+\%Y_\%m_\%d-\%H_\%M"` {% endraw %} + {{'_daily.zip'}}"
"{{ online_basedir }}/online_tools/db-tools.py -b {{ settings.port }} -s {{ settings.online_master_pw }} -x {{ instance + '.domainname.net' }} backup -d {{ instance }} -f {{ '/opt/onlinebackupdir/' + instance + '/' + instance + '-odoo_db-' + {% raw %} `date "+\%Y_\%m_\%d-\%H_\%M"` {% endraw %} + '_daily.zip'}}"
This does not work either
OK i solved the Problem with this solution, maybe this is not the best way but it solves my problem....
If someone reads this i would be interested in why {% raw %} .... {% endraw % }
does not work
SOLUTION:
"{{ online_basedir }}/online_tools/db-tools.py -b {{ settings.port }} -s {{ settings.online_master_pw }} -x {{ instance + '.domainname.net' }} backup -d {{ instance }} -f {{ '/opt/onlinebackupdir/' + instance + '/' + instance + '-odoo_db-' + 'date \\\"+\\\\%Y_\\\\%m_\\\\%d-\\\\%H_\\\\%M\\\"' + '_weekly.zip'}}"
now the line in the crontab looks exactly like i need it:
.......`date "+\%Y_\%m_\%d-\%H_\%M"`..... .zip
RESULT in my BACKUP Folder: instance-odoo_db-2016_10_19-22_00_daily.zip

Ansible conditional based on stdout of result?

How do I use the when statement based on the standard output of register: result? If standard output exists I want somecommand to run if no standard output exists I want someothercommand to run.
- hosts: myhosts
tasks:
- name: echo hello
command: echo hello
register: result
- command: somecommand {{ result.stdout }}
when: result|success
- command: someothercommand
when: result|failed
Try checking to see it if equals a blank string or not?
- hosts: myhosts
tasks:
- name: echo hello
command: echo hello
register: result
- command: somecommand {{ result.stdout }}
when: result.stdout != ""
- command: someothercommand
when: result.stdout == ""
As of 2018, the recommended way to test if output is empty is just:
when: result.stdout | length > 0
That is the pythonic way of evaluating truth, null, empty strings, empty lists all evaluate as false.
Other older alternatives not recommended or even not working:
result.stdout != "" would not pass ansible-lint check!
result.stdout | bool will NOT work as most strings will evaluate as False, only cases where it would return true is if stdout happens to be one of the true, yes,... kind of strings.
result.stdout used to work but now triggers:
[DEPRECATION WARNING]: evaluating as a bare variable, this
behaviour will go away and you might need to add |bool to the
expression in the future. Also see CONDITIONAL_BARE_VARS configuration
toggle.. This feature will be removed in version 2.12. Deprecation
warnings can be disabled by setting deprecation_warnings=False in
ansible.cfg.`
To expand on this answer and address the comment regarding potential problems if stdout isn't defined, the following when statement can be used to ensure stdout is defined before trying to check its length:
when: result.stdout is defined and result.stdout | length > 0

Resources