format
This commit is contained in:
@@ -7,8 +7,9 @@
|
|||||||
in {
|
in {
|
||||||
sops.age.keyFile = "/Users/${user}/.config/sops/age/keys.txt";
|
sops.age.keyFile = "/Users/${user}/.config/sops/age/keys.txt";
|
||||||
|
|
||||||
sops.secrets = secrets.mkSyncthingSecrets {
|
sops.secrets =
|
||||||
inherit hostname user;
|
secrets.mkSyncthingSecrets {
|
||||||
isDarwin = true;
|
inherit hostname user;
|
||||||
};
|
isDarwin = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ in {
|
|||||||
sops.age.sshKeyPaths = [];
|
sops.age.sshKeyPaths = [];
|
||||||
sops.gnupg.sshKeyPaths = [];
|
sops.gnupg.sshKeyPaths = [];
|
||||||
|
|
||||||
sops.secrets = secrets.mkSyncthingSecrets {
|
sops.secrets =
|
||||||
inherit hostname user;
|
secrets.mkSyncthingSecrets {
|
||||||
isDarwin = true;
|
inherit hostname user;
|
||||||
};
|
isDarwin = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
{config, hostname, ...}: {
|
{
|
||||||
|
config,
|
||||||
|
hostname,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
networking = {
|
networking = {
|
||||||
hostName = hostname;
|
hostName = hostname;
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
|
|||||||
@@ -10,231 +10,254 @@ in {
|
|||||||
options.my.pgbackrest = {
|
options.my.pgbackrest = {
|
||||||
enable = mkEnableOption "pgBackRest PostgreSQL backup";
|
enable = mkEnableOption "pgBackRest PostgreSQL backup";
|
||||||
|
|
||||||
stanza = mkOption {
|
stanza =
|
||||||
type = types.str;
|
mkOption {
|
||||||
default = "main";
|
type = types.str;
|
||||||
description = "Name of the pgBackRest stanza";
|
default = "main";
|
||||||
};
|
description = "Name of the pgBackRest stanza";
|
||||||
|
|
||||||
secretFile = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
description = "Path to the environment file containing S3 credentials and cipher passphrase";
|
|
||||||
};
|
|
||||||
|
|
||||||
s3 = mkOption {
|
|
||||||
type = types.submodule {
|
|
||||||
options = {
|
|
||||||
endpoint = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "s3.eu-central-003.backblazeb2.com";
|
|
||||||
description = "S3 endpoint URL";
|
|
||||||
};
|
|
||||||
|
|
||||||
bucket = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "S3 bucket name";
|
|
||||||
};
|
|
||||||
|
|
||||||
region = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "eu-central-003";
|
|
||||||
description = "S3 region";
|
|
||||||
};
|
|
||||||
|
|
||||||
path = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/backups";
|
|
||||||
description = "Path within the S3 bucket";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
default = {};
|
|
||||||
description = "S3 storage configuration";
|
|
||||||
};
|
|
||||||
|
|
||||||
retention = mkOption {
|
secretFile =
|
||||||
type = types.submodule {
|
mkOption {
|
||||||
options = {
|
type = types.path;
|
||||||
full = mkOption {
|
description = "Path to the environment file containing S3 credentials and cipher passphrase";
|
||||||
type = types.int;
|
|
||||||
default = 7;
|
|
||||||
description = "Number of full backups to retain";
|
|
||||||
};
|
|
||||||
|
|
||||||
diff = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 7;
|
|
||||||
description = "Number of differential backups to retain";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
default = {};
|
|
||||||
description = "Backup retention configuration";
|
|
||||||
};
|
|
||||||
|
|
||||||
compression = mkOption {
|
s3 =
|
||||||
type = types.submodule {
|
mkOption {
|
||||||
options = {
|
type =
|
||||||
type = mkOption {
|
types.submodule {
|
||||||
type = types.str;
|
options = {
|
||||||
default = "zst";
|
endpoint =
|
||||||
description = "Compression algorithm (none, gz, lz4, zst)";
|
mkOption {
|
||||||
};
|
type = types.str;
|
||||||
|
default = "s3.eu-central-003.backblazeb2.com";
|
||||||
|
description = "S3 endpoint URL";
|
||||||
|
};
|
||||||
|
|
||||||
level = mkOption {
|
bucket =
|
||||||
type = types.int;
|
mkOption {
|
||||||
default = 3;
|
type = types.str;
|
||||||
description = "Compression level";
|
description = "S3 bucket name";
|
||||||
|
};
|
||||||
|
|
||||||
|
region =
|
||||||
|
mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "eu-central-003";
|
||||||
|
description = "S3 region";
|
||||||
|
};
|
||||||
|
|
||||||
|
path =
|
||||||
|
mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/backups";
|
||||||
|
description = "Path within the S3 bucket";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
default = {};
|
||||||
|
description = "S3 storage configuration";
|
||||||
};
|
};
|
||||||
default = {};
|
|
||||||
description = "Compression configuration";
|
|
||||||
};
|
|
||||||
|
|
||||||
processMax = mkOption {
|
retention =
|
||||||
type = types.int;
|
mkOption {
|
||||||
default = 2;
|
type =
|
||||||
description = "Maximum number of processes for parallel operations";
|
types.submodule {
|
||||||
};
|
options = {
|
||||||
|
full =
|
||||||
|
mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 7;
|
||||||
|
description = "Number of full backups to retain";
|
||||||
|
};
|
||||||
|
|
||||||
schedule = mkOption {
|
diff =
|
||||||
type = types.submodule {
|
mkOption {
|
||||||
options = {
|
type = types.int;
|
||||||
full = mkOption {
|
default = 7;
|
||||||
type = types.str;
|
description = "Number of differential backups to retain";
|
||||||
default = "daily";
|
};
|
||||||
description = "OnCalendar expression for full backups";
|
};
|
||||||
};
|
};
|
||||||
|
default = {};
|
||||||
diff = mkOption {
|
description = "Backup retention configuration";
|
||||||
type = types.str;
|
};
|
||||||
default = "hourly";
|
|
||||||
description = "OnCalendar expression for differential backups";
|
compression =
|
||||||
};
|
mkOption {
|
||||||
};
|
type =
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
type =
|
||||||
|
mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "zst";
|
||||||
|
description = "Compression algorithm (none, gz, lz4, zst)";
|
||||||
|
};
|
||||||
|
|
||||||
|
level =
|
||||||
|
mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 3;
|
||||||
|
description = "Compression level";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = {};
|
||||||
|
description = "Compression configuration";
|
||||||
|
};
|
||||||
|
|
||||||
|
processMax =
|
||||||
|
mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Maximum number of processes for parallel operations";
|
||||||
|
};
|
||||||
|
|
||||||
|
schedule =
|
||||||
|
mkOption {
|
||||||
|
type =
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
full =
|
||||||
|
mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "daily";
|
||||||
|
description = "OnCalendar expression for full backups";
|
||||||
|
};
|
||||||
|
|
||||||
|
diff =
|
||||||
|
mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "hourly";
|
||||||
|
description = "OnCalendar expression for differential backups";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = {};
|
||||||
|
description = "Backup schedule configuration";
|
||||||
};
|
};
|
||||||
default = {};
|
|
||||||
description = "Backup schedule configuration";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable (let
|
config =
|
||||||
archivePushScript = pkgs.writeShellScript "pgbackrest-archive-push" ''
|
mkIf cfg.enable (let
|
||||||
set -a
|
archivePushScript =
|
||||||
source ${cfg.secretFile}
|
pkgs.writeShellScript "pgbackrest-archive-push" ''
|
||||||
set +a
|
set -a
|
||||||
exec ${pkgs.pgbackrest}/bin/pgbackrest --stanza=${cfg.stanza} archive-push "$1"
|
source ${cfg.secretFile}
|
||||||
'';
|
set +a
|
||||||
in {
|
exec ${pkgs.pgbackrest}/bin/pgbackrest --stanza=${cfg.stanza} archive-push "$1"
|
||||||
environment.systemPackages = [
|
'';
|
||||||
pkgs.pgbackrest
|
in {
|
||||||
(pkgs.writeShellScriptBin "pgbackrest-wrapper" ''
|
environment.systemPackages = [
|
||||||
set -a
|
pkgs.pgbackrest
|
||||||
source ${cfg.secretFile}
|
(pkgs.writeShellScriptBin "pgbackrest-wrapper" ''
|
||||||
set +a
|
set -a
|
||||||
exec ${pkgs.pgbackrest}/bin/pgbackrest "$@"
|
source ${cfg.secretFile}
|
||||||
'')
|
set +a
|
||||||
];
|
exec ${pkgs.pgbackrest}/bin/pgbackrest "$@"
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
|
||||||
services.postgresql.settings = {
|
services.postgresql.settings = {
|
||||||
archive_mode = "on";
|
archive_mode = "on";
|
||||||
archive_command = "${archivePushScript} %p";
|
archive_command = "${archivePushScript} %p";
|
||||||
};
|
|
||||||
|
|
||||||
environment.etc."pgbackrest/pgbackrest.conf".text = ''
|
|
||||||
[global]
|
|
||||||
repo1-type=s3
|
|
||||||
repo1-s3-endpoint=${cfg.s3.endpoint}
|
|
||||||
repo1-s3-bucket=${cfg.s3.bucket}
|
|
||||||
repo1-s3-region=${cfg.s3.region}
|
|
||||||
repo1-path=${cfg.s3.path}
|
|
||||||
repo1-retention-full=${toString cfg.retention.full}
|
|
||||||
repo1-retention-diff=${toString cfg.retention.diff}
|
|
||||||
repo1-cipher-type=aes-256-cbc
|
|
||||||
compress-type=${cfg.compression.type}
|
|
||||||
compress-level=${toString cfg.compression.level}
|
|
||||||
process-max=${toString cfg.processMax}
|
|
||||||
log-level-console=info
|
|
||||||
log-level-file=detail
|
|
||||||
log-path=/var/log/pgbackrest
|
|
||||||
spool-path=/var/spool/pgbackrest
|
|
||||||
|
|
||||||
[${cfg.stanza}]
|
|
||||||
pg1-path=/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}
|
|
||||||
pg1-user=postgres
|
|
||||||
'';
|
|
||||||
|
|
||||||
systemd.services.pgbackrest-stanza-create = {
|
|
||||||
description = "pgBackRest Stanza Create";
|
|
||||||
after = ["postgresql.service"];
|
|
||||||
requires = ["postgresql.service"];
|
|
||||||
path = [pkgs.pgbackrest];
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "postgres";
|
|
||||||
EnvironmentFile = cfg.secretFile;
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
};
|
||||||
script = ''
|
|
||||||
pgbackrest --stanza=${cfg.stanza} stanza-create || true
|
environment.etc."pgbackrest/pgbackrest.conf".text = ''
|
||||||
|
[global]
|
||||||
|
repo1-type=s3
|
||||||
|
repo1-s3-endpoint=${cfg.s3.endpoint}
|
||||||
|
repo1-s3-bucket=${cfg.s3.bucket}
|
||||||
|
repo1-s3-region=${cfg.s3.region}
|
||||||
|
repo1-path=${cfg.s3.path}
|
||||||
|
repo1-retention-full=${toString cfg.retention.full}
|
||||||
|
repo1-retention-diff=${toString cfg.retention.diff}
|
||||||
|
repo1-cipher-type=aes-256-cbc
|
||||||
|
compress-type=${cfg.compression.type}
|
||||||
|
compress-level=${toString cfg.compression.level}
|
||||||
|
process-max=${toString cfg.processMax}
|
||||||
|
log-level-console=info
|
||||||
|
log-level-file=detail
|
||||||
|
log-path=/var/log/pgbackrest
|
||||||
|
spool-path=/var/spool/pgbackrest
|
||||||
|
|
||||||
|
[${cfg.stanza}]
|
||||||
|
pg1-path=/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}
|
||||||
|
pg1-user=postgres
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.pgbackrest-backup = {
|
systemd.services.pgbackrest-stanza-create = {
|
||||||
description = "pgBackRest Full Backup";
|
description = "pgBackRest Stanza Create";
|
||||||
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
after = ["postgresql.service"];
|
||||||
requires = ["postgresql.service"];
|
requires = ["postgresql.service"];
|
||||||
wants = ["pgbackrest-stanza-create.service"];
|
path = [pkgs.pgbackrest];
|
||||||
path = [pkgs.pgbackrest];
|
serviceConfig = {
|
||||||
serviceConfig = {
|
Type = "oneshot";
|
||||||
Type = "oneshot";
|
User = "postgres";
|
||||||
User = "postgres";
|
EnvironmentFile = cfg.secretFile;
|
||||||
EnvironmentFile = cfg.secretFile;
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
pgbackrest --stanza=${cfg.stanza} stanza-create || true
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
script = ''
|
|
||||||
pgbackrest --stanza=${cfg.stanza} backup --type=full
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.pgbackrest-backup = {
|
systemd.services.pgbackrest-backup = {
|
||||||
wantedBy = ["timers.target"];
|
description = "pgBackRest Full Backup";
|
||||||
timerConfig = {
|
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
||||||
OnCalendar = cfg.schedule.full;
|
requires = ["postgresql.service"];
|
||||||
Persistent = true;
|
wants = ["pgbackrest-stanza-create.service"];
|
||||||
RandomizedDelaySec = "1h";
|
path = [pkgs.pgbackrest];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "postgres";
|
||||||
|
EnvironmentFile = cfg.secretFile;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
pgbackrest --stanza=${cfg.stanza} backup --type=full
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.pgbackrest-backup-diff = {
|
systemd.timers.pgbackrest-backup = {
|
||||||
description = "pgBackRest Differential Backup";
|
wantedBy = ["timers.target"];
|
||||||
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
timerConfig = {
|
||||||
requires = ["postgresql.service"];
|
OnCalendar = cfg.schedule.full;
|
||||||
wants = ["pgbackrest-stanza-create.service"];
|
Persistent = true;
|
||||||
path = [pkgs.pgbackrest];
|
RandomizedDelaySec = "1h";
|
||||||
serviceConfig = {
|
};
|
||||||
Type = "oneshot";
|
|
||||||
User = "postgres";
|
|
||||||
EnvironmentFile = cfg.secretFile;
|
|
||||||
};
|
};
|
||||||
script = ''
|
|
||||||
pgbackrest --stanza=${cfg.stanza} backup --type=diff
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.pgbackrest-backup-diff = {
|
systemd.services.pgbackrest-backup-diff = {
|
||||||
wantedBy = ["timers.target"];
|
description = "pgBackRest Differential Backup";
|
||||||
timerConfig = {
|
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
||||||
OnCalendar = cfg.schedule.diff;
|
requires = ["postgresql.service"];
|
||||||
Persistent = true;
|
wants = ["pgbackrest-stanza-create.service"];
|
||||||
RandomizedDelaySec = "5m";
|
path = [pkgs.pgbackrest];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "postgres";
|
||||||
|
EnvironmentFile = cfg.secretFile;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
pgbackrest --stanza=${cfg.stanza} backup --type=diff
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.timers.pgbackrest-backup-diff = {
|
||||||
"d /var/lib/pgbackrest 0750 postgres postgres -"
|
wantedBy = ["timers.target"];
|
||||||
"d /var/log/pgbackrest 0750 postgres postgres -"
|
timerConfig = {
|
||||||
"d /var/spool/pgbackrest 0750 postgres postgres -"
|
OnCalendar = cfg.schedule.diff;
|
||||||
];
|
Persistent = true;
|
||||||
});
|
RandomizedDelaySec = "5m";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/lib/pgbackrest 0750 postgres postgres -"
|
||||||
|
"d /var/log/pgbackrest 0750 postgres postgres -"
|
||||||
|
"d /var/spool/pgbackrest 0750 postgres postgres -"
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,24 +127,25 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
home.file.".config/opencode/oh-my-opencode.json".text = builtins.toJSON {
|
home.file.".config/opencode/oh-my-opencode.json".text =
|
||||||
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
|
builtins.toJSON {
|
||||||
google_auth = false;
|
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
|
||||||
agents = {
|
google_auth = false;
|
||||||
oracle = {
|
agents = {
|
||||||
model = "opencode/gpt-5.2";
|
oracle = {
|
||||||
};
|
model = "opencode/gpt-5.2";
|
||||||
frontend-ui-ux-engineer = {
|
};
|
||||||
model = "google/gemini-3-pro-high";
|
frontend-ui-ux-engineer = {
|
||||||
};
|
model = "google/gemini-3-pro-high";
|
||||||
document-writer = {
|
};
|
||||||
model = "google/gemini-3-flash";
|
document-writer = {
|
||||||
};
|
model = "google/gemini-3-flash";
|
||||||
multimodal-looker = {
|
};
|
||||||
model = "google/gemini-3-flash";
|
multimodal-looker = {
|
||||||
|
model = "google/gemini-3-flash";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
OPENCODE_EXPERIMENTAL_EXA = "true";
|
OPENCODE_EXPERIMENTAL_EXA = "true";
|
||||||
|
|||||||
Reference in New Issue
Block a user