1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.zookeeper;
7
8 zookeeperConfig = ''
9 dataDir=${cfg.dataDir}
10 clientPort=${toString cfg.port}
11 autopurge.purgeInterval=${toString cfg.purgeInterval}
12 ${cfg.extraConf}
13 ${cfg.servers}
14 '';
15
16 configDir = pkgs.buildEnv {
17 name = "zookeeper-conf";
18 paths = [
19 (pkgs.writeTextDir "zoo.cfg" zookeeperConfig)
20 (pkgs.writeTextDir "log4j.properties" cfg.logging)
21 ];
22 };
23
24in {
25
26 options.services.zookeeper = {
27 enable = mkOption {
28 description = "Whether to enable Zookeeper.";
29 default = false;
30 type = types.bool;
31 };
32
33 port = mkOption {
34 description = "Zookeeper Client port.";
35 default = 2181;
36 type = types.int;
37 };
38
39 id = mkOption {
40 description = "Zookeeper ID.";
41 default = 0;
42 type = types.int;
43 };
44
45 purgeInterval = mkOption {
46 description = ''
47 The time interval in hours for which the purge task has to be triggered. Set to a positive integer (1 and above) to enable the auto purging.
48 '';
49 default = 1;
50 type = types.int;
51 };
52
53 extraConf = mkOption {
54 description = "Extra configuration for Zookeeper.";
55 type = types.lines;
56 default = ''
57 initLimit=5
58 syncLimit=2
59 tickTime=2000
60 '';
61 };
62
63 servers = mkOption {
64 description = "All Zookeeper Servers.";
65 default = "";
66 type = types.lines;
67 example = ''
68 server.0=host0:2888:3888
69 server.1=host1:2888:3888
70 server.2=host2:2888:3888
71 '';
72 };
73
74 logging = mkOption {
75 description = "Zookeeper logging configuration.";
76 default = ''
77 zookeeper.root.logger=INFO, CONSOLE
78 log4j.rootLogger=INFO, CONSOLE
79 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
80 log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
81 log4j.appender.CONSOLE.layout.ConversionPattern=[myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
82 '';
83 type = types.lines;
84 };
85
86 dataDir = mkOption {
87 type = types.path;
88 default = "/var/lib/zookeeper";
89 description = ''
90 Data directory for Zookeeper
91 '';
92 };
93
94 extraCmdLineOptions = mkOption {
95 description = "Extra command line options for the Zookeeper launcher.";
96 default = [ "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
97 type = types.listOf types.str;
98 example = [ "-Djava.net.preferIPv4Stack=true" "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
99 };
100
101 preferIPv4 = mkOption {
102 type = types.bool;
103 default = true;
104 description = ''
105 Add the -Djava.net.preferIPv4Stack=true flag to the Zookeeper server.
106 '';
107 };
108
109 };
110
111
112 config = mkIf cfg.enable {
113 systemd.services.zookeeper = {
114 description = "Zookeeper Daemon";
115 wantedBy = [ "multi-user.target" ];
116 after = [ "network-interfaces.target" ];
117 environment = { ZOOCFGDIR = configDir; };
118 serviceConfig = {
119 ExecStart = ''
120 ${pkgs.jre}/bin/java \
121 -cp "${pkgs.zookeeper}/lib/*:${pkgs.zookeeper}/${pkgs.zookeeper.name}.jar:${configDir}" \
122 ${toString cfg.extraCmdLineOptions} \
123 -Dzookeeper.datadir.autocreate=false \
124 ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \
125 org.apache.zookeeper.server.quorum.QuorumPeerMain \
126 ${configDir}/zoo.cfg
127 '';
128 User = "zookeeper";
129 PermissionsStartOnly = true;
130 };
131 preStart = ''
132 mkdir -m 0700 -p ${cfg.dataDir}
133 if [ "$(id -u)" = 0 ]; then chown zookeeper ${cfg.dataDir}; fi
134 echo "${toString cfg.id}" > ${cfg.dataDir}/myid
135 '';
136 };
137
138 users.extraUsers = singleton {
139 name = "zookeeper";
140 uid = config.ids.uids.zookeeper;
141 description = "Zookeeper daemon user";
142 home = cfg.dataDir;
143 };
144 };
145}