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.
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 have snippet like this in the init.sls:
{% for server, args in pillar.get('servers', {}).items() %}
software-server#{{ server }}
service.running:
- enable: true
- require:
- pkg: software_pkgs
- watch:
- file: software_config
/etc/software/{{server}}.json:
file.managed:
- source: salt://software/files/config.json.j2
- template: jinja
{% endfor %}
config.json.j2:
{
listen: {{server}}:{{listen_addr}}
}
and in the pillar:
software.servers:
server1:
listen_addr:10.0.0.1
server2:
listen_addr:127.0.01
in each of the {{server}}.json the listen_addr is different. I don't know if saltstack has something like a scope for current loop, or is there a workaround for this.
You probably need to use context or defaults options in file.managed:
file.managed
In your example it would like like :
/etc/software/{{server}}.json:
file.managed:
- source: salt://software/files/config.json.j2
- template: jinja
- context:
server: {{ server }}
listen_addr: {{ server['listen_addr'] }}
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'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
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 %}