Add initial scripts, which make up the infra-rebuild tool

infra-rebuild is a simple NixOS deployment tool, which simply uses
nixos-rebuild internally, but tries to make it more convenient to deploy
infrastructure.

It supports most of the nixos-rebuild operations - build, build-vm,
build-vm-with-bootloader, switch, boot, test - but also provides a
reboot operation, which runs nixos-rebuild boot followed by initiating a
reboot.

The tool doesn't need any configuration for a standard use case. It
tries to get the hosts FQDN from its NixOS configuration and tries to
deploy to it. However for special cases, where a custom target hostname,
user or port is needed, it allows one to define those in a
deployment_configuration.json.

infra-rebuild also allows for multiple hosts to be specified at once.
The tool then simply runs the specified operation for each host
sequentially.

Much inspiration was taken from bij.
See here: https://git.clerie.de/clerie/bij
And inspiration was also taken from Colmena.
See here: https://github.com/zhaofengli/colmena
This commit is contained in:
June 2024-05-28 00:14:29 +02:00
commit 946ab46275
Signed by: june
SSH key fingerprint: SHA256:o9EAq4Y9N9K0pBQeBTqhSDrND5E7oB+60ZNx0U1yPe0
6 changed files with 208 additions and 0 deletions

3
helper/msg_error.sh Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/bash
echo "$(tput bold)$(tput setaf 9)$@$(tput sgr0)"

3
helper/msg_info.sh Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/bash
echo "$(tput bold)$(tput setaf 12)$@$(tput sgr0)"

3
helper/msg_warning.sh Executable file
View file

@ -0,0 +1,3 @@
#!/usr/bin/bash
echo "$(tput bold)$(tput setaf 11)$@$(tput sgr0)"

39
infra-rebuild.sh Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
REAL_BASE_DIR=$( dirname $( realpath "$0" ) )
if [ $# -lt 2 ] || [ $# -gt 2 ]; then
$REAL_BASE_DIR/helper/msg_error.sh "\
Error: Incorrect amount of arguments given.
You need to provide exactly two arguments. The first one being the operation you want to run and the second one being the host or hosts (comma separated) you want to run the operation for."
exit 1
fi
OPERATION="$1"
HOSTS="$2"
case $OPERATION in
build|build-vm|build-vm-with-bootloader|switch|boot|test|reboot)
;;
*)
$REAL_BASE_DIR/helper/msg_error.sh "\
Error: No valid operation given.
The operation must be one of:
build, build-vm, build-vm-with-bootloader, switch, boot, test, reboot."
exit 1
;;
esac
set -e
for HOST in ${HOSTS//,/ }; do
case $OPERATION in
build|build-vm|build-vm-with-bootloader)
env OPERATION="$OPERATION" HOST="$HOST" $REAL_BASE_DIR/operations/local.sh
;;
switch|boot|test|reboot)
env OPERATION="$OPERATION" HOST="$HOST" $REAL_BASE_DIR/operations/remote.sh
;;
esac
done

45
operations/local.sh Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
REAL_BASE_DIR=$( dirname $( realpath "$0" ) )
# Wrapper for nixos-rebuild operations, which act locally.
# Takes the following arguments supplied as environment variables.
# HOST: The host as defined in nixosConfigurations.
# OPERATION: The nixos-rebuild operation to execute. Can be one of:
# build, build-vm, build-vm-with-bootloader
# All operations are as defined in the nixos-rebuild man page.
if [ -z $HOST ]; then
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No host given.
A host needs to be provided via the HOST environment variable."
exit 1
fi
if [ -z $OPERATION ]; then
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No operation given.
An operation needs to be provided via the OPERATION environment variable."
exit 1
fi
case $OPERATION in
build|build-vm|build-vm-with-bootloader)
;;
*)
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No valid operation given.
The operation provided via the OPERATION environment variable needs to be one of:
build, build-vm, build-vm-with-bootloader."
exit 1
;;
esac
set -e
$REAL_BASE_DIR/../helper/msg_info.sh "\
Running nixos-rebuild $OPERATION for $HOST..."
nixos-rebuild "$OPERATION" --flake ".#$HOST"

115
operations/remote.sh Executable file
View file

@ -0,0 +1,115 @@
#!/usr/bin/env bash
REAL_BASE_DIR=$( dirname $( realpath "$0" ) )
# Wrapper for nixos-rebuild operations, which act remotely.
# Gets the necessary configuration to do so.
# Takes the following arguments supplied as environment variables.
# HOST: The host as defined in nixosConfigurations and the
# deployment_configuration.json.
# OPERATION: The nixos-rebuild operation to execute. Can be one of:
# switch, boot, test, reboot
# All operations are as defined in the nixos-rebuild man page except
# for reboot, which runs boot, but then also reboots the host.
if [ -z $HOST ]; then
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No host given.
A host needs to be provided via the HOST environment variable."
exit 1
fi
if [ -z $OPERATION ]; then
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No operation given.
An operation needs to be provided via the OPERATION environment variable."
exit 1
fi
ACTUAL_OPERATION=""
case $OPERATION in
switch|boot|test)
ACTUAL_OPERATION="$OPERATION"
;;
reboot)
ACTUAL_OPERATION="boot"
;;
*)
$REAL_BASE_DIR/../helper/msg_error.sh "\
Internal Error: No valid operation given.
The operation provided via the OPERTION environment variable needs to be one of:
switch, boot, test, reboot."
exit 1
;;
esac
TARGET_HOSTNAME=""
TARGET_USER=""
TARGET_PORT=""
DEPLOYMENT_CONFIGURATION_EXISTS=true
if ! [ -f deployment_configuration.json ]; then
$REAL_BASE_DIR/../helper/msg_warning.sh "\
Warning: No deployment_configuration.json exists and therefore it can't be used to retrieve configuration values."
DEPLOYMENT_CONFIGURATION_EXISTS=false
fi
if $DEPLOYMENT_CONFIGURATION_EXISTS && ! cat deployment_configuration.json | jq . >/dev/null 2>&1; then
$REAL_BASE_DIR/../helper/msg_warning.sh "\
Warning: jq can't parse the deployment_configuration.json and therefore it can't be used to retrieve configuration values."
fi
if $DEPLOYMENT_CONFIGURATION_EXISTS && CONFIG_TARGET_HOSTNAME="$(cat deployment_configuration.json | jq -re .hosts.\"$HOST\".targetHostname 2>/dev/null)"; then
TARGET_HOSTNAME=$CONFIG_TARGET_HOSTNAME
elif NIX_CONFIG_FQDN="$(nix eval --raw .\#nixosConfigurations.$HOST.config.networking.fqdn 2>/dev/null)"; then
TARGET_HOSTNAME=$NIX_CONFIG_FQDN
else
$REAL_BASE_DIR/../helper/msg_error.sh "\
Error: Couldn't determine target hostname for $HOST.
You either need to set targetHostname for this host in the deployment_configuration.json or have an FQDN available in the NixOS configuration of this host, which then gets used for the target hostname."
exit 1
fi
if $DEPLOYMENT_CONFIGURATION_EXISTS && CONFIG_TARGET_USER="$(cat deployment_configuration.json | jq -re .hosts.\"$HOST\".targetUser 2>/dev/null)"; then
TARGET_USER=$CONFIG_TARGET_USER
elif $DEPLOYMENT_CONFIGURATION_EXISTS && CONFIG_DEFAULT_TARGET_USER="$(cat deployment_configuration.json | jq -re '.default.targetUser' 2>/dev/null)"; then
TARGET_USER=$CONFIG_DEFAULT_TARGET_USER
fi
if $DEPLOYMENT_CONFIGURATION_EXISTS && CONFIG_TARGET_PORT="$(cat deployment_configuration.json | jq -re .hosts.\"$HOST\".targetPort 2>/dev/null)"; then
TARGET_PORT=$CONFIG_TARGET_PORT
elif $DEPLOYMENT_CONFIGURATION_EXISTS && CONFIG_DEFAULT_TARGET_PORT="$(cat deployment_configuration.json | jq -re '.default.targetPort' 2>/dev/null)"; then
TARGET_PORT=$CONFIG_DEFAULT_TARGET_PORT
fi
TARGET_HOST="$TARGET_HOSTNAME"
if [ -n "$TARGET_USER" ]; then
TARGET_HOST="$TARGET_USER@$TARGET_HOST"
fi
SSHOPTS=""
if [ -n "$TARGET_PORT" ]; then
SSHOPTS="-o Port=$TARGET_PORT"
fi
set -e
if [ -n "$TARGET_PORT" ]; then
$REAL_BASE_DIR/../helper/msg_info.sh "\
Running nixos-rebuild $ACTUAL_OPERATION for $HOST on $TARGET_HOST:$TARGET_PORT..."
else
$REAL_BASE_DIR/../helper/msg_info.sh "\
Running nixos-rebuild $ACTUAL_OPERATION for $HOST on $TARGET_HOST..."
fi
env NIX_SSHOPTS="$SSHOPTS" nixos-rebuild "$ACTUAL_OPERATION" --flake ".#$HOST" --target-host "$TARGET_HOST" --use-substitutes --use-remote-sudo
if [ "$OPERATION" = "reboot" ]; then
$REAL_BASE_DIR/../helper/msg_info.sh "\
Rebooting $TARGET_HOSTNAME..."
ssh $SSH_OPTS "$TARGET_HOST" sudo systemctl reboot
fi