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