]> git.immae.eu Git - perso/Immae/Config/Nix.git/blobdiff - systems/backup-2/databases/redis_replication.nix
Squash changes containing private information
[perso/Immae/Config/Nix.git] / systems / backup-2 / databases / redis_replication.nix
diff --git a/systems/backup-2/databases/redis_replication.nix b/systems/backup-2/databases/redis_replication.nix
new file mode 100644 (file)
index 0000000..53fa904
--- /dev/null
@@ -0,0 +1,171 @@
+{ 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;
+  };
+}
+
+