foreman provisioning tests mit gitlab-ci und serverspec
Eine meiner Hauptbeschäftigungen ist die Administration unseres Foreman/orcharhino und Pflege der diversen Betriebssysteme, die wir tagtäglich an unsere Kunden ausliefern. Nachdem immer wieder neue Releases kommen, Anforderungen verändert werden oder einfach mal ein Update des Betriebssystems den Provisionierungsprozess verändert, habe ich mir mal die Zeit genommen einen automatischen Test des Provisionings zu bauen. Hier hat sich gitlab-ci mit den kürzlich eingeführten Rules als sehr nützlich erwiesen. Davor habe ich mir Jenkins von unseren Entwicklern ausgeborgt, aber voll integriert in gitlab find ichs irgendwie schöner.
Der Ablauf in .gitlab-ci.yml:
workflow:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
stages:
- build
- wait
- verify
- cleanup
- hammer host create erzeugt den Server in VMWare.
.build: &build
image: hammer:latest
stage: build
resource_group: foreman
only:
- master
before_script:
- hammer auth login basic -u ${FOREMAN_USER} -p ${FOREMAN_PASSWORD}
script:
- ./build_${OS}.sh
hammer ist das commandline interface für Foreman.
Damit die Authentifizierung bei Foreman funktioniert muss der session support in hammer aktiviert werden. Dies mache ich bereits im hammer-image mit sed
.
Das build_ubuntu2004.sh
enthält dann die notwendigen Parameter. Hier fand ich möglichst wenig Dynamik vorteilhaft, da meine Kollegen gerne solche Commands kopieren wenn mal mehr hosts aufzusetzen sind. Der geneigte Leser kann dies auch gerne mit Makefiles (und argbash zB) und/oder anderen Dingen vereinfachen.
hammer \
host create \
--name="ubuntu20" \
--domain "test.lan" \
--ip="192.168.5.20" \
\
--operatingsystem "Ubuntu 20.04 LTS" \
--partition-table "preseed-default" \
--medium "Ubuntu" \
--lifecycle-environment-id 1 \
--content-view "Ubuntu 20.04" \
\
--subnet 'provisioning_tests' \
--organization 'APA-IT' \
--location 'DC1' \
--compute-profile "small" \
--hostgroup-title "Canary" \
--compute-resource='vcenter' \
--compute-attributes='start=1,annotation="provisioning tests #nobackup# required.",guest_id="ubuntu64Guest"'
- wait-for-it.sh testet regelmäßig ob ein Login per ssh möglich ist. Da der Key erst mit dem ersten puppetrun ausgebracht wird, wird sichergestellt dass wir “nicht zu früh” vorbeikommen.
.wait: &wait
stage: wait
image: toughiq/toolbox:gitlab
only:
- master
before_script:
- 'which ssh-agent || ( apk add openssh-client )'
- eval $(ssh-agent -s)
script:
- ./wait.sh $OS_IP
wait.sh sieht entsprechend aus:
#!/bin/bash
# shellcheck disable=SC1090
set -euo pipefail
IFS=$'\n\t'
OS_IP=$1
# We need to wait for the ssh port to be reachable
./utils/wait-for-it.sh -h "${OS_IP}" -p 22 -t 1800 && \
echo "Waiting for puppet to finish..." # && sleep 600
until ssh "${OS_IP}" -l provtest -o "PasswordAuthentication=no" -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" id; do
echo "sleeping 2 seconds until ssh becomes available..." && sleep 2
done
echo "Login successful. Continuing in a few seconds..."
sleep 60
echo 'Done waiting.'
- serverspec überprüft ob die Anforderung erfüllt sind und nicht versehentlich Settings geändert wurden
.verify: &verify
stage: verify
image: serverspec:latest
only:
- master
artifacts:
when: always
paths:
- rspec.xml
reports:
junit: rspec.xml
before_script:
- 'which ssh-agent || ( apk add openssh-client )'
- eval $(ssh-agent -s)
script:
- rake spec:${OS_FQDN}
spec/base_spec.rb
sieht dann zum Beispiel so aus:
require 'spec_helper'
describe port(22) do
it { should be_listening }
end
describe cron do
its(:table) do
should match %r{/opt/puppetlabs/bin/puppet agent --onetime --no-daemonize}
end
end
describe package('sudo') do
it { should be_installed }
end
- cleanup löscht den Server mittels
hammer host delete
:
.cleanup: &cleanup
stage: cleanup
image: hammer:latest
when: always
resource_group: foreman
allow_failure: true
before_script:
- hammer auth login basic -u ${FOREMAN_USER} -p ${FOREMAN_PASSWORD}
script:
- hammer host delete --name ${OS_FQDN}
only:
- master
- Ab hier kopiert man die jeweilige Konfiguration und lädt die dazupassenden Steps:
# OS Config
.ubuntu2004: &ubuntu2004
variables:
OS: ubuntu2004
OS_FQDN: ubuntu20.test.lan
OS_IP: '192.168.5.20'
ubuntu2004:build:
<<: [*ubuntu2004, *build]
ubuntu2004:wait:
needs: ['ubuntu2004:build']
<<: [*ubuntu2004, *wait]
ubuntu2004:verify:
needs: ['ubuntu2004:wait']
<<: [*ubuntu2004, *verify]
ubuntu2004:cleanup:
needs: ['ubuntu2004:verify']
<<: [*ubuntu2004, *cleanup]
Jetzt nur noch den Build regelmäßig von gitlab triggern lassen - fertig.
Leider musste ich nahezu alle DockerImages selbst bauen, welche jedoch relativ simpel sind (serverspec installieren, hammer nach Anleitung installieren).
Ein wenig störend fand ich jeden Tag ein Email von Foreman zu bekommen, dass alle Server erfolgreich gebaut wurden. Hier wäre es schön einen Schalter in hammer zu haben um built notifications für diesen Host abzuschalten.