aboutsummaryrefslogblamecommitdiff
path: root/flakes/private/monitoring/flake.nix
blob: b7c3997dd9b10467fbc8f1d6249e43d2897ca32a (plain) (tree)










































































































































































































































































                                                                                                                                                              
{
  inputs = {
    environment.url = "path:../environment";
    secrets.url = "path:../../secrets";
    naemon.url = "path:../../naemon";
    nixpkgs-lib.url = "github:NixOS/nixpkgs?dir=lib";
  };
  outputs = { self, environment, nixpkgs-lib, secrets, naemon }: {
    nagios-cli-config = ./nagios-cli.cfg;
    lib = rec {
      expandedObject = kind: object: objects:
        if object ? "use"
        then expandedObject kind objects.templates.${kind}.${object.use} objects // object
        else object;

      objectsCommon = import ./objects_common.nix;
      toObjects = import ./to_objects.nix { inherit (nixpkgs-lib) lib; };

      toMasterPassiveObject = svcTemplate: freshnessThresholdMultiplier: objects:
        {
          service = with nixpkgs-lib.lib; map (s:
            {
              host_name = (expandedObject "service" s objects).host_name;
              use = svcTemplate;
              retry_interval = "1";
              freshness_threshold = let
                fs = expandedObject "service" s objects;
              in if builtins.isInt fs.check_interval
                then builtins.ceil (freshnessThresholdMultiplier * 60 * fs.check_interval)
                else fs.check_interval;
            }
            // filterAttrs (k: v: builtins.elem k ["service_description"] || builtins.substring 0 1 k == "_") s
            // mapAttrs'
                (n: nameValuePair (removePrefix "__passive_" n))
                (filterAttrs (k: _: hasPrefix "__passive_" k) s)
          ) objects.service;
          host = objects.host;
        };

      emailCheck = allCfg: host: hostFQDN: let
        cfg = allCfg."${host}";
        reverseTargets = builtins.attrNames (nixpkgs-lib.lib.filterAttrs (k: v: builtins.elem host v.targets) allCfg);
        to_email = cfg': host':
          let sep = if nixpkgs-lib.lib.hasInfix "+" cfg'.mail_address then "_" else "+";
          in "${cfg'.mail_address}${sep}${host'}@${cfg'.mail_domain}";
        mails_to_send = builtins.concatStringsSep "," (map (n: to_email allCfg."${n}" host) cfg.targets);
        mails_to_receive = builtins.concatStringsSep "," (map (n: "${to_email cfg n}:${n}") reverseTargets);
        command = if cfg.local
        then
          [ "check_emails_local" "/var/lib/naemon/checks/email" mails_to_send mails_to_receive ]
        else
          [ "check_emails" cfg.login cfg.port mails_to_send mails_to_receive ];
      in
        {
          service_description = "${hostFQDN} email service is active";
          use = "mail-service";
          host_name = hostFQDN;
          servicegroups = "webstatus-email";
          check_command = command;
        };
    };
    nixosModule = self.nixosModules.monitoring;
    nixosModules.monitoring = { config, pkgs, lib, ... }:
      let
        cfg = config.myServices.monitoring;
        allPluginsConfig = import ./myplugins.nix {
          inherit pkgs lib config;
          sudo = "/run/wrappers/bin/sudo";
        };
        mypluginsConfig = lib.mapAttrs (n: v:
          if builtins.isFunction v
          then v (cfg.pluginsArgs."${n}" or {})
          else v
        ) (lib.getAttrs cfg.activatedPlugins allPluginsConfig);
        myplugins = let
          mypluginsChunk = builtins.concatStringsSep "\n" (lib.mapAttrsToList (k: v: v.chunk or "") mypluginsConfig);
        in pkgs.runCommand "buildplugins" {
          buildInputs = [ pkgs.makeWrapper pkgs.perl ];
        } ''
          mkdir $out
          ${mypluginsChunk}
          '';
        objectsModule = with lib.types; submodule {
          options = {
            command = lib.mkOption {
              type = attrsOf str;
              default = {};
              description = "Command definitions";
            };

            host = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Host definitions";
            };
            hostgroup = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Host group definitions";
            };
            hostdependency = lib.mkOption {
              type = listOf (attrsOf str);
              default = [];
              description = "Host dependency definitions";
            };

            service = lib.mkOption {
              type = listOf (attrsOf (oneOf [ str (listOf str) int ]));
              # str -> string
              # listOf str -> list to be concatenated with "!"
              # int -> toString
              default = [];
              description = "Service definitions";
            };
            servicegroup = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Service group definitions";
            };
            servicedependency = lib.mkOption {
              type = listOf (attrsOf str);
              default = [];
              description = "Service dependency definitions";
            };

            contact = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Contact definitions";
            };
            contactgroup = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Contact group definitions";
            };

            timeperiod = lib.mkOption {
              type = attrsOf (attrsOf str);
              default = {};
              description = "Time period definitions";
            };

            templates = lib.mkOption {
              description = "Template definitions";
              default = {};
              type = submodule {
                options = {
                  service = lib.mkOption { type = attrsOf (attrsOf (either str int)); default = {}; };
                  contact = lib.mkOption { type = attrsOf (attrsOf str); default = {}; };
                  host = lib.mkOption { type = attrsOf (attrsOf str); default = {}; };
                };
              };
            };
          };
        };
      in
      {
        options = {
          myServices.monitoring = {
            enable = lib.mkOption {
              type = lib.types.bool;
              default = false;
              description = ''
                Whether to enable monitoring.
              '';
            };
            master = lib.mkOption {
              type = lib.types.bool;
              default = false;
              description = ''
                This instance is the master instance
              '';
            };
            pluginsArgs = lib.mkOption {
              default = {};
              description = "Arguments to pass to the naemon plugin configuration";
              type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
            };
            activatedPlugins = lib.mkOption {
              default = [];
              description = "List of naemon plugins to activate";
              type = lib.types.listOf (lib.types.enum (builtins.attrNames allPluginsConfig));
            };
            fromMasterActivatedPlugins = lib.mkOption {
              default = [];
              description = "List of naemon plugins to activate from master";
              type = lib.types.listOf (lib.types.str);
            };
            resources = lib.mkOption {
              default = {};
              description = "List of additionnal resources elements";
              type = lib.types.attrsOf (lib.types.str);
            };
            objects = lib.mkOption {
              default = {};
              description = "Object definitions";
              type = objectsModule;
            };
            fromMasterObjects = lib.mkOption {
              default = {};
              description = "Object definitions of checks that should be executed from master";
              type = objectsModule;
            };
          };
        };

        imports = [
          environment.nixosModule
          secrets.nixosModule
          naemon.nixosModule
        ];
        config = lib.mkIf cfg.enable {
          myServices.monitoring.objects.command =
            lib.foldr (v: o: o // (v.commands or {})) {} (builtins.attrValues mypluginsConfig);

          security.sudo.extraRules = let
            pluginsSudo = lib.lists.remove null (lib.mapAttrsToList (k: v:
              if (v ? sudo)
              then ({ users = [ "naemon" ]; } // (v.sudo myplugins))
              else null) mypluginsConfig);
          in pluginsSudo;

          environment.etc.cnagios.source = "${pkgs.cnagios}/share/doc/cnagios";
          environment.systemPackages = let
            nagios-cli = pkgs.writeScriptBin "nagios-cli" ''
              #!${pkgs.stdenv.shell}
              sudo -u naemon ${pkgs.nagios-cli}/bin/nagios-cli -c ${self.nagios-cli-config}
              '';
          in [
            pkgs.cnagios
            nagios-cli
          ];
          secrets.keys = {
            "naemon/id_rsa" = {
              user = "naemon";
              group = "naemon";
              permissions = "0400";
              text = config.myEnv.monitoring.ssh_secret_key;
            };
            "naemon/resources.cfg".keyDependencies = [ myplugins ];
          };
          services.naemon = {
            enable = true;
            extraConfig = ''
              use_syslog=1
              log_initial_states=1
              date_format=iso8601
              admin_email=${config.myEnv.monitoring.email}
            '' + lib.optionalString (!cfg.master) ''
              obsess_over_services=1
              ocsp_command=notify-master
            '';
            extraResource = let
              resources = [cfg.resources or {}] ++ (lib.mapAttrsToList (k: v: v.resources or {}) mypluginsConfig);
              joined = lib.zipAttrsWith (n: v: if builtins.length (lib.unique v) == 1 then builtins.head v else abort "Non-unique resources names") resources;
              joinedStr = builtins.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "$" + "${k}$=${v}") joined);
            in ''
              $USER2$=${myplugins}
              ${joinedStr}
            '';
            objectDefs =
              self.lib.toObjects cfg.objects;
          };
        };
      };
  };
}