1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.zookeeper;
9
10 zookeeperConfig = ''
11 dataDir=${cfg.dataDir}
12 clientPort=${toString cfg.port}
13 autopurge.purgeInterval=${toString cfg.purgeInterval}
14 ${cfg.extraConf}
15 ${cfg.servers}
16 '';
17
18 configDir = pkgs.buildEnv {
19 name = "zookeeper-conf";
20 paths = [
21 (pkgs.writeTextDir "zoo.cfg" zookeeperConfig)
22 (pkgs.writeTextDir "logback.xml" cfg.logging)
23 ];
24 };
25
26in
27{
28
29 options.services.zookeeper = {
30 enable = lib.mkEnableOption "Zookeeper";
31
32 port = lib.mkOption {
33 description = "Zookeeper Client port.";
34 default = 2181;
35 type = lib.types.port;
36 };
37
38 id = lib.mkOption {
39 description = "Zookeeper ID.";
40 default = 0;
41 type = lib.types.int;
42 };
43
44 purgeInterval = lib.mkOption {
45 description = ''
46 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.
47 '';
48 default = 1;
49 type = lib.types.int;
50 };
51
52 extraConf = lib.mkOption {
53 description = "Extra configuration for Zookeeper.";
54 type = lib.types.lines;
55 default = ''
56 initLimit=5
57 syncLimit=2
58 tickTime=2000
59 '';
60 };
61
62 servers = lib.mkOption {
63 description = "All Zookeeper Servers.";
64 default = "";
65 type = lib.types.lines;
66 example = ''
67 server.0=host0:2888:3888
68 server.1=host1:2888:3888
69 server.2=host2:2888:3888
70 '';
71 };
72
73 logging = lib.mkOption {
74 description = "Zookeeper logging configuration, logback.xml.";
75 default = ''
76 <configuration>
77 <property name="zookeeper.console.threshold" value="INFO" />
78 <property name="zookeeper.log.dir" value="." />
79 <property name="zookeeper.log.file" value="zookeeper.log" />
80 <property name="zookeeper.log.threshold" value="INFO" />
81 <property name="zookeeper.log.maxfilesize" value="256MB" />
82 <property name="zookeeper.log.maxbackupindex" value="20" />
83 <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
84 <encoder>
85 <pattern>%d{ISO8601} [myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n</pattern>
86 </encoder>
87 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
88 <level>''${zookeeper.console.threshold}</level>
89 </filter>
90 </appender>
91 <root level="INFO">
92 <appender-ref ref="CONSOLE" />
93 </root>
94 </configuration>
95 '';
96 type = lib.types.lines;
97 };
98
99 dataDir = lib.mkOption {
100 type = lib.types.path;
101 default = "/var/lib/zookeeper";
102 description = ''
103 Data directory for Zookeeper
104 '';
105 };
106
107 extraCmdLineOptions = lib.mkOption {
108 description = "Extra command line options for the Zookeeper launcher.";
109 default = [
110 "-Dcom.sun.management.jmxremote"
111 "-Dcom.sun.management.jmxremote.local.only=true"
112 ];
113 type = lib.types.listOf lib.types.str;
114 example = [
115 "-Djava.net.preferIPv4Stack=true"
116 "-Dcom.sun.management.jmxremote"
117 "-Dcom.sun.management.jmxremote.local.only=true"
118 ];
119 };
120
121 preferIPv4 = lib.mkOption {
122 type = lib.types.bool;
123 default = true;
124 description = ''
125 Add the -Djava.net.preferIPv4Stack=true flag to the Zookeeper server.
126 '';
127 };
128
129 package = lib.mkPackageOption pkgs "zookeeper" { };
130
131 jre = lib.mkOption {
132 description = "The JRE with which to run Zookeeper";
133 default = cfg.package.jre;
134 defaultText = lib.literalExpression "pkgs.zookeeper.jre";
135 example = lib.literalExpression "pkgs.jre";
136 type = lib.types.package;
137 };
138 };
139
140 config = lib.mkIf cfg.enable {
141 environment.systemPackages = [ cfg.package ];
142
143 systemd.tmpfiles.rules = [
144 "d '${cfg.dataDir}' 0700 zookeeper - - -"
145 "Z '${cfg.dataDir}' 0700 zookeeper - - -"
146 ];
147
148 systemd.services.zookeeper = {
149 description = "Zookeeper Daemon";
150 wantedBy = [ "multi-user.target" ];
151 after = [ "network.target" ];
152 serviceConfig = {
153 ExecStart = ''
154 ${cfg.jre}/bin/java \
155 -cp "${cfg.package}/lib/*:${configDir}" \
156 ${lib.escapeShellArgs cfg.extraCmdLineOptions} \
157 -Dzookeeper.datadir.autocreate=false \
158 ${lib.optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \
159 org.apache.zookeeper.server.quorum.QuorumPeerMain \
160 ${configDir}/zoo.cfg
161 '';
162 User = "zookeeper";
163 };
164 preStart = ''
165 echo "${toString cfg.id}" > ${cfg.dataDir}/myid
166 mkdir -p ${cfg.dataDir}/version-2
167 '';
168 };
169
170 users.users.zookeeper = {
171 isSystemUser = true;
172 group = "zookeeper";
173 description = "Zookeeper daemon user";
174 home = cfg.dataDir;
175 };
176 users.groups.zookeeper = { };
177 };
178}