{ pkgs, config, lib, ... }: let cfg = config.myServices.databasesReplication.redis; in { options.myServices.databasesReplication.redis = { enable = lib.mkEnableOption "Enable redis replication"; base = lib.mkOption { type = lib.types.path; description = '' Base path to put the replications ''; }; hosts = lib.mkOption { default = {}; description = '' Hosts to backup ''; type = lib.types.attrsOf (lib.types.submodule { options = { package = lib.mkOption { type = lib.types.package; default = pkgs.redis; description = '' Redis package for this host ''; }; host = lib.mkOption { type = lib.types.str; description = '' Host to connect to ''; }; port = lib.mkOption { type = lib.types.str; description = '' Port to connect to ''; }; password = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = '' Password to use ''; }; }; }); }; }; config = lib.mkIf cfg.enable { users.users.redis = { description = "Redis database user"; group = "redis"; uid = config.ids.uids.redis; extraGroups = [ "keys" ]; }; users.groups.redis.gid = config.ids.gids.redis; services.spiped = { # sync from eldiron enable = true; config.redis = { encrypt = true; source = "127.0.0.1:16379"; target = "${config.myEnv.servers.eldiron.ips.main.ip4}:16379"; keyfile = "${config.secrets.location}/redis/spiped_eldiron_keyfile"; }; }; secrets.keys = lib.flatten (lib.mapAttrsToList (name: hcfg: [ { dest = "redis_replication/${name}/config"; user = "redis"; group = "redis"; permissions = "0400"; text = '' pidfile ${cfg.base}/${name}/redis/redis.pid port 0 unixsocket /run/redis_${name}/redis.sock loglevel notice logfile /dev/null syslog-enabled yes databases 16 save 900 1 save 300 10 save 60 10000 dbfilename dump.rdb dir ${cfg.base}/${name}/redis/ slaveof ${hcfg.host} ${hcfg.port} ${if hcfg.password != null then "masterauth ${hcfg.password}" else ""} appendOnly no appendfsync everysec slowlog-log-slower-than 10000 slowlog-max-len 128 unixsocketperm 777 maxclients 1024 ''; } ]) cfg.hosts) ++ [ { # For eldiron only dest = "redis/spiped_eldiron_keyfile"; user = "spiped"; group = "spiped"; permissions = "0400"; text = config.myEnv.databases.redis.spiped_key; } ]; services.cron = { enable = true; systemCronJobs = lib.flatten (lib.mapAttrsToList (name: hcfg: let dataDir = "${cfg.base}/${name}/redis"; backupDir = "${cfg.base}/${name}/redis_backup"; backup_script = pkgs.writeScript "backup_redis_${name}" '' #!${pkgs.stdenv.shell} ${pkgs.coreutils}/bin/cp ${cfg.base}/${name}/redis/dump.rdb \ ${backupDir}/$(${pkgs.coreutils}/bin/date -Iminutes).rdb ''; u = pkgs.callPackage ./utils.nix {}; cleanup_script = pkgs.writeScript "cleanup_redis_${name}" (u.exponentialDumps "rdb" backupDir); in [ "0 22,4,10,16 * * * root ${backup_script}" "0 3 * * * root ${cleanup_script}" ]) cfg.hosts); }; system.activationScripts = lib.attrsets.mapAttrs' (name: hcfg: lib.attrsets.nameValuePair "redis_replication_${name}" { deps = [ "users" "groups" ]; text = '' install -m 0700 -o redis -g redis -d ${cfg.base}/${name}/redis install -m 0700 -o redis -g redis -d ${cfg.base}/${name}/redis_backup ''; }) cfg.hosts; systemd.services = { spiped_redis = { # For eldiron description = "Secure pipe 'redis'"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Restart = "always"; User = "spiped"; PermissionsStartOnly = true; SupplementaryGroups = "keys"; }; script = "exec ${pkgs.spiped}/bin/spiped -F `cat /etc/spiped/redis.spec`"; }; } // lib.attrsets.mapAttrs' (name: hcfg: let dataDir = "${cfg.base}/${name}/redis"; in lib.attrsets.nameValuePair "redis_backup_${name}" { description = "Redis replication for ${name}"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; unitConfig.RequiresMountsFor = dataDir; serviceConfig = { ExecStart = "${hcfg.package}/bin/redis-server ${config.secrets.location}/redis_replication/${name}/config"; User = "redis"; RuntimeDirectory = "redis_${name}"; }; }) cfg.hosts; }; }