Salt stack execute a command/invoke a different state upon state failure - salt-stack

I am trying to run multiple states in a sls file and I have a requirement to execute a command upon failure of a state.
e.g.
test_cmd1:
cmd.run:
- name: |
echo 'Command 1'
test_cmd2:
cmd.run:
- name: |
echo 'Command 2'
on_fail_command:
cmd.run:
- name: |
echo 'On failure'
exit 1
I want on_fail_command to be executed when any of test_cmd1 or test_cmd2 fails... but not run when both test commands successfully execute. I have failHard set to True globally in our system.
I tried using onfail but that does not behave the way I want. onfail executes a state if any of the state listed under onfail fails, but here I am looking to skip executing other states upon a state fail but instead jump to on_fail_command and then exit.

Set the order of your on_fail_command state so it runs before anything else, and failhard so it fails the whole job.

Related

How to Schedule any script on Salt-Master

We are new in the salt stack. Our use case is to Schedule a run python/go script on salt-master. Is there any way or configuration to do the same?
Yes, you can schedule anything: Job Management
To run a script from the master process (not a minion):
schedule:
job1:
function: salt.cmd
args:
- cmd.run
- /path/to/script
when: whenever
That uses the salt.cmd runner to run the cmd.run function on the master, running the given script.
If you have a minion on the master server, you can use that instead and save a level of indirection.

Get Github Action to fail when R throws an error [duplicate]

I want to exit a job if a specific condition is met:
jobs:
foo:
steps:
...
- name: Early exit
run: exit_with_success # I want to know what command I should write here
if: true
- run: foo
- run: ...
...
How can I do this?
There is currently no way to exit a job arbitrarily, but there is a way to allow skipping subsequent steps if an earlier step failed, by using conditionals:
jobs:
foo:
steps:
...
- name: Early exit
run: exit_with_success # I want to know what command I should write here
- if: failure()
run: foo
- if: failure()
run: ...
...
The idea is that if the first step fails, then the rest will run, but if the first step doesn't fail the rest will not run.
However, it comes with the caveat that if any of the subsequent steps fail, the steps following them will still run, which may or may not be desirable.
Another option is to use step outputs to indicate failure or success:
jobs:
foo:
steps:
...
- id: s1
name: Early exit
run: # exit_with_success
- id: s2
if: steps.s1.conclusion == 'failure'
run: foo
- id: s3
if: steps.s2.conclusion == 'success'
run: ...
...
This method works pretty well and gives you very granular control over which steps are allowed to run and when, however it became very verbose with all the conditions you need.
Yet another option is to have two jobs:
one which checks your condition
another which depends on it:
jobs:
check:
outputs:
status: ${{ steps.early.conclusion }}
steps:
- id: early
name: Early exit
run: # exit_with_success
work:
needs: check
if: needs.check.outputs.status == 'success'
steps:
- run: foo
- run: ...
...
This last method works very well by moving the check into a separate job and having another job wait and check the status. However, if you have more jobs, then you have to repeat the same check in each one. This is not too bad as compared to doing a check in each step.
Note: In the last example, you can have the check job depend on the outputs of multiple steps by using the object filter syntax, then use the contains function in further jobs to ensure none of the steps failed:
jobs:
check:
outputs:
status: ${{ join(steps.*.conclusion) }}
steps:
- id: early
name: Early exit
run: # exit_with_success
- id: more_steps
name: Mooorreee
run: # exit_maybe_with_success
work:
needs: check
if: !contains(needs.check.outputs.status, 'failure')
steps:
- run: foo
- run: ...
Furthermore, keep in mind that "failure" and "success" are not the only conclusions available from a step. See steps.<step id>.conclusion for other possible reasons.

SaltStack result success only if return is expected

I'm using win_wua.list to check if the servers have available updates
update_system:
module.run:
- name: win_wua.list
The problem is that no meter if the server have pending updates or not the state result is "True"
But my goal is to run this as post-check so I want the state to be "successful" only if the return is "Nothing to return" in any other case I would like the state to be with result "False"
LKA5:
----------
ID: update_system
Function: module.run
Name: win_wua.list
Result: True
Comment: Module function win_wua.list executed
Started: 17:04:29.326587
Duration: 4017.653 ms
Changes:
----------
ret:
Nothing to return
Summary for LKA5
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 4.018 s
LKA3:
----------
ID: update_system
Function: module.run
Name: win_wua.list
Result: True
Comment: Module function win_wua.list executed
Started: 17:04:25.563111
Duration: 7113.497 ms
Changes:
----------
ret:
Nothing to return
Summary for LKA3
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 7.113 s
So there are two modules to manage Windows updates with Saltstack:
win_wua execution module
win_wua state module
Seems you are using the execution module, which always runs irrespective of the current state of system. So it will always report as changed. On the other hand, the state module will only run if updates are required.
The following state ID will ensure that the system is updated (as specified), and it will report as changed. Then we can use the requisite system to trigger another state.
Example:
# Including driver updates for example
update_system:
wua.uptodate:
- drivers: True
# Verify if further updates are there
verify_updates:
module.run:
- name: win_wua.list
- install: True
- onchanges:
- wua: update_system
In the above example, if update_system didn't update anything (there were no updates), then verify_updates won't run. If some packages were updated, then verify_updates will run. There are other requisites (linked above) that can be considered as per your use case.

Ansible async module with poll=0 doesn't finish the task

First of all, I'm using Ansible 2.0.0 (which I can't avoid).
I've a task like this. Here I'm using ping command to send traffic to a destination machine for 2 minutes. This command runs on a remote machine.
- name: Ping destination VM from host VM.
shell: ping -n -i 0.004 100.1.1.1 -c 30000 | grep "received" | cut -d"," -f2 | xargs | cut -d" " -f1
delegate_to: 172.25.11.207
async: 250
poll: 0
register: ping_result
failed_when: ping_result.rc != 0
I've 2-3 other tasks after this. That should not take more than a minute.
Now, after these tasks, I want to capture the output of ping_result. So I check the status of the above task like below:
- name: Check ping status
async_status:
jid: "{{ ping_result.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 10
Now this fails with the below error:
FAILED! => {"failed": true, "msg": "ERROR! The conditional check 'job_result.finished' failed. The error was: ERROR! error while evaluating conditional (job_result.finished): ERROR! 'dict object' has no attribute 'finished'"}
From the error, it looks like the original task has not finished. I even tried to increase the async time, say till 5000. No luck.
Any help on this would be appreciated.
Answer from the comment:
You should use delegate_to to check status of async job, because original async task has been delegated as well.
Following worked for me
until: job_result.finished is defined and job_result.finished

Run downloaded SaltStack formula

I've downloaded the PHP formula by following the instructions here: https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html
I've changed apache to php. In my salt config file (which I assume is /etc/salt/master), I've set file_roots like so:
file_roots:
base:
- /srv/salt
- /srv/formulas/php-formula
I don't know how I'm supposed to run it now. I've successfully run a salt state file by discovering that the documentation is incomplete, so I'd missed a step I wasn't aware of.
If I try to run the formula the same way I've been running the state, I just get errors.
salt '*' state.apply php-formula
salt-minion:
Data failed to compile:
----------
No matching sls found for 'php-formula' in env 'base'
ERROR: Minions returned with non-zero exit code
I've also tried: sudo salt '*' state.highstate, and it also has errors:
salt-minion:
----------
ID: states
Function: no.None
Result: False
Comment: No Top file or master_tops data matches found.
Changes:
Summary for salt-minion
------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
Total run time: 0.000 ms
ERROR: Minions returned with non-zero exit code
You have to add a top.sls file to /srv/salt/, not just in /srv/pillar/. If you have a file called /srv/salt/php.sls, you have remove it, otherwise it will interfere with /srv/pillar/php.sls.
Contents of /srv/salt/top.sls:
base:
'*':
- php
This is kind of bizarre, because my previous test (which wasn't a formula) used /srv/salt/php.sls and /srv/pillar/top.sls. Now I'm using /srv/pillar/php.sls and /srv/salt/top.sls.

Resources