1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.zabbixAgent;
10
11 inherit (lib)
12 mkDefault
13 mkEnableOption
14 mkPackageOption
15 mkIf
16 mkMerge
17 mkOption
18 ;
19 inherit (lib)
20 attrValues
21 concatMapStringsSep
22 literalExpression
23 optionalString
24 types
25 ;
26 inherit (lib.generators) toKeyValue;
27
28 user = "zabbix-agent";
29 group = "zabbix-agent";
30
31 moduleEnv = pkgs.symlinkJoin {
32 name = "zabbix-agent-module-env";
33 paths = attrValues cfg.modules;
34 };
35
36 configFile = pkgs.writeText "zabbix_agent.conf" (
37 toKeyValue { listsAsDuplicateKeys = true; } cfg.settings
38 );
39
40in
41
42{
43 imports = [
44 (lib.mkRemovedOptionModule [
45 "services"
46 "zabbixAgent"
47 "extraConfig"
48 ] "Use services.zabbixAgent.settings instead.")
49 ];
50
51 # interface
52
53 options = {
54
55 services.zabbixAgent = {
56 enable = mkEnableOption "the Zabbix Agent";
57
58 package = mkPackageOption pkgs [ "zabbix" "agent" ] { };
59
60 extraPackages = mkOption {
61 type = types.listOf types.package;
62 default = with pkgs; [ net-tools ];
63 defaultText = literalExpression "with pkgs; [ net-tools ]";
64 example = literalExpression "with pkgs; [ net-tools mysql ]";
65 description = ''
66 Packages to be added to the Zabbix {env}`PATH`.
67 Typically used to add executables for scripts, but can be anything.
68 '';
69 };
70
71 modules = mkOption {
72 type = types.attrsOf types.package;
73 description = "A set of modules to load.";
74 default = { };
75 example = literalExpression ''
76 {
77 "dummy.so" = pkgs.stdenv.mkDerivation {
78 name = "zabbix-dummy-module-''${cfg.package.version}";
79 src = cfg.package.src;
80 buildInputs = [ cfg.package ];
81 sourceRoot = "zabbix-''${cfg.package.version}/src/modules/dummy";
82 installPhase = '''
83 mkdir -p $out/lib
84 cp dummy.so $out/lib/
85 ''';
86 };
87 }
88 '';
89 };
90
91 server = mkOption {
92 type = types.str;
93 description = ''
94 The IP address or hostname of the Zabbix server to connect to.
95 '';
96 };
97
98 listen = {
99 ip = mkOption {
100 type = types.str;
101 default = "0.0.0.0";
102 description = ''
103 List of comma delimited IP addresses that the agent should listen on.
104 '';
105 };
106
107 port = mkOption {
108 type = types.port;
109 default = 10050;
110 description = ''
111 Agent will listen on this port for connections from the server.
112 '';
113 };
114 };
115
116 openFirewall = mkOption {
117 type = types.bool;
118 default = false;
119 description = ''
120 Open ports in the firewall for the Zabbix Agent.
121 '';
122 };
123
124 settings = mkOption {
125 type =
126 with types;
127 attrsOf (oneOf [
128 int
129 str
130 (listOf str)
131 ]);
132 default = { };
133 description = ''
134 Zabbix Agent configuration. Refer to
135 <https://www.zabbix.com/documentation/current/manual/appendix/config/zabbix_agentd>
136 for details on supported values.
137 '';
138 example = {
139 Hostname = "example.org";
140 DebugLevel = 4;
141 };
142 };
143
144 };
145
146 };
147
148 # implementation
149
150 config = mkIf cfg.enable {
151
152 services.zabbixAgent.settings = mkMerge [
153 {
154 LogType = "console";
155 Server = cfg.server;
156 ListenPort = cfg.listen.port;
157 }
158 (mkIf (cfg.modules != { }) {
159 LoadModule = builtins.attrNames cfg.modules;
160 LoadModulePath = "${moduleEnv}/lib";
161 })
162
163 # the default value for "ListenIP" is 0.0.0.0 but zabbix agent 2 cannot accept configuration files which
164 # explicitly set "ListenIP" to the default value...
165 (mkIf (cfg.listen.ip != "0.0.0.0") { ListenIP = cfg.listen.ip; })
166 ];
167
168 networking.firewall = mkIf cfg.openFirewall {
169 allowedTCPPorts = [ cfg.listen.port ];
170 };
171
172 users.users.${user} = {
173 description = "Zabbix Agent daemon user";
174 inherit group;
175 isSystemUser = true;
176 };
177
178 users.groups.${group} = { };
179
180 systemd.services.zabbix-agent = {
181 description = "Zabbix Agent";
182
183 wantedBy = [ "multi-user.target" ];
184
185 # https://www.zabbix.com/documentation/current/manual/config/items/userparameters
186 # > User parameters are commands executed by Zabbix agent.
187 # > /bin/sh is used as a command line interpreter under UNIX operating systems.
188 path =
189 with pkgs;
190 [
191 bash
192 "/run/wrappers"
193 ]
194 ++ cfg.extraPackages;
195
196 serviceConfig = {
197 ExecStart = "@${cfg.package}/sbin/zabbix_agentd zabbix_agentd -f --config ${configFile}";
198 Restart = "always";
199 RestartSec = 2;
200
201 User = user;
202 Group = group;
203 PrivateTmp = true;
204 };
205 };
206
207 };
208
209}