Infrastructure as Code Basics

Week 1 of Configuration Management Systems course.

This is the first week of the Configuration Management Systems course at Haaga-Helia University of Applied Sciences. The course lasts for the next 2.5 months until the end of 2022. This week we learned the basic concepts of master-minion architecture, Salt fundamentals, remote code execution, and infrastructure as code.

Course material: https://terokarvinen.com/2022/palvelinten-hallinta-2022p2/

Environment: VirtualBox VM running Debian 11 XFCE. VM has 4 GB of RAM and 40 GB of disk space.


Read and summarize.

Objective: Read the provided material and summarize with a few points.

Karvinen 2020: Command Line Basics Revisited

  • Many commands have built-in help e.g. ls ā€”help. The manual ā€” man ā€” isnā€™t the only place to read documentation.

Karvinen 2018: Salt States ā€“ I Want My Computers Like This

  • Master instructions are stored in /srv/salt.
  • Use state.apply to run the instruction file.
  • Create a top.sls file which runs automatically every 30 minutes.

Karvinen 2006: Raportin kirjoittaminen

  • A report is a good way to debug
  • If you give your report to someone else they have to be able to replicate all actions using the report.
  • List your sources.

Salt file creation

Objective: Create a file using a Salt command (state.single).

I started by updating packages and installing salt-master and salt-minion.

$ sudo apt-get update   
$ sudo apt-get install -y salt-master salt-minion

Salt master and minion install

I constructed the command from what I remembered from the example shown in class.

$ sudo salt --local state.single file.managed /tmp/foobar.txt
Usage: salt [options] '<target>' <function> [arguments]

salt: error: no such option: --local

I ran the command

First I thought the ā€”local target was wrong because the error message mentioned it. I looked up my notes and spotted my actual error which was using salt and not salt-call. I fixed the command and ran it again. This time it went through.

$ sudo salt-call --local state.single file.managed /tmp/foobar.txt

I ran the fixed command

I double-checked that foobar.txt was actually created to /tmp/.

foobar.txt was listed in /tmp/


Creating a idempotent Hello World as infrastructure code

I created a directory to house the Hello World code.

$ cd /srv
$ sudo mkdir salt/helloworld
mkdir: cannot create directory ā€˜salt/helloworldā€™: No such file or directory

error message

Oops, I forgot sudo.

$ sudo mkdir -p  salt/helloworld

I created the init.sls YAML file which will contain the code.

$ cd /salt/helloworld
$ sudoedit init.sls
$ cat init.sls
/tmp/helloworld:
  file.managed:
    contents: "Hello World"

I ran the command to run the code but it returned with an error message.

$ sudo salt-call --local state.apply helloworld
local:
    Data failed to compile:
----------
    State '/tmp/helloworld' in SLS 'helloworld' is not formed as a list

error message

I made a mistake in the code. The third line should start with a dash because itā€™s supposed to be a list. I went and fixed my mistake and ran the command again.

$ sudoedit init.sls
$ cat init.sls
/tmp/helloworld:
  file.managed:
    - contents: "Hello World"

$ sudo salt-call --local state.apply helloworld

helloworld file was created

I again double-checked that the file was created properly.

file was created successfully


Collect system information using Salt

Objective: Collect information about the system using Salt and the grains.items state function

I used the grains.items state function. I got back a long list of information.

$ sudo salt-call --local grains.items

list of system info

I did and additional call to get specific information.

$ sudo salt-call --local grains.item osfullname osrelease

operating system name and release


Creating a new user and group using Salt

Objective: Try out state functions other than file.managed. Important ones are pkg.installed, file.managed, service.running, file.symlink, user.present, group.present. For help: ā€œsudo salt-call ā€”local sys.state_doc pkg.installed|lessā€

I wanted to try the user.present and group.present state functions to create a new user and a new group to which to add the new user to.

I started by creating a new directory to /srv/salt/.

$ sudo mkdir createtestuser
$ sudoedit createtestuser/init.sls

I wrote the init file using the information I found from state_doc.

salt-test-user:
  user.present:
  	- fullname: Salt test user - Tuomas Valkamo
  	- password: $5$S5ZMYPuSpqukbmKB$90MzKLG/HBwUPTjCrdD83HGPeKacvOe8E13zIpOfYNA
  	- createhome: False

salt-test-group:
  group.present:
    - addusers:
      - salt-test-user

The documentation recommended generating a hash for the user password using mkpasswd -m sha-256, so thatā€™s what I did. I set createhome to be False so that there would be no /home directory created.

Regarding the user and group name, I chose to include the names as the state ID because that is what the example in the state_doc did. There was a name argument that could be set but I left it out.

I ran the file to see what would happen.

$ sudo salt-call --local state.apply createtestuser
[CRITICAL] Rendering SLS 'base:createtestuser' failed: found character that cannot start any token
local:
    Data failed to compile:
----------
    Rendering SLS 'base:createtestuser' failed: found character that cannot start any token

error message

Unsurprisingly something went wrong. My first thought was to add double quotes around the String values fullname and password.

salt-test-user:
  user.present:
  	- fullname: "Salt test user - Tuomas Valkamo"
  	- password: "$5$S5ZMYPuSpqukbmKB$90MzKLG/HBwUPTjCrdD83HGPeKacvOe8E13zIpOfYNA"
  	- createhome: False

salt-test-group:
  group.present:
    - addusers:
      - salt-test-user

I ran the state.apply command again but the same error persisted.

I googled the error message and found a Stack Overflow answer that diagnosed the issue to be the use a tab indentation instead of spaces somewhere. Unfortunately, in the editor Iā€™m using (micro) there is no way of seeing the difference between the two.

I went through all the lines and deleted the indentations and replaced them with spaces. The problem spot turned out to be the list under user.present. Iā€™m just glad my file wasnā€™t longer than the ten lines I had.

Finally I ran the state.apply command again. This time it worked.

$ sudo salt-call --local state.apply createtestuser

user and group were created

I checked that the user was created by reading /etc/passwd file.

$ cat /etc/passwd

salt-test-user shows up

The salt-test-user seemed to have a home directory even though I specified it to not have one. I checked the /home directory see if it was there.

$ cd /home
$ ls -al

there was no salt-test-user home directory

Thankfully nothing was there. Weird that /etc/passwd showed /home/salt-test-user.

I also checked that the new group was created

$ groups salt-test-user

salt-test-user was added to salt-test-group


Profile picture

Written by Tuomas Valkamo who is studying IT at Haaga-Helia University of Applied Sciences.

Check out my GitHub. or Connect with me.

Ā© 2022 Tuomas Valkamo