Salt State minion id variable - salt-stack

I have a state where at the end I make an API call. I need to use the minion id as a parameter in that call but I'm not sure how to get it. Is there a default variable to use so I can include the id in the call?

So, there are a couple of variables that can be called.
{{grains["id"]}}
{{salt["grains.get"]("id")}}
{{opts["id"]}}
{{salt["config.get"]("id")}}
This is 4 ways to get the same value 2 from grains. 1 from opts. and 1 from config.get. the id of the minion rendering the state.
here it is being rendered on my salt-master through a salt-call.
[root#salt00 tests]# salt-call slsutil.renderer salt://tests/test4.sls default_renderer=jinja
local:
salt00.wolfnet.bad4.us
salt00.wolfnet.bad4.us
salt00.wolfnet.bad4.us
salt00.wolfnet.bad4.us

Related

SaltStack events got lost?

We setup a Salt state which will send an event to Salt Master when certain files missing. We also configured a reactor to capture the event and copy missing files accordingly. It is tested successfully on any single minion. However, when we apply the state to multiple minions (number range from 8 to 80+), only a portion (number range from 5 to 40+, randomly) of the minions triggered the reactors. We saw the events all being sent, just reactor never picks up all of them. With no configuration change, if we run the state again, some of the remaining minions (again, number is random) would trigger the reactor and get the missing files. Only after enough re-states, all of the minions will be completed successfully.
We tried to adjust REACTOR_WORKER_THREADS and/or REACTOR_WORKER_HWM, thinking maybe the queue is too small. However, I don't think it helped.
did you try to add the
queue=True
parameter on your state file, look below:
{% if data['tag'] == 'picachu' %}
trigger_picachu:
local.state.apply:
- tgt: {{ data['id'] }}
- arg:
- gitfs.picachu
- queue=True
{% endif %}

How to store a particular node from an output of a state.sls file in a variable for SaltStack

I'm working on a project where I need to check the status of a service, let's call it RunningService on multiple(more than 500 machines) Windows servers. We are using Saltstack extensively for our deployments.
I'm able to check the status of my service using the below code
status_ser:
module.run:
- name: service.status
- m_name: RunningService
The response that I'm getting on running via this particular code is as below:
----------
ID: status_ser
Function: module.run
Name: service.status
**Result: True**
Comment: Module function service.status executed
Started: 16:20:58.295237
Duration: 78.124 ms
Changes:
----------
ret:
True
Summary for minion-3
------------
Succeeded: 1 (changed=1)
Failed: 0
------------
Total states run: 1
Total run time: 78.124 ms
However, I only want the result part(which could be True or False) out of this in a bigger code probably saved in a variable. And then I'll verify
if var == 'False'
then start RunningService
else
do nothing
endif
How can I get only the result of the service as True or False?
Or a more generic question would be how to store one part of the output as variable or input to something else?
Thanks in advance.
To store the output of a command or salt module as variable (the short answer) is that you use set in a Jinja expression. Like:
{% set service_status = salt['service.status']('RunningService') %}
Either True or False will now be stored in service_status. This can be used in conditional statements. Start service taking example from your question:
{% if not service_status %}
start_service:
module.run:
- service.start:
- name: RunningService
{% endif %}
However, there are few things to consider:
All Jinja expression is evaluated before the States are run
Saltstack can be better used to define the state of service, i.e. if you want a particular service to be running, just define it so.
So, its better to use the Salt state service, which does such checks internally. Then this is all the code you'll need.
start_service:
service.running:
- name: RunningService
Now, whenever you run this state. The service will be started if its not running, and nothing will be done if its already running.

How do I find if a variable has been defined?

How do I find out if a variable has been defined in my Robot Framework script? I am doing API testing, not UI testing. I have a complex set up and tear-down sequence and, since I am interacting with multiple computers through the script, it is important to know the current state if a fatal error has occurred. I could track what I have done with some complex set of meta variables or a variable tracking list, but I would prefer to query if a particular variable has been defined and if so take the appropriate tear-down steps.
A simplified version is something like:
*** Test Cases ***
Check monitor
${monitored}= Connect to Monitor ${Monitor IP Address} ${User name} ${password}
${peer connected}= Connect to Monitor ${Peer IP Address} ${User name} ${password}
Get Information from Monitor ${IP Address}
Send Info to Peer ${buffer1}
Report back to Monitor ${Monitor IP Address}
We are assuming that the tear-down closes the connections. I want to close any connections that are open, but if I failed to open the peer connection I will close the monitor connection and fail on closing the monitor connection.
I am trying to determine if ${peer connected} is defined. Can I look into Robot Framework's variable storage to see if it is there (in that dictionary?)?
You can call Get Variables to get a dictionary of all variables, then check whether the variable you're interested in is in the dictionary.
*** Test cases ***
Example
${foo}= set variable hello, world
${variables}= Get variables
Should be true "\${foo}" in $variables
Should not be true "\${bar}" in $variables
There a pretty straightforward approach - the built-in keyword Get Variable Value returns python's None (by default) if there is no such variable defined:
${the var}= Get Variable Value ${peer connected}
${is set}= Set Variable If """${the var}""" != 'None' ${True} ${False}
I am fine with this approach. In case the variable is not defined, the test case does not fail....
${variables} Get variables
${status} Run Keyword And Return Status Evaluate $new_table in $variables
${new_table} Set variable if ${status}==${FALSE} new_tbl ${new_table}
Also possible is:
${variables} Get Variables
IF "\${dataPluginVersion}" in "${variables}"
No Operation
ELSE
${dataPluginVersion} Set Variable 0
END
Or:
${variables} Get Variables
IF not "\${dataPluginVersion}" in "${variables}"
${dataPluginVersion} Set Variable 0
END
A shorter way:
OEM-T01-99-Test-variables
[Tags] TEST
Variable Should Not Exist \${TESTDEVICE_SSH_CONNECTION}
Variable Should Exist \${TEST_NAME}
This method is more readable and less verbose than using "Get Variables" keyword, IMHO
Reference: Robotframework built-in keywords

SaltStack - map.jinja file cannot match on grain of type dictionary, am I defining grains incorrectly?

I'm using a map.jinja file in a state that uses grains.filter_by, matching on a grain w/ id 'role'. This is used to dynamically set the version of Java that an application uses. I know, weird, but that's how the system I inherited works today, so I'm setting it up as such in configuration management as step 1 to making things better. The map file has no problems at all on hosts with the grain value 'role' being a single item (which I believe is a list in yaml).
Example of the map file:
{% set java = salt['grains.filter_by']({
'default': {
'link_target': '/path/jdk1.7.0_03',
},
'appA': {
'link_target': '/path/jdk1.7.0_75',
},
'appB': {
'link_target': '/path/jdk1.6.0_06',
},
},
grain='role',
default='default'
)%}
Grain values for host w/ a dictionary of role values, I get the error on these hosts:
role:
----------
appA:
None
appC:
None
appD:
----------
someBool:
True
someVendor:
microsoft
someBool2:
False
someVendor2:
apple
type:
delayed
Grain values for hosts without a dictionary for grains, no error:
role:
appB
Error:
Data failed to compile:
----------
Rendering SLS 'base:java' failed: Jinja error: unhashable type: 'dict'
/var/cache/salt/minion/files/base/java/map.jinja(1):
---
{% set java = salt['grains.filter_by']({ <======================
Now, I'm pretty sure this is because my grain value with a dictionary of role values parses into yaml differently than my grain values that are a simple key:value pair.
I'm new to SaltStack and YAML, so I'm likely missing something trivial here. Am I getting too complex with my grain values? Do you have a fix or recommendation on a better way to do this?
Perhaps you should check the documentation of salt.modules.grains again.
So this is what I see :
salt.modules.grains.filter_by(lookup_dict, grain='os_family', merge=None, default='default', base=None)
lookup_dict -- A dictionary, keyed by a grain, containing a value or
values relevant to systems matching that grain. For example, a key
could be the grain for an OS and the value could the name of a package
on that particular OS.
It seems the dictionary value key must be a grain.

Salt States and grain values

I added the following logic to my state file which basically sets a new grain value after installing a utility called agent for the first time.
{% if salt['grains.get']('agent') != 'installed' %}
..............
agent_status:
grains.present:
- name: agent
- value: installed
{% endif %}
The first time I run salt 'server1' state.highstate it returns the following which is what I expect:
----------
ID: agent_status
Function: grains.present
Name: agent
Result: True
Comment: Set grain agent to installed
Started: 16:03:27.083578
Duration: 709.795 ms
Changes:
----------
agent:
installed
When I subsequently run salt 'server1' state.highstate it returns:
server1:
----------
ID: states
Function: no.None
Result: False
Comment: No states found for this minion
Started:
Duration:
Changes:
Summary
------------
Succeeded: 0
Failed: 1
Is this the correct behaviour as I'm a little confused because I would have expected this not to show as a failed? Also, the comment is seems to be a bit misleading here.
Yeah, this is the correct behavior. What's happening is that first Salt renders the jinja. Since the second time you run this the grain exists, your minion is seeing an empty sls file. Hence the "No states found for this minion"
Edit: If you want to avoid getting the "No states found for this minion" error, you could add an innocuous state at the bottom, outside the jinja like this
/tmp/deletemeplease.txt:
file.absent

Resources