No Matching SLS found for 'mods.sls (result - No Matching sls found for 'mods' in env 'base') - salt-stack

Context: I am noob to salt stack open and working on evaluating as an option for state management. I am getting my hands on it. Currently I am running into not been able to run my mods.sls file.
Environment: Three AWS linux systems (t2) One master and two nodes/minions.
/srv/salt/apache/ contains init.sls, map.sls, mods.sls, and welcome.sls.
# mods.sls
{% for conf in ['status', 'info'] %}
mod_{{ conf }}:
file.managed:
- name: /etc/apache2/conf-available/mod_{{ conf }}.conf
- contents: |
<Location "/{{ conf }}">
SetHandler server-{{ conf }}
</Location>
{% if salt.grains.get('os_family') == 'Debian' %}
cmd.run:
- name: a2enmod {{ conf }} && a2enconf mod_{{ conf }}
- creates: /etc/apache2/conf-enabled/mod_{{ conf }}.conf
{% endif %}
{% endfor %}
# salt '*' state.show_sls mods`
node2:
- No matching sls found for 'mods' in env 'base'
node:
- No matching sls found for 'mods' in env 'base'
ERROR: Minions returned with non-zero exit code
Any advice from the community would be appreciated or anything I can do to make the question easier to understand.

The sls path is apache.mods, not mods.

Related

Access listed grain values

I'm trying to access listed grain values from state file, need help on this.
State file is as below
{% set list = grains['selinux'] %}
echo {{ list }}:
cmd.run
But when i run the state file got the error.
# salt '*' state.sls list_grains
client1:
Data failed to compile:
----------
Rendering SLS 'base:list_grains' failed: mapping values are not allowed in this context
ERROR: Minions returned with non-zero exit code
[root#server ~]# vim /srv/salt/list_grains.sls
grain values accessed are as below
# salt '*' grains.item selinux
client1:
----------
selinux:
----------
enabled:
True
enforced:
Permissive
The selinux grain is a dictionary/map like:
selinux:
enabled: True
enforced: Permissive
So in a state ID you cannot have dictionary/map. You can pick the required dictionary key like list.enabled or list.enforced.
For example, the below state ID will output Permissive:
{% set list = grains['selinux'] %}
echo {{ list.enforced }}:
cmd.run
If you want to get the complete dict as output, you can use a module like test.echo:
{% set list = grains['selinux'] %}
show-selinux-grains:
module.run:
- name: test.echo
- text: "{{ list }}"

Using Requisites in Reactor Files

How do I use requisites in reactor files?
I only want to run the second state if the first completes successfully.
{% if ('id' in data) and ('act' in data) and ('pub' in data) and
((data['act'] == 'pend') and (data['pub'] != '')) %}
check_minion_domain_joined:
local.cmd.run:
- tgt: 'MINIONNAME'
- arg:
- powershell.exe -ExecutionPolicy Bypass -File "C:/salt/auth-minion.ps1" {{ data['id'] }}
accept_key_domain_joined:
wheel.key.accept:
- match: {{ data['id'] }}
- require:
- cmd: check_minion_domain_joined
{% endif %}
I can see that the first state is being run by the master via the output of salt-run state.event, but "accept_key_domain_joined" never runs.
As per the official documentation, reactor SLS files do not support requisites.
Reactor SLS files, by design, do not support requisites, ordering, onlyif/unless conditionals and most other powerful constructs from Salt's State system.
The better option is to trigger orchestration from the reactor. So instead of having the two actions performed from reactor, just call for an orchestration run:
Example reactor/file.sls:
create-file-with-content:
runner.state.orch:
- args:
- mods: orch.create_file
- pillar:
min_id: {{ data['id'] }}
min_act: {{ data['act'] }}
Then in orch/create_file.sls, we can use the pillar data and accomplish the tasks.
Example:
{% set minion_id = salt.pillar.get('min_id') %}
{% set minion_act = salt.pillar.get('min_act') %}
touch-a-tmp-file:
salt.function:
- name: file.touch
- tgt: {{ minion_id }}
- arg:
- /tmp/dummy.file
update-tmp-file:
salt.function:
- name: file.append
tgt: {{ minion_id }}
arg:
- /tmp/dummy.file
- minion_act is {{ minion_act }}
- require:
- salt: touch-a-tmp-file
There is some more information on troubleshooting pillar information in reactor-orchestration states here.

If statements with nested grain returns nothing

I am trying to write an if statement based on a nested grain. I have tried this statement in multiple different ways:
System Services Needed:
module.run:
- name: service.systemctl_reload
- onchanges:
- file: /lib/systemd/system/salt-minion.service
{% if salt['grains.get']('Project:DeviceTypeID') == '2' %}
- file: /etc/rc.local
- file: /opt/interfaces_init.sh
{% endif %}
Returns:
Rendering SLS 'Development:System' failed: Jinja variable 'dict object' has no attribute 'Project:DeviceTypeID'
System Services Needed:
module.run:
- name: service.systemctl_reload
- onchanges:
- file: /lib/systemd/system/salt-minion.service
{% if grains['Project']['DeviceTypeID'] == '2' %}
- file: /etc/rc.local
- file: /opt/interfaces_init.sh
{% endif %}
System Services Needed:
module.run:
- name: service.systemctl_reload
- onchanges:
- file: /lib/systemd/system/salt-minion.service
{% if grains['Project:DeviceTypeID'] == '2' %}
- file: /etc/rc.local
- file: /opt/interfaces_init.sh
{% endif %}
As you can tell from the example their are multiple device type IDs. In this example DeviceTypeID = 2 I need to worry about rc.local and a shell script. I can not seem to get this work for the life of me. I know the grain exists as I can run the following:
sudo salt 'Dev-Box' grains.get Project
and I will get:
Dev-Box:
DeviceTypeID:
1
IsActive:
True
SoftwareEnvironmentName:
Production
SoftwareVersion:
Foo
This is either a bug or I am missing something (significantly more likely I am missing something). Any help would be much appreciated.
Edit 1:
Added ['grains.get']('Project:DeviceTypeID') example
in salt grains.get return a dictionary in the following format:
{'minion-id': value}
I believe if you change your code into something like bellow, it should works.
{% if salt['grains.get']('Project:DeviceTypeID')[minion-id] == '2' %}
If you can't do:
salt 'Dev-Box' grains.get 'Project:DeviceTypeID'
Then you don't actually have the proper grain set.
Try the following:
salt 'Dev-Box' grains.setval Project '{"DeviceTypeID": 2, "IsActive": True, "SoftwareEnvironmentName": "Production", "SoftwareVersion": "Foo"}'
Then the following state:
Do the {{ salt['grains.get']('Project:DeviceTypeID') }} things:
test.succeed_with_changes:
- some: thing
You should get:
ID: Do the 2 things
Function: test.succeed_with_changes
Result: True
Comment: Success!
Started: 17:10:42.739240
Duration: 0.491 ms
Changes:
----------
testing:
----------
new:
Something pretended to change
old:
Unchanged
Given what you wrote elsewhere
salt Dev-Box grains.setval BETTI "{'DeviceTypeID': 2, 'IsActive': True SoftwareEnvironmentName': 'Production', 'SoftwareVersion': 'Foo'}"
Your problem is that you have ' and " confused.
Wrapping the value with " makes it a string. Wrapping it with ' and providing valid JSON makes it a dictionary value.

Salt State Rendering: Can I See the Output of the Jinja Phase?

Question:
Is there any way to see the output of the Jinja phase, before attempting to parse as YAML?
Background:
I was trying to debug a Salt problem where I was getting this error:
local:
Data failed to compile:
----------
Rendering SLS ':test.sls' failed: mapping values are not allowed in this context
Not very helpful: No line number? What's a 'mapping value'? etc.
The problem boiled down to something like this:
{%- for x in [1, 2] -%}
Test {{ x }}:
cmd.run:
- name: echo Test {{ x }}
{%- endfor -%}
A seasoned Salt person will recognize that I've messed up the whitespace so that the Jinja was producing the output below:
Test 1:
cmd.run:
- name: echo Test 1 Test 2:
cmd.run:
- name: echo Test 2
However, this was frustrating to find in a complex set of states with no information on where the problem was occurring and no clear description of what the problem even was.
In the process of debugging this I learned that you can get the YAML tree using slsutil.renderer, like this:
% salt-call --local slsutil.renderer `pwd`/test.sls 'jinja'
local:
----------
Test 1:
----------
cmd.run:
|_
----------
name:
echo Test 1
Test 2:
----------
cmd.run:
|_
----------
name:
echo Test 2
But this of course requires that the YAML is valid. So how can I get Salt to output the templates as in my third snippet above, AFTER the Jinja has been evaluated but BEFORE Salt tries to parse it as YAML?
Oh wow, as I revisit this I've learned something new. I believe the answer is cp.get_template.
Test file:
% cat test.sls
{%- for x in [1, 2] -%}
Test {{ x }}:
cmd.run:
- name: echo Test {{ x }}
{%- endfor -%}
Now cp.get_template renders the Jinja and shows the raw output:
% salt-call --local cp.get_template `pwd`/test.sls /dev/stdout
Test 1:
cmd.run:
- name: echo Test 1Test 2:
cmd.run:
- name: echo Test 2
local:
/dev/stdout

For saltstack,how to get nodegroup of the minion in the jinjia template?

I want to get nodegroup of the minion in the jinjia template or pillar.How can I do it?
e.g. /path/jinjia_template_for_nginx.conf
{% if nodegroup == 'web' %}//nodegroup == get the minion's group
param_xxx 1;
{% else %}
param_xxx 2;
{% endif %}
AFAIK there is no way to get the node group of the current minion via a grain or a pillar directly. You can choose to export your master's configuration to you minion using pillar_opts = True in your master configuration, but any salt-call pillar.get master:nodegroups:web will get you an unexpanded list of hosts that is if no use here.
I suggest you create a pillar for this that maches on the group ...
# pillar top.sls
base:
web:
- match: nodegroup
- webserver
Then set a value of your choice ...
# webserver.sls
mygroup: web
And then use it in the template ...
# nginx.conf
{% if salt['pillar.get']('mygroup', 'unknown') == 'web' %}
param_xxx 1;
{% else %}
param_xxx 2;
{% endif %}
I hope this helps.
Looking at the functionality of nodegroups, pillars and compound matchers you could consider configuring only pillar information and either skip nodegroups, or use a compound matcher using pillar data to define your nodegroups.

Resources