summary refs log tree commit diff
path: root/nixos/modules/services/databases/dragonflydb.nix
blob: e72afa9d908905ee8450962d931b82c807827a56 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.dragonflydb;
  dragonflydb = pkgs.dragonflydb;

  settings =
    {
      port = cfg.port;
      dir = "/var/lib/dragonflydb";
      keys_output_limit = cfg.keysOutputLimit;
    } //
    (lib.optionalAttrs (cfg.bind != null) { bind = cfg.bind; }) //
    (lib.optionalAttrs (cfg.requirePass != null) { requirepass = cfg.requirePass; }) //
    (lib.optionalAttrs (cfg.maxMemory != null) { maxmemory = cfg.maxMemory; }) //
    (lib.optionalAttrs (cfg.memcachePort != null) { memcache_port = cfg.memcachePort; }) //
    (lib.optionalAttrs (cfg.dbNum != null) { dbnum = cfg.dbNum; }) //
    (lib.optionalAttrs (cfg.cacheMode != null) { cache_mode = cfg.cacheMode; });
in
{

  ###### interface

  options = {
    services.dragonflydb = {
      enable = mkEnableOption "DragonflyDB";

      user = mkOption {
        type = types.str;
        default = "dragonfly";
        description = "The user to run DragonflyDB as";
      };

      port = mkOption {
        type = types.port;
        default = 6379;
        description = "The TCP port to accept connections.";
      };

      bind = mkOption {
        type = with types; nullOr str;
        default = "127.0.0.1";
        description = ''
          The IP interface to bind to.
          <literal>null</literal> means "all interfaces".
        '';
      };

      requirePass = mkOption {
        type = with types; nullOr str;
        default = null;
        description = "Password for database";
        example = "letmein!";
      };

      maxMemory = mkOption {
        type = with types; nullOr ints.unsigned;
        default = null;
        description = ''
          The maximum amount of memory to use for storage (in bytes).
          <literal>null</literal> means this will be automatically set.
        '';
      };

      memcachePort = mkOption {
        type = with types; nullOr port;
        default = null;
        description = ''
          To enable memcached compatible API on this port.
          <literal>null</literal> means disabled.
        '';
      };

      keysOutputLimit = mkOption {
        type = types.ints.unsigned;
        default = 8192;
        description = ''
          Maximum number of returned keys in keys command.
          <literal>keys</literal> is a dangerous command.
          We truncate its result to avoid blowup in memory when fetching too many keys.
        '';
      };

      dbNum = mkOption {
        type = with types; nullOr ints.unsigned;
        default = null;
        description = "Maximum number of supported databases for <literal>select</literal>";
      };

      cacheMode = mkOption {
        type = with types; nullOr bool;
        default = null;
        description = ''
          Once this mode is on, Dragonfly will evict items least likely to be stumbled
          upon in the future but only when it is near maxmemory limit.
        '';
      };
    };
  };

  ###### implementation

  config = mkIf config.services.dragonflydb.enable {

    users.users = optionalAttrs (cfg.user == "dragonfly") {
      dragonfly.description = "DragonflyDB server user";
      dragonfly.isSystemUser = true;
      dragonfly.group = "dragonfly";
    };
    users.groups = optionalAttrs (cfg.user == "dragonfly") { dragonfly = { }; };

    environment.systemPackages = [ dragonflydb ];

    systemd.services.dragonflydb = {
      description = "DragonflyDB server";

      wantedBy = [ "multi-user.target" ];
      after = [ "network.target" ];

      serviceConfig = {
        ExecStart = "${dragonflydb}/bin/dragonfly --alsologtostderr ${builtins.concatStringsSep " " (attrsets.mapAttrsToList (n: v: "--${n} ${strings.escapeShellArg v}") settings)}";

        User = cfg.user;

        # Filesystem access
        ReadWritePaths = [ settings.dir ];
        StateDirectory = "dragonflydb";
        StateDirectoryMode = "0700";
        # Process Properties
        LimitMEMLOCK = "infinity";
        # Caps
        CapabilityBoundingSet = "";
        NoNewPrivileges = true;
        # Sandboxing
        ProtectSystem = "strict";
        ProtectHome = true;
        PrivateTmp = true;
        PrivateDevices = true;
        ProtectKernelTunables = true;
        ProtectKernelModules = true;
        ProtectControlGroups = true;
        LockPersonality = true;
        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
        RestrictRealtime = true;
        PrivateMounts = true;
        MemoryDenyWriteExecute = true;
      };
    };
  };
}