IT 3110: System Automation

Automated Configuration - SaltStack

Salt stack Install

Master:

Minion:

Terraform

Make sure minions can find the salt master

When a minion starts, by default it searches for a system that resolves to the salt hostname on the network. If found, the minion initiates the handshake and key authentication process with the Salt master. This means that the easiest configuration approach is to set internal DNS to resolve the name salt back to the Salt Master IP.

Minions finding master

Otherwise, the minion configuration file will need to be edited so that the configuration option master points to the DNS name or the IP of the Salt Master:

In /etc/salt/minion, you have to:

    master: saltmaster.example.com

Then, you can do a service salt-minion restart

Salt stack keys

After you think you have installed the master and minions, you must accept the minion keys. On master:

  • sudo salt-key -L
  • sudo salt-key -A (accept all the keys)

Salt stack ping test

  • sudo salt '*' test.ping

or execute shell commands on multiple systems simultaneously with:

  • salt '*' cmd.run 'ls -l /etc'

Salt command structure

  • `salt '*' pkg.install cowsay
    • '*' refers to the target
      • Could also be minion name (other globbing functions)
    • pkg.install refers to the module function
    • cowsay is the args to the function

Salt

Just as when we used ansible, we shouldn't use 'raw' shell commands for everything. Salt has many 'execution functions' that we should use:

  • salt '*' disk.usage
  • salt '*' network.interfaces

Salt targeting

Can target hosts by:

    • = all hosts
  • 'minion*' = all hosts that start with minion
  • salt -G 'os:Ubuntu' test.ping targets host running Ubuntu
  • more

Salt Top file

A Top file describes where states should be applied (maybe analogous to ansible inventory file). States and top file work together.

Should be place in /srv/salt/top.sls

Top file

Create a top file like:

   #top.sls
   base:
     '*':
       - common
     'ns*':
       - nettools
  • sudo salt '*' state.apply

Salt states

  • Defined using yaml (kind of analogous to playbooks)

      apache:                 # ID declaration
        pkg:                  # state declaration
          - installed         # function declaration
    
  • Two space indentation

Salt state example

   #/srv/salt/examples.sls
   install vim:
     pkg.installed:
       - name: vim
  • sudo salt 'ns1*' state.apply examples

Salt state example

   remove vim:
     pkg.removed:
       - name: vim

Salt state example

  • These do the same thing:

      /opt/another_new_directory:
        file.directory:
          - user: root
          - group: root
          - mode: 755
      
      create my_new_directory:
        file.directory:
          - name: /opt/my_new_directory
          - user: root
          - group: root
          - mode: 755
    

Salt service example

    apache2:
      pkg.installed
    
    foo:
      service.running:
        - name: apache2
  • Note that I couldn't refer to both as apache2... I can name them though.

Salt state

    tom:
      user.present:
        - shell: /bin/bash
        - home: /home/tom
        - groups:
          - sudo
    
    pete:
      user.absent

Salt random stuff

  • List your minions
    • salt-run manage.up
  • Remember that salt-key -L just listed keys that we had accepted or not, it doesn't show the state of our minions.

Salt Grains

Salt comes with an interface to derive information about the underlying system. This is called the grains interface, because it presents salt with grains of information. Grains are collected for the operating system, domain name, IP address, kernel, OS type, memory, and many other system properties.

  • salt '*' grains.ls #lists grains available
  • salt '*' grains.items #shows the actual data
  • salt -G 'os:Ubuntu' test.ping #targets host running Ubuntu
  • salt '*' grains.item zmqversion #shows just this grain detail

can create custom grains (have to configure on each minion)

Salt pillar

Pillar is an interface for Salt designed to offer global values that can be distributed to minions. (Similar to grains, but configured on the server)

See the link here

Salt Variables

  • Created in /srv/pillar

      #core.sls
      foo: bar
      users:
        - larry
        - moe
        - curly
      some_more_data: data
    

Salt Variables

Also created in /srv/pillar/top.sls

    base:
      '*':
        - core

View variables with sudo salt '*' pillar.items

Salt Using variables

Created in /srv/salt

    #make_users.sls
    {% for user in pillar['users'] %}
    add_{{ user }}:
      user.present:
        - name: {{ user }}
    {% endfor %}

or

    {% for user in pillar['users'] %}
      {{ user }}:
        user.present
    {% endfor %}

Salt stack debug

You can see your rendered jinja by doing:

sudo salt 'minion-2' state.show_sls make_users

Won't actually execute it

Salt stack debug

If you are getting the following error:

  • AttributeError: 'module' object has no attribute 'SSL_ST_INIT'

You may be able to solve it by doing a sudo pip install --upgrade pyOpenSSL

Requiring other states

Sometimes we may want to make sure a certain state exists before applying another one.

    apache:
      pkg.installed: []
      service.running:
        - require:
          - pkg: apache
    
    /var/www/index.html:                        # ID declaration
      file:                                     # state declaration
        - managed                               # function
        - source: salt://webserver/index.html   # function arg
        - require:                              # requisite declaration
          - pkg: apache                         # requisite reference

Require vs watch

Not every state supports watch. If the file we are watching changes, we will restart the service below.

    /etc/httpd/extra/httpd-vhosts.conf:
      file.managed:
        - source: salt://webserver/httpd-vhosts.conf
    
    apache:
      pkg.installed: []
      service.running:
        - watch:
          - file: /etc/httpd/extra/httpd-vhosts.conf
        - require:
          - pkg: apache

Templating sls modules

SLS modules may require programming logic or inline execution. This is accomplished with module templating. The default module templating system used is Jinja2.

   {% for usr in ['moe','larry','curly'] %}
   {{ usr }}:
     user.present
   {% endfor %}

Would generate:

    moe:
      user.present
    larry:
      user.present
    curly:
      user.present

Templating sls modules

Example with salt grains;

    apache:
      pkg.installed:
        {{% if grains['os'] == 'RedHat' %}}
        - name: httpd
        {{% elif grains['os'] == 'Ubuntu' %}}
        - name: apache2
        {{% endif %}}