feat(services): openrgb + restic toggles; close out the opt-in services item
Finishing the four remaining "opt-in services" candidates — but two of
them aren't service-shaped, so the package-vs-toggle principle applies:
- Nextcloud client → a bare tray app; already in the app-suite menu,
not a service.
- WireGuard → NetworkManager (on distro-wide) imports .conf
tunnels natively, so there's no daemon to "just
enable". Only the wg/wg-quick CLI is missing →
wireguard-tools added to the app-suite menu.
The two that ARE config-backed become nomarchy.services.* toggles:
- openrgb → services.hardware.openrgb (daemon + device udev rules).
- restic → a small scaffolded surface (repository / passwordFile /
paths) over services.restic.backups: daily timer, 7/4/6
retention, --exclude-caches, repo auto-init. Asserts that
repository + passwordFile are set when enabled. passwordFile
is typed `str`, not `path`, so a flake-relative secret can't
be copied into the world-readable store.
README option table and ROADMAP (services now "Seventeen shipped";
cloud-sync / networking / backup / devices areas updated) + the downstream
system.nix examples. Both branches eval-verified; the restic assertions
confirmed firing when repo/password are unset.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,47 @@ in
|
||||
printing.enable = lib.mkEnableOption ''
|
||||
CUPS printing with Avahi/mDNS, so network printers are auto-discovered
|
||||
(add vendor drivers via `services.printing.drivers`)'';
|
||||
|
||||
openrgb.enable = lib.mkEnableOption ''
|
||||
the OpenRGB daemon and GUI for controlling RGB lighting on peripherals
|
||||
and (where supported) motherboards — installs the udev rules for device
|
||||
access. Some motherboard controllers also need `hardware.i2c.enable`'';
|
||||
|
||||
restic = {
|
||||
enable = lib.mkEnableOption ''
|
||||
a scheduled (daily) restic backup — headless, complementing the Pika
|
||||
GUI. Backs up `paths` with sane retention (7 daily / 4 weekly /
|
||||
6 monthly); needs a `repository` and a `passwordFile` (below)'';
|
||||
|
||||
repository = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
example = "/mnt/backup/restic";
|
||||
description = ''
|
||||
The restic repository as a path or URL — e.g. `/mnt/backup/restic`,
|
||||
`sftp:user@host:/srv/restic`, `b2:bucket:/path`. Required when
|
||||
`restic.enable` is set.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/etc/nomarchy/restic-password";
|
||||
description = ''
|
||||
Path to a file holding the repository password. Give an absolute
|
||||
path that lives ON THE MACHINE — not a `./file` in the flake, which
|
||||
would copy the secret into the world-readable Nix store. Required
|
||||
when `restic.enable` is set.
|
||||
'';
|
||||
};
|
||||
|
||||
paths = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "/home" ];
|
||||
description = "Paths to include in the backup.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
@@ -204,5 +245,34 @@ in
|
||||
openFirewall = true;
|
||||
};
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.openrgb.enable {
|
||||
services.hardware.openrgb.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.restic.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.restic.repository != "";
|
||||
message = "nomarchy.services.restic.repository must be set when restic is enabled.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.restic.passwordFile != null;
|
||||
message = "nomarchy.services.restic.passwordFile must be set when restic is enabled.";
|
||||
}
|
||||
];
|
||||
services.restic.backups.nomarchy = {
|
||||
repository = cfg.restic.repository;
|
||||
passwordFile = cfg.restic.passwordFile;
|
||||
paths = cfg.restic.paths;
|
||||
initialize = true; # create the repo on first run if it doesn't exist
|
||||
extraBackupArgs = [ "--exclude-caches" ];
|
||||
pruneOpts = [ "--keep-daily 7" "--keep-weekly 4" "--keep-monthly 6" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true; # catch up a missed run after downtime
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user