Saltstack get grains of a minion in orchestration - salt-stack

I'm using salt-cloud to deploy VMs and I'm trying to get them registred in my DNS with the Saltstack Reactor system.
I have a reactor.conf with this trigger:
reactor:
- 'salt/cloud/*/created': # Add a VM
- /srv/reactor/initialize_vm.sls
initilize_vm.sls :
invoke_orchestrate_add_to_dns:
runner.state.orchestrate:
- mods: orch.add_to_dns
- pillar:
event_name: {{ name }}
event_profile: {{ profile }}
orch/add_to_dns.sls:
{% set name = pillar['event_name'] %}
{% set profile = pillar['event_profile'] %}
vm-add-dns-{{ name }}:
sqlite3.row_present:
- db: /var/lib/powerdns/pdns.sqlite3
- table: records
- where_sql: "name='{{ name }}' and type='A'"
- data:
domain_id: 1
name: {{ name }}
type: A
content: {{ ??? }}
ttl: 300
prio: 0
disabled: 0
I just need to know the IP address of the new minion. But as the orchestration run on the master, I can't just do a content: {{ grains['fqdn_ip4'] }}.
Any ideas to get minions informations ?

You can use the Salt Mine to get information from minions. To use the Salt Mine you need to know which minion you want to have information from. Luckily the reactor receives the data from the event bus. data['id'] contains the minion ID.
In the Salt Mine you can add a function to retrieve a minions IP like this:
mine_functions:
public_ip4:
- mine_function: grains.get
- fqdn_ip4
Now you can use mine.get in your sls files to get the IP address from a minion. In your case it will be the minion ID you just received from the event bus like this:
{%- for server, addrs in salt['mine.get'](data['id']', 'public_ip4') %}
{{ addrs[0] }}
{% endfor %}
Notes:
I don't use Salt Cloud and orchestration for DNS so I can't combine
your code with mine and check if it works. I hope it will be useful
for you :)
I named the mine public_ip4 instead of fqdn_ip4. It's to
clarify that this is a name in the Salt Mine and not the Grain you
are requesting.

If you don't wish to add configuration you can also do the following:
{% set ip = salt.saltutil.runner('salt.execute', [data['id']], {'fun': 'grains.get', 'kwarg': {'key':'fqdn_ip4'}})[data['id']] %}
Or as mentioned in the comments:
{% set ip = salt['saltutil.runner']('cache.grains', tgt=data['id'])[data['id']]['fqdn_ip4'][0] %}
Figured I'd add this here as a reference for others.

Related

sending customized salt event with cmd.run and onfail

I want to trigger custom named event if sls state fails.
I have following code:
check-if-needs-restarting:
{% if grains['os'] == 'CentOS' %}
cmd.run:
- name: needs-restarting -r
- onfail:
- cmd.run:
- name: salt-call event.send needs-restarting
{% endif %}
but somehow it crashes salt renderer:
An un-handled exception was caught by salt's global exception handler:
SaltRenderError: Could not locate requisite of [cmd] present in state with name
Any idea why? I tried fire_event instead but thn I dont have custom name I want "needs-restarting"
onfail like other global state arguments works only with states as arguments
See examples in the official documentation

Is it possible to have two files of translation for the same language?

Can I have two translation files for the same language ? for example :
messages1.fr.yml
hello: "Salut"
messages2.fr.yml
here: "ici"
Yes, it's called translation domain
{{ "hello"|trans({},"messages1") }}
{{ "here"|trans({},"messages2") }}
To use it in controller it is the same logic:
the args are the key, the array of parameters then the translation domain
$this->get('translator')->trans('key', [], 'yourDomain);
In your case
$this->get('translator')->trans('hello', [], 'message1);
The translation documentation is here

What does 'with context' mean when doing an import?

I've been looking for an explanation in the SaltStack docs about what 'with context' means. But there's only examples of using context.
What is 'context'?
What does it do here? And why is Debian ignored in the map.jinja file? (for example map.log_dir seems to "jump down" a level)
# config.sls
{% from "bind/map.jinja" import map with context %}
include:
- bind
{{ map.log_dir }}:
file.directory:
- user: root
- group: {{ salt['pillar.get']('bind:config:group', map.group) }}
- mode: 775
- require:
- pkg: bind
# map.jinja
{% set map = salt['grains.filter_by']({
'Debian': {
'pkgs': ['bind9', 'bind9utils', 'dnssec-tools'],
'service': 'bind9',
'config_source_dir': 'bind/files/debian',
'zones_source_dir': 'zones',
'config': '/etc/bind/named.conf',
'local_config': '/etc/bind/named.conf.local',
'key_config': '/etc/bind/named.conf.key',
'options_config': '/etc/bind/named.conf.options',
'default_config': '/etc/default/bind9',
'default_zones_config': '/etc/bind/named.conf.default-zones',
'named_directory': '/var/cache/bind/zones',
'log_dir': '/var/log/bind9',
'user': 'root',
'group': 'bind',
'mode': '644'
},
'RedHat': {
'pkgs': ['bind'],
'service': 'named',
'config_source_dir': 'bind/files/redhat',
'zones_source_dir': 'zones',
'config': '/etc/named.conf',
'local_config': '/etc/named.conf.local',
'default_config': '/etc/sysconfig/named',
'named_directory': '/var/named/data',
'log_dir': '/var/log/named',
'user': 'root',
'group': 'named',
'mode': '640'
},
Since this page is the top search result for "jinja import with context" (and the other answer doesn't actually say what it does), and I keep coming back to this page every couple of months when I need to mess with Salt but forget what with context does:
When you import foo in jinja, normally the macros you've defined in foo don't have access to variables in the file you're importing it from. As an optimization, Jinja will then cache this if you import again later in the file. If instead you do import foo with context, then the macros in foo can access the variables in the file it's being imported from. The trade-off is that Jinja no longer caches foo, so you pay in render time.
When you do include, your variables do get passed into the other file. You then render the contents of the other file and paste them in. If you do include foo without context, you don't pass the variables of the current file in. This is useful, because Jinja will optimize this by caching the contents of foo, speeding up your render.
with context is part of the jinja template engine.
You can read more about it in the jinja docs:
import context
behavior
context API
Regarding the missing debian data - is this your complete map.jinja? the snippet misses }, default='Debian') %} according to grains.filter_by

take username as a parameter to a salt state file (sls)

I'd like to use saltstack to standardize developers workspaces. As such, I need to take the username as a parameter. This could come from $USER or be typed in. Either would be fine. I see that I could write a grain to expose this, but that seems overly complicated. I'm thinking I'm missing something simpler.
I want to enable something like this
https://...../reponame.git:
git.latest:
- target: '/home/{{ username }}/src/reponame'
- user: {{ username }}
What is the best/easiest way to do this?
Maybe not elegant, but effective: use the cmd.run module to get the user that the Salt minion is currently running as (assuming that the Salt minion is running as user, and not as root):
{% set username = salt['cmd.run']('id -u -n') | trim %}
https://...../reponame.git:
git.latest:
- target: '/home/{{ username }}/src/reponame'
- user: {{ username }}
You can temporarily set/overwrite a pillar at state execution.
https://docs.saltstack.com/en/latest/topics/tutorials/pillar.html#setting-pillar-data-on-the-command-line
So, with a sls (eg. workstation/gitrepo.sls) like
{% set username = salt['pillar.get']('username') %}
https://...../reponame.git:
git.latest:
- target: '/home/{{ username }}/src/reponame'
- user: {{ username }}
You could call
salt 'phils-pc' state.sls workstation.gitrepo pillar='{"username": "phil"}'
{% set username = salt['cmd.run']('logname') | trim %}

Access to global parameters in Symfony2 and Twig

I would like to search some parameters in my parameters.yml file from a template in twig, depending on a variable. I have tried the following but it didn't work:
parameters.yml
twig:
globals:
status:
0: Paused
1: Running
2: Closed
template.html.twig
(game.status value can be 1, 2 or 3)
{% set var_status = game.status %}
{% set var_statustext = status.get(var_status) %}
<p>Status: {{ var_statustext }}</p>
Also I would like to access this parameters in the controller.
How could I do it? Thanks in advance.
You're looking for a way to access the value of the the global variable status (type => array) for a given key that is itself stored in another variable game.status (type => integer/string ).
Assuming game.status returns 1 ...
Then you can output Running using:
{{ attribute(status, game.status) }}
The attribute function is what you're looking for.

Resources