tl;dr Config depend on itself. I understand why it could cause problem but from the following two lines, only one run into infinite recursion even tho the backups2
and backups3
variables are the same but one wraping the same value in an array itself:
backups_to_set = [config.nindouja.backups3];
VS
backups_to_set = config.nindouja.backups2
Basically, creating the array in my custom config breaks; but creating it where I need it does not. And I’ll need an array
All relevant files will be at the bottom as minified for posterity but also include link to the actual file on my GitLab instance.
Hello there, I’m trying to make my config really make it really easy to reuse it across different computers. In order to do that, I’ve defined a custom module under config; then each of my users will set attributes of this module based on their needs and then my whole config is generated using reference to my submodule of config.
Explaining that, it should be evident that some self recursion might occur. But it wasn’t that clear to me at first when I “designed” it that way, and also I’ve had some infinite recursion problems I’ve always managed to solve them. Well not this time !
I’ve simplified the file causing the recursion almost as much as possible. It’s below, and on my gitlab.
In the current state, it does build as i’m not referencing my actual config (cf comment ‘CASE 1’); if i replace that line with the one under ‘case 2’, it still build even tho i’m referencing my own config; but if i put the value from my config in an array in goes into an infinite recursion.
You’ll probably need access to my config module definition and usage. You find both minified version below with links to the actual.
Last note; I’ve tried striping backups2 and backups3 of their inner call to the config in the following snippet. But that changes nothing. remote = /run/media/nindouja/portable_bckp/Backups/${config.nindouja.user.username}__at__${config.nindouja.hostname}"
. As expected because its used in the version that does not cause infinite recursion anyway.
Thanks a lot for taking the time !
Minified version of the file causing infinite recursion
{
lib,
pkgs,
config,
...
}: let
# Common values
username = config.nindouja.user.username;
hostname = config.nindouja.hostname;
# Secret key and resolved password file path
backupRepoPasswordSopsKey = "users/${username}/backup_repo";
backupPasswordFilePath = config.sops.secrets."${backupRepoPasswordSopsKey}".path;
# Function to generate a full backup configuration from a backup submodule defined in ninja-config
generic_backup = backup: {
environment.etc."rclone-${backup.id}-backup.conf".text =
''
[${backup.id}_backup]
''
+ backup.config;
};
# CASE 1 (OK): static data works great
backups_to_set = [
{
id = "localtmp";
config = ''
type = alias
remote = /run/media/${username}/portable_bckp/Backups/${username}__at__${hostname}
'';
}
];
# CASE 2 (OK): getting one backup from personal config, and wraping it in a list
#backups_to_set = [config.nindouja.backups3];
# CASE 3 (KO): getting all backups from config
#backups_to_set = config.nindouja.backups2;
in {
config = lib.mkIf (lib.length backups_to_set > 0) (lib.mkMerge [
# Individual backup configurations
(lib.mkMerge (builtins.map generic_backup backups_to_set))
# Base configuration
{
environment.systemPackages = with pkgs; [
restic
rclone
];
sops.secrets."${backupRepoPasswordSopsKey}" = {
owner = config.users.users.${username}.name;
inherit (config.users.users.${username}) group;
};
}
]);
}
Relevant part of my config module definition
{
lib,
pkgs,
config,
ninja-base-config,
...
}: let
in {
options.nindouja = {
backups3 = lib.mkOption {
type = submodule {
options = {
id = T_str;
config = T_str; # REF: https://rclone.org/docs/
includes = mkOption {
type = listOf str;
default = [];
};
excludes = mkOption {
type = listOf str;
default = [];
};
timer = mkOption {
type = str;
# REF: https://silentlad.com/systemd-timers-oncalendar-(cron)-format-explained
default = "Monday *-*-* 20:00:00";
};
};
};
};
backups2 = mkOption {
type = listOf (submodule {
options = {
id = T_str;
config = T_str; # REF: https://rclone.org/docs/
includes = mkOption {
type = listOf str;
default = [];
};
excludes = mkOption {
type = listOf str;
default = [];
};
extraArgs = mkOption {
type = listOf str;
default = [];
};
timer = mkOption {
type = str;
# REF: https://silentlad.com/systemd-timers-oncalendar-(cron)-format-explained
default = "Monday *-*-* 20:00:00";
};
};
});
};
}
Relevant part of my custom config module config usage
{
lib,
config,
...
}: {
config.nindouja = {
backups3 = {
id = "newlocal";
config = ''
type = alias
remote = /run/media/nindouja/portable_bckp/Backups/${config.nindouja.user.username}__at__${config.nindouja.hostname}"
'';
};
backups2 = [
{
id = "newlocal";
config = ''
type = alias
remote = /run/media/nindouja/portable_bckp/Backups/${config.nindouja.user.username}__at__${config.nindouja.hostname}"
'';
}
];
};
}