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