1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.cockroachdb;
7 crdb = cfg.package;
8
9 escape = builtins.replaceStrings ["%"] ["%%"];
10 ifNotNull = v: s: optionalString (v != null) s;
11
12 startupCommand = lib.concatStringsSep " "
13 [ # Basic startup
14 "${crdb}/bin/cockroach start"
15 "--logtostderr"
16 "--store=/var/lib/cockroachdb"
17 (ifNotNull cfg.locality "--locality='${cfg.locality}'")
18
19 # WebUI settings
20 "--http-addr='${cfg.http.address}:${toString cfg.http.port}'"
21
22 # Cluster listen address
23 "--listen-addr='${cfg.listen.address}:${toString cfg.listen.port}'"
24
25 # Cluster configuration
26 (ifNotNull cfg.join "--join=${cfg.join}")
27
28 # Cache and memory settings. Must be escaped.
29 "--cache='${escape cfg.cache}'"
30 "--max-sql-memory='${escape cfg.maxSqlMemory}'"
31
32 # Certificate/security settings.
33 (if cfg.insecure then "--insecure" else "--certs-dir=${cfg.certsDir}")
34 ];
35
36 addressOption = descr: defaultPort: {
37 address = mkOption {
38 type = types.str;
39 default = "localhost";
40 description = "Address to bind to for ${descr}";
41 };
42
43 port = mkOption {
44 type = types.port;
45 default = defaultPort;
46 description = "Port to bind to for ${descr}";
47 };
48 };
49in
50
51{
52 options = {
53 services.cockroachdb = {
54 enable = mkEnableOption "CockroachDB Server";
55
56 listen = addressOption "intra-cluster communication" 26257;
57
58 http = addressOption "http-based Admin UI" 8080;
59
60 locality = mkOption {
61 type = types.nullOr types.str;
62 default = null;
63 description = ''
64 An ordered, comma-separated list of key-value pairs that describe the
65 topography of the machine. Topography might include country,
66 datacenter or rack designations. Data is automatically replicated to
67 maximize diversities of each tier. The order of tiers is used to
68 determine the priority of the diversity, so the more inclusive
69 localities like country should come before less inclusive localities
70 like datacenter. The tiers and order must be the same on all nodes.
71 Including more tiers is better than including fewer. For example:
72
73 <literal>
74 country=us,region=us-west,datacenter=us-west-1b,rack=12
75 country=ca,region=ca-east,datacenter=ca-east-2,rack=4
76
77 planet=earth,province=manitoba,colo=secondary,power=3
78 </literal>
79 '';
80 };
81
82 join = mkOption {
83 type = types.nullOr types.str;
84 default = null;
85 description = "The addresses for connecting the node to a cluster.";
86 };
87
88 insecure = mkOption {
89 type = types.bool;
90 default = false;
91 description = "Run in insecure mode.";
92 };
93
94 certsDir = mkOption {
95 type = types.nullOr types.path;
96 default = null;
97 description = "The path to the certificate directory.";
98 };
99
100 user = mkOption {
101 type = types.str;
102 default = "cockroachdb";
103 description = "User account under which CockroachDB runs";
104 };
105
106 group = mkOption {
107 type = types.str;
108 default = "cockroachdb";
109 description = "User account under which CockroachDB runs";
110 };
111
112 openPorts = mkOption {
113 type = types.bool;
114 default = false;
115 description = "Open firewall ports for cluster communication by default";
116 };
117
118 cache = mkOption {
119 type = types.str;
120 default = "25%";
121 description = ''
122 The total size for caches.
123
124 This can be a percentage, expressed with a fraction sign or as a
125 decimal-point number, or any bytes-based unit. For example,
126 <literal>"25%"</literal>, <literal>"0.25"</literal> both represent
127 25% of the available system memory. The values
128 <literal>"1000000000"</literal> and <literal>"1GB"</literal> both
129 represent 1 gigabyte of memory.
130
131 '';
132 };
133
134 maxSqlMemory = mkOption {
135 type = types.str;
136 default = "25%";
137 description = ''
138 The maximum in-memory storage capacity available to store temporary
139 data for SQL queries.
140
141 This can be a percentage, expressed with a fraction sign or as a
142 decimal-point number, or any bytes-based unit. For example,
143 <literal>"25%"</literal>, <literal>"0.25"</literal> both represent
144 25% of the available system memory. The values
145 <literal>"1000000000"</literal> and <literal>"1GB"</literal> both
146 represent 1 gigabyte of memory.
147 '';
148 };
149
150 package = mkOption {
151 type = types.package;
152 default = pkgs.cockroachdb;
153 defaultText = literalExpression "pkgs.cockroachdb";
154 description = ''
155 The CockroachDB derivation to use for running the service.
156
157 This would primarily be useful to enable Enterprise Edition features
158 in your own custom CockroachDB build (Nixpkgs CockroachDB binaries
159 only contain open source features and open source code).
160 '';
161 };
162 };
163 };
164
165 config = mkIf config.services.cockroachdb.enable {
166 assertions = [
167 { assertion = !cfg.insecure -> cfg.certsDir != null;
168 message = "CockroachDB must have a set of SSL certificates (.certsDir), or run in Insecure Mode (.insecure = true)";
169 }
170 ];
171
172 environment.systemPackages = [ crdb ];
173
174 users.users = optionalAttrs (cfg.user == "cockroachdb") {
175 cockroachdb = {
176 description = "CockroachDB Server User";
177 uid = config.ids.uids.cockroachdb;
178 group = cfg.group;
179 };
180 };
181
182 users.groups = optionalAttrs (cfg.group == "cockroachdb") {
183 cockroachdb.gid = config.ids.gids.cockroachdb;
184 };
185
186 networking.firewall.allowedTCPPorts = lib.optionals cfg.openPorts
187 [ cfg.http.port cfg.listen.port ];
188
189 systemd.services.cockroachdb =
190 { description = "CockroachDB Server";
191 documentation = [ "man:cockroach(1)" "https://www.cockroachlabs.com" ];
192
193 after = [ "network.target" "time-sync.target" ];
194 requires = [ "time-sync.target" ];
195 wantedBy = [ "multi-user.target" ];
196
197 unitConfig.RequiresMountsFor = "/var/lib/cockroachdb";
198
199 serviceConfig =
200 { ExecStart = startupCommand;
201 Type = "notify";
202 User = cfg.user;
203 StateDirectory = "cockroachdb";
204 StateDirectoryMode = "0700";
205
206 Restart = "always";
207
208 # A conservative-ish timeout is alright here, because for Type=notify
209 # cockroach will send systemd pings during startup to keep it alive
210 TimeoutStopSec = 60;
211 RestartSec = 10;
212 };
213 };
214 };
215
216 meta.maintainers = with lib.maintainers; [ thoughtpolice ];
217}