diff options
Diffstat (limited to 'nixos/modules/services')
16 files changed, 928 insertions, 138 deletions
diff --git a/nixos/modules/services/continuous-integration/gocd-agent/default.nix b/nixos/modules/services/continuous-integration/gocd-agent/default.nix index 36f6527ee47b..21f319f7fcf6 100644 --- a/nixos/modules/services/continuous-integration/gocd-agent/default.nix +++ b/nixos/modules/services/continuous-integration/gocd-agent/default.nix @@ -36,7 +36,7 @@ in { }; packages = mkOption { - default = [ pkgs.stdenv pkgs.jre config.programs.ssh.package pkgs.nix ]; + default = [ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ]; type = types.listOf types.package; description = '' Packages to add to PATH for the Go.CD agent process. @@ -57,18 +57,10 @@ in { }; goServer = mkOption { - default = "127.0.0.1"; + default = "https://127.0.0.1:8154/go"; type = types.str; description = '' - Address of GoCD Server to attach the Go.CD Agent to. - ''; - }; - - goServerPort = mkOption { - default = 8153; - type = types.int; - description = '' - Port that Go.CD Server is Listening on. + URL of the GoCD Server to attach the Go.CD Agent to. ''; }; @@ -80,26 +72,26 @@ in { ''; }; - heapSize = mkOption { + initialJavaHeapSize = mkOption { default = "128m"; type = types.str; description = '' - Specifies the java heap memory size for the Go.CD agent java process. + Specifies the initial java heap memory size for the Go.CD agent java process. ''; }; - maxMemory = mkOption { + maxJavaHeapMemory = mkOption { default = "256m"; type = types.str; description = '' - Specifies the java maximum memory size for the Go.CD agent java process. + Specifies the java maximum heap memory size for the Go.CD agent java process. ''; }; startupOptions = mkOption { default = [ - "-Xms${cfg.heapSize}" - "-Xmx${cfg.maxMemory}" + "-Xms${cfg.initialJavaHeapSize}" + "-Xmx${cfg.maxJavaHeapMemory}" "-Djava.io.tmpdir=/tmp" "-Dcruise.console.publish.interval=10" "-Djava.security.egd=file:/dev/./urandom" @@ -112,8 +104,8 @@ in { extraOptions = mkOption { default = [ ]; - example = [ - "-X debug" + example = [ + "-X debug" "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5006" "-verbose:gc" "-Xloggc:go-agent-gc.log" @@ -170,7 +162,7 @@ in { config.environment.sessionVariables; in selectedSessionVars // - { + { NIX_REMOTE = "daemon"; AGENT_WORK_DIR = cfg.workDir; AGENT_STARTUP_ARGS = ''${concatStringsSep " " cfg.startupOptions}''; @@ -199,13 +191,14 @@ in { ${pkgs.jre}/bin/java ${concatStringsSep " " cfg.startupOptions} \ ${concatStringsSep " " cfg.extraOptions} \ -jar ${pkgs.gocd-agent}/go-agent/agent-bootstrapper.jar \ - ${cfg.goServer} \ - ${toString cfg.goServerPort} + -serverUrl ${cfg.goServer} ''; serviceConfig = { User = cfg.user; WorkingDirectory = cfg.workDir; + RestartSec = 30; + Restart = "on-failure"; }; }; }; diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix new file mode 100644 index 000000000000..c98af617587d --- /dev/null +++ b/nixos/modules/services/databases/cassandra.nix @@ -0,0 +1,449 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.cassandra; + cassandraPackage = cfg.package.override { + jre = cfg.jre; + }; + cassandraUser = { + name = cfg.user; + home = "/var/lib/cassandra"; + description = "Cassandra role user"; + }; + + cassandraRackDcProperties = '' + dc=${cfg.dc} + rack=${cfg.rack} + ''; + + cassandraConf = '' + cluster_name: ${cfg.clusterName} + num_tokens: 256 + auto_bootstrap: ${if cfg.autoBootstrap then "true" else "false"} + hinted_handoff_enabled: ${if cfg.hintedHandOff then "true" else "false"} + hinted_handoff_throttle_in_kb: ${builtins.toString cfg.hintedHandOffThrottle} + max_hints_delivery_threads: 2 + max_hint_window_in_ms: 10800000 # 3 hours + authenticator: ${cfg.authenticator} + authorizer: ${cfg.authorizer} + permissions_validity_in_ms: 2000 + partitioner: org.apache.cassandra.dht.Murmur3Partitioner + data_file_directories: + ${builtins.concatStringsSep "\n" (map (v: " - "+v) cfg.dataDirs)} + commitlog_directory: ${cfg.commitLogDirectory} + disk_failure_policy: stop + key_cache_size_in_mb: + key_cache_save_period: 14400 + row_cache_size_in_mb: 0 + row_cache_save_period: 0 + saved_caches_directory: ${cfg.savedCachesDirectory} + commitlog_sync: ${cfg.commitLogSync} + commitlog_sync_period_in_ms: ${builtins.toString cfg.commitLogSyncPeriod} + commitlog_segment_size_in_mb: 32 + seed_provider: + - class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + - seeds: "${builtins.concatStringsSep "," cfg.seeds}" + concurrent_reads: ${builtins.toString cfg.concurrentReads} + concurrent_writes: ${builtins.toString cfg.concurrentWrites} + memtable_flush_queue_size: 4 + trickle_fsync: false + trickle_fsync_interval_in_kb: 10240 + storage_port: 7000 + ssl_storage_port: 7001 + listen_address: ${cfg.listenAddress} + start_native_transport: true + native_transport_port: 9042 + start_rpc: true + rpc_address: ${cfg.rpcAddress} + rpc_port: 9160 + rpc_keepalive: true + rpc_server_type: sync + thrift_framed_transport_size_in_mb: 15 + incremental_backups: ${if cfg.incrementalBackups then "true" else "false"} + snapshot_before_compaction: false + auto_snapshot: true + column_index_size_in_kb: 64 + in_memory_compaction_limit_in_mb: 64 + multithreaded_compaction: false + compaction_throughput_mb_per_sec: 16 + compaction_preheat_key_cache: true + read_request_timeout_in_ms: 10000 + range_request_timeout_in_ms: 10000 + write_request_timeout_in_ms: 10000 + cas_contention_timeout_in_ms: 1000 + truncate_request_timeout_in_ms: 60000 + request_timeout_in_ms: 10000 + cross_node_timeout: false + endpoint_snitch: ${cfg.snitch} + dynamic_snitch_update_interval_in_ms: 100 + dynamic_snitch_reset_interval_in_ms: 600000 + dynamic_snitch_badness_threshold: 0.1 + request_scheduler: org.apache.cassandra.scheduler.NoScheduler + server_encryption_options: + internode_encryption: ${cfg.internodeEncryption} + keystore: ${cfg.keyStorePath} + keystore_password: ${cfg.keyStorePassword} + truststore: ${cfg.trustStorePath} + truststore_password: ${cfg.trustStorePassword} + client_encryption_options: + enabled: ${if cfg.clientEncryption then "true" else "false"} + keystore: ${cfg.keyStorePath} + keystore_password: ${cfg.keyStorePassword} + internode_compression: all + inter_dc_tcp_nodelay: false + preheat_kernel_page_cache: false + streaming_socket_timeout_in_ms: ${toString cfg.streamingSocketTimoutInMS} + ''; + + cassandraLog = '' + log4j.rootLogger=${cfg.logLevel},stdout + log4j.appender.stdout=org.apache.log4j.ConsoleAppender + log4j.appender.stdout.layout=org.apache.log4j.PatternLayout + log4j.appender.stdout.layout.ConversionPattern=%5p [%t] %d{HH:mm:ss,SSS} %m%n + ''; + + cassandraConfFile = pkgs.writeText "cassandra.yaml" cassandraConf; + cassandraLogFile = pkgs.writeText "log4j-server.properties" cassandraLog; + cassandraRackFile = pkgs.writeText "cassandra-rackdc.properties" cassandraRackDcProperties; + + cassandraEnvironment = { + CASSANDRA_HOME = cassandraPackage; + JAVA_HOME = cfg.jre; + CASSANDRA_CONF = "/etc/cassandra"; + }; + +in { + + ###### interface + + options.services.cassandra = { + enable = mkOption { + description = "Whether to enable cassandra."; + default = false; + type = types.bool; + }; + package = mkOption { + description = "Cassandra package to use."; + default = pkgs.cassandra; + defaultText = "pkgs.cassandra"; + type = types.package; + }; + jre = mkOption { + description = "JRE package to run cassandra service."; + default = pkgs.jre; + defaultText = "pkgs.jre"; + type = types.package; + }; + user = mkOption { + description = "User that runs cassandra service."; + default = "cassandra"; + type = types.string; + }; + group = mkOption { + description = "Group that runs cassandra service."; + default = "cassandra"; + type = types.string; + }; + envFile = mkOption { + description = "path to cassandra-env.sh"; + default = "${cassandraPackage}/conf/cassandra-env.sh"; + defaultText = "\${cassandraPackage}/conf/cassandra-env.sh"; + type = types.path; + }; + clusterName = mkOption { + description = "set cluster name"; + default = "cassandra"; + example = "prod-cluster0"; + type = types.string; + }; + commitLogDirectory = mkOption { + description = "directory for commit logs"; + default = "/var/lib/cassandra/commit_log"; + type = types.string; + }; + savedCachesDirectory = mkOption { + description = "directory for saved caches"; + default = "/var/lib/cassandra/saved_caches"; + type = types.string; + }; + hintedHandOff = mkOption { + description = "enable hinted handoff"; + default = true; + type = types.bool; + }; + hintedHandOffThrottle = mkOption { + description = "hinted hand off throttle rate in kb"; + default = 1024; + type = types.int; + }; + commitLogSync = mkOption { + description = "commitlog sync method"; + default = "periodic"; + type = types.str; + example = "batch"; + }; + commitLogSyncPeriod = mkOption { + description = "commitlog sync period in ms "; + default = 10000; + type = types.int; + }; + envScript = mkOption { + default = "${cassandraPackage}/conf/cassandra-env.sh"; + defaultText = "\${cassandraPackage}/conf/cassandra-env.sh"; + type = types.path; + description = "Supply your own cassandra-env.sh rather than using the default"; + }; + extraParams = mkOption { + description = "add additional lines to cassandra-env.sh"; + default = []; + example = [''JVM_OPTS="$JVM_OPTS -Dcassandra.available_processors=1"'']; + type = types.listOf types.str; + }; + dataDirs = mkOption { + type = types.listOf types.path; + default = [ "/var/lib/cassandra/data" ]; + description = "Data directories for cassandra"; + }; + logLevel = mkOption { + type = types.str; + default = "INFO"; + description = "default logging level for log4j"; + }; + internodeEncryption = mkOption { + description = "enable internode encryption"; + default = "none"; + example = "all"; + type = types.str; + }; + clientEncryption = mkOption { + description = "enable client encryption"; + default = false; + type = types.bool; + }; + trustStorePath = mkOption { + description = "path to truststore"; + default = ".conf/truststore"; + type = types.str; + }; + keyStorePath = mkOption { + description = "path to keystore"; + default = ".conf/keystore"; + type = types.str; + }; + keyStorePassword = mkOption { + description = "password to keystore"; + default = "cassandra"; + type = types.str; + }; + trustStorePassword = mkOption { + description = "password to truststore"; + default = "cassandra"; + type = types.str; + }; + seeds = mkOption { + description = "password to truststore"; + default = [ "127.0.0.1" ]; + type = types.listOf types.str; + }; + concurrentWrites = mkOption { + description = "number of concurrent writes allowed"; + default = 32; + type = types.int; + }; + concurrentReads = mkOption { + description = "number of concurrent reads allowed"; + default = 32; + type = types.int; + }; + listenAddress = mkOption { + description = "listen address"; + default = "localhost"; + type = types.str; + }; + rpcAddress = mkOption { + description = "rpc listener address"; + default = "localhost"; + type = types.str; + }; + incrementalBackups = mkOption { + description = "enable incremental backups"; + default = false; + type = types.bool; + }; + snitch = mkOption { + description = "snitch to use for topology discovery"; + default = "GossipingPropertyFileSnitch"; + example = "Ec2Snitch"; + type = types.str; + }; + dc = mkOption { + description = "datacenter for use in topology configuration"; + default = "DC1"; + example = "DC1"; + type = types.str; + }; + rack = mkOption { + description = "rack for use in topology configuration"; + default = "RAC1"; + example = "RAC1"; + type = types.str; + }; + authorizer = mkOption { + description = " + Authorization backend, implementing IAuthorizer; used to limit access/provide permissions + "; + default = "AllowAllAuthorizer"; + example = "CassandraAuthorizer"; + type = types.str; + }; + authenticator = mkOption { + description = " + Authentication backend, implementing IAuthenticator; used to identify users + "; + default = "AllowAllAuthenticator"; + example = "PasswordAuthenticator"; + type = types.str; + }; + autoBootstrap = mkOption { + description = "It makes new (non-seed) nodes automatically migrate the right data to themselves."; + default = true; + example = true; + type = types.bool; + }; + streamingSocketTimoutInMS = mkOption { + description = "Enable or disable socket timeout for streaming operations"; + default = 3600000; #CASSANDRA-8611 + example = 120; + type = types.int; + }; + repairStartAt = mkOption { + default = "Sun"; + type = types.string; + description = '' + Defines realtime (i.e. wallclock) timers with calendar event + expressions. For more details re: systemd OnCalendar at + https://www.freedesktop.org/software/systemd/man/systemd.time.html#Displaying%20Time%20Spans + ''; + example = ["weekly" "daily" "08:05:40" "mon,fri *-1/2-1,3 *:30:45"]; + }; + repairRandomizedDelayInSec = mkOption { + default = 0; + type = types.int; + description = ''Delay the timer by a randomly selected, evenly distributed + amount of time between 0 and the specified time value. re: systemd timer + RandomizedDelaySec for more details + ''; + }; + repairPostStop = mkOption { + default = null; + type = types.nullOr types.string; + description = '' + Run a script when repair is over. One can use it to send statsd events, email, etc. + ''; + }; + repairPostStart = mkOption { + default = null; + type = types.nullOr types.string; + description = '' + Run a script when repair starts. One can use it to send statsd events, email, etc. + It has same semantics as systemd ExecStopPost; So, if it fails, unit is consisdered + failed. + ''; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + environment.etc."cassandra/cassandra-rackdc.properties" = { + source = cassandraRackFile; + }; + environment.etc."cassandra/cassandra.yaml" = { + source = cassandraConfFile; + }; + environment.etc."cassandra/log4j-server.properties" = { + source = cassandraLogFile; + }; + environment.etc."cassandra/cassandra-env.sh" = { + text = '' + ${builtins.readFile cfg.envFile} + ${concatStringsSep "\n" cfg.extraParams} + ''; + }; + systemd.services.cassandra = { + description = "Cassandra Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + environment = cassandraEnvironment; + restartTriggers = [ cassandraConfFile cassandraLogFile cassandraRackFile ]; + serviceConfig = { + + User = cfg.user; + PermissionsStartOnly = true; + LimitAS = "infinity"; + LimitNOFILE = "100000"; + LimitNPROC = "32768"; + LimitMEMLOCK = "infinity"; + + }; + script = '' + ${cassandraPackage}/bin/cassandra -f + ''; + path = [ + cfg.jre + cassandraPackage + pkgs.coreutils + ]; + preStart = '' + mkdir -m 0700 -p /etc/cassandra/triggers + mkdir -m 0700 -p /var/lib/cassandra /var/log/cassandra + chown ${cfg.user} /var/lib/cassandra /var/log/cassandra /etc/cassandra/triggers + ''; + postStart = '' + sleep 2 + while ! nodetool status >/dev/null 2>&1; do + sleep 2 + done + nodetool status + ''; + }; + + environment.systemPackages = [ cassandraPackage ]; + + networking.firewall.allowedTCPPorts = [ + 7000 + 7001 + 9042 + 9160 + ]; + + users.extraUsers.cassandra = + if config.ids.uids ? "cassandra" + then { uid = config.ids.uids.cassandra; } // cassandraUser + else cassandraUser ; + + boot.kernel.sysctl."vm.swappiness" = pkgs.lib.mkOptionDefault 0; + + systemd.timers."cassandra-repair" = { + timerConfig = { + OnCalendar = "${toString cfg.repairStartAt}"; + RandomizedDelaySec = cfg.repairRandomizedDelayInSec; + }; + }; + + systemd.services."cassandra-repair" = { + description = "Cassandra repair daemon"; + environment = cassandraEnvironment; + script = "${cassandraPackage}/bin/nodetool repair -pr"; + postStop = mkIf (cfg.repairPostStop != null) cfg.repairPostStop; + postStart = mkIf (cfg.repairPostStart != null) cfg.repairPostStart; + serviceConfig = { + User = cfg.user; + }; + }; + }; +} diff --git a/nixos/modules/services/games/factorio.nix b/nixos/modules/services/games/factorio.nix index 90834c5b2605..0369752997a7 100644 --- a/nixos/modules/services/games/factorio.nix +++ b/nixos/modules/services/games/factorio.nix @@ -4,14 +4,17 @@ with lib; let cfg = config.services.factorio; + factorio = pkgs.factorio-headless; name = "Factorio"; stateDir = "/var/lib/factorio"; + mkSavePath = name: "${stateDir}/saves/${name}.zip"; configFile = pkgs.writeText "factorio.conf" '' use-system-read-write-data-directories=true [path] - read-data=${pkgs.factorio-headless}/share/factorio/data + read-data=${factorio}/share/factorio/data write-data=${stateDir} ''; + modDir = pkgs.factorio-mkModDirDrv cfg.mods; in { options = { @@ -32,7 +35,8 @@ in description = '' The name of the savegame that will be used by the server. - When not present in ${stateDir}/saves, it will be generated before starting the service. + When not present in ${stateDir}/saves, a new map with default + settings will be generated before starting the service. ''; }; # TODO Add more individual settings as nixos-options? @@ -51,6 +55,26 @@ in customizations. ''; }; + mods = mkOption { + type = types.listOf types.package; + default = []; + description = '' + Mods the server should install and activate. + + The derivations in this list must "build" the mod by simply copying + the .zip, named correctly, into the output directory. Eventually, + there will be a way to pull in the most up-to-date list of + derivations via nixos-channel. Until then, this is for experts only. + ''; + }; + autosave-interval = mkOption { + type = types.nullOr types.int; + default = null; + example = 2; + description = '' + The time, in minutes, between autosaves. + ''; + }; }; }; @@ -74,12 +98,14 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - preStart = '' - test -e ${stateDir}/saves/${cfg.saveName}.zip || \ - ${pkgs.factorio-headless}/bin/factorio \ - --config=${cfg.configFile} \ - --create=${stateDir}/saves/${cfg.saveName}.zip - ''; + preStart = toString [ + "test -e ${stateDir}/saves/${cfg.saveName}.zip" + "||" + "${factorio}/bin/factorio" + "--config=${cfg.configFile}" + "--create=${mkSavePath cfg.saveName}" + (optionalString (cfg.mods != []) "--mod-directory=${modDir}") + ]; serviceConfig = { User = "factorio"; @@ -90,10 +116,12 @@ in PrivateTmp = true; UMask = "0007"; ExecStart = toString [ - "${pkgs.factorio-headless}/bin/factorio" + "${factorio}/bin/factorio" "--config=${cfg.configFile}" "--port=${toString cfg.port}" - "--start-server=${stateDir}/saves/${cfg.saveName}.zip" + "--start-server=${mkSavePath cfg.saveName}" + (optionalString (cfg.mods != []) "--mod-directory=${modDir}") + (optionalString (cfg.autosave-interval != null) "--autosave-interval ${toString cfg.autosave-interval}") ]; }; }; diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix new file mode 100644 index 000000000000..57ac37bb1bd3 --- /dev/null +++ b/nixos/modules/services/games/terraria.nix @@ -0,0 +1,139 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.terraria; + worldSizeMap = { "small" = 1; "medium" = 2; "large" = 3; }; + valFlag = name: val: optionalString (val != null) "-${name} \"${escape ["\\" "\""] (toString val)}\""; + boolFlag = name: val: optionalString val "-${name}"; + flags = [ + (valFlag "port" cfg.port) + (valFlag "maxPlayers" cfg.maxPlayers) + (valFlag "password" cfg.password) + (valFlag "motd" cfg.messageOfTheDay) + (valFlag "world" cfg.worldPath) + (valFlag "autocreate" (builtins.getAttr cfg.autoCreatedWorldSize worldSizeMap)) + (valFlag "banlist" cfg.banListPath) + (boolFlag "secure" cfg.secure) + (boolFlag "noupnp" cfg.noUPnP) + ]; +in +{ + options = { + services.terraria = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + If enabled, starts a Terraria server. The server can be connected to via <literal>tmux -S /var/lib/terraria/terraria.sock attach</literal> + for administration by users who are a part of the <literal>terraria</literal> group (use <literal>C-b d</literal> shortcut to detach again). + ''; + }; + + port = mkOption { + type = types.int; + default = 7777; + description = '' + Specifies the port to listen on. + ''; + }; + + maxPlayers = mkOption { + type = types.int; + default = 255; + description = '' + Sets the max number of players (between 1 and 255). + ''; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Sets the server password. Leave <literal>null</literal> for no password. + ''; + }; + + messageOfTheDay = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Set the server message of the day text. + ''; + }; + + worldPath = mkOption { + type = types.path; + default = null; + description = '' + The path to the world file (<literal>.wld</literal>) which should be loaded. + If no world exists at this path, one will be created with the size + specified by <literal>autoCreatedWorldSize</literal>. + ''; + }; + + autoCreatedWorldSize = mkOption { + type = types.enum [ "small" "medium" "large" ]; + default = "medium"; + description = '' + Specifies the size of the auto-created world if <literal>worldPath</literal> does not + point to an existing world. + ''; + }; + + banListPath = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + The path to the ban list. + ''; + }; + + secure = mkOption { + type = types.bool; + default = false; + description = "Adds additional cheat protection to the server."; + }; + + noUPnP = mkOption { + type = types.bool; + default = false; + description = "Disables automatic Universal Plug and Play."; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers.terraria = { + description = "Terraria server service user"; + home = "/var/lib/terraria"; + createHome = true; + uid = config.ids.uids.terraria; + }; + + users.extraGroups.terraria = { + gid = config.ids.gids.terraria; + members = [ "terraria" ]; + }; + + systemd.services.terraria = { + description = "Terraria Server Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + User = "terraria"; + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.tmux.bin}/bin/tmux -S /var/lib/terraria/terraria.sock new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}"; + ExecStop = "${pkgs.tmux.bin}/bin/tmux -S /var/lib/terraria/terraria.sock send-keys Enter \"exit\" Enter"; + }; + + postStart = '' + ${pkgs.coreutils}/bin/chmod 660 /var/lib/terraria/terraria.sock + ${pkgs.coreutils}/bin/chgrp terraria /var/lib/terraria/terraria.sock + ''; + }; + }; +} diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 267442bd1f8b..ac2e94c25c33 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -57,42 +57,23 @@ let issues = true; merge_requests = true; wiki = true; - snippets = false; + snippets = true; builds = true; + container_registry = true; }; }; - artifacts = { - enabled = true; - }; - lfs = { - enabled = true; - }; - gravatar = { - enabled = true; - }; - cron_jobs = { - stuck_ci_builds_worker = { - cron = "0 0 * * *"; - }; - }; - gitlab_ci = { - builds_path = "${cfg.statePath}/builds"; - }; - ldap = { - enabled = false; - }; - omniauth = { - enabled = false; - }; - shared = { - path = "${cfg.statePath}/shared"; - }; - backup = { - path = "${cfg.backupPath}"; - }; + repositories.storages.default = "${cfg.statePath}/repositories"; + artifacts.enabled = true; + lfs.enabled = true; + gravatar.enabled = true; + cron_jobs = { }; + gitlab_ci.builds_path = "${cfg.statePath}/builds"; + ldap.enabled = false; + omniauth.enabled = false; + shared.path = "${cfg.statePath}/shared"; + backup.path = "${cfg.backupPath}"; gitlab_shell = { path = "${cfg.packages.gitlab-shell}"; - repos_path = "${cfg.statePath}/repositories"; hooks_path = "${cfg.statePath}/shell/hooks"; secret_file = "${cfg.statePath}/config/gitlab_shell_secret"; upload_pack = true; @@ -125,21 +106,42 @@ let unicornConfig = builtins.readFile ./defaultUnicornConfig.rb; - gitlab-runner = pkgs.stdenv.mkDerivation rec { - name = "gitlab-runner"; - buildInputs = [ cfg.packages.gitlab bundler pkgs.makeWrapper ]; + gitlab-rake = pkgs.stdenv.mkDerivation rec { + name = "gitlab-rake"; + buildInputs = [ cfg.packages.gitlab cfg.packages.gitlab.env pkgs.makeWrapper ]; phases = "installPhase fixupPhase"; buildPhase = ""; installPhase = '' mkdir -p $out/bin - makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner \ - ${concatStrings (mapAttrsToList (name: value: "--set ${name} '\"${value}\"' ") gitlabEnv)} \ - --set GITLAB_CONFIG_PATH '"${cfg.statePath}/config"' \ - --set PATH '"${pkgs.nodejs}/bin:${pkgs.gzip}/bin:${config.services.postgresql.package}/bin:$PATH"' \ - --set RAKEOPT '"-f ${cfg.packages.gitlab}/share/gitlab/Rakefile"' - ''; + makeWrapper ${cfg.packages.gitlab.env}/bin/bundle $out/bin/gitlab-bundle \ + ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \ + --set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \ + --set PATH '${pkgs.nodejs}/bin:${pkgs.gzip}/bin:${config.services.postgresql.package}/bin:$PATH' \ + --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \ + --run 'cd ${cfg.packages.gitlab}/share/gitlab' + makeWrapper $out/bin/gitlab-bundle $out/bin/gitlab-rake \ + --add-flags "exec rake" + ''; }; + smtpSettings = pkgs.writeText "gitlab-smtp-settings.rb" '' + if Rails.env.production? + Rails.application.config.action_mailer.delivery_method = :smtp + + ActionMailer::Base.delivery_method = :smtp + ActionMailer::Base.smtp_settings = { + address: "${cfg.smtp.address}", + port: ${toString cfg.smtp.port}, + ${optionalString (cfg.smtp.username != null) ''user_name: "${cfg.smtp.username}",''} + ${optionalString (cfg.smtp.password != null) ''password: "${cfg.smtp.password}",''} + domain: "${cfg.smtp.domain}", + ${optionalString (cfg.smtp.authentication != null) "authentication: :${cfg.smtp.authentication},"} + enable_starttls_auto: ${toString cfg.smtp.enableStartTLSAuto}, + openssl_verify_mode: '${cfg.smtp.opensslVerifyMode}' + } + end + ''; + in { options = { @@ -255,6 +257,62 @@ in { ''; }; + smtp = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable gitlab mail delivery over SMTP."; + }; + + address = mkOption { + type = types.str; + default = "localhost"; + description = "Address of the SMTP server for Gitlab."; + }; + + port = mkOption { + type = types.int; + default = 465; + description = "Port of the SMTP server for Gitlab."; + }; + + username = mkOption { + type = types.nullOr types.str; + default = null; + description = "Username of the SMTP server for Gitlab."; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = "Password of the SMTP server for Gitlab."; + }; + + domain = mkOption { + type = types.str; + default = "localhost"; + description = "HELO domain to use for outgoing mail."; + }; + + authentication = mkOption { + type = types.nullOr types.str; + default = null; + description = "Authentitcation type to use, see http://api.rubyonrails.org/classes/ActionMailer/Base.html"; + }; + + enableStartTLSAuto = mkOption { + type = types.bool; + default = true; + description = "Whether to try to use StartTLS."; + }; + + opensslVerifyMode = mkOption { + type = types.str; + default = "peer"; + description = "How OpenSSL checks the certificate, see http://api.rubyonrails.org/classes/ActionMailer/Base.html"; + }; + }; + extraConfig = mkOption { type = types.attrs; default = {}; @@ -275,7 +333,7 @@ in { config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.git gitlab-runner cfg.packages.gitlab-shell ]; + environment.systemPackages = [ pkgs.git gitlab-rake cfg.packages.gitlab-shell ]; assertions = [ { assertion = cfg.databasePassword != ""; @@ -308,6 +366,7 @@ in { systemd.services.gitlab-sidekiq = { after = [ "network.target" "redis.service" ]; wantedBy = [ "multi-user.target" ]; + partOf = [ "gitlab.service" ]; environment = gitlabEnv; path = with pkgs; [ config.services.postgresql.package @@ -322,7 +381,7 @@ in { Group = cfg.group; TimeoutSec = "300"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailers -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\""; + ExecStart="${cfg.packages.gitlab.env}/bin/bundle exec \"sidekiq -q post_receive -q mailers -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\""; }; }; @@ -397,6 +456,9 @@ in { chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME}/ cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config + ${optionalString cfg.smtp.enable '' + ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb + ''} ln -sf ${cfg.statePath}/config /run/gitlab/config cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION @@ -420,14 +482,14 @@ in { touch "${cfg.statePath}/db-created" # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database - ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production - ${gitlab-runner}/bin/gitlab-runner exec rake db:seed_fu RAILS_ENV=production \ + ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production + ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \ GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}"; fi fi # Always do the db migrations just to be sure the database is up-to-date - ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production + ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production # Change permissions in the last step because some of the # intermediary scripts like to create directories as root. @@ -441,8 +503,9 @@ in { User = cfg.user; Group = cfg.group; TimeoutSec = "300"; + Restart = "on-failure"; WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\""; + ExecStart = "${cfg.packages.gitlab.env}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\""; }; }; diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml index b630fe421130..a8147b3a74f9 100644 --- a/nixos/modules/services/misc/gitlab.xml +++ b/nixos/modules/services/misc/gitlab.xml @@ -14,29 +14,22 @@ <literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to configure a webserver to proxy HTTP requests to the socket.</para> -<para>For instance, this could be used for Nginx: +<para>For instance, the following configuration could be used to use nginx as + frontend proxy: <programlisting> -services.nginx.httpConfig = '' - server { - server_name git.example.com; - listen 443 ssl spdy; - listen [::]:443 ssl spdy; - - ssl_certificate /var/lib/acme/git.example.com/fullchain.pem; - ssl_certificate_key /var/lib/acme/git.example.com/key.pem; - - location / { - proxy_http_version 1.1; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Ssl on; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - proxy_pass http://unix:/run/gitlab/gitlab-workhorse.socket; - } - } + services.nginx = { + enable = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + virtualHosts."git.example.com" = { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "http://unix:/run/gitlab/gitlab-workhorse.socket"; + }; + }; ''; </programlisting> </para> @@ -49,10 +42,10 @@ services.nginx.httpConfig = '' both services. In the case of PostgreSQL, a database and a role will be created. </para> -<para>The default state dir is /var/gitlab/state. This is where all data like -the repositories and uploads will be stored.</para> +<para>The default state dir is <literal>/var/gitlab/state</literal>. This is where +all data like the repositories and uploads will be stored.</para> -<para>A basic configuration could look like this: +<para>A basic configuration with some custom settings could look like this: <programlisting> services.gitlab = { @@ -64,8 +57,16 @@ services.gitlab = { port = 443; user = "git"; group = "git"; + smtp = { + enable = true; + address = "localhost"; + port = 25; + }; extraConfig = { gitlab = { + email_from = "gitlab-no-reply@example.com"; + email_display_name = "Example GitLab"; + email_reply_to = "gitlab-no-reply@example.com"; default_projects_features = { builds = false; }; }; }; @@ -80,21 +81,21 @@ options for the <literal>services.gitlab</literal> module.</para> <section><title>Maintenance</title> -<para>You can run all Gitlab related commands like rake tasks with -<literal>gitlab-runner</literal> which will be available on the system -when gitlab is enabled. You will have to run the commands as the user that -you configured to run gitlab.</para> +<para>You can run Gitlab's rake tasks with <literal>gitlab-rake</literal> +which will be available on the system when gitlab is enabled. You will +have to run the command as the user that you configured to run gitlab +with.</para> -<para>For instance, to backup a Gitlab instance: +<para>For example, to backup a Gitlab instance: <programlisting> -$ sudo -u git -H gitlab-runner exec rake gitlab:backup:create +$ sudo -u git -H gitlab-rake gitlab:backup:create </programlisting> A list of all availabe rake tasks can be obtained by running: <programlisting> -$ sudo -u git -H gitlab-runner exec rake -T +$ sudo -u git -H gitlab-rake -T </programlisting> </para> diff --git a/nixos/modules/services/networking/offlineimap.nix b/nixos/modules/services/networking/offlineimap.nix index 31ce9280f319..daf6196d3706 100644 --- a/nixos/modules/services/networking/offlineimap.nix +++ b/nixos/modules/services/networking/offlineimap.nix @@ -54,7 +54,7 @@ in { description = "Offlineimap: a software to dispose your mailbox(es) as a local Maildir(s)"; serviceConfig = { Type = "oneshot"; - ExecStart = "${cfg.package}/bin/offlineimap -u basic -o -1"; + ExecStart = "${cfg.package}/bin/offlineimap -u syslog -o -1"; TimeoutStartSec = cfg.timeoutStartSec; }; path = cfg.path; diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index a464733a6a03..f900ef494abf 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -263,6 +263,7 @@ in serviceConfig = { ExecStart = + (optionalString cfg.startWhenNeeded "-") + "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; KillMode = "process"; diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index b44b03dc0bf3..8a430734319b 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -23,6 +23,18 @@ let RestartForceExitStatus="3 4"; }; + iNotifyHeader = { + description = "Syncthing Inotify File Watcher service"; + after = [ "network.target" "syncthing.service" ]; + requires = [ "syncthing.service" ]; + }; + + iNotifyService = { + SuccessExitStatus = "2"; + RestartForceExitStatus = "3"; + Restart = "on-failure"; + }; + in { @@ -39,6 +51,12 @@ in available on http://127.0.0.1:8384/. ''; + useInotify = mkOption { + type = types.bool; + default = false; + description = "Provide syncthing-inotify as a service."; + }; + systemService = mkOption { type = types.bool; default = true; @@ -112,27 +130,40 @@ in config.ids.gids.syncthing; }; - environment.systemPackages = [ cfg.package ]; - - systemd.services = mkIf cfg.systemService { - syncthing = header // { + systemd.services = { + syncthing = mkIf cfg.systemService (header // { + wants = mkIf cfg.useInotify [ "syncthing-inotify.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = service // { + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = true; + ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}"; + }; + }); + + syncthing-inotify = mkIf (cfg.systemService && cfg.useInotify) (iNotifyHeader // { wantedBy = [ "multi-user.target" ]; - serviceConfig = service // { + serviceConfig = iNotifyService // { User = cfg.user; - Group = cfg.group; - PermissionsStartOnly = true; - ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}"; + ExecStart = "${pkgs.syncthing-inotify.bin}/bin/syncthing-inotify -home=${cfg.dataDir} -logflags=0"; }; - }; + }); }; - systemd.user.services.syncthing = - header // { - wantedBy = [ "default.target" ]; + systemd.user.services = { + syncthing = header // { serviceConfig = service // { ExecStart = "${cfg.package}/bin/syncthing -no-browser"; }; }; + syncthing-inotify = mkIf cfg.useInotify (iNotifyHeader // { + serviceConfig = iNotifyService // { + ExecStart = "${pkgs.syncthing-inotify.bin}/bin/syncthing-inotify -logflags=0"; + }; + }); + }; + }; } diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 8385d8e60266..af7753470de6 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -18,7 +18,9 @@ let ${cfg.config} - ${optionalString (cfg.httpConfig == "") '' + ${optionalString (cfg.httpConfig == "" && cfg.config == "") '' + events {} + http { include ${cfg.package}/conf/mime.types; include ${cfg.package}/conf/fastcgi.conf; @@ -96,6 +98,7 @@ let }''} ${optionalString (cfg.httpConfig != "") '' + events {} http { include ${cfg.package}/conf/mime.types; include ${cfg.package}/conf/fastcgi.conf; @@ -233,9 +236,12 @@ in }; config = mkOption { - default = "events {}"; + default = ""; description = " Verbatim nginx.conf configuration. + This is mutually exclusive with the structured configuration + via virtualHosts and the recommendedXyzSettings configuration + options. See appendConfig for appending to the generated http block. "; }; @@ -268,8 +274,8 @@ in default = ""; description = " Configuration lines to be appended to the generated http block. - This is mutually exclusive with using httpConfig for specifying the whole - http block verbatim. + This is mutually exclusive with using config and httpConfig for + specifying the whole http block verbatim. "; }; diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm/default.nix index 2658d7117e37..819d0c251bf3 100644 --- a/nixos/modules/services/web-servers/phpfpm.nix +++ b/nixos/modules/services/web-servers/phpfpm/default.nix @@ -9,6 +9,12 @@ let pidFile = "${stateDir}/phpfpm.pid"; + mkPool = n: p: '' + [${n}] + listen = ${p.listen} + ${p.extraConfig} + ''; + cfgFile = pkgs.writeText "phpfpm.conf" '' [global] pid = ${pidFile} @@ -16,6 +22,8 @@ let daemonize = yes ${cfg.extraConfig} + ${concatStringsSep "\n" (mapAttrsToList mkPool cfg.pools)} + ${concatStringsSep "\n" (mapAttrsToList (n: v: "[${n}]\n${v}") cfg.poolConfigs)} ''; @@ -62,8 +70,8 @@ in { }; poolConfigs = mkOption { - type = types.attrsOf types.lines; default = {}; + type = types.attrsOf types.lines; example = literalExample '' { mypool = ''' listen = /run/phpfpm/mypool @@ -84,10 +92,20 @@ in { the phpfpm service is disabled. ''; }; + + pools = mkOption { + type = types.attrsOf (types.submodule (import ./pool-options.nix { + inherit lib; + })); + default = {}; + description = '' + If no pools are defined, the phpfpm service is disabled. + ''; + }; }; }; - config = mkIf (cfg.poolConfigs != {}) { + config = mkIf (cfg.pools != {}) { systemd.services.phpfpm = { wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/web-servers/phpfpm/pool-options.nix b/nixos/modules/services/web-servers/phpfpm/pool-options.nix new file mode 100644 index 000000000000..cc688c2c48a2 --- /dev/null +++ b/nixos/modules/services/web-servers/phpfpm/pool-options.nix @@ -0,0 +1,35 @@ +{ lib }: + +with lib; { + + options = { + + listen = mkOption { + type = types.str; + example = "/path/to/unix/socket"; + description = '' + The address on which to accept FastCGI requests. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + example = '' + user = nobody + pm = dynamic + pm.max_children = 75 + pm.start_servers = 10 + pm.min_spare_servers = 5 + pm.max_spare_servers = 20 + pm.max_requests = 500 + ''; + + description = '' + Extra lines that go into the pool configuration. + See the documentation on <literal>php-fpm.conf</literal> for + details on configuration directives. + ''; + }; + }; +} + diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix index 364f6c68faca..61df43ec2352 100644 --- a/nixos/modules/services/web-servers/varnish/default.nix +++ b/nixos/modules/services/web-servers/varnish/default.nix @@ -28,7 +28,7 @@ with lib; }; stateDir = mkOption { - default = "/var/spool/varnish"; + default = "/var/spool/varnish/${config.networking.hostName}"; description = " Directory holding all state for Varnish to run. "; @@ -46,6 +46,9 @@ with lib; mkdir -p ${cfg.stateDir} chown -R varnish:varnish ${cfg.stateDir} ''; + postStop = '' + rm -rf ${cfg.stateDir} + ''; path = [ pkgs.gcc ]; serviceConfig.ExecStart = "${pkgs.varnish}/sbin/varnishd -a ${cfg.http_address} -f ${pkgs.writeText "default.vcl" cfg.config} -n ${cfg.stateDir} -u varnish"; serviceConfig.Type = "forking"; diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix index 14c7131e611c..b358550ba41d 100644 --- a/nixos/modules/services/x11/hardware/libinput.nix +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -25,16 +25,21 @@ in { accelProfile = mkOption { type = types.enum [ "flat" "adaptive" ]; - default = "flat"; - example = "adaptive"; + default = "adaptive"; + example = "flat"; description = '' - Sets the pointer acceleration profile to the given profile. Permitted values are adaptive, flat. - Not all devices support this option or all profiles. If a profile is unsupported, the default profile - for this is used. For a description on the profiles and their behavior, see the libinput documentation. + Sets the pointer acceleration profile to the given profile. + Permitted values are adaptive, flat. + Not all devices support this option or all profiles. + If a profile is unsupported, the default profile for this is used. + <literal>flat</literal>: Pointer motion is accelerated by a constant + (device-specific) factor, depending on the current speed. + <literal>adaptive</literal>: Pointer acceleration depends on the input speed. + This is the default profile for most devices. ''; - }; - + }; + accelSpeed = mkOption { type = types.nullOr types.string; default = null; @@ -216,7 +221,7 @@ in { Option "LeftHanded" "${xorgBool cfg.leftHanded}" Option "MiddleEmulation" "${xorgBool cfg.middleEmulation}" Option "NaturalScrolling" "${xorgBool cfg.naturalScrolling}" - ${optionalString (cfg.scrollButton != null) ''Option "ScrollButton" "${cfg.scrollButton}"''} + ${optionalString (cfg.scrollButton != null) ''Option "ScrollButton" "${toString cfg.scrollButton}"''} Option "ScrollMethod" "${cfg.scrollMethod}" Option "HorizontalScrolling" "${xorgBool cfg.horizontalScrolling}" Option "SendEventsMode" "${cfg.sendEventsMode}" @@ -227,6 +232,14 @@ in { EndSection ''; + assertions = [ + # already present in synaptics.nix + /* { + assertion = !config.services.xserver.synaptics.enable; + message = "Synaptics and libinput are incompatible, you cannot enable both (in services.xserver)."; + } */ + ]; + }; } diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix index e74b19c8e710..5c068e89dd71 100644 --- a/nixos/modules/services/x11/hardware/synaptics.nix +++ b/nixos/modules/services/x11/hardware/synaptics.nix @@ -205,6 +205,13 @@ in { EndSection ''; + assertions = [ + { + assertion = !config.services.xserver.libinput.enable; + message = "Synaptics and libinput are incompatible, you cannot enable both (in services.xserver)."; + } + ]; + }; } diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index e7df2e6b4690..b03f70385b1f 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -14,6 +14,9 @@ let # Map video driver names to driver packages. FIXME: move into card-specific modules. knownVideoDrivers = { virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; }; + + # modesetting does not have a xf86videomodesetting package as it is included in xorgserver + modesetting = {}; }; fontsForXServer = @@ -443,7 +446,7 @@ in then { modules = [xorg.${"xf86video" + name}]; } else null) knownVideoDrivers; - in optional (driver != null) ({ inherit name; driverName = name; } // driver)); + in optional (driver != null) ({ inherit name; modules = []; driverName = name; } // driver)); assertions = [ { assertion = config.security.polkit.enable; |