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