server
Architecture: any
Architecture: any
name: server
variables:
- name: password
value: ''
secret: true
- name: maxmemory
value: ''
fodder:
- name: server
type: cloud-config
secret: true
content: |
# Append (don't replace) write_files/runcmd when combined with other
# cloud-config fodder on the same catlet, e.g. a co-located application.
merge_how:
- name: list
settings: [append]
- name: dict
settings: [no_replace, recurse_list]
write_files:
- path: /opt/eryph-valkey-setup.sh
permissions: '0755'
content: |
#!/bin/bash
set -euo pipefail
PASSWORD='{{ password }}'
MAXMEMORY='{{ maxmemory }}'
. /etc/os-release
FAMILY=rhel
case " ${ID:-} ${ID_LIKE:-} " in
*" debian "*|*" ubuntu "*) FAMILY=debian ;;
esac
# Valkey is the Redis-compatible server shipped by both families
# (the RHEL family no longer packages redis). Debian provides both;
# we standardise on valkey so behaviour is identical everywhere.
if [ "$FAMILY" = debian ]; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq valkey-server
else
dnf install -y -q valkey
fi
# Service unit name differs (Debian: valkey-server, RHEL: valkey)
SVC=valkey
systemctl list-unit-files | grep -q '^valkey-server.service' && SVC=valkey-server
# Stop the service before relocating its data directory (Debian
# auto-starts it on install and would hold the old directory open).
systemctl stop "$SVC" >/dev/null 2>&1 || true
# --- Persistent state drive mounted at the data directory, so the saved
# data (RDB/AOF snapshots) survives a redeploy. A named data drive on the
# catlet is required. ---
STATE=/var/lib/valkey
STATE_LABEL=valkey
if ! mountpoint -q "$STATE"; then
mkdir -p "$STATE"
dev=$(blkid -L "$STATE_LABEL" 2>/dev/null || true)
if [ -z "$dev" ]; then
root_src=$(findmnt -no SOURCE / || true)
root_disk=$(lsblk -no PKNAME "$root_src" 2>/dev/null || true)
[ -z "$root_disk" ] && root_disk=$(basename "$root_src")
for d in $(lsblk -dn -o NAME,TYPE | awk '$2=="disk"{print $1}'); do
[ "$d" = "$root_disk" ] && continue
if [ -z "$(lsblk -no FSTYPE "/dev/$d" | tr -d '[:space:]')" ]; then
mkfs.ext4 -q -L "$STATE_LABEL" "/dev/$d"
dev="/dev/$d"; break
fi
done
fi
if [ -z "$dev" ]; then
echo "ERROR: no empty data drive found for persistent state." >&2
echo "Add a data drive to the catlet, e.g. drives: - name: sdb / size: 10" >&2
exit 1
fi
grep -q "LABEL=$STATE_LABEL[[:space:]]" /etc/fstab || \
echo "LABEL=$STATE_LABEL $STATE ext4 defaults,nofail 0 2" >> /etc/fstab
mount "$STATE"
fi
chown valkey:valkey "$STATE"; chmod 750 "$STATE"
command -v restorecon >/dev/null 2>&1 && restorecon -R "$STATE" || true
# Configure remote access (config path is /etc/valkey/valkey.conf on both)
CONF=/etc/valkey/valkey.conf
sed -i '/# eryph-begin/,/# eryph-end/d' "$CONF"
{
echo "# eryph-begin"
echo "bind 0.0.0.0"
echo "protected-mode no"
[ -n "$PASSWORD" ] && echo "requirepass $PASSWORD"
if [ -n "$MAXMEMORY" ]; then
echo "maxmemory $MAXMEMORY"
echo "maxmemory-policy allkeys-lru"
fi
echo "# eryph-end"
} >> "$CONF"
systemctl enable "$SVC" >/dev/null 2>&1 || true
systemctl restart "$SVC"
# Open the firewall only when one is active
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
firewall-cmd --permanent --add-port=6379/tcp >/dev/null; firewall-cmd --reload >/dev/null
fi
if command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q "Status: active"; then
ufw allow 6379/tcp >/dev/null
fi
runcmd:
- bash /opt/eryph-valkey-setup.sh