Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SaltStack: Properties (computed values) for data from SLS files?

We run several Python virtual environments on our minions managed by salt.

The name of the system is build by this schema:

project_customer_stage

Example:

supercms_favoritcustomer_p

The pillar data:

systems:
  - customer: favoritcustomer
    project: supercms
    stage: p
  - customer: favoritcustomer
    project: supercms
    stage: q 

For every virtualenv we have one linux user. Up to now we compute values like "home" like this:

{% for system in pillar.systems %}
  {% set system_name = system.project + '_' + system.customer + '_' + system.stage %}
  {% set system_home = '/home/' + system_name %}
  ...

But it is redundant.

How could we avoid copy+pasting {% set system_home = ...%}?

I am like the way object oriented programming works:

  • You could define a property for the home-directory
  • If you need a different home-directory in a special case, then you could subclass the base class and overwrite the way the base class works.

In Salt you have YAML and templating ... Both nice things. But in my case OOP would be nice.

like image 469
guettli Avatar asked Dec 21 '15 12:12

guettli


1 Answers

You can also generate pillar data dynamically. Consider the following example for a pillar file:

{% import_yaml "systems.yml" as systems %}

systems:
{% for system in systems %}
{% set name = system['name'] | default(system.project + '_' + system.customer + '_' + system.stage) %}
{% set home = system['home'] | default('/home/' + name) %}
  - name: {{ name }}
    customer: {{ system['customer'] }}
    project: {{ system['project'] }}
    stage: {{ system['stage'] }}
    home: {{ home }}
{% endfor %}

This pillar definition loads YAML data from a systems.yml file for which Salt will look in your pillar_root directory. This file might look like this (very similar to your initial example):

- customer: smith
  project: cms
  stage: p
- customer: jones
  project: shop
  stage: p
  name: jones_webshop_p  # <-- alternate name here!

Note that this example computes properties like the project name and the user's home directory dynamically, unless they are explicitly defined in your data file. For this, the Jinja default() filter is used in the pillar definition.

Using this pillar definition, you can simply use name and home in your state definitions directly from the pillar data:

{% for system in salt['pillar.get']('systems') %}
{{ system.home }}:
  file.directory
{% endfor %}

Additionally, as in my opinion these Jinja-heavy SLS files get a little hard to read, you might consider switching to the Python renderer for your pillar file:

#!py

import yaml

def run():
  systems = []
  with open('systems.yml', 'r') as f:
    data = yaml.safe_load(f)

    for system in data:
      if not 'name' in system:
        system['name'] = "%s_%s_%s" % (system['project'], system['customer'], system['stage'])

      if not 'home' in system:
        system['home'] = "/home/%s" % name

      systems.append(system)

  return {"systems": systems}
like image 198
helmbert Avatar answered Oct 05 '22 04:10

helmbert