You may want to inform yourself about human rights in China.

On Sugar, a Sweeter Salt: Multiple Systems

date: 2022-03-20
update: 2022-06-01

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.


Daifuku 大福餅, a Japanese confection, typically made from a glutinous rice cake (mochi) filled with a sweeten azuki beans paste, 豆沙 / 紅豆沙

Daifuku 大福餅, a Japanese confection, typically made from a glutinous rice cake (mochi) filled with a sweeten azuki beans paste, 豆沙 / 紅豆沙 by Alice Wiegand through wikimedia.orgCC-BY-SA-3.0

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
#
# Input:
#	$1: service name
# Output:
#	Exit on error
assertenabled() {
	# Special case
	x=1
	if [ "$1" == "pf" ]; then
		rcctl get pf | grep -qF 'pf=YES'
		x=$?
	else
		rcctl get $1 | grep -F $1_flags | grep -vqF $1'_flags=NO'
		x=$?
	fi
	if [ $x != "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

...
Traditional Japanese confectionary food collon, or Wagashi 和菓子

Traditional Japanese confectionary food collon, or Wagashi 和菓子 by Lzen9216 through wikimedia.orgCC-BY-SA-4.0


In the series:


Comments

By email, at mathieu.bivert chez:

email