diff options
Diffstat (limited to 'nixos/modules/services/monitoring/netdata.nix')
-rw-r--r-- | nixos/modules/services/monitoring/netdata.nix | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix new file mode 100644 index 00000000000..f528d183042 --- /dev/null +++ b/nixos/modules/services/monitoring/netdata.nix @@ -0,0 +1,310 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.netdata; + + wrappedPlugins = pkgs.runCommand "wrapped-plugins" { preferLocalBuild = true; } '' + mkdir -p $out/libexec/netdata/plugins.d + ln -s /run/wrappers/bin/apps.plugin $out/libexec/netdata/plugins.d/apps.plugin + ln -s /run/wrappers/bin/cgroup-network $out/libexec/netdata/plugins.d/cgroup-network + ln -s /run/wrappers/bin/perf.plugin $out/libexec/netdata/plugins.d/perf.plugin + ln -s /run/wrappers/bin/slabinfo.plugin $out/libexec/netdata/plugins.d/slabinfo.plugin + ln -s /run/wrappers/bin/freeipmi.plugin $out/libexec/netdata/plugins.d/freeipmi.plugin + ''; + + plugins = [ + "${cfg.package}/libexec/netdata/plugins.d" + "${wrappedPlugins}/libexec/netdata/plugins.d" + ] ++ cfg.extraPluginPaths; + + configDirectory = pkgs.runCommand "netdata-config-d" { } '' + mkdir $out + ${concatStringsSep "\n" (mapAttrsToList (path: file: '' + mkdir -p "$out/$(dirname ${path})" + ln -s "${file}" "$out/${path}" + '') cfg.configDir)} + ''; + + localConfig = { + global = { + "config directory" = "/etc/netdata/conf.d"; + "plugins directory" = concatStringsSep " " plugins; + }; + web = { + "web files owner" = "root"; + "web files group" = "root"; + }; + "plugin:cgroups" = { + "script to get cgroup network interfaces" = "${wrappedPlugins}/libexec/netdata/plugins.d/cgroup-network"; + "use unified cgroups" = "yes"; + }; + }; + mkConfig = generators.toINI {} (recursiveUpdate localConfig cfg.config); + configFile = pkgs.writeText "netdata.conf" (if cfg.configText != null then cfg.configText else mkConfig); + + defaultUser = "netdata"; + +in { + options = { + services.netdata = { + enable = mkEnableOption "netdata"; + + package = mkOption { + type = types.package; + default = pkgs.netdata; + defaultText = literalExpression "pkgs.netdata"; + description = "Netdata package to use."; + }; + + user = mkOption { + type = types.str; + default = "netdata"; + description = "User account under which netdata runs."; + }; + + group = mkOption { + type = types.str; + default = "netdata"; + description = "Group under which netdata runs."; + }; + + configText = mkOption { + type = types.nullOr types.lines; + description = "Verbatim netdata.conf, cannot be combined with config."; + default = null; + example = '' + [global] + debug log = syslog + access log = syslog + error log = syslog + ''; + }; + + python = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable python-based plugins + ''; + }; + extraPackages = mkOption { + type = types.functionTo (types.listOf types.package); + default = ps: []; + defaultText = literalExpression "ps: []"; + example = literalExpression '' + ps: [ + ps.psycopg2 + ps.docker + ps.dnspython + ] + ''; + description = '' + Extra python packages available at runtime + to enable additional python plugins. + ''; + }; + }; + + extraPluginPaths = mkOption { + type = types.listOf types.path; + default = [ ]; + example = literalExpression '' + [ "/path/to/plugins.d" ] + ''; + description = '' + Extra paths to add to the netdata global "plugins directory" + option. Useful for when you want to include your own + collection scripts. + </para><para> + Details about writing a custom netdata plugin are available at: + <link xlink:href="https://docs.netdata.cloud/collectors/plugins.d/"/> + </para><para> + Cannot be combined with configText. + ''; + }; + + config = mkOption { + type = types.attrsOf types.attrs; + default = {}; + description = "netdata.conf configuration as nix attributes. cannot be combined with configText."; + example = literalExpression '' + global = { + "debug log" = "syslog"; + "access log" = "syslog"; + "error log" = "syslog"; + }; + ''; + }; + + configDir = mkOption { + type = types.attrsOf types.path; + default = {}; + description = '' + Complete netdata config directory except netdata.conf. + The default configuration is merged with changes + defined in this option. + Each top-level attribute denotes a path in the configuration + directory as in environment.etc. + Its value is the absolute path and must be readable by netdata. + Cannot be combined with configText. + ''; + example = literalExpression '' + "health_alarm_notify.conf" = pkgs.writeText "health_alarm_notify.conf" ''' + sendmail="/path/to/sendmail" + '''; + "health.d" = "/run/secrets/netdata/health.d"; + ''; + }; + + enableAnalyticsReporting = mkOption { + type = types.bool; + default = false; + description = '' + Enable reporting of anonymous usage statistics to Netdata Inc. via either + Google Analytics (in versions prior to 1.29.4), or Netdata Inc.'s + self-hosted PostHog (in versions 1.29.4 and later). + See: <link xlink:href="https://learn.netdata.cloud/docs/agent/anonymous-statistics"/> + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = + [ { assertion = cfg.config != {} -> cfg.configText == null ; + message = "Cannot specify both config and configText"; + } + ]; + + environment.etc."netdata/netdata.conf".source = configFile; + environment.etc."netdata/conf.d".source = configDirectory; + + systemd.services.netdata = { + description = "Real time performance monitoring"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = (with pkgs; [ curl gawk iproute2 which procps ]) + ++ lib.optional cfg.python.enable (pkgs.python3.withPackages cfg.python.extraPackages) + ++ lib.optional config.virtualisation.libvirtd.enable (config.virtualisation.libvirtd.package); + environment = { + PYTHONPATH = "${cfg.package}/libexec/netdata/python.d/python_modules"; + } // lib.optionalAttrs (!cfg.enableAnalyticsReporting) { + DO_NOT_TRACK = "1"; + }; + restartTriggers = [ + config.environment.etc."netdata/netdata.conf".source + config.environment.etc."netdata/conf.d".source + ]; + serviceConfig = { + ExecStart = "${cfg.package}/bin/netdata -P /run/netdata/netdata.pid -D -c /etc/netdata/netdata.conf"; + ExecReload = "${pkgs.util-linux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID"; + TimeoutStopSec = 60; + Restart = "on-failure"; + # User and group + User = cfg.user; + Group = cfg.group; + # Performance + LimitNOFILE = "30000"; + # Runtime directory and mode + RuntimeDirectory = "netdata"; + RuntimeDirectoryMode = "0750"; + # State directory and mode + StateDirectory = "netdata"; + StateDirectoryMode = "0750"; + # Cache directory and mode + CacheDirectory = "netdata"; + CacheDirectoryMode = "0750"; + # Logs directory and mode + LogsDirectory = "netdata"; + LogsDirectoryMode = "0750"; + # Configuration directory and mode + ConfigurationDirectory = "netdata"; + ConfigurationDirectoryMode = "0755"; + # Capabilities + CapabilityBoundingSet = [ + "CAP_DAC_OVERRIDE" # is required for freeipmi and slabinfo plugins + "CAP_DAC_READ_SEARCH" # is required for apps plugin + "CAP_FOWNER" # is required for freeipmi plugin + "CAP_SETPCAP" # is required for apps, perf and slabinfo plugins + "CAP_SYS_ADMIN" # is required for perf plugin + "CAP_SYS_PTRACE" # is required for apps plugin + "CAP_SYS_RESOURCE" # is required for ebpf plugin + "CAP_NET_RAW" # is required for fping app + "CAP_SYS_CHROOT" # is required for cgroups plugin + "CAP_SETUID" # is required for cgroups and cgroups-network plugins + ]; + # Sandboxing + ProtectSystem = "full"; + ProtectHome = "read-only"; + PrivateTmp = true; + ProtectControlGroups = true; + PrivateMounts = true; + }; + }; + + systemd.enableCgroupAccounting = true; + + security.wrappers = { + "apps.plugin" = { + source = "${cfg.package}/libexec/netdata/plugins.d/apps.plugin.org"; + capabilities = "cap_dac_read_search,cap_sys_ptrace+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+x,o-rwx"; + }; + + "cgroup-network" = { + source = "${cfg.package}/libexec/netdata/plugins.d/cgroup-network.org"; + capabilities = "cap_setuid+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+x,o-rwx"; + }; + + "perf.plugin" = { + source = "${cfg.package}/libexec/netdata/plugins.d/perf.plugin.org"; + capabilities = "cap_sys_admin+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+x,o-rwx"; + }; + + "slabinfo.plugin" = { + source = "${cfg.package}/libexec/netdata/plugins.d/slabinfo.plugin.org"; + capabilities = "cap_dac_override+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+x,o-rwx"; + }; + + } // optionalAttrs (cfg.package.withIpmi) { + "freeipmi.plugin" = { + source = "${cfg.package}/libexec/netdata/plugins.d/freeipmi.plugin.org"; + capabilities = "cap_dac_override,cap_fowner+ep"; + owner = cfg.user; + group = cfg.group; + permissions = "u+rx,g+x,o-rwx"; + }; + }; + + security.pam.loginLimits = [ + { domain = "netdata"; type = "soft"; item = "nofile"; value = "10000"; } + { domain = "netdata"; type = "hard"; item = "nofile"; value = "30000"; } + ]; + + users.users = optionalAttrs (cfg.user == defaultUser) { + ${defaultUser} = { + group = defaultUser; + isSystemUser = true; + }; + }; + + users.groups = optionalAttrs (cfg.group == defaultUser) { + ${defaultUser} = { }; + }; + + }; +} |