Include multiple salt states in specific order - salt-stack

I want to compose multiple existing salt states into a new one, where they need to be executed in a specific order.
The SaltStack documentation explains that salt states can be included.
As I understand, the included states will be run before the rest of the sls file.
Example:
include:
- config-pulled
- service-restarted
Using this example, I want service-restarted to be executed after config-pulled and only if config-pulled was successful.
But the execution order of multiple included states is not guaranteed. The docs say:
... If you need to guarantee order of execution, consider using requisites.
I could imagine to use requisities directly on the include. For example:
include:
- config-pulled
- service-restarted:
require:
- config-pulled
But this does not work.
Questions
How to use requisites when including states?
Do I have to use an orchestrate script instead?

You don't have to use orch and you can use onchanges requisites with a test.succeed_with_changes.
tested on salt 3004.2
To sum up the demo, onchanges inhibits the execution of the test.succeed_with_changes by default unless there is a change in the given state (tests.config-pulled). onchanges_in does the same the other way around and inhibits server reload unless test.succeed_with_changes is modified (in the salt sense).
Example:
/srv/salt
├── tests
│   ├── config-pulled.sls
│   ├── init.sls
│   └── service-restarted.sls
config-pulled.sls
config-pulled:
file.managed:
- name: /tmp/config
- contents: 1000
# uncomment random to simulate a change (or change 1000 just over)
# - contents: {{ range(1000, 9999) | random }}
service-restarted.sls
service-restarted:
cmd.run:
- name: echo service-restarted
init.sls
include:
- tests.config-pulled
- tests.service-restarted
demo:
test.succeed_with_changes:
- onchanges:
- sls: tests.config-pulled
- onchanges_in:
- sls: tests.service-restarted
This approach might become a bit difficult to maintain.
A completely different approach would be a reorganization of sls.
I usually separate server install and reload from customization (two separate sls), therefore when I have to handle configs, I include the "install and reload" one (usually init.sls) on top of any/all the sls managing the conf to import the states and configure my config states with require_in, ex:
myconf:
file.managed:
- [...]
- require_in:
- cmd: rndc-reload
or
myconf:
file.managed:
- [...]
- require_in:
- service: haproxy
Note: this approach scale well as several states or even sls can manage configs using this mechanism and the daemon will be reloaded only once after all configs are set.
UPDATE
Add output to show specific order
Without changes
# salt-call state.apply tests
local:
----------
ID: config-pulled
Function: file.managed
Name: /tmp/config
Result: True
Comment: File /tmp/config is in the correct state
Started: 14:49:20.363480
Duration: 15.688 ms
Changes:
----------
ID: demo
Function: test.succeed_with_changes
Result: True
Comment: State was not run because none of the onchanges reqs changed
Started: 14:49:20.380447
Duration: 0.004 ms
Changes:
----------
ID: service-restarted
Function: cmd.run
Name: echo service-restarted
Result: True
Comment: State was not run because none of the onchanges reqs changed
Started: 14:49:20.380536
Duration: 0.002 ms
Changes:
Summary for local
------------
Succeeded: 3
Failed: 0
------------
Total states run: 3
Total run time: 15.694 ms
With changes
# salt-call state.apply tests
local:
----------
ID: config-pulled
Function: file.managed
Name: /tmp/config
Result: True
Comment: File /tmp/config updated
Started: 14:49:15.757487
Duration: 18.292 ms
Changes:
----------
diff:
---
+++
## -1 +1 ##
-1001
+1002
----------
ID: demo
Function: test.succeed_with_changes
Result: True
Comment: Success!
Started: 14:49:15.777084
Duration: 0.549 ms
Changes:
----------
testing:
----------
new:
Something pretended to change
old:
Unchanged
----------
ID: service-restarted
Function: cmd.run
Name: echo service-restarted
Result: True
Comment: Command "echo service-restarted" run
Started: 14:49:15.777785
Duration: 7.69 ms
Changes:
----------
pid:
4130033
retcode:
0
stderr:
stdout:
service-restarted
Summary for local
------------
Succeeded: 3 (changed=3)
Failed: 0
------------
Total states run: 3
Total run time: 26.531 ms

includes are not states. so requisites will not work with them.
as for the ticket you pointed to that became https://docs.saltproject.io/en/latest/ref/states/all/salt.states.test.html#salt.states.test.nop test.nop which is just a state that doesn't do anything.
for handling what you are talking about you would do something like
include:
- http
- libvirt
run_http:
test.nop:
- require:
- sls: http
run_libvirt:
test.nop:
- require:
- test: run_http
- sls: libvirt

Related

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.

Set up a conditional cmd.run based on file.managed in SaltStack

I have a SaltStack state file (sls) that has a pretty simple state defined.
MyStateRule:
file.managed:
- source: salt://scripts/rule.ps1
- name: 'c:\scripts\rule.ps1'
cmd.run:
- name: powershell c:\scripts\rule.ps1
- require:
- file: MyStateRule
When I run a state.apply command, the cmd.run appears to execute every time, which I can see makes sense. What I want is to only run when the managed file needs to be copied over to the minion. Can I use file.managed in that case? What do I need to change, such that the script only runs when the file is copied over?
Got it -- rather than using "require," use onchanges:
cmd.run:
- name: powershell c:\scripts\rule.ps1
- onchanges:
- file: MyStateRule

Unable to apply State files on Salt

Having issues applying state files to minions on salt, they're just basic test ones, nothing complicated.
In my master config file I have the following file roots definition:
file_roots:
base:
- /srv/salt/
My /srv/salt/top.sls file looks like this:
base:
'*':
- vim
Then at /srv/salt/vim/init.sls I have the following:
vim:
pkg.installed
So, that should be applied to all minions when applied, so I run the following:
sudo salt '*' state.apply
I get the following output, and it's not applied, as it seems to not be detecting the top.sls file?
salt-master-1:
----------
ID: states
Function: no.None
Result: False
Comment: No Top file or master_tops data matches found.
Changes:
Summary for salt-master-1
------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
Total run time: 0.000 ms
dev-docker-1:
----------
ID: states
Function: no.None
Result: False
Comment: No Top file or master_tops data matches found.
Changes:
Summary for dev-docker-1
------------
Succeeded: 0
Failed: 1
------------
Total states run: 1
Total run time: 0.000 ms
ERROR: Minions returned with non-zero exit code
If I look at the logs for the minion, dev-docker-1 nothing is logged as an error, all that I see is this.
2018-11-08 18:33:12,993 [salt.minion :1429][INFO ][4883] User sudo_salt Executing command state.apply with jid 20181108183312990343
2018-11-08 18:33:13,015 [salt.minion :1564][INFO ][5438] Starting a new job with PID 5438
2018-11-08 18:33:13,331 [salt.state :933 ][INFO ][5438] Loading fresh modules for state activity
2018-11-08 18:33:13,448 [salt.minion :1863][INFO ][5438] Returning information for job: 20181108183312990343
Any help greatly appreciated as I'm a bit lost as to why this isn't working . . .
Edit 1
I have enabled verbose logging on the minion, and I see the following, seems it can't see the top.sls file
[DEBUG ] Could not find file 'salt://top.sls' in saltenv 'base'
[DEBUG ] No contents loaded for saltenv 'base'
[DEBUG ] No contents found in top file. If this is not expected, verify that the 'file_roots' specified in 'etc/master' are accessible. The 'file_roots' configuration is: {u'base': []}
Ok so I worked this out, operator error.
I had enabled gitfs backend in the config file, which has overridden the default base file system, so I just needed to do.
fileserver_backend:
- gitfs
- base
Doh!

State 'cp.push' was not found in SLS

In salt (2018.3.0) I created the following statefile that I started to write to collect existing ssh hostkey files from minions.
sshHostKeys:
cp.push:
- path: '/etc/ssh/ssh_host_dsa_key.pub'
- upload_path: '/'
Calling
salt-call state.apply sshHostKeys
I get:
local:
----------
ID: sshHostKeys
Function: cp.push
Result: False
Comment: State 'cp.push' was not found in SLS 'sshHostKeys'
Reason: 'cp.push' is not available.
Manually calling:
salt-call cp.push /etc/ssh/ssh_host_dsa_key.pub
works just fine, the file is copied to the salt master.
Anyone has an idea what I am doing wrong in the state file?
Thanks Rainer
Had the same problem. This should work:
custom function name:
module.run:
- name: cp.push
- path: <<your path>>
See issue on github for reference:
https://github.com/saltstack/salt/issues/42330

What are "states" when using SaltStack?

I'm trying SaltStack after using Puppet for a while, but I can't understand their use of the word "state".
My understanding is that, for example, a light switch has 2 possible states - on or off. When I write my SLS configuration I am describing what state a server should be in. When I ask SaltStack to provision a server I issue the command salt '*' state.highstate. I understand that a server can be in a highstate (as described in my config) or not. All good so far.
But this page describes other states. It describes lowstate, highstate and overstate (amongst others) as layers. Does this mean a server passes through several states to get to a highstate? Or all states are maintained simultaneously as layers? Or can I configure multiple possible states in my SLS and have SaltStack switch between them? Or are they just layers to SaltStack that have 'state' in the name and I'm confused?
I'm probably missing something obvious, if anyone can nudge me in the right direction I think a lot of the documentation will become clear to me!
Here, top.sls wihch contain,
# cat top.sls
base:
'*':
- httpd_require
and,
# cat httpd_require.sls
install_httpd:
pkg.installed:
- name: httpd
service.running:
- name: httpd
- enable: True
- require:
- file: install_httpd
file.managed:
- name: /var/www/html/index.html
- source: salt://index1.html
- user: root
- group: root
- mode: 644
- require:
- pkg: install_httpd
High state:
We can see all the aspects of high state system while working with state files( .sls), There are three specific components.
High data:
SLS file:
High State
Each individual State represents a piece of high data(pkg.installed:'s block), Salt will compile all relevant SLS inside the top.sls, When these files are tied together using includes, and further glued together for use inside an environment using a top.sls file, they form a High State.
# salt 'remote_minion' state.show_highstate --out yaml
remote_minion:
install_httpd:
__env__: base
__sls__: httpd_require
file:
- name: /var/www/html/index.html
- source: salt://index1.html
- user: root
- group: root
- mode: 644
- require:
- pkg: install_httpd
- managed
- order: 10002
pkg:
- name: httpd
- installed
- order: 10000
service:
- name: httpd
- enable: true
- require:
- file: install_httpd
- running
- order: 10001
First, an order is declared, All States that are set to be first will have their order adjusted accordingly. Salt will then add 10000 to the last defined number (which is 0 by default), and add any States that are not explicitly ordered.
Salt will also add some variables that it uses internally, to know which environment (__env__) to execute the State in, and which SLS file (__sls__) the State declaration came from, Remember that the order is still no more than a starting point; the actual High State will be executed based first on requisites, and then on order.
"In other words, "High" data refers generally to data as it is seen by the user."
Low States:
""Low" data refers generally to data as it is ingested and used by Salt."
Once the final High State has been generated, it will be sent to the State compiler. This will reformat the State data into a format that Salt uses internally to evaluate each declaration, and feed data into each State module (which will in turn call the execution modules, as necessary). As with high data, low data can be broken into individual components:
Low State
Low chunks
State module
Execution module(s)
# salt 'remote_minion' state.show_lowstate --out yaml
remote_minion:
- __env__: base
__id__: install_httpd
__sls__: httpd_require
fun: installed
name: httpd
order: 10000
state: pkg
- __env__: base
__id__: install_httpd
__sls__: httpd_require
enable: true
fun: running
name: httpd
order: 10001
require:
- file: install_httpd
state: service
- __env__: base
__id__: install_httpd
__sls__: httpd_require
fun: managed
group: root
mode: 644
name: /var/www/html/index.html
order: 10002
require:
- pkg: install_httpd
source: salt://index1.html
state: file
user: root
Together, all this comprises a Low State. Each individual item is a Low Chunk. The first Low Chunk on this list looks like this:
- __env__: base
__id__: install_httpd
__sls__: httpd_require
fun: installed
name: http
order: 10000
state: pkg
Each low chunk maps to a State module (in this case, pkg) and a function inside that State module (in this case, installed). An ID is also provided at this level (__id__). Salt will map relationships (that is, requisites) between States using a combination of State and __id__. If a name has not been declared by the user, then Salt will automatically use the __id__ as the name.Once a function inside a State module has been called, it will usually map to one or more execution modules which actually do the work.
salt '\*' state.highstate
'*' refers to all the minions connected to the master.
'state.highstate' is used to run all modules / scripts mentioned in top.sls defined in master
To invoke a specific module / script on all minions, use the following salt command where the state information is defined in state.sls for apache in the example given below.
salt '\*' state.sls apache
To invoke the above salt call only on a specific minion, use the below command.
salt 'minion-name' state.sls apache
I don't know all levels of state, but when you run :
salt '*' state.highstate
Saltstack apply the states you provide in /srv/salt/top.sls.
If you write nothing in it, you can't apply an highstate.
You can apply other state with this command :
salt '*' state.sls state.example
A highstate is just the collection of states that is applied to your server. There is a process in the background where Salt's "state compiler" goes through several stages preparing the data in order to produce the highstate, but you don't really need to worry about those.
Things like the lowstate can help with debugging, but aren't necessary for day to day usage. The highstate is only applied once.

Resources