This report is written from my desktop and I’m reporting Assignment 1 from Tero Karvinen’s Configuration management systems-course. I have to do the assignment and report it now because I’m leaving to Japan for 2.5 weeks (which makes it so that I’m going to miss the first 2 classes of the course). A close friend of mine offered to help me with the given assignments since I have no earlier background using salt. Assignment started 09.10.2018 @ 17:23
What am I working with?
- Operating system: Xubuntu-18.04.1 64b (Bootable USB)
- CPU: Intel I5-6600k @ 3.5GHz
- GPU: Geforce GTX 1070, 8Gb VRAM
- RAM: 2x 8Gb DDR4 @ 2667MHz
- MoBo: Asus Maximus VIII Ranger (boot menu F8)
- Laptop: HP ProBook 655 G1
- CPU: AMD A10-5750M APU with Radeon(tm) HD Graphics
- OS: Xubuntu-18.04.1 64b (Bootable USB)
I started by booting my desktop and the laptop that my friend brought with him using a bootable USB-drive which had Xubuntu-18.04.1inside. Both systems booted normally so all I had to do was to test was that the systems actually worked and I did this by opening the web-browser.
I then opened terminal on both computers and changed the keyboard layout to Finnish
and updated the packages
sudo apt-get update
Now that I had all my personalized settings done; It was time to move to the given assignments.
Install salt master and slave with pull-architecture (master being the server). Try it out by using commands remotely.
I started by installing salt-master on my desktop and salt-minion on my slave computer.
Both setups were done at the same time.
Setting up the master
I installed salt-master
sudo apt-get -y install salt-master
Looked up my ip-adress for the slave computer
After I had installed salt-minion and configured the /etc/salt/minion file on the slave computer; I checked the unaccepted keys
And accepted the keys
sudo salt-key -A
Setting up the minion
I installed salt-minion
sudo apt-get -y install salt-minion
I configured the minion file from /etc/salt/
Master: ip.ad.re.ss id: robs-orja (slaves id)
Then I restarted the salt-minion service
sudo systemctl restart salt-minion.service
Seeing if it works
After configuring both systems it was time to try them out.
I ran a few simple commands
master$ sudo salt 'robs-orja' cmd.run 'whoami' robs-orja: root
- sudo: I used salt with sudo since it didn’t work without it.
- salt: Salt is the primary command when using salt.
- ‘slave-id’: Is the minion-computer that I am targeting. ‘*’ targets every minion and you can use it to target specific minions like ‘management.*’.
- cmd.run: Is a salt function that runs a given command on the minion computer.
- ‘whoami’: Is the command that i ran on the minion computer.
- robs-orja: root: Shows the output of the command.
I also listed the directories under /home/
master$ sudo salt 'robs-orja' cmd.run 'ls /home/' robs-orja: xubuntu
Seems to work like it should.
Try out one state from Laine and test that it works.
I decided to repeat the user.sls state from Laine.
I started by making a new directory /salt under /srv
cd /srv sudo mkdir salt
Then i created a new state called user.sls
cd salt sudo nano user.sls
The state is written in YAML
- orjatesti: is the name of the future user and the name of the part of the state.
- user.present: is the function and everything under it is going to be the settings of the user.
- fullname: Sets the full name of the user.
- shell: Privileges to use interactive shell
- home: The directory that is going to be created.
- password: Password given to the user.
- enforce_password: Set to False to keep the password from being changed if it has already been set and the password hash differs from what is specified in the “password” field. This option will be ignored if “password” is not specified, Default is
True. (I really have no clue why you need it since it would be true by default anyways)
After creating the state I applied it to my minion
master$ sudo salt '*' state.apply user
And it created a user called orjatesti on my minions computer
I applied the state again after manually deleting the user on the minion-computer and it created the user again like it should have.
Gather device-information from the computers using salts grain-mechanism.
To gather information from the minion I used the salt function grains.items
sudo salt 'robs-orja' grains.items
and it printed out a huge list of information about the target minion. Information such as the operating system version, computer model, what CPU the computer had etc.
I figured out that you can also grep the output of grains if you only want to see certain information from the minion
sudo salt 'robs-orja' grains.items | grep python
And it printed out the following information
(In this case I grepped everything that had to do with Python)
In my opinion grains.items is a really useful function, since you can get a lot of different kinds of information from the target minions computer in a matter of seconds. Usually finding information about computers is really bothersome and kind of hard to find.
Configure something outside of your test environment “real life situation”.
I decided to install something very important to my desktop using my VPS as the salt-master and my desktop as the salt-minion.
I started out by connecting to my VPS via ssh
then I installed salt-master and opened up the ports required
sudo apt-get -y install salt-master sudo ufw allow 4505/tcp sudo ufw allow 4506/tcp
And added the required directory
sudo mkdir /srv/salt
I then installed salt-minion on my desktop
sudo apt-get -y install salt-minion
After that I edited the /etc/salt/minion and added the lines
master: ip.ad.re.ss id: slave
After that I restarted my salt-minion
minion$ sudo systemctl restart salt-minion
Then i checked for unaccepted keys
master$ sudo salt-key
and accepted them
master$ sudo salt-key -A
The one tool to rule them all
I wanted the master to make sure that I would always have cmatrix on my desktop, no matter what happens.
I started by creating a state in /srv/salt
master$ cd /srv/salt master$ sudo nano cmatrix.sls ↓ cmatrix: pkg.installed
I applied the configuration
master$ sudo salt '*' state.apply cmatrix
I the tested cmatrix
minion$ cmatrix -C cyan
And it worked like a charm
I then wanted to try out state.highstate and my salty-tutor showed me how to do it.
So I removed cmatrix from my salt-minion.
minion$ sudo apt-get remove cmatrix
I created cmatrix directory under /srv/salt
master$ sudo mkdir cmatrix
I then moved the state to the new directory and renamed it to init.sls
master$ sudo mv cmatrix.sls cmatrix/ master$ cd cmatrix/master$ sudo mv cmatrix.sls init.sls
I learned that this is the correct way to create states since they get the name from the directory they are in and you can store all the files used in the state inside the same directory. This keeps the salt directory neat and tidy.
Then I created a new state top.sls in /srv/salt
master$ cd .. sudo nano top.sls ↓ base: '*': - cmatrix - notfound
The first one I created was false just to see what happens if I apply it
sudo salt '*' state.highstate
I then corrected the state
master$ sudoedit top.sls ↓ base: '*': - cmatrix
And tried it again
sudo salt '*' state.highstate
And I tested cmatrix again
minion$ cmatrix -C magenta
And it worked like a charm! (again)
Now I could use my favorite tool in Linux without having a risk of losing it.
I decided that it would be easier to make both of these assignments back to back since H2 is basically continuation from H1. H1 was technically scratching the surface of salt and H2 takes a more in-depth approach to salt, which I think will be the theme for the rest of the course.
Since I already have everything set up because of the last assignment I can just start from the first assignment.
Everything from here on out needs to be done through the usage of salts states, unless the assignment says otherwise.
Get user directories to work with Apache.
Before creating the state I went through the steps that I would take when installing Apache normally. By doing this it was easier for me to perceive what I would have to do when creating the salt state and in what order everything should be in.
- sudo apt-get -y install apache2
- to install apache
- echo moi | sudo tee /var/www/html/index.html
- to overwrite the localhost default page
- sudo a2enmod userdir
- to enable the user directory module to get user directories to work
- this creates the symlink that enables the user directory module
- mkdir public_html
- creating the directory while under /home/xubuntu/
- nano index.html
- creating the index.html while under /home/xubuntu/public_html/
- writing something inside the index.html file
- sudo systemctl restart apache2
- to restart the apache service
I started by creating a new directory under /srv/salt/ as the salt-master
master$ sudo mkdir apache
Then I created an init.sls state under /srv/salt/apache/ and the first step the state would have to take is to install apache I wrote the first line accordingly
master$ sudo nano init.sls ↓ apache2: pkg.installed
I ran the state to try it out
master$ sudo salt '*' state.apply apache
Since the state is named init.sls the state that i’m applying comes from the directory the state is located and in this case it’s in “apache”.
The state ran without errors.
I ran it again and everything succeeded but nothing changed since I already had Apache on the minion.
I then removed Apache from the minion-computer and ran the state, which installed Apache again.
Overwriting the localhost default page from /var/www/html/index.html on the target minion
I copied the index.html (that had already been overwritten with sudo tee) from /var/www/html/ to /srv/salt/apache/
master$ sudo cp /var/www/html/index.html /srv/salt/apache
Then I edited init.sls
master$ sudoedit init.sls ↓ apache2: pkg.installed /var/www/html/index.html: file.managed: - source: salt://apache/index.html
The newest line of YAML shows the path where the file I want to replace is located, what function the state is using and what I’m replacing the file with. By running this state the index.html got replaced and the localhost default page was over written instantly after the state had installed apache2.
Next up was to enable the user directory mod. Normally it’s done by using
master$ sudo a2enmod userdir
which creates a symlink (symbolic link) to the directory ../mods-enabled/ from the configuration file in ../mods-available/.
When in /etc/apache2/mods-enabled/ directory you can see what symlinks are created when you enable the module and disable it
master$ ls master$ sudo a2dismod userdir master$ ls master$ sudo a2enmod userdir master$ ls
This way you will see what modules turn up after creating the symlink and what modules disappear when you destroy the symlink
The symlinks that appeared and disappeared were userdir.conf and userdir.load
Now that you know which files get changed you can check which file the symlink targets
master$ file userdir.conf master$ file userdir.load
and in this case the symlink is to ../mods-available/userdir.conf and ../userdir.load
Now I need a way to create the symlink to both files with the state
master$ cd /srv/salt/apache/ master$ sudoedit init.sls ↓ /etc/apache2/mods-enabled/userdir.load: file.symlink: - target: ../mods-available/userdir.load /etc/apache2/mods-enabled/userdir.conf: file.symlink: - target: ../mods-available/userdir.conf
The first one creates a symlink for ../mods-enable/userdir.load, uses file.symlink function to create it which targets ../mods-available/userdir.load. The same thing happens with the second part. This basically turns the module on (creates a symlink) through the state that I apply.
The last thing to do is to restart Apache2 this is done using the service.running function.
master$ sudoedit init.sls ↓ apache2restart: service.running: - name: apache2 - watch: - file: /etc/apache2/mods-enabled/userdir.load - file: /etc/apache2/mods-enabled/userdir.conf
- I named the ID as apache2restart (it can’t be apache2 since there already is a part called apache2 in this same state).
- the function service.running (takes care that the service you have named is running).
- name: apache2 (service name).
- watch: (restarts the service if the files listed under “file:” are changed in any way).
- file: These are the files that have to be changed for the “watch:” condition to trigger.
Applying the state as a whole
master$ sudo '*' state.apply apache
init.sls ended up looking like this:
apache2: pkg.installed /var/www/html/index.html: file.managed: - source: salt://apache/index.html /etc/apache2/mods-enabled/userdir.load: file.symlink: - target: ../mods-available/userdir.load /etc/apache2/mods-enabled/userdir.conf: file.symlink: - target: ../mods-available/userdir.conf apache2restart: service.running: - name: apache2 - watch: - file: /etc/apache2/mods-enabled/userdir.load - file: /etc/apache2/mods-enabled/userdir.conf
Get PHP to work on the user directory sites.
What needs to be done when getting php to work normally.
- sudo apt-get -y install libapache2-mod-php
- to install the apache2-php-mod that allows them to work together, when installing the module it creates the symlink for you.
- you need to comment out some lines from ../mods-available/php7.2.conf
- Specificly the lines starting from
- commenting out is done using # in front of the lines
- sudo systemctl restart apache2
- restarts apache server and applies new configurations
I started by creating a new directory under /srv/salt/
master$ sudo mkdir php
and a new state under /srv/salt/php/
master$ sudo nano init.sls ↓ libapache2-mod-php: pkg.installed /etc/apache2/mods-available/php7.2.conf: file.managed: - source: salt://php/php7.2.conf phprestart: service.running: - service: apache2 - watch: - file: /etc/apache2/mods-enabled/php7.2.conf - file: /etc/apache2/mods-available/php7.2.conf
This is the first init.sls state I ended up creating, now for the test
master$ sudo salt '*' state.apply php
A keen eye might’ve already noticed that something was wrong in one part of the state; specifically the “– service: apache2” should’ve been “- name: apache“.
I corrected the error and added a new part to the state which creates a symlink for the ../mods-available/php7.2.conf
master$ sudoedit init.sls ↓ libapache2-mod-php: pkg.installed /etc/apache2/mods-available/php7.2.conf: file.managed: - source: salt://php/php7.2.conf /etc/apache2/mods-enabled/php7.2.conf: file.symlink: - target: ../mods-available/php7.2.conf phprestart: service.running: - name: apache2 - watch: - file: /etc/apache2/mods-enabled/php7.2.conf - file: /etc/apache2/mods-available/php7.2.conf
- Name of the package that I want installed
- Function that makes sure that the package already exists; if not it installs it.
- Name of the file I want to manage
- Function that handles the managing, checks if the file matches the one inside “masters source.” (if not it replaces it with the one in the masters source) or if it exists at all (if not it copies one from the masters source)
- – source: salt://php/php7.2.conf
- Masters source: “salt://” = “/srv/salt/..”
- This part isn’t nescessary (because the symlink is already created when the package is installed), but it serves as a back up if the symlink is somehow destroyed.
- ID of the restart.
- Checks if the service is running (if not, it starts it)
- name: Which service is checked.
- watch: If files listed below are changed restarts service.
- files: Files that need to have an inconsistency compared to the files in masters source which trigger the “watch:” if there are any inconsistencies.
Applying the php state
master$ sudo salt '*' state.apply php
Create a state, which makes a new name based virtual host for Apache.
What I would do manually.
- edit hosts under /etc/
- create a new .conf under etc/apache2/sites-available/ called “whatever.example.com”
- use a2ensite to create the symlink for me
- restart apache2 service
I started by editing hosts under /etc/ and added a line inside
sudoedit /etc/hosts ↓ 127.0.0.1 localhost 127.0.1.1 xubuntu 192.168.10.51 salty.example.com # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts
I then created a new .conf file under ../sites-available/
master$ cd /etc/apache2/sites-available/ master$ sudoedit saltwebsite.conf ↓ ServerName salty.example.com ServerAlias www.salty.example.com DocumentRoot /home/xubuntu/public_html/ Require all granted
I copied both of these files under /srv/salt/apache/
master$ sudo cp /etc/hosts /srv/salt/apache/ master$ sudo cp /etc/apache2/sites-available/saltwebsite.conf /srv/salt/apache/
I have to edit the init.sls that is already under /srv/salt/apache/
master$ sudoedit init.sls ↓ /etc/hosts: file.managed: - source: salt://apache/hosts /etc/apache2/sites-available/saltwebsite.conf: file.managed: - source: salt://apache/saltwebsite.conf /etc/apache2/sites-enabled/saltwebsite.conf: file.symlink: - target: ../sites-available/saltwebsite.conf
I wrote these parts in between the part where userdir symlink is created and the part where apache2 service is restarted.
The first part targets /etc/hosts and checks that the file is the same, if not it replaces it with the one from masters source or creates one if its missing completely.
The second part targets /etc/apache2/sites-available/saltwebsite.conf and checks that the file is the same, if not it replaces the file (saltwebsite.conf) with the one from masters source or creates a completely new one (saltwebsite.conf).
The third part creates a symlink (basically turns the settings on found in the saltwebsite.conf) that applies the configuration from /sites-available/saltwebsite.conf.
init.sls after adding the parts.
apache2: pkg.installed /var/www/html/index.html: file.managed: - source: salt://apache/index.html /etc/apache2/mods-enabled/userdir.load: file.symlink: - target: ../mods-available/userdir.load /etc/apache2/mods-enabled/userdir.conf: file.symlink: - target: ../mods-available/userdir.conf /etc/hosts: file.managed: - source: salt://apache/hosts /etc/apache2/sites-available/saltwebsite.conf: file.managed: - source: salt://apache/saltwebsite.conf /etc/apache2/sites-enabled/saltwebsite.conf: file.symlink: - target: ../sites-available/saltwebsite.conf apache2restart: service.running: - name: apache2 - watch: - file: /etc/apache2/mods-enabled/userdir.load - file: /etc/apache2/mods-enabled/userdir.conf - file: /etc/apache2/sites-enabled/saltwebsite.conf
I ran the state in the same fashion as before.
master$ sudo salt '*' state.apply apache
It now installed apache, added the userdir.conf from masters source created the symlink for userdir, added hosts file from masters source, added satlwebsite.conf in sites-available from masters source, created the symlink for saltwebsite.conf and restarted apache.
Create a state that creates userdir pages for users.
How I would do this manually?
- Go to /etc/skel
- Everything from /skel is copied to new user directories /home/”newuser”/
- create a directory called public_html under /skel/
- create a new file under ../skel/public_html/ called index.html (or index.php depending if you want to use php).
I wasn’t sure how to go about this, but Roope told me that there is a function which can create directories. This way I wouldn’t have to even think about /etc/skel/.
I started by creating a new directory under /srv/salt/
master$ sudo mkdir skeleton
I then created a new php file under /srv/salt/skeleton/ that will later act as the masters source file
master$ sudo nano index.php ↓ hello new user
Now to create the state
master$ sudo nano init.sls ↓ /etc/skel/public_html/: file.directory: - makedirs: True /etc/skel/public_html/index.php: file.managed: - source: salt://skeleton/index.php
First part creates “public_html” directory under /etc/skel/ if one doesn’t already exist.
Second part checks if there is any changes in the index.php file under ../skel/public_html/ if there is changes, it replaces it with the one from masters source, if the file doesn’t exist at all it copies the one from the masters source.
Applying the state
master$ sudo salt '*' state.apply skeleton
Then creating a new user on the minion computer
minion$ sudo adduser "new user"
And lastly testing that the userdir page works.
Different settings. Create different settings from the ones that you have already created in package-file-service style
I decided that a good example would be sysstat installation, since you need to manage all three from package-file-service.
What I would do manually
- Install sysstat
- Edit the sysstat file from /etc/default/
- Restart sysstat
Since this will be a completely new state I want to create a new directory under /srv/salt
master$ sudo mkdir sysstat
Then I created a new init.sls state under ../salt/sysstat and added the first part which is package installation
master$ sudo nano init.sls ↓ sysstat: pkg.installed
Then I would have to edit the sysstat file under /etc/default/ and edit the last line that says ” ENABLED=”false” ” to ” ENABLED=”true” ”
# Default settings for /etc/init.d/sysstat, /etc/cron.d/sysstat # and /etc/cron.daily/sysstat files # # Should sadc collect system activity informations? Valid values # are "true" and "false". Please do not put other values, they # will be overwritten by debconf! ENABLED="true"
Then I want to copy this file to /srv/salt/sysstat/ since I want it to be modified when the state is applied, or if the minion has for any reason changed the file
master$ sudo cp sysstat /srv/salt/sysstat/
After that I want to add a new part to the state
sudo nano init.sls ↓ sysstat: pkg.installed /etc/default/sysstat: file.managed: - source: salt://sysstat/sysstat
The new part now check if the file exists, if it does it changes it the one from masters source, if it doesn’t it adds it from masters source
Last thing is to check if the service is alive and to restart it if something has changed in the /etc/default/sysstat file we do this by using service.running function so the init.sls state should look something this
sysstat: pkg.installed /etc/default/sysstat: file.managed: - source: salt://sysstat/sysstat restartstat: service.running: - name: sysstat - watch: - file: /etc/default/sysstat
Applying the state:
master$ sudo salt '*' state.apply sysstat
This now installed sysstat, enabled it and restarted the sysstat service for its various commands to work.
This part wasn’t necessary, but I wanted to try state.highstate with all the states that I had already created so far.
I restarted the minion computer, configured the /etc/salt/minion file (masters ip and minion id: “minion name”).
Then I accepted the key from master computer and the computer was now ready to be mastered.
I started by creating top.sls under /srv/salt/
master$ sudo nano top.sls ↓ base: '*': - apache - php - skeleton - sysstat
I then applied the state on the fresh minion computer
master$ sudo salt '*' state.highstate
And it did most of the things that I had learned from the Linux Servers -course in approx. 65 seconds.
So what did I learn from all this?
- Read from top to bottom
- You have to indent it with two(2)/four(4)/six(6)/.. spaces
- Even a small syntax error like one extra ‘ at the start of the state can break the whole thing
- The error report doesn’t always give credible information where the error might’ve happened, it was a 50/50 in my case.
Why salt and other centralized management systems like puppet and chef are amazing.
- Installing something like LAMP-webstack can be done in a matter of minutes.
- Controlling multiple computers, no matter the Operating System.
- You can also target certain minions with “*” e.g. you have 5 minions called:
- Applying to minions that have windows is marked like this: ‘windows*’
- Applying to minions that have a windows laptop like: ‘windows-l*’
- And so on.
Pull architecture and why it’s better than push.
- We didn’t use pull architecture, but I learned the basics of how it works.
- Ports only need to be open for master.
- Pull basically asks the master computer for changes.
- Only master computer/server needs to be up (compared to push which needs every minion to be connected) for the changes to go through.
- So when minions come back online they ask for new changes in e.g. 1hr cycles.
- Holy triangle of centralized management
- In salt pkg.installed, file.managed and service.running
- E.g. In apache when you enable a module, it creates a symbolic link inside the ../mods-available/ directory. And the symlink targets the file in ../mods-available/ directory and uses the configurations found in the file.
- Means that when we e.g. apply a state, it can be applied multiple times without changing the outcome from the initial application.
- The most useful thing known to man
- had to use this command multiple times since I tended to forget to use sudo when in root directories.
All these assignments (H1 and H2) were done by trial and error instead of me copying and running the states. Roope tried to go through everything with me as thoroughly as possible.
Roope had me write YAML on my own and instead of telling me what was wrong; he made me figure out the problem myself by pointing out that something was wrong.
We only used Roopes and Laineens states as a source when were checking the syntax or function names (and at the start to get a better understanding of YAML:s structure).
In addition we did the assignments in small parts to better understand what certain configurations do or don’t do and why.
We also analyzed errors that occurred when they happened to get a closer understanding of the common problems when using salt.
Our session was finished – 10.10.2018 @ 23:50
The states I created can also be found from my GitHub.
 Course and its assignments: http://terokarvinen.com/2018/aikataulu-%e2%80%93-palvelinten-hallinta-ict4tn022-4-ti-5-ke-5-loppukevat-2018-5p
 Salty-tutor: https://roopelinux.wordpress.com/
 Laine salt: https://github.com/joonaleppalahti/CCM/tree/master/salt/srv/salt
 Laine user.sls src: https://github.com/joonaleppalahti/CCM/blob/master/salt/srv/salt/user.sls
 explaining parts of user.sls: https://docs.saltstack.com/en/latest/ref/states/all/salt.states.user.html