Explicit high-level dependencies in Puppet
I’ve noticed that some people - I won’t reveal their names here to protect them - love using contain and/or ordering arrows in Puppet. A typical use-case is for role classes:
class role::webserver { contain ::packetfilter::endpoint contain ::profile::monit contain ::profile::unixbase contain ::profile::ipa_client contain ::profile::webserver
Class[::packetfilter::endpoint]
-> Class[::profile::monit]
-> Class[::profile::unixbase]
-> Class[::profile::ipa_client]
-> Class[::profile::webserver]
}
The above code nicely ensures that all the classes get applied in the exact order defined above. What happens under the hood is that Puppet generates dependencies between the classes and applies them in order.
Reprovisioning bare metal Linux servers with Foreman and IPMI
Recently we had to reprovision a bare metal server that was in Foreman and had IPMI support. The goal was to check if our automated “force-join to FreeIPA domain after reprovisioning” logic worked as intented. We did not have access to any graphical IPMI console, nor Foreman’s GUI, so we had to do everything from the command-line. The host we reprovisioned was a CentOS 7 instance. It is assumed that IPMI tools are installed. This post was inspired by the Automate SuperMicro Server Provisioning or Die Trying blog post.
Enabling PHP 7.4 on CentOS 7 with Puppet
The PHP version comes in default CentOS 7 repositories is rather horribly outdated. This is problematic when running Wordpress, which has to be upgraded constantly, and really old PHP versions may not be accepted, security-patched or not. The solution is to get updated PHP from the remi yum repositories. There are two sets of PHP packages as described here:
-
Install updated packages that replace the old PHP 5 packages (i.e. names are the same)
Terraform S3 access denied problems
I’ve stumbled upon interesting access denied problems with S3-based Terraform state files recently. Suppose you have two or more Terraform root modules which use the same bucket for storing the state and just use a different key (=state file):
terraform { backend "s3" { bucket = "terraform-state" key = "root-module-1" region = "eu-central-1" } }
and
terraform { backend "s3" { bucket = "terraform-state" key = "root-module-2" region = "eu-central-1" } }
However, trying to access the state file in one root module works, but on the other you get a generic S3 Access Denied error:
Puppet module rspec testing with PDK
If you’ve searched for instructions on how to write unit tests for Puppet code you’ve probably stumbled upon tutorials such as this that are of good quality, but suggest installing and using tools such as puppetlabs_rspec_helper directly. Or you may encounter references to rake, bundler, rvm and rspec. Then you start experimenting these tools, some of which (rvm and bundler) are aimed at managing the dependency hell that arises when you, or your team, works simultaneously on multiple projects with different dependency requirements. In the end you are maybe able to run spec tests on your Puppet module, but after all installations of gems and experiments you’re unsure what you did to make everything work. You also don’t want to become a hard-core Ruby developer who actually understands all these tools well - you just want to test your Puppet code.
Lack of default connection settings in Terraform 0.12.x
I was recently bit by a feature (one might call it a bug) in Terraform. We wanted to try out the “Networks” feature in Hetzner Cloud but that required upgrading terraform-provider-hcloud, which in turn required upgrading Terraform to 0.12.x. For the most part migration from 0.11.x code to 0.12.x code was straightforward with some help from the automated migration tool. I even went as far as read some of the migration documentation, but missed one important part: connection blocks no longer have default values. To make the matter worse Terraform 0.12 does not error out if values are unset: instead if just runs the provisioner and then times out. This seems to be related to Terraform bug #21690.
Moving Jenkins user home directory
Jenkins is a continuous integration (CI) / continuous delivery (CD) platform consisting of a Jenkins master - essentially a controller - which launches jobs on Jenkins slaves. Often slaves are controlled via SSH.
Recently I ran into an issue with a legacy Jenkins slave where the “jenkins” where Puppet tried to enforce the home directory of “jenkins” to be /home/jenkins instead of /var/lib/jenkins:
Error: Could not set home on user[jenkins]: Execution of '/usr/sbin/usermod -d /home/jenkins jenkins' returned 8: usermod: user jenkins is currently used by p rocess 802
The usermod command failed because several Jenkins processes (ssh-agent, Java) locked the user from modification. The solution was relatively straightforward:
Foreman and the Puppetserver environment cache
Importing classes is a two-phase process when you’re using r10k with Foreman. Say you’ve created a new class, “role::ipa_server” to the “production” environment; without Foreman it would be sufficient to deploy the change on the Puppetserver with r10k:
$ r10k deploy environment production -vp
At this point Foreman does not, however, know anything about this new class deployed with r10k:
$ hammer puppet-class list --environment production|grep ipa_server
The “Smart proxy” component in Foreman - also known as “foreman-proxy” - is responsible for fetching new classes from Puppetserver. With the latest Puppet versions it uses the Puppetserver API to do the import. It is fairly trivial to update Foreman’s list of classes using the command-line
Foreman ja puppetserverin environment cache
Kun käytetään r10k:ta ja Foremania yhdessä on uusien luokkien tuonti kaksivaiheinen prosessi. Oletetaan vaikka, että “production” environmentiin on luotu uusi luokka, esim. “role::ipa_server”. Ilman Foremania riittäisi tuoda muutos puppetmasterille r10k:lla:
$ r10k deploy environment production -vp
Foreman ei kuitenkaan vielä tiedä uudesta luokasta mitään:
$ hammer puppet-class list --environment production|grep ipa_server
Foremanin komponentti, joka hakee Puppetmasterilta uudet luokat on nimeltään “Smart proxy”, joka tunnetaan myös nimellä “foreman-proxy”. Uusimpien Puppetin versioiden kanssa se hakee luokat Puppetserverin API:a käyttäen. Luokat saa päivitettyä komentoriviltä melko triviaalisti:
Neulan erottaminen Git-muutosten heinäsuovasta
Toisinaan käy niin, että on tarpeen varmistua siitä aiheuttaako iso kasa Git-committeja jotain sivuvaikutuksia esimerkiksi Puppet-tuotantoympäristössä. Hyvistä commit-viesteistä on aina toki apua, mutta toisinaan commitit eivät ole täysin atomisia, eli tekevät enemmän kuin yhden (dokumentoidun) asian. Lisäksi esimerkiksi Puppet control reposta saattaa löytyä paitsi Puppet-koodia, myös Terraformia ja Ansiblea. Tälläisessä tapauksessa on kätevää näyttää vain muutokset, jotka ovat oikeasti relevantteja. Ensin tarkistetaan, mikä “production”-ympäristön viimeisin commit on:
$ ssh puppet$ cd /etc/puppetlabs/code/environments/production$ git rev-parse --short HEAD86c2152
Tämän jälkeen voidaan tarkista control reposta muutokset Puppetin kannalta oleellisiin kansioihin ja tiedostoihin: