at 23.11-beta 9.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.datadog-agent; 7 8 ddConf = { 9 skip_ssl_validation = false; 10 confd_path = "/etc/datadog-agent/conf.d"; 11 additional_checksd = "/etc/datadog-agent/checks.d"; 12 use_dogstatsd = true; 13 } 14 // optionalAttrs (cfg.logLevel != null) { log_level = cfg.logLevel; } 15 // optionalAttrs (cfg.hostname != null) { inherit (cfg) hostname; } 16 // optionalAttrs (cfg.ddUrl != null) { dd_url = cfg.ddUrl; } 17 // optionalAttrs (cfg.site != null) { site = cfg.site; } 18 // optionalAttrs (cfg.tags != null ) { tags = concatStringsSep ", " cfg.tags; } 19 // optionalAttrs (cfg.enableLiveProcessCollection) { process_config = { enabled = "true"; }; } 20 // optionalAttrs (cfg.enableTraceAgent) { apm_config = { enabled = true; }; } 21 // cfg.extraConfig; 22 23 # Generate Datadog configuration files for each configured checks. 24 # This works because check configurations have predictable paths, 25 # and because JSON is a valid subset of YAML. 26 makeCheckConfigs = entries: mapAttrs' (name: conf: { 27 name = "datadog-agent/conf.d/${name}.d/conf.yaml"; 28 value.source = pkgs.writeText "${name}-check-conf.yaml" (builtins.toJSON conf); 29 }) entries; 30 31 defaultChecks = { 32 disk = cfg.diskCheck; 33 network = cfg.networkCheck; 34 }; 35 36 # Assemble all check configurations and the top-level agent 37 # configuration. 38 etcfiles = with pkgs; with builtins; 39 { "datadog-agent/datadog.yaml" = { 40 source = writeText "datadog.yaml" (toJSON ddConf); 41 }; 42 } // makeCheckConfigs (cfg.checks // defaultChecks); 43 44 # Apply the configured extraIntegrations to the provided agent 45 # package. See the documentation of `dd-agent/integrations-core.nix` 46 # for detailed information on this. 47 datadogPkg = cfg.package.override { 48 pythonPackages = pkgs.datadog-integrations-core cfg.extraIntegrations; 49 }; 50in { 51 options.services.datadog-agent = { 52 enable = mkEnableOption (lib.mdDoc "Datadog-agent v7 monitoring service"); 53 54 package = mkOption { 55 default = pkgs.datadog-agent; 56 defaultText = literalExpression "pkgs.datadog-agent"; 57 description = lib.mdDoc '' 58 Which DataDog v7 agent package to use. Note that the provided 59 package is expected to have an overridable `pythonPackages`-attribute 60 which configures the Python environment with the Datadog 61 checks. 62 ''; 63 type = types.package; 64 }; 65 66 apiKeyFile = mkOption { 67 description = lib.mdDoc '' 68 Path to a file containing the Datadog API key to associate the 69 agent with your account. 70 ''; 71 example = "/run/keys/datadog_api_key"; 72 type = types.path; 73 }; 74 75 ddUrl = mkOption { 76 description = lib.mdDoc '' 77 Custom dd_url to configure the agent with. Useful if traffic to datadog 78 needs to go through a proxy. 79 Don't use this to point to another datadog site (EU) - use site instead. 80 ''; 81 default = null; 82 example = "http://haproxy.example.com:3834"; 83 type = types.nullOr types.str; 84 }; 85 86 site = mkOption { 87 description = lib.mdDoc '' 88 The datadog site to point the agent towards. 89 Set to datadoghq.eu to point it to their EU site. 90 ''; 91 default = null; 92 example = "datadoghq.eu"; 93 type = types.nullOr types.str; 94 }; 95 96 tags = mkOption { 97 description = lib.mdDoc "The tags to mark this Datadog agent"; 98 example = [ "test" "service" ]; 99 default = null; 100 type = types.nullOr (types.listOf types.str); 101 }; 102 103 hostname = mkOption { 104 description = lib.mdDoc "The hostname to show in the Datadog dashboard (optional)"; 105 default = null; 106 example = "mymachine.mydomain"; 107 type = types.nullOr types.str; 108 }; 109 110 logLevel = mkOption { 111 description = lib.mdDoc "Logging verbosity."; 112 default = null; 113 type = types.nullOr (types.enum ["DEBUG" "INFO" "WARN" "ERROR"]); 114 }; 115 116 extraIntegrations = mkOption { 117 default = {}; 118 type = types.attrs; 119 120 description = lib.mdDoc '' 121 Extra integrations from the Datadog core-integrations 122 repository that should be built and included. 123 124 By default the included integrations are disk, mongo, network, 125 nginx and postgres. 126 127 To include additional integrations the name of the derivation 128 and a function to filter its dependencies from the Python 129 package set must be provided. 130 ''; 131 132 example = literalExpression '' 133 { 134 ntp = pythonPackages: [ pythonPackages.ntplib ]; 135 } 136 ''; 137 }; 138 139 extraConfig = mkOption { 140 default = {}; 141 type = types.attrs; 142 description = lib.mdDoc '' 143 Extra configuration options that will be merged into the 144 main config file {file}`datadog.yaml`. 145 ''; 146 }; 147 148 enableLiveProcessCollection = mkOption { 149 description = lib.mdDoc '' 150 Whether to enable the live process collection agent. 151 ''; 152 default = false; 153 type = types.bool; 154 }; 155 156 processAgentPackage = mkOption { 157 default = pkgs.datadog-process-agent; 158 defaultText = literalExpression "pkgs.datadog-process-agent"; 159 description = lib.mdDoc '' 160 Which DataDog v7 agent package to use. Note that the provided 161 package is expected to have an overridable `pythonPackages`-attribute 162 which configures the Python environment with the Datadog 163 checks. 164 ''; 165 type = types.package; 166 }; 167 168 enableTraceAgent = mkOption { 169 description = lib.mdDoc '' 170 Whether to enable the trace agent. 171 ''; 172 default = false; 173 type = types.bool; 174 }; 175 176 checks = mkOption { 177 description = lib.mdDoc '' 178 Configuration for all Datadog checks. Keys of this attribute 179 set will be used as the name of the check to create the 180 appropriate configuration in `conf.d/$check.d/conf.yaml`. 181 182 The configuration is converted into JSON from the plain Nix 183 language configuration, meaning that you should write 184 configuration adhering to Datadog's documentation - but in Nix 185 language. 186 187 Refer to the implementation of this module (specifically the 188 definition of `defaultChecks`) for an example. 189 190 Note: The 'disk' and 'network' check are configured in 191 separate options because they exist by default. Attempting to 192 override their configuration here will have no effect. 193 ''; 194 195 example = { 196 http_check = { 197 init_config = null; # sic! 198 instances = [ 199 { 200 name = "some-service"; 201 url = "http://localhost:1337/healthz"; 202 tags = [ "some-service" ]; 203 } 204 ]; 205 }; 206 }; 207 208 default = {}; 209 210 # sic! The structure of the values is up to the check, so we can 211 # not usefully constrain the type further. 212 type = with types; attrsOf attrs; 213 }; 214 215 diskCheck = mkOption { 216 description = lib.mdDoc "Disk check config"; 217 type = types.attrs; 218 default = { 219 init_config = {}; 220 instances = [ { use_mount = "false"; } ]; 221 }; 222 }; 223 224 networkCheck = mkOption { 225 description = lib.mdDoc "Network check config"; 226 type = types.attrs; 227 default = { 228 init_config = {}; 229 # Network check only supports one configured instance 230 instances = [ { collect_connection_state = false; 231 excluded_interfaces = [ "lo" "lo0" ]; } ]; 232 }; 233 }; 234 }; 235 config = mkIf cfg.enable { 236 environment.systemPackages = [ datadogPkg pkgs.sysstat pkgs.procps pkgs.iproute2 ]; 237 238 users.users.datadog = { 239 description = "Datadog Agent User"; 240 uid = config.ids.uids.datadog; 241 group = "datadog"; 242 home = "/var/log/datadog/"; 243 createHome = true; 244 }; 245 246 users.groups.datadog.gid = config.ids.gids.datadog; 247 248 systemd.services = let 249 makeService = attrs: recursiveUpdate { 250 path = [ datadogPkg pkgs.sysstat pkgs.procps pkgs.iproute2 ]; 251 wantedBy = [ "multi-user.target" ]; 252 serviceConfig = { 253 User = "datadog"; 254 Group = "datadog"; 255 Restart = "always"; 256 RestartSec = 2; 257 }; 258 restartTriggers = [ datadogPkg ] ++ map (x: x.source) (attrValues etcfiles); 259 } attrs; 260 in { 261 datadog-agent = makeService { 262 description = "Datadog agent monitor"; 263 preStart = '' 264 chown -R datadog: /etc/datadog-agent 265 rm -f /etc/datadog-agent/auth_token 266 ''; 267 script = '' 268 export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) 269 exec ${datadogPkg}/bin/agent run -c /etc/datadog-agent/datadog.yaml 270 ''; 271 serviceConfig.PermissionsStartOnly = true; 272 }; 273 274 dd-jmxfetch = lib.mkIf (lib.hasAttr "jmx" cfg.checks) (makeService { 275 description = "Datadog JMX Fetcher"; 276 path = [ datadogPkg pkgs.python pkgs.sysstat pkgs.procps pkgs.jdk ]; 277 serviceConfig.ExecStart = "${datadogPkg}/bin/dd-jmxfetch"; 278 }); 279 280 datadog-process-agent = lib.mkIf cfg.enableLiveProcessCollection (makeService { 281 description = "Datadog Live Process Agent"; 282 path = [ ]; 283 script = '' 284 export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) 285 ${cfg.processAgentPackage}/bin/process-agent --config /etc/datadog-agent/datadog.yaml 286 ''; 287 }); 288 289 datadog-trace-agent = lib.mkIf cfg.enableTraceAgent (makeService { 290 description = "Datadog Trace Agent"; 291 path = [ ]; 292 script = '' 293 export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) 294 ${datadogPkg}/bin/trace-agent -config /etc/datadog-agent/datadog.yaml 295 ''; 296 }); 297 298 }; 299 300 environment.etc = etcfiles; 301 }; 302}