+{ 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 = "${lib.head config.myEnv.servers.eldiron.ips.main.ip4}:16379";
+ keyfile = config.secrets.fullPaths."redis/spiped_eldiron_keyfile";
+ };
+ };
+
+ secrets.keys = lib.mapAttrs' (name: hcfg:
+ lib.nameValuePair "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 // {
+ "redis/spiped_eldiron_keyfile" = { # For eldiron only
+ 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.fullPaths."redis_replication/${name}/config"}";
+ User = "redis";
+ RuntimeDirectory = "redis_${name}";
+ };
+ }) cfg.hosts;
+ };
+}
+
+