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 = mkEnableOption "Zookeeper";
28
29 port = mkOption {
30 description = "Zookeeper Client port.";
31 default = 2181;
32 type = types.port;
33 };
34
35 id = mkOption {
36 description = "Zookeeper ID.";
37 default = 0;
38 type = types.int;
39 };
40
41 purgeInterval = mkOption {
42 description = ''
43 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.
44 '';
45 default = 1;
46 type = types.int;
47 };
48
49 extraConf = mkOption {
50 description = "Extra configuration for Zookeeper.";
51 type = types.lines;
52 default = ''
53 initLimit=5
54 syncLimit=2
55 tickTime=2000
56 '';
57 };
58
59 servers = mkOption {
60 description = "All Zookeeper Servers.";
61 default = "";
62 type = types.lines;
63 example = ''
64 server.0=host0:2888:3888
65 server.1=host1:2888:3888
66 server.2=host2:2888:3888
67 '';
68 };
69
70 logging = mkOption {
71 description = "Zookeeper logging configuration.";
72 default = ''
73 zookeeper.root.logger=INFO, CONSOLE
74 log4j.rootLogger=INFO, CONSOLE
75 log4j.logger.org.apache.zookeeper.audit.Log4jAuditLogger=INFO, CONSOLE
76 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
77 log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
78 log4j.appender.CONSOLE.layout.ConversionPattern=[myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
79 '';
80 type = types.lines;
81 };
82
83 dataDir = mkOption {
84 type = types.path;
85 default = "/var/lib/zookeeper";
86 description = ''
87 Data directory for Zookeeper
88 '';
89 };
90
91 extraCmdLineOptions = mkOption {
92 description = "Extra command line options for the Zookeeper launcher.";
93 default = [ "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
94 type = types.listOf types.str;
95 example = [ "-Djava.net.preferIPv4Stack=true" "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ];
96 };
97
98 preferIPv4 = mkOption {
99 type = types.bool;
100 default = true;
101 description = ''
102 Add the -Djava.net.preferIPv4Stack=true flag to the Zookeeper server.
103 '';
104 };
105
106 package = mkPackageOption pkgs "zookeeper" { };
107
108 jre = mkOption {
109 description = "The JRE with which to run Zookeeper";
110 default = cfg.package.jre;
111 defaultText = literalExpression "pkgs.zookeeper.jre";
112 example = literalExpression "pkgs.jre";
113 type = types.package;
114 };
115 };
116
117
118 config = mkIf cfg.enable {
119 environment.systemPackages = [cfg.package];
120
121 systemd.tmpfiles.rules = [
122 "d '${cfg.dataDir}' 0700 zookeeper - - -"
123 "Z '${cfg.dataDir}' 0700 zookeeper - - -"
124 ];
125
126 systemd.services.zookeeper = {
127 description = "Zookeeper Daemon";
128 wantedBy = [ "multi-user.target" ];
129 after = [ "network.target" ];
130 serviceConfig = {
131 ExecStart = ''
132 ${cfg.jre}/bin/java \
133 -cp "${cfg.package}/lib/*:${configDir}" \
134 ${escapeShellArgs cfg.extraCmdLineOptions} \
135 -Dzookeeper.datadir.autocreate=false \
136 ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \
137 org.apache.zookeeper.server.quorum.QuorumPeerMain \
138 ${configDir}/zoo.cfg
139 '';
140 User = "zookeeper";
141 };
142 preStart = ''
143 echo "${toString cfg.id}" > ${cfg.dataDir}/myid
144 mkdir -p ${cfg.dataDir}/version-2
145 '';
146 };
147
148 users.users.zookeeper = {
149 isSystemUser = true;
150 group = "zookeeper";
151 description = "Zookeeper daemon user";
152 home = cfg.dataDir;
153 };
154 users.groups.zookeeper = {};
155 };
156}