We add a bit of complexity to the previous setup, by sharing code & data between multiple OpenBSD boxes, and exploring one way of writing sh(1) OS-agnostic code for sugar(1), using a well-known “ducktyping” method.
Multiple OpenBSD boxes with shared items
Given our setup-sshd
and setup-pf
, we’re likely to use
those exact same files on multiple OpenBSD servers we’d have to
manage, and parametrize the templates with distinct configuration
files.
The sugar.imports
provides a main pre-hook that can
import files to the ready/
directory. Here’s our final raw/$name/pre-hook
;
sugar.lib
will now be imported through sugar.imports
:
#!/bin/sh
set -e
cp $2/config $3/config
sugar.imports $@
sugar.mkautos $@
The imports are configured in raw/imports
; the sugard-openbsd/
directory contains the shared data:
# Basic rc.conf.local(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-rc.conf.local bin/
$HOME/gits/sugard-openbsd/rc.conf.local.base
# Basic motd(5) setup
$HOME/gits/sugard-openbsd/bin/*setup-motd bin/
# Basic pf(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-pf bin/
$HOME/gits/sugard-openbsd/pf.conf.base
$HOME/gits/sugard-openbsd/pf.tests
# Basic sshd(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-sshd bin/
$HOME/gits/sugard-openbsd/sshd_config.base
# Basic relayd(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-relayd bin/
$HOME/gits/sugard-openbsd/relayd.conf.base
# Basic httpd(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-httpd bin/
$HOME/gits/sugard-openbsd/httpd/* httpd/
$HOME/gits/sugard-openbsd/httpd.conf.base
# Basic acme-client(1) setup
$HOME/gits/sugard-openbsd/bin/*setup-acme-client bin/
$HOME/gits/sugard-openbsd/acme-client.conf.base
# Basic cron(8) setup
$HOME/gits/sugard-openbsd/bin/*setup-cron bin/
$HOME/gits/sugard-openbsd/crontabs/root crontabs/
$HOME/gits/sugard-openbsd/bin/renew-certs bin/
# git(1) setup
$HOME/gits/sugard-openbsd/bin/*setup-git bin/
# package update script
$HOME/gits/sugard-openbsd/bin/update bin/
# ip2location update/installation script
$HOME/gits/sugard-openbsd/bin/get-ip2location bin/
# gmail setup for use via mail(1)/sendmail(1) + mmail
$HOME/gits/sugard-openbsd/bin/*setup-gmail bin/
$HOME/gits/sugard-openbsd/bin/*setup-mmail bin/
$HOME/gits/sugard-openbsd/mail/* mail/
# log-tools setup
$HOME/gits/sugard-openbsd/bin/*setup-log-tools bin/
# daily scripts
$HOME/gits/sugard-openbsd/bin/daily bin/
$HOME/gits/sugard-openbsd/bin/daily-01-security bin/
$HOME/gits/sugard-openbsd/bin/daily-02-sshd bin/
$HOME/gits/sugard-openbsd/bin/daily-03-disk bin/
$HOME/gits/sugard-openbsd/bin/daily-04-httpd bin/
# Base configuration
$HOME/gits/sugard-openbsd/config bin/config.base
# Required by sugard-openbsd/bin/*'s scripts.
$HOME/gits/sugar/sugar.lib bin/
# Required by sugard-openbsd/bin/*'s scripts.
$HOME/gits/sugard-openbsd/sugar.lib.OpenBSD bin/
Most of the setup scripts and hooks are left unchanged when migrated
to sugard-openbsd/
; we just need to tweak the template processing,
as the *.base
files will now be located in the ready/
directory rather
than in the raw/
directory; for instance, for
sugard-openbsd/bin/hook-pre-setup-pf
:
#!/bin/sh
set -e
. `which sugar.lib`
log Preparing pf.conf for sync...
samuraibase $2 $3 pf.conf > $3/pf.conf
log Ensure we have a backup ssh link...
mksshlink backup-ssh-link-pf $1
OS-agnostic code
The default sugar.lib
defines two functions with no implementation,
assertuser()
and assertgroup()
, and a function loadoslib()
that will look for a sugar.lib.$OS
file in the $PATH
. Through
this ducktyping-like approach, traditionally used
for portable C, see for instance
9term(1)’s Plan9port implementation, we have
a simple mechanism to wrap OS idiosyncrasies.
We can for instance define a sugar.lib.OpenBSD
in our generic
OpenBSD directory implementing the two interfaces assertuser()
and assertgroup()
:
#!/bin/sh
set -e
# Assert user exists with given uid/gid/home/shell.
#
# Input:
# $1 : user name
# $2 : uid
# $3 : gid
# $4 : home directory
# $5 : shell
# Output:
# Exit on error
assertuser() {
if ! grep -q "^$1:\*:$2:$3::$4:$5$" /etc/passwd; then
x=`grep "^$1:" /etc/passwd`
fail "user $1:\*:$2:$3::$4:$5 not found; got '$x' instead"
fi
}
# Assert group exists with given gid
#
# NOTE: Last field, list of group members, is ignored.
#
# Input:
# $1 : group name
# $2 : gid
# Output:
# Exit on error
assertgroup() {
if ! grep -q "^$1:\*:$2:" /etc/group; then
x=`grep "^$1:" /etc/group`
fail "group $1:\*:$2: not found; got '$x' instead"
fi
}
# Assert a given service is enabled (i.e. configured
# to start on boot)
#
# Input:
# $1: service name
# Output:
# Exit on error
assertenabled() {
rcctl get "$1" status
if [ "$?" != "0" ]; then
fail "$1 not enabled"
fi
}
They can now be used as such e.g. in a remotely executed script:
#!/bin/sh
set -e
. `which sugar.lib`
log Logging OS-specific code...
loadoslib
log Asserting wheel group ID...
assertgroup wheel 0
...
Comments
By email, at mathieu.bivert chez: