at master 6.2 kB view raw
1{ 2 config, 3 options, 4 lib, 5 pkgs, 6 ... 7}: 8 9let 10 inherit (lib) types; 11 cfg = config.services.nvme-rs; 12 opt = options.services.nvme-rs; 13 settingsFormat = pkgs.formats.toml { }; 14in 15{ 16 options.services.nvme-rs = { 17 enable = lib.mkEnableOption "nvme-rs, a monitoring service"; 18 19 package = lib.mkPackageOption pkgs "nvme-rs" { }; 20 21 settings = lib.mkOption { 22 type = types.submodule { 23 freeformType = settingsFormat.type; 24 options = { 25 check_interval_secs = lib.mkOption { 26 type = types.int; 27 default = 3600; 28 description = "Check interval in seconds"; 29 example = 86400; 30 }; 31 32 thresholds = lib.mkOption { 33 type = types.submodule { 34 freeformType = settingsFormat.type; 35 options = { 36 temp_warning = lib.mkOption { 37 type = types.int; 38 default = 55; 39 description = "Temperature warning threshold (°C)"; 40 }; 41 42 temp_critical = lib.mkOption { 43 type = types.int; 44 default = 65; 45 description = "Temperature critical threshold (°C)"; 46 }; 47 48 wear_warning = lib.mkOption { 49 type = types.int; 50 default = 20; 51 description = "Wear warning threshold (%)"; 52 }; 53 54 wear_critical = lib.mkOption { 55 type = types.int; 56 default = 50; 57 description = "Wear critical threshold (%)"; 58 }; 59 60 spare_warning = lib.mkOption { 61 type = types.int; 62 default = 50; 63 description = "Available spare warning threshold (%)"; 64 }; 65 66 error_threshold = lib.mkOption { 67 type = types.int; 68 default = 100; 69 description = "Error count warning threshold"; 70 }; 71 }; 72 }; 73 default = { }; 74 description = "Threshold configuration for NVMe monitoring"; 75 }; 76 77 email = lib.mkOption { 78 type = types.nullOr ( 79 types.submodule { 80 freeformType = settingsFormat.type; 81 options = { 82 smtp_server = lib.mkOption { 83 type = types.str; 84 default = "smtp.gmail.com"; 85 description = "SMTP server address"; 86 example = "mail.example.com"; 87 }; 88 89 smtp_port = lib.mkOption { 90 type = types.port; 91 default = 587; 92 description = "SMTP server port"; 93 }; 94 95 smtp_username = lib.mkOption { 96 type = types.str; 97 description = "SMTP username"; 98 example = "your-email@gmail.com"; 99 }; 100 101 smtp_password_file = lib.mkOption { 102 type = types.path; 103 description = "File containing SMTP password"; 104 example = "/run/secrets/smtp-password"; 105 }; 106 107 from = lib.mkOption { 108 type = types.str; 109 description = "Sender email address"; 110 example = "nvme-monitor@example.com"; 111 }; 112 113 to = lib.mkOption { 114 type = types.str; 115 description = "Recipient email address"; 116 example = "admin@example.com"; 117 }; 118 119 use_tls = lib.mkOption { 120 type = types.bool; 121 default = true; 122 description = "Use TLS for SMTP connection"; 123 }; 124 }; 125 } 126 ); 127 default = null; 128 description = "Email notification configuration"; 129 }; 130 }; 131 }; 132 default = { }; 133 description = '' 134 Configuration for nvme-rs in TOML format. 135 See the config.toml example for all available options. 136 ''; 137 }; 138 }; 139 140 config = lib.mkIf cfg.enable { 141 services.nvme-rs.settings = opt.settings.default; 142 143 systemd.services.nvme-rs = { 144 description = "NVMe health monitoring service"; 145 after = [ "network.target" ]; 146 wantedBy = [ "multi-user.target" ]; 147 148 serviceConfig = 149 let 150 settingsWithoutNull = 151 if cfg.settings.email == null then lib.removeAttrs cfg.settings [ "email" ] else cfg.settings; 152 configFile = settingsFormat.generate "nvme-rs.toml" settingsWithoutNull; 153 in 154 { 155 ExecStart = lib.escapeShellArgs [ 156 "${lib.getExe cfg.package}" 157 "daemon" 158 "--config" 159 "${configFile}" 160 ]; 161 162 DynamicUser = true; 163 SupplementaryGroups = [ "disk" ]; 164 CapabilityBoundingSet = [ "CAP_SYS_ADMIN" ]; 165 AmbientCapabilities = [ "CAP_SYS_ADMIN" ]; 166 LimitCORE = 0; 167 LimitNOFILE = 65535; 168 LockPersonality = true; 169 MemorySwapMax = 0; 170 MemoryZSwapMax = 0; 171 PrivateTmp = true; 172 ProcSubset = "pid"; 173 ProtectClock = true; 174 ProtectControlGroups = true; 175 ProtectHome = true; 176 ProtectHostname = true; 177 ProtectKernelLogs = true; 178 ProtectKernelModules = true; 179 ProtectKernelTunables = true; 180 ProtectProc = "invisible"; 181 ProtectSystem = "strict"; 182 Restart = "on-failure"; 183 RestartSec = "10s"; 184 RestrictAddressFamilies = [ 185 "AF_INET" 186 "AF_INET6" 187 "AF_UNIX" 188 ]; 189 RestrictNamespaces = true; 190 RestrictRealtime = true; 191 SystemCallArchitectures = "native"; 192 SystemCallFilter = [ 193 "@system-service" 194 "@resources" 195 "~@privileged" 196 ]; 197 NoNewPrivileges = true; 198 UMask = "0077"; 199 }; 200 }; 201 202 environment.systemPackages = [ cfg.package ]; 203 }; 204}