at 23.11-pre 7.7 kB view raw
1{ config, pkgs, lib, ... }: 2let 3 inherit (lib) mapAttrs' nameValuePair filterAttrs types mkEnableOption 4 mdDoc mkPackageOptionMD mkOption literalExpression mkIf flatten 5 maintainers attrValues; 6 7 cfg = config.services.autosuspend; 8 9 settingsFormat = pkgs.formats.ini { }; 10 11 checks = 12 mapAttrs' 13 (n: v: nameValuePair "check.${n}" (filterAttrs (_: v: v != null) v)) 14 cfg.checks; 15 wakeups = 16 mapAttrs' 17 (n: v: nameValuePair "wakeup.${n}" (filterAttrs (_: v: v != null) v)) 18 cfg.wakeups; 19 20 # Whether the given check is enabled 21 hasCheck = class: 22 (filterAttrs 23 (n: v: v.enabled && (if v.class == null then n else v.class) == class) 24 cfg.checks) 25 != { }; 26 27 # Dependencies needed by specific checks 28 dependenciesForChecks = { 29 "Smb" = pkgs.samba; 30 "XIdleTime" = [ pkgs.xprintidle pkgs.sudo ]; 31 }; 32 33 autosuspend-conf = 34 settingsFormat.generate "autosuspend.conf" ({ general = cfg.settings; } // checks // wakeups); 35 36 autosuspend = cfg.package; 37 38 checkType = types.submodule { 39 freeformType = settingsFormat.type.nestedTypes.elemType; 40 41 options.enabled = mkEnableOption (mdDoc "this activity check") // { default = true; }; 42 43 options.class = mkOption { 44 default = null; 45 type = with types; nullOr (enum [ 46 "ActiveCalendarEvent" 47 "ActiveConnection" 48 "ExternalCommand" 49 "JsonPath" 50 "Kodi" 51 "KodiIdleTime" 52 "LastLogActivity" 53 "Load" 54 "LogindSessionsIdle" 55 "Mpd" 56 "NetworkBandwidth" 57 "Ping" 58 "Processes" 59 "Smb" 60 "Users" 61 "XIdleTime" 62 "XPath" 63 ]); 64 description = mdDoc '' 65 Name of the class implementing the check. If this option is not specified, the check's 66 name must represent a valid internal check class. 67 ''; 68 }; 69 }; 70 71 wakeupType = types.submodule { 72 freeformType = settingsFormat.type.nestedTypes.elemType; 73 74 options.enabled = mkEnableOption (mdDoc "this wake-up check") // { default = true; }; 75 76 options.class = mkOption { 77 default = null; 78 type = with types; nullOr (enum [ 79 "Calendar" 80 "Command" 81 "File" 82 "Periodic" 83 "SystemdTimer" 84 "XPath" 85 "XPathDelta" 86 ]); 87 description = mdDoc '' 88 Name of the class implementing the check. If this option is not specified, the check's 89 name must represent a valid internal check class. 90 ''; 91 }; 92 }; 93in 94{ 95 options = { 96 services.autosuspend = { 97 enable = mkEnableOption (mdDoc "the autosuspend daemon"); 98 99 package = mkPackageOptionMD pkgs "autosuspend" { }; 100 101 settings = mkOption { 102 type = types.submodule { 103 freeformType = settingsFormat.type.nestedTypes.elemType; 104 105 options = { 106 # Provide reasonable defaults for these two (required) options 107 suspend_cmd = mkOption { 108 default = "systemctl suspend"; 109 type = with types; str; 110 description = mdDoc '' 111 The command to execute in case the host shall be suspended. This line can contain 112 additional command line arguments to the command to execute. 113 ''; 114 }; 115 wakeup_cmd = mkOption { 116 default = ''sh -c 'echo 0 > /sys/class/rtc/rtc0/wakealarm && echo {timestamp:.0f} > /sys/class/rtc/rtc0/wakealarm' ''; 117 type = with types; str; 118 description = mdDoc '' 119 The command to execute for scheduling a wake up of the system. The given string is 120 processed using Pythons `str.format()` and a format argument called `timestamp` 121 encodes the UTC timestamp of the planned wake up time (float). Additionally `iso` 122 can be used to acquire the timestamp in ISO 8601 format. 123 ''; 124 }; 125 }; 126 }; 127 default = { }; 128 example = literalExpression '' 129 { 130 enable = true; 131 interval = 30; 132 idle_time = 120; 133 } 134 ''; 135 description = mdDoc '' 136 Configuration for autosuspend, see 137 <https://autosuspend.readthedocs.io/en/latest/configuration_file.html#general-configuration> 138 for supported values. 139 ''; 140 }; 141 142 checks = mkOption { 143 default = { }; 144 type = with types; attrsOf checkType; 145 description = mdDoc '' 146 Checks for activity. For more information, see: 147 - <https://autosuspend.readthedocs.io/en/latest/configuration_file.html#activity-check-configuration> 148 - <https://autosuspend.readthedocs.io/en/latest/available_checks.html> 149 ''; 150 example = literalExpression '' 151 { 152 # Basic activity check configuration. 153 # The check class name is derived from the section header (Ping in this case). 154 # Remember to enable desired checks. They are disabled by default. 155 Ping = { 156 hosts = "192.168.0.7"; 157 }; 158 159 # This check is disabled. 160 Smb.enabled = false; 161 162 # Example for a custom check name. 163 # This will use the Users check with the custom name RemoteUsers. 164 # Custom names are necessary in case a check class is used multiple times. 165 # Custom names can also be used for clarification. 166 RemoteUsers = { 167 class = "Users"; 168 name = ".*"; 169 terminal = ".*"; 170 host = "[0-9].*"; 171 }; 172 173 # Here the Users activity check is used again with different settings and a different name 174 LocalUsers = { 175 class = "Users"; 176 name = ".*"; 177 terminal = ".*"; 178 host = "localhost"; 179 }; 180 } 181 ''; 182 }; 183 184 wakeups = mkOption { 185 default = { }; 186 type = with types; attrsOf wakeupType; 187 description = mdDoc '' 188 Checks for wake up. For more information, see: 189 - <https://autosuspend.readthedocs.io/en/latest/configuration_file.html#wake-up-check-configuration> 190 - <https://autosuspend.readthedocs.io/en/latest/available_wakeups.html> 191 ''; 192 example = literalExpression '' 193 { 194 # Wake up checks reuse the same configuration mechanism as activity checks. 195 Calendar = { 196 url = "http://example.org/test.ics"; 197 }; 198 } 199 ''; 200 }; 201 }; 202 }; 203 204 config = mkIf cfg.enable { 205 systemd.services.autosuspend = { 206 description = "A daemon to suspend your server in case of inactivity"; 207 documentation = [ "https://autosuspend.readthedocs.io/en/latest/systemd_integration.html" ]; 208 wantedBy = [ "multi-user.target" ]; 209 after = [ "network.target" ]; 210 path = flatten (attrValues (filterAttrs (n: _: hasCheck n) dependenciesForChecks)); 211 serviceConfig = { 212 ExecStart = ''${autosuspend}/bin/autosuspend -l ${autosuspend}/etc/autosuspend-logging.conf -c ${autosuspend-conf} daemon''; 213 }; 214 }; 215 216 systemd.services.autosuspend-detect-suspend = { 217 description = "Notifies autosuspend about suspension"; 218 documentation = [ "https://autosuspend.readthedocs.io/en/latest/systemd_integration.html" ]; 219 wantedBy = [ "sleep.target" ]; 220 after = [ "sleep.target" ]; 221 serviceConfig = { 222 ExecStart = ''${autosuspend}/bin/autosuspend -l ${autosuspend}/etc/autosuspend-logging.conf -c ${autosuspend-conf} presuspend''; 223 }; 224 }; 225 }; 226 227 meta = { 228 maintainers = with maintainers; [ xlambein ]; 229 }; 230}