I've just installed a vanilla SaltStack master and minions. I'm trying to follow the instructions on https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html to create a very basic PHP state.
/srv/salt/php.sls:
php_ini:
file.managed:
- name: /etc/php.ini
- source: salt://php.ini.tmpl
- template: jinja
- context:
php_ini_settings: {{ salt.pillar.get('php_ini', {}) | json() }}
/srv/pillar/php.sls:
php_ini:
PHP:
engine: 'On'
short_open_tag: 'Off'
error_reporting: 'E_ALL & ~E_DEPRECATED & ~E_STRICT'
/srv/salt/php.ini.tmpl:
{% macro php_ini_serializer(data) %}
{% for section_name, name_val_pairs in data.items() %}
[{{ section_name }}]
{% for name, val in name_val_pairs.items() -%}
{{ name }} = "{{ val }}"
{% endfor %}
{% endfor %}
{% endmacro %}
; File managed by Salt at <{{ source }}>.
; Your changes will be overwritten.
{{ php_ini_serializer(php_ini_settings) }}
The output file looks like this:
VVV File starts on the next line
; File managed by Salt at <salt://php.ini.tmpl>.
; Your changes will be overwritten.
^^^ File ends on the previous line
I've added extra lines so that Stack Overflow will display the blank lines in the output file correctly.
I would expect it to look something link this:
VVV File starts on the next line
; File managed by Salt at <salt://php.ini.tmpl>.
; Your changes will be overwritten.
[PHP]
engine = "On"
short_open_tag = "Off"
error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT"
^^^ File ends on the previous line
It appears that Salt isn't reading the pillar file at all. What have I done wrong?
It looks like php_ini_settings: {{ salt.pillar.get('php_ini', {}) | json() }} does not add any data to the context of your jinja template salt://php.ini.tmpl.
To debug check if the pillar data is available use the pillar module
salt 'minionid' pilar.ls # to check the existence of keys
salt 'minionid' pilar.items # to explore whole the pillar data of your minion
Pillar data needs to be applied to minions like states using a top.sls file. My guess is that you did not apply your pillar data to your minion. Does /srv/pillar/top.sls includes somthing like that?
base:
'minionid':
- php
Related
{% set value = salt['mine.get']('{{ server }}', 'xml.set_value')('/opt/suite/version.xml', './/Version']) %}
Get value:
cmd.run:
- name: echo {{ value }}
Need help in writing the set value.
I would like to check if a file exist in salt file system (salt://) and add an instruction depending on that.
I precise that I use gitfs as a mount point in the salt file system and don't use /srv directory.
So more concretely I want to do something like that :
{% if salt['file.directory_exists']('salt://a_directory') %}
file.recurse:
- name: dest
- source: salt://a_directory
- template: jinja
{% endif %}
but it seem not to work.
I wanted to load yaml-files with package-lists for pkg.installed, but only if the yaml is on the master (file names are constructed by variables).
I'm using salt.modules.cp.list_master:
# Search path on the master:
{% set found = salt.cp.list_master(prefix='my/path/example.yaml') | count %}
{% if found %}
{# Do something… #}
{% endif %}
If you want to check a Directory, you can use this:
{% set found = salt.cp.list_master_dirs(prefix='my/path') | count %}
after seeing Mayr's answer, I did this:
{%- if not salt.cp.list_master(saltenv=saltenv, prefix='some/path/' ~ some_version ~ '/server.conf') | count %}
config_not_found_failure:
test.fail_without_changes:
- name: "some/path/{{some_version}}/server.conf not found in salt"
- failhard: True
{%- endif %}
I want to add a mine function that gets the hostname of a minion.
pillar/custom.sls
mine_functions:
custom:
- mine_function: grains.get
- nodename
I manually refresh the pillar data by running a
salt '*' saltutil.refresh_pillar
and when running salt '*' mine.get '*' custom the output is as expected, showing a list of minions all with the nodename data underneath.
The issue is when I try to do thew following in a template file:
{%- set custom_nodes = [] %}
bootstrap.servers={% for host, custom in salt['mine.get']('role:foo', 'custom', expr_form='grain').items() %}
{% do hosts.append(custom + ':2181') %}
{% endfor %}{{ custom_nodes|join(',') }}
I just get an empty space where my list of server nodenames should be.
I was hoping someone might be able to point out where I'm going wrong with this?
It looks like you are appending the list to hosts but then using custom_nodes with the join?
Was this on purpose?
I think what you actually want is
{%- set custom_nodes = [] %}
bootstrap.servers={% for host, custom in salt['mine.get']('role:foo', 'custom', expr_form='grain').items() %}
{% do custom_nodes.append(custom + ':2181') %}
{% endfor %}{{ custom_nodes|join(',') }}
This works fine for me:
pillar/custom.sls
mine_functions:
id_list:
mine_function: grains.get
key : nodename
templete.sls
{% for server in salt['mine.get']('*', 'id_list') | dictsort() %}
server {{ server }} {{ addrs[0] }}:80 check
{% endfor %}
Actually the answer was quite simple. I was unaware one needed to restart existing minions before they could access the mine data.
I'm trying to learn SaltStack and now I'm facing a problem.
I have a property file (propertyfile.properties) with values being populated by salt pillar. Now this property file exists in multiple directories. The issue that I have is that I want the values of the property file be populated/rendered by salt pillar.get function base on what directory currently it is into. To give you more idea, let's consider this example:
propertyfile.property (in directory 1)
name={{ salt['pillar.get']['dir1.name'] }}
propertyfile.property (in directory 2)
name={{ salt['pillar.get']['dir2.name'] }}
#pillar
dir1.name=dir1
dir2.name=dir2
note that the property file is only one and is generated by salt to multiple directories via loop like this:
{% for dir in 'dir1', 'dir2' %}
propertyfile_properties_{{ dir }}:
file.managed:
- name: /home/devuser/{{ dir }}/propertyfile.properties
- source: {{ propertyfile_source }}
- source_hash: {{ propertyfile_source }}.MD5
- template: jinja
- show_diff: True
- makedirs: True
{% endfor %}
Any ideas? Your help is very much appreciated. Thanks
You can do this by passing each directory to the template as context, as it's rendered:
# In .sls
{% for dir in salt['pillar.get']("directories") %}
propertyfile_properties_{{ dir }}:
file.managed:
- name: /home/devuser/{{ dir }}/propertyfile.properties
- source: salt://path/to/template.jinja
- template: jinja
- context:
dir: {{ dir }}
{% endfor %}
# In template:
dirname={{ dir }}
fullpath=/home/devuser/{{ dir }}/propertyfile.properties
# In pillar:
directories:
- dir1
- dir2
- ...and so on
Note the extra indentation of the contents of the context dictionary. There's an explanation of why that's sometimes necessary here.
I want to copy ssh keys for users automatically, some users do not have keys.
What I have now is:
ssh_auth:
- present
- user: {{ usr }}
- source: salt://users/keys/{{usr}}.id_rsa.pub
When a key for a user does not exist on salt:// fileserver, I get an error. Is there some function to check for existence of a file in salt:// fileserver?
If you feel you MUST learn how to do this with just states, you can use the fallback mechanism by specifying a list of sources:
From the docs:
ssh_auth:
- present
- user:{{usr}}
- source:
- salt://users/keys/{{usr}}.id_rsa.pub
- salt://users/keys/null.id_rsa.pub
Where cat /dev/null > /srv/salt/users/keys/null.id_dsa.pub
Professionally, user keys should be stored in pillars. This presents the additional functionality that pillars are stored and retrieved from the master at execution time - which means you can test for the existence of the file per your original request. I do something just like that for openvpn certificates:
http://garthwaite.org/virtually-secure-with-openvpn-pillars-and-salt.html
I don't know of a jinja or salt function which can check the master's file server for a specific file. I would recommend you put those keys as a key in the pillar's file which contains your user's and use jinja to detect the existence of that key and create the key when necessary. For example:
The pillars file:
# Name of file : user_pillar.sls
users:
root:
ssh_key: some_key_value
home : /root
createhome: True
The state file:
# Name of file : users_salt_state_file.sls
{% for user,args in salt['pillar.get']('users',{}).iteritems() %}
# Ensure user is present
{{ user }}_user:
user.present:
- name: {{ user }}
# Home Creation
{% if args and 'home' in args %}
- home: {{ args['home'] }}
{% endif %}
{% if args and 'createhome' in args %}
- createhome: {{ args['createhome'] }}
{% endif %}
# SSH_auth
{% if args and 'ssh_key' in args %}
{{ args['ssh_key'] }}
ssh_auth:
- present
- user: {{ user }}
{% endfor %}