Getting started with Hiera

I am using puppet since the end of 2012 and I finally found a use case for Hiera. This is my way of implementing it:

What is Hiera
Hiera is split into two parts: The backend is a key/value store that supports hierarchies. The data can be stored in flat files like yaml or in complex RDBMS like postgresql. The other part is the frontend, this are are tools that you use to access the data, for example a shell client or a Hiera lookup function in puppet.

Justification
Why should anybody use Hiera? What are the advantages? There are two reasons for using Hiera. You want to separate your data from code and from business logic. This allows you a higher level of abstraction. Also Hiera supports a hierarchy. this makes it easy for your to automatically assign the correct values to your busines logic. An example: Every of your nodes should report to the same Zabbix master. Except for every node with two two interfaces, they should use their internal interface and IP. And axcept for every node in the management LAN, this should also use the internal IP range but public interface and so on and so on. There is always a big base of nodes that shares the same value but several edge cases that need exceptions. Normally you would use huge case and if statements to determine which node gets which value, Hieras hierarchie makes this obsolet. Let us take a look at the implementation:

Implementation
I’m running r10k on my masters to deploy dynamic environments, I want to bundle Hiera into my controlrepo. hiera.yaml is a per-environment configuration file which defines the path to the data and the hierarchy. My hiera.yaml:

---
:backends:
  - yaml
:hierarchy:
  - clientcert/%{clientcert}
  - puppet_role/%{puppet_role}
  - type/%{type}
  - global

:yaml:
  :datadir: /etc/puppet/environments/%{environment}/hiera

Hiera can work with variables (facts in this case, but unlike to puppet, without :: in front of them), this allows us to point to a Hiera directory in our environment. This directory has a global file(global.yaml), for the highest lookup, than a type lookup (I’ve got two types of systems, hypervisors and infrastructure nodes, both types highly differ in their data), than a role based directory and a node based one for the deepest lookup (this layout highly depends on your infrastructure, maybe you also need a layer for the location or something else).

$ tree
.
├── documentation
├── hiera
│   ├── clientcert
│   ├── global.yaml
│   ├── puppet_role
│   └── type
├── hypervisors.yaml
│   └── infrastructure.yaml
├── hiera.yaml
├── manifests
│   └── site.pp
└── Puppetfile

I created the infrastructure.yaml as an example file:

---
zabbix_server_ip: '192.168.1.15'

You can now commit everything and redeploy your environment with r10k, after that, you can test Hiera via CLI:

root@puppet-master ~ # hiera zabbix_server_ip environment=hieratest type=infrastructure --config /etc/puppet/environments/hieratest/hiera.yaml --debug
DEBUG: 2015-11-26 16:34:38 +0100: Hiera YAML backend starting
DEBUG: 2015-11-26 16:34:38 +0100: Looking up zabbix_server in YAML backend
DEBUG: 2015-11-26 16:34:38 +0100: Looking for data source type/infrastructure
DEBUG: 2015-11-26 16:34:38 +0100: Found zabbix_server in type/infrastructure
192.168.0.8
root@puppet-master ~ #

To use Hiera in Puppet, I had to symlink the Hiera config:

ln -sf /etc/puppet/environments/hieratest/hiera.yaml /etc/puppet/hiera.yaml
ln -sf /etc/puppet/environments/hieratest/hiera.yaml /etc/hiera.yaml

Hiera takes a look at /etc/hiera.yaml as the default config path, Puppet accepts one global Hiera config which isn’t environment specific, so it has to be at /etc/puppet/hiera.yaml. You can also enforce the links via Puppet (maybe in your puppetmaster profile):

file{['/etc/hiera.yaml', '/etc/puppet/hiera.yaml']:
  ensure  => 'link',
  source  => '/etc/puppet/environments/production/hiera.yaml',
}

(this should create two symlinks, but creates two copies of the original file, not sure if I use the file resource wrong or if it is a bug)

You can also change the path to Puppets Hiera config, than you only need one symlink.

You need to restart your master to accept the new Hiera config. Than you finally can use Hiera in your Puppet code:

  class { '::zabbix::agent':
    server                => hiera('zabbix_server_ip'),
    zabbix_package_state  => 'latest',
    zabbix_version        => '2.4',
    manage_resources      => false,
    serveractive          => '10.111.2.50',
    hostmetadata          => $::sach_type,
    hostmetadataitem      => 'system.uname',
    listenip              => $ipaddr,
  }

Hiera also support “automatic param lookup”, where you specify a class param like this:

class profiles::zabbixagent (
  $zabbix_server_ip,
) {
  class { '::zabbix::agent':
    server                => $zabbix_server_ip,
    zabbix_package_state  => 'latest',
    zabbix_version        => '2.4',
    manage_resources      => false,
    serveractive          => '10.111.2.50',
    hostmetadata          => $::sach_type,
    hostmetadataitem      => 'system.uname',
    listenip              => $ipaddr,
  }
}

And you include that profile in your role:

class roles::awesomethingything{
  include ::profiles::beautifulcode
  include ::profiles::omgthisissonice
  include ::profiles::zabbixagent
}

in your infrastructure.yaml, you change the explicit key to a class param key:

---
profiles::zabbixagent::zabbix_server_ip: '192.168.1.15'

Summary
Puppet will notice that you included a class via include, without passing any variables. This follows a lookup of the class param in Hiera. The Hiera syntax just needs to be class:subclass::paramoftheclass. If you use Hiera like this, you don’t need explicit hiera() calls, but it will be hard to determine where values are coming from.

Posted in 30in30, General, Linux, Puppet | Leave a comment

Link collection of the week

Here is another collection of links I found during the past week:

Posted in 30in30, General, Internet found pieces | Leave a comment

Extending Disk Capacity for KVM Virtual Machines

From time to time, your data grows and a virtual machine is getting filled up. Here is a short tutorial for extending the disk capacity for KVM machines on LVM2:

First step: Poweroff the machine. This is a good situation to also update the kernel. Now you can extend the LVM2 volume in the host:

host@host01 ~ # lvextend -L 100G /dev/vg0/mysql01
  WARNING: lvmetad is running but disabled. Restart lvmetad before enabling it!
  Size of logical volume vg0/mysql01 changed from 50.00 GiB (12800 extents) to 100.00 GiB (25600 extents).
  Logical volume mysql01 successfully resized
root@host01 ~ #

Now you can boot up any live linux and determine the correct partition and disk:

root@rescue ~ # blkid
/dev/loop0: UUID="40c4ea95-0ecc-4c51-9f3e-e49d8f62f160" TYPE="ext2"
/dev/sda1: UUID="c8357796-3185-4f8f-a987-79652339bb0d" TYPE="swap" PARTUUID="00096cad-01"
/dev/sda2: UUID="c0b805e3-30d0-4af2-9724-58c651e41641" TYPE="ext4" PARTUUID="00096cad-02"
/dev/sda3: UUID="bb435f41-f0e4-438b-a4b0-b17874fd0504" TYPE="ext4" PARTUUID="00096cad-03"
root@rescue ~ # parted /dev/sda print
Model: QEMU QEMU HARDDISK (scsi)
Disk /dev/sda: 107GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system     Flags
 1      1049kB  2149MB  2147MB  primary  linux-swap(v1)
 2      2150MB  2686MB  537MB   primary  ext4
 3      2688MB  53.7GB  51.0GB  primary  ext4

root@rescue ~ #

My VM has only one disk, sda1 is swap, sda2 is for /boot and sda3 is the rest, the Disk capacity amounts to 107GB, sda3 only has 51.0GB, this is the partition that I want to grow:

parted /dev/sda resizepart 3 100%

Than we need to do a fsck, otherwise we can not grow the filesystem:

root@rescue ~ # fsck.ext4 -fvC0 /dev/sda3
e2fsck 1.42.12 (29-Aug-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity                                        
Pass 4: Checking reference counts
Pass 5: Checking group summary information                                     
                                                                               
       67570 inodes used (2.18%, out of 3100800)
        4449 non-contiguous files (6.6%)
         136 non-contiguous directories (0.2%)
             # of inodes with ind/dind/tind blocks: 2603/46/0
             Extent depth histogram: 16320/165
     6130225 blocks used (49.23%, out of 12451072)
           0 bad blocks
           2 large files

       56433 regular files
        5856 directories
           2 character device files
           0 block device files
           2 fifos
          11 links
        5241 symbolic links (5030 fast symbolic links)
          27 sockets
------------
       67572 files
root@rescue ~ # 

# the grow:

root@rescue ~ # resize2fs -p /dev/sda3 
resize2fs 1.42.12 (29-Aug-2014)
Resizing the filesystem on /dev/sda3 to 25558272 (4k) blocks.
The filesystem on /dev/sda3 is now 25558272 (4k) blocks long.

root@rescue ~ #

Now you can reboot and your system should boot up and report the new size for sda3:

root@mysql01 ~ # dfc
FILESYSTEM  (=) USED      FREE (-) %USED AVAILABLE     TOTAL MOUNTED ON
rootfs      [======--------------]   29%     67.9G     95.8G /
udev        [--------------------]    0%     10.0M     10.0M /dev
tmpfs       [=-------------------]    1%      1.6G      1.6G /run
/dev/sda3   [======--------------]   29%     67.9G     95.8G /
tmpfs       [=-------------------]    0%      3.9G      3.9G /dev/shm
tmpfs       [--------------------]    0%      5.0M      5.0M /run/lock
tmpfs       [--------------------]    0%      3.9G      3.9G /sys/fs/cgroup
/dev/sda2   [===-----------------]   14%    419.3M    487.9M /boot
tmpfs       [--------------------]    0%    624.1M    624.1M /run/user/0
root@mysql01 ~ #
Posted in 30in30, General, Linux, Short Tips | Leave a comment

DRY – Don’t Repeat Yourself

Don’t Repeat Yourself – This is an important mantra, I’m trying to work like this for the past years, but the fancy abbreviation never came up my mind, I just found it online. What does it mean? We system administrators often have repeating tasks that we should automate. This has two purposes:

Time is expensive
Things that are automated don’t consume your time, your time is expensive so we all should use it wisley. Automating an assignment often takes longer than doing it one or two times by hand. But how long does it take if your colleage, who doesn’t know the system, has to do it by hand. Or how long do you need if you need to do it again in three years and you forgot almost everything?

Deterministic stuff is important
An assignment often consists of multiple tasks, and people often forget one or a few tasks and than the complete assignment fails. This won’t happen if you automate it wisley. Points for a good automatization:

  • Testable
  • Deterministic
  • Repeatable
  • Idempotent

Do you know any other important points? Let me know!

the DRY mantra is an essential point for beeing a good system administrator so I added it to the Sysadmin Manifesto

Posted in 30in30, General, Linux, Puppet | 1 Comment

Installing pry on verrrrry old systems

Everybody loves pry. If you don’t know it: pry is an interactive ruby shell, like irb, but nicer (it hase more colours![and other cool features]). I’ve got a few old CentOS 6 nodes with a very old ruby version:
# ruby --version
ruby 1.8.7 (2013-06-27 patchlevel 374) [x86_64-linux]

The latest pry releases don’t support Ruby 1.8.7 anymore, you can install it, but you can’t start it anymore:

# gem install pry
Successfully installed coderay-1.1.0
Successfully installed slop-3.6.0
Successfully installed method_source-0.8.2
Successfully installed pry-0.10.3
4 gems installed
Installing ri documentation for coderay-1.1.0...
Installing ri documentation for slop-3.6.0...
Installing ri documentation for method_source-0.8.2...
Installing ri documentation for pry-0.10.3...
Installing RDoc documentation for coderay-1.1.0...
Installing RDoc documentation for slop-3.6.0...
Installing RDoc documentation for method_source-0.8.2...
Installing RDoc documentation for pry-0.10.3...

And starting failes :(

# pry
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': /usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:39: syntax error, unexpected ':', expecting ')' (SyntaxError)
    output.puts Pry.view_clip(value, id: true)
                                        ^
/usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:43: syntax error, unexpected kDO_BLOCK, expecting kEND
  DEFAULT_EXCEPTION_HANDLER = proc do |output, exception, _|
                                     ^
/usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:43: syntax error, unexpected '|', expecting '='
/usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:84: syntax error, unexpected kDO_BLOCK, expecting ']'
                proc do |_, _, _pry_|
                       ^
/usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:84: syntax error, unexpected '|', expecting '='
/usr/lib/ruby/gems/1.8/gems/pry-0.10.3/lib/pry.rb:87: syntax error, unexpected ',', expecting $end
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
        from /usr/lib/ruby/gems/1.8/gems/pry-0.10.3/bin/pry:9
        from /usr/bin/pry:19:in `load'
        from /usr/bin/pry:19

But we can uninstall it and install the latest version from the older minor release (0.9.0):

# gem uninstall pry
Remove executables:
        pry

in addition to the gem? [Yn]  y
Removing pry
Successfully uninstalled pry-0.10.3

# gem install pry --version=0.9.12.6 
Successfully installed pry-0.9.12.6
1 gem installed
Installing ri documentation for pry-0.9.12.6...
Installing RDoc documentation for pry-0.9.12.6...

And now, pry works again \o/

# pry
[1] pry(main)> puts "hi"
hi                      
=> nil
[2] pry(main)>
Posted in 30in30, General, Linux, Short Tips | 1 Comment

Fixing a messed up git directory

Following situation:
You have got a cloned repository in your home directory, you noticed that something changed upstream und you want to get all the fancy changes. You do a:

git fetch upstream && git pull upstream tags/2.1.0

to get the latest tag. What you didn’t check: What is your current branch, have you uncommited changes? And boom, everything is broken:

$ git status
Auf Branch master
Ihr Branch ist auf dem selben Stand wie 'origin/master'.
Sie haben nicht zusammengeführte Pfade.
 (beheben Sie die Konflikte und führen Sie "git commit" aus)

zum Commit vorgemerkte Änderungen:

	neue Datei:     .coveralls.yml
	neue Datei:     .fixtures.yml
	neue Datei:     .gitignore
	neue Datei:     .gitmodules
	neue Datei:     .sync.yml
	neue Datei:     .travis.sh
	neue Datei:     .travis.yml

Nicht zusammengeführte Pfade:
  (benutzen Sie "git add/rm <Datei>...", um die Auflösung zu markieren)

	von beiden hinzugefügt: CHANGELOG.md
	von beiden hinzugefügt: Gemfile
	von beiden hinzugefügt: README.md
	von beiden hinzugefügt: lib/puppet/provider/kernel_parameter/grub2.rb
	von beiden hinzugefügt: metadata.json
	von beiden hinzugefügt: spec/spec_helper.rb

How do we fix that?
We start with:

git reset --hard

What does it do?

Resets the index and working tree. Any changes to tracked files in the working tree since
are discarded.

Than we add:

git clean --force -d

This basically deletes all untracked directories and files. We can simulate this with:

git clean --force -d --dry-run

Now we got a clean directory again, all files with merge conflicts or whatsoever are gone. Please note that this will also remove every change that you did before the pull but forgot to commit. If you want to keep that changes than you shouldn’t copy&paste the git commands!

Posted in 30in30, General, Linux, Short Tips | Leave a comment

How to be a good Admin/DevOps/IT person

There are two types of system administrators/DevOps/admins/whatever, the first group has a normal 9-5 job, they stop thinking about IT after work, it is a normal job for them. Then there is another group, these people really love their job, it is their passion. They go to conferences on the weekend, they provide help for juniors in their company or to complete strangers on the internet. Another important difference: They feel responsible for their infrastructure, they have got a manifest or guidelines or directions for work and they honour them.

I blogged my Sysadmin Manifest a while back and wanted to write about the things at work that are important to honour these guidelines and what it takes to implement these rules in your team. While doing a bit of research I found a perfect article on the internet:

On Becoming a Senior Engineer from Katherine Daniels

She wrote about all the important points that I planned to mention so I will not repeat it.

@all: Please read her awesome post and take a look at the others (and also you can take a look at my Sysadmin Manifest and provide some feedback or add a point)

@Katherine thanks for the great post!

Posted in 30in30, General, Internet found pieces, Linux, Nerd Stuff | Leave a comment

#puppethack is coming again!

The event description:

###########
Join us for #puppethack, our online puppet community hack day, on December 15th!
#puppethack is a collaborative, relaxed online puppet community hack day. It will be an opportunity for Puppet community members and Puppet Labs employees to tackle interesting or fun puppet projects that they haven’t had the time for. Everyone will gather online, getting to know each other, and collaborating on pull requests for modules and code.
Who it is for: #puppethack is an event for intermediate/advanced Puppet users, contributors, developers, module authors, docs writers, and anyone else contributing to the Puppet community.
Don’t forget that this, like all Puppet Community participation, falls under our community guidelines, which also contain helpful tips for using IRC, our bug tracker and other relevant tools.
Join us online in the #puppethack IRC channel on Freenode! You’re welcome to drop in at any point during the day – the event has extended hours to reflect the many timezones that Puppet contributors call home. We look forward to chatting with you!

###########

I participated a very little bit in the last event (it was in june?), there was a lot of module hacking going around, and I’m planning to hack on my backup module this time. #puppethack will start on the 15. of December, you can register here. Last time there were even prizes! If I remember correctly, Puppetlabs draw a lot every hour, I won the price in the last hour, a 50$ amazon voucher, which I used for the smoker.

Posted in 30in30, General, Linux, Nerd Stuff, Puppet | Leave a comment

Augeas Bug while playing with ” in /etc/default/grub

Today seems to be the day of buggy software. I am using the Puppet module herculesteam/augeasproviders_grub to manage entries in /etc/default/grub on Debian and CentOS systems, here is an example:

  $elevator = $::virtual ? { 
    'kvm'       => 'noop',
    'physical'  => 'deadline',
    'openvzhn'  => 'deadline',
  }
  Kernel_parameter {
    ensure    => present,
    provider  => 'grub2',
  }
  kernel_parameter { 'quiet':
  }
  kernel_parameter { 'elevator':
    value => $elevator,
  }
  kernel_parameter {'LANG':
    value => 'en_US.UTF-8',
  }
  kernel_parameter {'KEYBOARDTYPE':
    value => 'pc',
  }
  kernel_parameter {'KEYTABLE':
    value => 'de-latin1-nodeadkeys',
  }

This should result in the following line in /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="nomodeset elevator=noop KEYBOARDTYPE=pc KEYTABLE=de-latin1-nodeadkeys LANG=en_US.UTF-8 quiet"

This works fine, but once every two months it fails and Puppet creates the following line (inserted quote):
GRUB_CMDLINE_LINUX_DEFAULT="nomodeset" elevator=noop KEYBOARDTYPE=pc KEYTABLE=de-latin1-nodeadkeys LANG=en_US.UTF-8 quiet"

I’ve seen this issue on multiple machines in the past half year, but I’m unable to reproduce it. It seems to happen totally random. I’m currently running Puppet 3.8.4 with future parser on all machines. My Augeas/Ruby Versions are:

Debian:
$ dpkg -l | grep augeas; puppet --version; ruby --version
ii augeas-lenses 1.2.0-0.2 all Set of lenses needed by libaugeas0 to parse config files
ii augeas-tools 1.2.0-0.2 amd64 Augeas command line tools
ii libaugeas-ruby 0.5.0-2 all Transitional package for ruby-augeas
ii libaugeas0 1.2.0-0.2 amd64 Augeas configuration editing library and API
ii ruby-augeas 0.5.0-2+b2 amd64 Augeas bindings for the Ruby language
3.8.4
ruby 2.1.5p273 (2014-11-13) [x86_64-linux-gnu]

CentOS:
$ rpm -qa | grep augeas; puppet --version; ruby --version
augeas-libs-1.1.0-17.el7.x86_64
ruby-augeas-0.5.0-1.el7.x86_64
3.8.4
ruby 2.0.0p598 (2014-11-13) [x86_64-linux]

The Augeas team released a new version of their module a few days ago, which I justed installed. If you ever wanted to know how to update your modules via puppet itself (without fancy r10k magic):

# puppet module upgrade herculesteam-augeasproviders_grub
Notice: Preparing to upgrade 'herculesteam-augeasproviders_grub' ...
Notice: Found 'herculesteam-augeasproviders_grub' (v2.0.1) in /etc/puppet/environments/production/modules ...
Notice: Downloading from https://forgeapi.puppetlabs.com ...
Notice: Upgrading -- do not interrupt ...
/etc/puppet/environments/production/modules
└── herculesteam-augeasproviders_grub (v2.0.1 -> v2.1.0)

I’ve no clue on how to debug this. Any thoughts? I will create a bug report if this happens again in the future.

Posted in 30in30, General, Linux, Puppet | Leave a comment

Cooking Chili con carne

I blogged a few recipes in the past, it is time to continue this series. I blogged this recipe a while back in german, this is an improved version, translated into English:

We need for 3 dinners:

Ingredients:

  • 3 garlic cloves
  • 300gr corn
  • 500gr ground beef
  • 1200gr chopped tomatoes
  • 800gr red kidney beans
  • 75gr mustard
  • 2 onions
  • 500gr tzatziki
  • 3 to infinity chili peppers
  • Olive oil
  • 60gr tomato paste

Spices:

  • salt
  • pepper
  • sugar

[because of stupid web browsers (chrome) the preview pictures can lie on their side, klick on them for high res blur pictures but with the correct orientation]

Heat up a pan (oven at 100%) and add the olive oil when the pan is hot:

You start with chopping the onions (please don’t ask for the weight, I forgot it, they were at normal size):

than throw the onions into the pan (you can also lay them into it, but throwing is more fun). While the onions are getting a light brown colour, you can start chopping the garlic as small as your blunt blade allows you to do (tip: a green arm on the garlic is a sign that he is getting old).
garlic

Now add the chopped garlic and the ground beef into the pan, lower the heat to ~ 50%.
[if somebody finds the photo that I did from the beef, please place it here]

The time of the spices comes:

Add a bit of everything, do it by instinct. Cover the pan now while you chop the chili peppers:

Just start with a small amount, you can always make it hotter with more chili peppers, but it is not so easy to make it milder. The final version has to taste a bit too hot for you, add the chili peppers by instinct. Now we put almost everything together, add the beef and the chili pepper into a big pot, than add the ingredients:

  • Two things: you will notice that 800gr (two cans) of tomatoes aren’t enough, so use your emergency can or you run very fast to the next grocery store.
  • Don’t add the corn/beans into the pot, only the water in it!

You also add the mustard and the tomato paste now (try to get the Bautz’ner mustard):

The combination should like like this:

Lower the heat until it lightly bubbles. It needs some time to thicken, let it cook for at least an hour (better 90mins) without a cap (or: let it cook until you wrote a blog post about it). After that time it should be really thick, perfect time to add the corn and all the beans. They need only around 5 minutes to heat up, take care that you don’t cook it too long or too hot, than the beans would explode.

Final stage, taste it! Is it too spicy? Perfect! Add tzatziki until the spice level is acceptable. The result can look like this:

Let me know if you tried this recipe!

Posted in 30in30, General, Recipes | Leave a comment