Merge pull request 'clan.core.state: wrap all commands in shell scripts' (#1639) from refactor-state into main
All checks were successful
deploy / deploy-docs (push) Successful in 19s
buildbot/nix-build .#checks.aarch64-darwin.nixos-test-backup Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-iso-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-no-breakpoints Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-deb Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-bash Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-e2fsprogs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-fakeroot Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-apk Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-git Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-nix Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-openssh Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-mypy" Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-qemu" Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-rsync Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sshpass Build done.
buildbot/nix-build .#checks.x86_64-linux.check-for-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-age Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-archlinux Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-rpm Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sops Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-tor Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-with-core Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-default Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-inventory-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.inventory-schema-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.borgbackup Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-ts-api Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-without-core Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-zbar Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-pytest Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.container Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-example-valid Build done.
buildbot/nix-build .#checks.x86_64-linux.deltachat Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.package-default Build done.
buildbot/nix-build .#checks.x86_64-linux.matrix-synapse Build done.
buildbot/nix-build .#checks.x86_64-linux.flash Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.package-editor Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-nix-unit-tests Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-inventory-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-merge-after-ci Build done.
buildbot/nix-build .#checks.x86_64-linux.package-moonlight-sunshine-accept Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotierone Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.renderClanOptions Build done.
buildbot/nix-build .#checks.x86_64-linux.package-deploy-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-impure-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.package-pending-reviews Build done.
buildbot/nix-build .#checks.x86_64-linux.package-tea-create-pr Build done.
buildbot/nix-build .#checks.x86_64-linux.package-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotier-members Build done.
buildbot/nix-build .#checks.x86_64-linux.syncthing Build done.
buildbot/nix-build .#checks.x86_64-linux.wayland-proxy-virtwl Build done.
buildbot/nix-build .#checks.x86_64-linux.test-installation Build done.
buildbot/nix-build .#checks.x86_64-linux.package-function-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.postgresql Build done.
buildbot/nix-build .#checks.x86_64-linux.secrets Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.template-minimal Build done.
buildbot/nix-build .#checks.x86_64-linux.test-backups Build done.
buildbot/nix-build .#checks.x86_64-linux.treefmt Build done.
buildbot/nix-build .#checks.x86_64-linux.package-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-install-test-ubuntu-22-04 Build done.
buildbot/nix-eval Build done.
checks / checks-impure (push) Successful in 2m11s

This commit is contained in:
clan-bot 2024-06-20 16:20:31 +00:00
commit b3123b150f
7 changed files with 129 additions and 34 deletions

View File

@ -70,15 +70,7 @@
};
clan.core.facts.secretStore = "vm";
environment.systemPackages = [
self.packages.${pkgs.system}.clan-cli
(pkgs.writeShellScriptBin "pre-restore-command" ''
touch /var/test-service/pre-restore-command
'')
(pkgs.writeShellScriptBin "post-restore-command" ''
touch /var/test-service/post-restore-command
'')
];
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
environment.etc.install-closure.source = "${closureInfo}/store-paths";
nix.settings = {
substituters = lib.mkForce [ ];
@ -90,11 +82,15 @@
clan.core.state.test-backups.folders = [ "/var/test-backups" ];
clan.core.state.test-service = {
preBackupCommand = ''
preBackupScript = ''
touch /var/test-service/pre-backup-command
'';
preRestoreCommand = "pre-restore-command";
postRestoreCommand = "post-restore-command";
preRestoreScript = ''
touch /var/test-service/pre-restore-command
'';
postRestoreScript = ''
touch /var/test-service/post-restore-command
'';
folders = [ "/var/test-service" ];
};
clan.borgbackup.destinations.test-backup.repo = "borg@machine:.";

View File

@ -50,7 +50,7 @@
machine.succeed("""
set -x
${nodes.machine.clan.core.state.postgresql-test.postRestoreCommand}
${nodes.machine.clan.core.state.test.postRestoreCommand}
""")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -l >&2")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
@ -66,7 +66,7 @@
# check if restore works if the database does not exist
machine.succeed("runuser -u postgres -- dropdb test")
machine.succeed("${nodes.machine.clanCore.state.postgresql-test.postRestoreCommand}")
machine.succeed("${nodes.machine.clan.core.state.test.postRestoreCommand}")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
'';
})

View File

@ -13,14 +13,14 @@ let
state:
lib.optionalString (state.preBackupCommand != null) ''
echo "Running pre-backup command for ${state.name}"
if ! ( ${state.preBackupCommand} ) then
if ! /run/current-system/sw/bin/${state.preBackupCommand}; then
preCommandErrors["${state.name}"]=1
fi
''
) (lib.attrValues config.clan.core.state)}
if [[ ''${#preCommandErrors[@]} -gt 0 ]]; then
echo "PreBackupCommand failed for the following services:"
echo "pre-backup commands failed for the following services:"
for state in "''${!preCommandErrors[@]}"; do
echo " $state"
done

View File

@ -125,7 +125,6 @@ in
}
${lib.concatMapStringsSep "\n" (target: ''
${mountHook target}
set -x
echo "Creating backup '${target.name}'"
${lib.optionalString (target.preBackupHook != null) ''
@ -139,7 +138,7 @@ in
state:
lib.optionalString (state.preBackupCommand != null) ''
echo "Running pre-backup command for ${state.name}"
if ! ( ${state.preBackupCommand} ) then
if ! /run/current-system/sw/bin/${state.preBackupCommand}; then
preCommandErrors["${state.name}"]=1
fi
''

View File

@ -185,7 +185,7 @@ in
+ lib.concatMapStringsSep "\n" (user: ''
# only create user if it doesn't exist
/run/current-system/sw/bin/matrix-synapse-register_new_matrix_user --exists-ok --password-file ${
config.clanCore.facts.services."matrix-password-${user.name}".secret."matrix-password-${user.name}".path
config.clan.core.facts.services."matrix-password-${user.name}".secret."matrix-password-${user.name}".path
} --user "${user.name}" ${if user.admin then "--admin" else "--no-admin"}
'') (lib.attrValues cfg.users);
in

View File

@ -14,7 +14,7 @@ let
in
{
folders = [ folder ];
preBackupCommand = ''
preBackupScript = ''
export PATH=${
lib.makeBinPath [
config.services.postgresql.package
@ -32,7 +32,41 @@ let
runuser -u postgres -- pg_dump ${compression} --dbname=${db.name} -Fc -c > "${current}.tmp"
mv "${current}.tmp" ${current}
'';
postRestoreCommand = "postgres-db-restore-command-${db.name}";
postRestoreScript = ''
export PATH=${
lib.makeBinPath [
config.services.postgresql.package
config.systemd.package
pkgs.coreutils
pkgs.util-linux
pkgs.zstd
pkgs.gnugrep
]
}
while [[ "$(systemctl is-active postgresql)" == activating ]]; do
sleep 1
done
echo "Waiting for postgres to be ready..."
while ! runuser -u postgres -- psql --port=${builtins.toString config.services.postgresql.settings.port} -d postgres -c "" ; do
if ! systemctl is-active postgresql; then exit 1; fi
sleep 0.1
done
if [[ -e "${current}" ]]; then
(
systemctl stop ${lib.concatStringsSep " " db.restore.stopOnRestore}
trap "systemctl start ${lib.concatStringsSep " " db.restore.stopOnRestore}" EXIT
mkdir -p "${folder}"
if runuser -u postgres -- psql -d postgres -c "SELECT 1 FROM pg_database WHERE datname = '${db.name}'" | grep -q 1; then
runuser -u postgres -- dropdb "${db.name}"
fi
runuser -u postgres -- pg_restore -C -d postgres "${current}"
)
else
echo No database backup found, skipping restore
fi
'';
};
createDatabase = db: ''
@ -66,6 +100,12 @@ in
name = lib.mkOption {
type = lib.types.str;
default = name;
description = "Database name.";
};
service = lib.mkOption {
type = lib.types.str;
default = name;
description = "Service name that we associate with the database.";
};
# set to false, in case the upstream module uses ensureDatabase option
create.enable = lib.mkOption {
@ -87,7 +127,7 @@ in
restore.stopOnRestore = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of services to stop before restoring the database.";
description = "List of systemd services to stop before restoring the database.";
};
};
}
@ -129,7 +169,7 @@ in
'';
clan.core.state = lib.mapAttrs' (
_: db: lib.nameValuePair "postgresql-${db.name}" (createDatatbaseState db)
_: db: lib.nameValuePair db.service (createDatatbaseState db)
) config.clan.postgresql.databases;
environment.systemPackages = builtins.map (

View File

@ -1,18 +1,20 @@
{ lib, ... }:
{
# defaults
config.clan.core.state.HOME.folders = [ "/home" ];
lib,
pkgs,
config,
...
}:
{
# interface
options.clan.core.state = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{ name, config, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
type = lib.types.strMatching "^[a-zA-Z0-9_-]+$";
default = name;
description = ''
Name of the state
@ -24,8 +26,9 @@
Folder where state resides in
'';
};
preBackupCommand = lib.mkOption {
type = lib.types.nullOr lib.types.str;
preBackupScript = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
description = ''
script to run before backing up the state dir
@ -34,6 +37,15 @@
'';
};
preBackupCommand = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = if config.preBackupScript == null then null else "pre-backup-${name}";
readOnly = true;
description = ''
Use this command in backup providers. It contains the content of preBackupScript.
'';
};
# TODO: implement this
#stopOnRestore = lib.mkOption {
# type = lib.types.listOf lib.types.str;
@ -45,8 +57,8 @@
# '';
#};
preRestoreCommand = lib.mkOption {
type = lib.types.nullOr lib.types.str;
preRestoreScript = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
description = ''
script to run before restoring the state dir from a backup
@ -55,8 +67,18 @@
'';
};
postRestoreCommand = lib.mkOption {
preRestoreCommand = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = if config.preRestoreScript == null then null else "pre-restore-${name}";
readOnly = true;
description = ''
This command can be called to restore the state dir from a backup.
It contains the content of preRestoreScript.
'';
};
postRestoreScript = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
description = ''
script to restore the service after the state dir was restored from a backup
@ -64,9 +86,47 @@
Utilize this to start services which were previously stopped
'';
};
postRestoreCommand = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = if config.postRestoreScript == null then null else "post-restore-${name}";
readOnly = true;
description = ''
This command is called after a restore of the state dir from a backup.
It contains the content of postRestoreScript.
'';
};
};
}
)
);
};
# defaults
config.clan.core.state.HOME.folders = [ "/home" ];
config.environment.systemPackages = lib.optional (config.clan.core.state != { }) (
pkgs.runCommand "state-commands" { } ''
${builtins.concatStringsSep "\n" (
builtins.map (state: ''
writeShellScript() {
local name=$1
local content=$2
printf "#!${pkgs.runtimeShell}\nset -eu -o pipefail\n%s" "$content" > $out/bin/$name
}
mkdir -p $out/bin/
${lib.optionalString (state.preBackupCommand != null) ''
writeShellScript ${lib.escapeShellArg state.preBackupCommand} ${lib.escapeShellArg state.preBackupScript}
''}
${lib.optionalString (state.preRestoreCommand != null) ''
writeShellScript ${lib.escapeShellArg state.preRestoreCommand} ${lib.escapeShellArg state.preRestoreScript}
''}
${lib.optionalString (state.postRestoreCommand != null) ''
writeShellScript ${lib.escapeShellArg state.postRestoreCommand} ${lib.escapeShellArg state.postRestoreScript}
''}
find $out/bin/ -type f -print0 | xargs --no-run-if-empty -0 chmod 755
'') (builtins.attrValues config.clan.core.state)
)}
''
);
}