This is an assignment h4 - Palvelinten hallinta ICT4TN022-5 in Haaga-Helia University of Applied Sciences

In this week assignment we learned about how static pillar data works in SaltStack. I’ll demonstrate the usage of pillars with few simple Salt states.

Setting Up

I’ve been testing Debian Sid in the last few days and I have encountered few problems with Salt and it. This is why I’ll demonstrate the usage of pillars and Salt states with two different minions which are running on Vagrant virtual machine and also one physical machine (which is the same as my master).

Installing Vagrant

$ sudo apt-get update
$ sudo apt-get install -y vagrant virtualbox

Vagrant Multimachine

My teacher, Tero Karvinen, had a great article about creating multiple Vagrant machines easily. They can be found here:

And also how to provision multiple minions easily (example made for Puppet but it is easily applicable for Salt). That can be found here:

I changed the latter one to work with SaltStack:

$ cat Vagrantfile
$tscript = <<TSCRIPT
apt-get update
apt-get install -y salt-minion
echo "master: ip-addr" > /etc/salt/minion
systemctl restart salt-minion
TSCRIPT

Vagrant.configure(2) do |config|
  config.vm.box = "bento/ubuntu-16.04"
  config.vm.provision "shell", inline: $tscript

  config.vm.define "slave01" do |slave01|
    slave01.vm.hostname = "slave01"
  end

  config.vm.define "slave02" do |slave02|
    slave02.vm.hostname = "slave02"
  end
end

$ vagrant up

Vagrant VM Keys

I saw that Salt gave default ids for my Vagrant minions, so I decided to manually give them their own ids:

(master)$ sudo salt-key
Accepted Keys:
linux-palvelimet
Denied Keys:
vagrant.vm
Unaccepted Keys:
vagrant.vm
Rejected Keys:
$ vagrant ssh slave01
(slave01)$ sudo nano /etc/salt/minion
master: ip-addr
id: slave01
$ vagrant ssh slave02
(slave02)$ sudo nano /etc/salt/minion
master: ip-addr
id: slave02

Lastly I accept these new keys on my master:

(master)$ sudo salt-key
Accepted Keys:
linux-palvelimet
Denied Keys:
Unaccepted Keys:
slave01
slave02
Rejected Keys:
(master)$ sudo salt-key -A
The following keys are going to be accepted:
Unaccepted Keys:
slave01
slave02
Proceed? [n/Y] y
Key for minion slave01 accepted.
Key for minion slave02 accepted.

And I test if they work as intended with a simple command:

(master)$ sudo salt '*' cmd.run 'whoami'
linux-palvelimet:
    root
slave01:
    root
slave02:
    root

And they respond!

Pillar Data

SaltStack uses pillar data for data that you don’t want to distribute to your minions. This kind of data can be for example anything confidential, e.g. passwords, ip-addresses, packages etc.

SaltStack stores pillars in their own directory called /srv/pillar.

Pillar data is stored in similar files to basic Salt states. To make a sample file containing pillar data, run:

(master)$ sudo emacs /srv/pillar/default.sls
editor: emacs

To apply this to your minions you need to make a top.sls file for that:

(master)$ sudo emacs /srv/pillar/top.sls

For testing purposes I only apply the default.sls only to one minion:

base:
  slave01:
    - default

Before you can use that data you need to refresh your pillar:

(master)$ sudo salt '*' saltutil.refresh_pillar
linux-palvelimet:
    True
slave02:
    True
slave01:
    True

Then I can see if that data is applied correctly:

(master)$ sudo salt '*' pillar.items
linux-palvelimet:
    ----------
slave01:
    ----------
    editor:
        emacs
slave02:
    ----------

And it was applied like I intended!

Obviously I want to use emacs on all my computers so I change my /srv/pillar/top.sls:

base:
  '*':
    - default
(master)$ sudo salt '*' saltutil.refresh_pillar
linux-palvelimet:
    True
slave02:
    True
slave01:
    True
	
(master)$ sudo salt '*' pillar.items
linux-palvelimet:
    ----------
    editor:
        emacs
slave01:
    ----------
    editor:
        emacs
slave02:
    ----------
    editor:
        emacs

Salt State Using Pillar Data

I decided to rewrite my Apache state which I wrote in the last week’s assignment, but now using pillar data.

I start by making default files for index.html and .conf files with few assigned variables:

(master)$ cat default_index.html 
Welcome to {{ virtual }}!
(master)$ cat default_vhost.conf 
<VirtualHost *:80>
             ServerName {{ vhost }}
             ServerAlias {{ vhost }}

             DocumentRoot /home/{{ user }}}/public_html/{{ vhost }}

             <Directory /home/{{ user }}/public_html/{{ vhost }}>
                        Require all granted
             </Directory>
</VirtualHost>

Then I start by writing the sample pillar files for this state:

(master)$ sudo emacs /srv/pillar/virtual.sls
{% if grains['virtual'] == 'oracle' %}
virtual: "Oracle VM"
{% endif %}

Then I add that file to /srv/pillar/top.sls:

base:
  '*':
    - default
  'slave*':
    - virtual

I apply the pillar data only to make Vagrant machines so I can demonstrate pillar.get later. Again I refresh the pillars and see if these values work:

(master)$ sudo salt '*' saltutil.refresh_pillar
linux-palvelimet:
    True
slave01:
    True
slave02:
    True
(master)$ sudo salt '*' pillar.items
linux-palvelimet:
    ----------
    editor:
        emacs
slave02:
    ----------
    editor:
        emacs
    virtual:
        Oracle VM
slave01:
    ----------
    editor:
        emacs
    virtual:
        Oracle VM

And seems to work!

Then I start to write the state itself:

(master)$ sudo emacs /srv/salt/vhost/init.sls
{% set vhost = 'test.example.com' %}
{% set user = {
    'oracle': 'vagrant',
    'kvm': 'topi',
}.get(grains.virtual) %}

apache2:
  pkg.installed

/etc/apache2/sites-available/{{ vhost }}.conf:
  file.managed:
    - source: salt://vhost/default_vhost.conf
    - template: jinja
    - context:
      user: {{ user }}
      vhost: {{ vhost }}

/home/{{ user }}/public_html/{{ vhost }}/index.html:
  file.managed:
    - user: {{ user }}
    - group: {{ user }}
    - mode: 644
    - makedirs: True
    - source: salt://vhost/default_index.html
    - template: jinja
    - context:
      virtual: {{ pillar.get('virtual', 'Kernel-based VM') }}

a2ensite {{ vhost }}.conf:
  cmd.run

apache2.service:
  service.running:
    - watch:
      - file: /etc/apache2/sites-available/{{ vhost }}.conf

(master)$ sudo salt '*' state.apply vhost --state-output terse
linux-palvelimet:
  Name: apache2 - Function: pkg.installed - Result: Clean Started: - 22:59:00.974486 Duration: 61.367 ms
  Name: /etc/apache2/sites-available/test.example.com.conf - Function: file.managed - Result: Changed Started: - 22:59:01.042373 Duration: 49.766 ms
  Name: /home/topi/public_html/test.example.com/index.html - Function: file.managed - Result: Changed Started: - 22:59:01.092480 Duration: 36.272 ms
  Name: a2ensite test.example.com.conf - Function: cmd.run - Result: Changed Started: - 22:59:01.130797 Duration: 54.15 ms
  Name: apache2.service - Function: service.running - Result: Changed Started: - 22:59:01.244839 Duration: 2472.039 ms

Summary for linux-palvelimet
------------
Succeeded: 5 (changed=4)
Failed:    0
------------
Total states run:     5
Total run time:   2.674 s
slave02:
  Name: apache2 - Function: pkg.installed - Result: Changed Started: - 22:59:01.370034 Duration: 16100.291 ms
  Name: /etc/apache2/sites-available/test.example.com.conf - Function: file.managed - Result: Changed Started: - 22:59:17.472643 Duration: 618.847 ms
  Name: /home/vagrant/public_html/test.example.com/index.html - Function: file.managed - Result: Changed Started: - 22:59:18.091606 Duration: 277.883 ms
  Name: a2ensite test.example.com.conf - Function: cmd.run - Result: Changed Started: - 22:59:18.370043 Duration: 31.146 ms
  Name: apache2.service - Function: service.running - Result: Changed Started: - 22:59:18.435723 Duration: 2167.504 ms

Summary for slave02
------------
Succeeded: 5 (changed=5)
Failed:    0
------------
Total states run:     5
Total run time:  19.196 s
slave01:
  Name: apache2 - Function: pkg.installed - Result: Changed Started: - 22:59:01.564832 Duration: 17404.635 ms
  Name: /etc/apache2/sites-available/test.example.com.conf - Function: file.managed - Result: Changed Started: - 22:59:18.971866 Duration: 647.648 ms
  Name: /home/vagrant/public_html/test.example.com/index.html - Function: file.managed - Result: Changed Started: - 22:59:19.619600 Duration: 273.673 ms
  Name: a2ensite test.example.com.conf - Function: cmd.run - Result: Changed Started: - 22:59:19.894015 Duration: 30.493 ms
  Name: apache2.service - Function: service.running - Result: Changed Started: - 22:59:19.956830 Duration: 2159.79 ms

Summary for slave01
------------
Succeeded: 5 (changed=5)
Failed:    0
------------
Total states run:     5
Total run time:  20.516 s

And it worked!

Then I can test if these virtual hosts work by running:

(master)$ sudo salt '*' cmd.run "curl -sH 'Host: test.example.com' localhost"
linux-palvelimet:
    Welcome to Kernel-based VM!
slave02:
    Welcome to Oracle VM!
slave01:
    Welcome to Oracle VM!

And here we can also see that the default value set in pillar.get also works!

These files can also be found on my GitHub at https://github.com/topikettunen/salt-states

Resources