diff options
Diffstat (limited to 'nixos/modules/services')
33 files changed, 940 insertions, 151 deletions
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index 31e585f211fe..0568b1af7d5c 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -65,11 +65,15 @@ in { }; environment = mkOption { - default = { NIX_REMOTE = "daemon"; }; + default = { }; type = with types; attrsOf str; description = '' Additional environment variables to be passed to the jenkins process. - The environment will always include JENKINS_HOME. + As a base environment, jenkins receives NIX_PATH, SSL_CERT_FILE and + GIT_SSL_CAINFO from <option>environment.sessionVariables</option>, + NIX_REMOTE is set to "daemon" and JENKINS_HOME is set to + the value of <option>services.jenkins.home</option>. This option has + precedence and can be used to override those mentioned variables. ''; }; @@ -106,12 +110,29 @@ in { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - environment = { - JENKINS_HOME = cfg.home; - } // cfg.environment; + environment = + let + selectedSessionVars = + lib.filterAttrs (n: v: builtins.elem n + [ "NIX_PATH" + "SSL_CERT_FILE" + "GIT_SSL_CAINFO" + ]) + config.environment.sessionVariables; + in + selectedSessionVars // + { JENKINS_HOME = cfg.home; + NIX_REMOTE = "daemon"; + } // + cfg.environment; path = cfg.packages; + # Force .war (re)extraction, or else we might run stale Jenkins. + preStart = '' + rm -rf ${cfg.home}/war + ''; + script = '' ${pkgs.jdk}/bin/java -jar ${pkgs.jenkins} --httpPort=${toString cfg.port} ${concatStringsSep " " cfg.extraOptions} ''; diff --git a/nixos/modules/services/continuous-integration/jenkins/job-builder.nix b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix new file mode 100644 index 000000000000..ec15a6a3d706 --- /dev/null +++ b/nixos/modules/services/continuous-integration/jenkins/job-builder.nix @@ -0,0 +1,155 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + jenkinsCfg = config.services.jenkins; + cfg = config.services.jenkins.jobBuilder; + +in { + options = { + services.jenkins.jobBuilder = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to enable the Jenkins Job Builder (JJB) service. It + allows defining jobs for Jenkins in a declarative manner. + + Jobs managed through the Jenkins WebUI (or by other means) are left + unchanged. + + Note that it really is declarative configuration; if you remove a + previously defined job, the corresponding job directory will be + deleted. + + Please see the Jenkins Job Builder documentation for more info: + <link xlink:href="http://docs.openstack.org/infra/jenkins-job-builder/"> + http://docs.openstack.org/infra/jenkins-job-builder/</link> + ''; + }; + + yamlJobs = mkOption { + default = ""; + type = types.lines; + example = '' + - job: + name: jenkins-job-test-1 + builders: + - shell: echo 'Hello world!' + ''; + description = '' + Job descriptions for Jenkins Job Builder in YAML format. + ''; + }; + + jsonJobs = mkOption { + default = [ ]; + type = types.listOf types.str; + example = literalExample '' + [ + ''' + [ { "job": + { "name": "jenkins-job-test-2", + "builders": [ "shell": "echo 'Hello world!'" ] + } + } + ] + ''' + ] + ''; + description = '' + Job descriptions for Jenkins Job Builder in JSON format. + ''; + }; + + nixJobs = mkOption { + default = [ ]; + type = types.listOf types.attrs; + example = literalExample '' + [ { job = + { name = "jenkins-job-test-3"; + builders = [ + { shell = "echo 'Hello world!'"; } + ]; + }; + } + ]; + ''; + description = '' + Job descriptions for Jenkins Job Builder in Nix format. + + This is a trivial wrapper around jsonJobs, using builtins.toJSON + behind the scene. + ''; + }; + }; + }; + + config = mkIf (jenkinsCfg.enable && cfg.enable) { + systemd.services.jenkins-job-builder = { + description = "Jenkins Job Builder Service"; + # JJB can run either before or after jenkins. We chose after, so we can + # always use curl to notify (running) jenkins to reload its config. + after = [ "jenkins.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = with pkgs; [ jenkins-job-builder curl ]; + + # Q: Why manipulate files directly instead of using "jenkins-jobs upload [...]"? + # A: Because this module is for administering a local jenkins install, + # and using local file copy allows us to not worry about + # authentication. + script = + let + yamlJobsFile = builtins.toFile "jobs.yaml" cfg.yamlJobs; + jsonJobsFiles = + map (x: (builtins.toFile "jobs.json" x)) + (cfg.jsonJobs ++ [(builtins.toJSON cfg.nixJobs)]); + jobBuilderOutputDir = "/run/jenkins-job-builder/output"; + # Stamp file is placed in $JENKINS_HOME/jobs/$JOB_NAME/ to indicate + # ownership. Enables tracking and removal of stale jobs. + ownerStamp = ".config-xml-managed-by-nixos-jenkins-job-builder"; + in + '' + rm -rf ${jobBuilderOutputDir} + cur_decl_jobs=/run/jenkins-job-builder/declarative-jobs + rm -f "$cur_decl_jobs" + + # Create / update jobs + mkdir -p ${jobBuilderOutputDir} + for inputFile in ${yamlJobsFile} ${concatStringsSep " " jsonJobsFiles}; do + HOME="${jenkinsCfg.home}" "${pkgs.jenkins-job-builder}/bin/jenkins-jobs" --ignore-cache test -o "${jobBuilderOutputDir}" "$inputFile" + done + + for file in "${jobBuilderOutputDir}/"*; do + test -f "$file" || continue + jobname="$(basename $file)" + jobdir="${jenkinsCfg.home}/jobs/$jobname" + echo "Creating / updating job \"$jobname\"" + mkdir -p "$jobdir" + touch "$jobdir/${ownerStamp}" + cp "$file" "$jobdir/config.xml" + echo "$jobname" >> "$cur_decl_jobs" + done + + # Remove stale jobs + for file in "${jenkinsCfg.home}"/jobs/*/${ownerStamp}; do + test -f "$file" || continue + jobdir="$(dirname $file)" + jobname="$(basename "$jobdir")" + grep --quiet --line-regexp "$jobname" "$cur_decl_jobs" 2>/dev/null && continue + echo "Deleting stale job \"$jobname\"" + rm -rf "$jobdir" + done + + echo "Asking Jenkins to reload config" + curl --silent -X POST http://localhost:${toString jenkinsCfg.port}/reload + ''; + serviceConfig = { + User = jenkinsCfg.user; + RuntimeDirectory = "jenkins-job-builder"; + }; + }; + }; +} diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index bae088c6610e..16e3235eb2c8 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -119,7 +119,7 @@ in extraPlugins = mkOption { type = types.listOf types.path; default = []; - example = literalExample "pkgs.postgis"; + example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql94; }).v_2_1_4 ]"; description = '' When this list contains elements a new store path is created. PostgreSQL and the elments are symlinked into it. Then pg_config, @@ -202,6 +202,8 @@ in # For non-root operation. initdb fi + # See postStart! + touch "${cfg.dataDir}/.first_startup" fi ln -sfn "${configFile}" "${cfg.dataDir}/postgresql.conf" diff --git a/nixos/modules/services/hardware/actkbd.nix b/nixos/modules/services/hardware/actkbd.nix index 82de362c371b..b16a8f50a3d8 100644 --- a/nixos/modules/services/hardware/actkbd.nix +++ b/nixos/modules/services/hardware/actkbd.nix @@ -125,6 +125,9 @@ in }; }; + # For testing + environment.systemPackages = [ pkgs.actkbd ]; + }; } diff --git a/nixos/modules/services/hardware/tlp.nix b/nixos/modules/services/hardware/tlp.nix index f221c82e2eda..23b6edcefd1a 100644 --- a/nixos/modules/services/hardware/tlp.nix +++ b/nixos/modules/services/hardware/tlp.nix @@ -6,9 +6,23 @@ let cfg = config.services.tlp; -tlp = pkgs.tlp.override { kmod = config.system.sbin.modprobe; }; - -confFile = pkgs.writeText "tlp" (builtins.readFile "${tlp}/etc/default/tlp" + cfg.extraConfig); +enableRDW = config.networking.networkmanager.enable; + +tlp = pkgs.tlp.override { + inherit enableRDW; + kmod = config.system.sbin.modprobe; +}; + +# XXX: We can't use writeTextFile + readFile here because it triggers +# TLP build to get the .drv (even on --dry-run). +confFile = pkgs.runCommand "tlp" + { config = cfg.extraConfig; + passAsFile = [ "config" ]; + } + '' + cat ${tlp}/etc/default/tlp > $out + cat $configPath >> $out + ''; in @@ -81,13 +95,15 @@ in environment.etc = [{ source = confFile; target = "default/tlp"; } - ] ++ optional tlp.enableRDW { + ] ++ optional enableRDW { source = "${tlp}/etc/NetworkManager/dispatcher.d/99tlp-rdw-nm"; target = "NetworkManager/dispatcher.d/99tlp-rdw-nm"; }; environment.systemPackages = [ tlp ]; + boot.kernelModules = [ "msr" ]; + }; } diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index e8beba4b3586..3a9e62a02052 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -11,6 +11,8 @@ let mainCf = '' + compatibility_level = 2 + queue_directory = /var/postfix/queue command_directory = ${pkgs.postfix}/sbin daemon_directory = ${pkgs.postfix}/libexec/postfix @@ -31,10 +33,7 @@ let mynetworks_style = ${cfg.networksStyle} '' else - # Postfix default is subnet, but let's play safe - '' - mynetworks_style = host - '') + "") + optionalString (cfg.hostname != "") '' myhostname = ${cfg.hostname} '' @@ -89,7 +88,7 @@ let masterCf = '' # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args - # (yes) (yes) (yes) (never) (100) + # (yes) (yes) (no) (never) (100) # ========================================================================== smtp inet n - n - - smtpd #submission inet n - n - - smtpd @@ -232,8 +231,7 @@ in default = null; example = ["localdomain"]; description = " - List of domains we agree to relay to. Default is the same as - destination. + List of domains we agree to relay to. Default is empty. "; }; @@ -357,32 +355,29 @@ in } ]; - jobs.postfix = - # I copy _lots_ of shipped configuration filed - # that can be left as is. I am afraid the exact - # will list slightly change in next Postfix - # release, so listing them all one-by-one in an - # accurate way is unlikely to be better. + systemd.services.postfix = { description = "Postfix mail server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - daemonType = "fork"; + serviceConfig = { + Type = "forking"; + Restart = "always"; + PIDFile = "/var/postfix/queue/pid/master.pid"; + }; preStart = '' - if ! [ -d /var/spool/postfix ]; then - ${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue - fi + ${pkgs.coreutils}/bin/mkdir -p /var/spool/mail /var/postfix/conf /var/postfix/queue ${pkgs.coreutils}/bin/chown -R ${user}:${group} /var/postfix ${pkgs.coreutils}/bin/chown -R ${user}:${setgidGroup} /var/postfix/queue ${pkgs.coreutils}/bin/chmod -R ug+rwX /var/postfix/queue ${pkgs.coreutils}/bin/chown root:root /var/spool/mail ${pkgs.coreutils}/bin/chmod a+rwxt /var/spool/mail - ${pkgs.coreutils}/bin/ln -sf /var/spool/mail /var/mail + ${pkgs.coreutils}/bin/ln -sf /var/spool/mail /var/ - ln -sf "${pkgs.postfix}/etc/postfix/"* /var/postfix/conf + ln -sf ${pkgs.postfix}/etc/postfix/postfix-files /var/postfix/conf ln -sf ${aliasesFile} /var/postfix/conf/aliases ln -sf ${virtualFile} /var/postfix/conf/virtual @@ -391,12 +386,18 @@ in ${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases ${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual + ''; + script = '' ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start ''; + reload = '' + ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf reload + ''; + preStop = '' - ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop + ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop ''; }; diff --git a/nixos/modules/services/misc/autofs.nix b/nixos/modules/services/misc/autofs.nix index f4a1059d09f0..b4dae79cf8a9 100644 --- a/nixos/modules/services/misc/autofs.nix +++ b/nixos/modules/services/misc/autofs.nix @@ -71,48 +71,17 @@ in config = mkIf cfg.enable { - environment.etc = singleton - { target = "auto.master"; - source = pkgs.writeText "auto.master" cfg.autoMaster; - }; - boot.kernelModules = [ "autofs4" ]; - jobs.autofs = + systemd.services.autofs = { description = "Filesystem automounter"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; - startOn = "started network-interfaces"; - stopOn = "stopping network-interfaces"; - - path = [ pkgs.nfs-utils pkgs.sshfsFuse ]; - - preStop = - '' - set -e; while :; do pkill -TERM automount; sleep 1; done - ''; - - # automount doesn't clean up when receiving SIGKILL. - # umount -l should unmount the directories recursively when they are no longer used - # It does, but traces are left in /etc/mtab. So unmount recursively.. - postStop = - '' - PATH=${pkgs.gnused}/bin:${pkgs.coreutils}/bin - exec &> /tmp/logss - # double quote for sed: - escapeSpaces(){ sed 's/ /\\\\040/g'; } - unescapeSpaces(){ sed 's/\\040/ /g'; } - sed -n 's@^\s*\(\([^\\ ]\|\\ \)*\)\s.*@\1@p' ${autoMaster} | sed 's/[\\]//' | while read mountPoint; do - sed -n "s@[^ ]\+\s\+\($(echo "$mountPoint"| escapeSpaces)[^ ]*\).*@\1@p" /proc/mounts | sort -r | unescapeSpaces| while read smountP; do - ${pkgs.utillinux}/bin/umount -l "$smountP" || true - done - done - ''; - - script = - '' - ${if cfg.debug then "exec &> /var/log/autofs" else ""} - exec ${pkgs.autofs5}/sbin/automount ${if cfg.debug then "-d" else ""} -f -t ${builtins.toString cfg.timeout} "${autoMaster}" ${if cfg.debug then "-l7" else ""} - ''; + serviceConfig = { + ExecStart = "${pkgs.autofs5}/sbin/automount ${if cfg.debug then "-d" else ""} -f -t ${builtins.toString cfg.timeout} ${autoMaster} ${if cfg.debug then "-l7" else ""}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; }; }; diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix new file mode 100644 index 000000000000..a920aa22ccdf --- /dev/null +++ b/nixos/modules/services/misc/calibre-server.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.calibre-server; + +in + +{ + + ###### interface + + options = { + + services.calibre-server = { + + enable = mkEnableOption "calibre-server"; + + libraryDir = mkOption { + description = '' + The directory where the Calibre library to serve is. + ''; + type = types.path; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.calibre-server = + { + description = "Calibre Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "calibre-server"; + Restart = "always"; + ExecStart = "${pkgs.calibre}/bin/calibre-server --with-library=${cfg.libraryDir}"; + }; + + }; + + environment.systemPackages = [ pkgs.calibre ]; + + users.extraUsers.calibre-server = { + uid = config.ids.uids.calibre-server; + group = "calibre-server"; + }; + + users.extraGroups.calibre-server = { + gid = config.ids.gids.calibre-server; + }; + + }; + +} diff --git a/nixos/modules/services/misc/ihaskell.nix b/nixos/modules/services/misc/ihaskell.nix index 7f7f981de498..13c41466eab2 100644 --- a/nixos/modules/services/misc/ihaskell.nix +++ b/nixos/modules/services/misc/ihaskell.nix @@ -22,9 +22,9 @@ in }; haskellPackages = mkOption { - default = pkgs.haskellngPackages; - defaultText = "pkgs.haskellngPackages"; - example = literalExample "pkgs.haskell-ng.packages.ghc784"; + default = pkgs.haskellPackages; + defaultText = "pkgs.haskellPackages"; + example = literalExample "pkgs.haskell.packages.ghc784"; description = '' haskellPackages used to build IHaskell and other packages. This can be used to change the GHC version used to build diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index c10d8197686f..7534eb0ae6a3 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -92,7 +92,9 @@ in system.build.manual = manual; - environment.systemPackages = [ manual.manpages manual.manual help ]; + environment.systemPackages = + [ manual.manual help ] + ++ optional config.programs.man.enable manual.manpages; boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"]; diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix index 0844190a5490..ea97d6e30e83 100644 --- a/nixos/modules/services/misc/parsoid.nix +++ b/nixos/modules/services/misc/parsoid.nix @@ -91,7 +91,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}"; + ExecStart = "${pkgs.nodePackages_0_10.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}"; }; }; diff --git a/nixos/modules/services/misc/synergy.nix b/nixos/modules/services/misc/synergy.nix index 054df965347d..7e8eadbe5f37 100644 --- a/nixos/modules/services/misc/synergy.nix +++ b/nixos/modules/services/misc/synergy.nix @@ -89,6 +89,7 @@ in wantedBy = optional cfgC.autoStart "multi-user.target"; path = [ pkgs.synergy ]; serviceConfig.ExecStart = ''${pkgs.synergy}/bin/synergyc -f ${optionalString (cfgC.screenName != "") "-n ${cfgC.screenName}"} ${cfgC.serverAddress}''; + serviceConfig.Restart = "on-failure"; }; }) (mkIf cfgS.enable { @@ -98,6 +99,7 @@ in wantedBy = optional cfgS.autoStart "multi-user.target"; path = [ pkgs.synergy ]; serviceConfig.ExecStart = ''${pkgs.synergy}/bin/synergys -c ${cfgS.configFile} -f ${optionalString (cfgS.address != "") "-a ${cfgS.address}"} ${optionalString (cfgS.screenName != "") "-n ${cfgS.screenName}" }''; + serviceConfig.Restart = "on-failure"; }; }) ]; diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix index 7e8dea4ec024..ebe4741f01bd 100644 --- a/nixos/modules/services/monitoring/bosun.nix +++ b/nixos/modules/services/monitoring/bosun.nix @@ -9,7 +9,7 @@ let tsdbHost = ${cfg.opentsdbHost} httpListen = ${cfg.listenAddress} stateFile = ${cfg.stateFile} - checkFrequency = 5m + checkFrequency = ${cfg.checkFrequency} ${cfg.extraConfig} ''; @@ -77,6 +77,14 @@ in { ''; }; + checkFrequency = mkOption { + type = types.str; + default = "5m"; + description = '' + Bosun's check frequency + ''; + }; + extraConfig = mkOption { type = types.string; default = ""; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index fa653565a67f..5302728eae91 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -318,7 +318,7 @@ in { wantedBy = ["multi-user.target"]; after = ["networking.target"]; serviceConfig = { - ExecStart = "${cfg.package-backend}/bin/grafana --config ${cfgFile} web"; + ExecStart = "${cfg.package}/bin/grafana --config ${cfgFile} web"; WorkingDirectory = cfg.dataDir; User = "grafana"; }; diff --git a/nixos/modules/services/monitoring/teamviewer.nix b/nixos/modules/services/monitoring/teamviewer.nix index beba5dcd1b06..533f1ea6644b 100644 --- a/nixos/modules/services/monitoring/teamviewer.nix +++ b/nixos/modules/services/monitoring/teamviewer.nix @@ -29,6 +29,7 @@ in wantedBy = [ "graphical.target" ]; after = [ "NetworkManager-wait-online.service" "network.target" ]; + preStart = "mkdir -pv /var/tmp/teamviewer10/{logs,config}"; serviceConfig = { Type = "forking"; diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix index b079cb227303..13617a1b6c58 100644 --- a/nixos/modules/services/networking/asterisk.nix +++ b/nixos/modules/services/networking/asterisk.nix @@ -201,6 +201,7 @@ in for d in '${varlibdir}' '${spooldir}' '${logdir}'; do # TODO: Make exceptions for /var directories that likely should be updated if [ ! -e "$d" ]; then + mkdir -p "$d" cp --recursive ${pkgs.asterisk}/"$d" "$d" chown --recursive ${asteriskUser} "$d" find "$d" -type d | xargs chmod 0755 diff --git a/nixos/modules/services/networking/autossh.nix b/nixos/modules/services/networking/autossh.nix new file mode 100644 index 000000000000..9ea17469870d --- /dev/null +++ b/nixos/modules/services/networking/autossh.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.autossh; + +in + +{ + + ###### interface + + options = { + + services.autossh = { + + sessions = mkOption { + type = types.listOf (types.submodule { + options = { + name = mkOption { + type = types.string; + example = "socks-peer"; + description = "Name of the local AutoSSH session"; + }; + user = mkOption { + type = types.string; + example = "bill"; + description = "Name of the user the AutoSSH session should run as"; + }; + monitoringPort = mkOption { + type = types.int; + default = 0; + example = 20000; + description = '' + Port to be used by AutoSSH for peer monitoring. Note, that + AutoSSH also uses mport+1. Value of 0 disables the keep-alive + style monitoring + ''; + }; + extraArguments = mkOption { + type = types.string; + example = "-N -D4343 bill@socks.example.net"; + description = '' + Arguments to be passed to AutoSSH and retransmitted to SSH + process. Some meaningful options include -N (don't run remote + command), -D (open SOCKS proxy on local port), -R (forward + remote port), -L (forward local port), -v (Enable debug). Check + ssh manual for the complete list. + ''; + }; + }; + }); + + default = []; + description = '' + List of AutoSSH sessions to start as systemd services. Each service is + named 'autossh-{session.name}'. + ''; + + example = [ + { + name="socks-peer"; + user="bill"; + monitoringPort = 20000; + extraArguments="-N -D4343 billremote@socks.host.net"; + } + ]; + + }; + }; + + }; + + ###### implementation + + config = mkIf (cfg.sessions != []) { + + systemd.services = + + lib.fold ( s : acc : acc // + { + "autossh-${s.name}" = + let + mport = if s ? monitoringPort then s.monitoringPort else 0; + in + { + description = "AutoSSH session (" + s.name + ")"; + + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + # To be able to start the service with no network connection + environment.AUTOSSH_GATETIME="0"; + + # How often AutoSSH checks the network, in seconds + environment.AUTOSSH_POLL="30"; + + serviceConfig = { + User = "${s.user}"; + PermissionsStartOnly = true; + # AutoSSH may exit with 0 code if the SSH session was + # gracefully terminated by either local or remote side. + Restart = "on-success"; + ExecStart = "${pkgs.autossh}/bin/autossh -M ${toString mport} ${s.extraArguments}"; + }; + }; + }) {} cfg.sessions; + + environment.systemPackages = [ pkgs.autossh ]; + + }; +} diff --git a/nixos/modules/services/networking/copy-com.nix b/nixos/modules/services/networking/copy-com.nix index 69a41ab97963..ee0d043d471b 100644 --- a/nixos/modules/services/networking/copy-com.nix +++ b/nixos/modules/services/networking/copy-com.nix @@ -39,7 +39,8 @@ in systemd.services."copy-com-${cfg.user}" = { description = "Copy.com client"; - after = [ "network.target" "local-fs.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" "local-fs.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${pkgs.copy-com}/bin/CopyConsole ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}"; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 8370eca21e52..7df194fa419b 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -6,16 +6,18 @@ with lib; let cfg = config.networking.networkmanager; - stateDirs = "/var/lib/NetworkManager /var/lib/dhclient"; + # /var/lib/misc is for dnsmasq.leases. + stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc"; configFile = writeText "NetworkManager.conf" '' [main] plugins=keyfile [keyfile] - ${optionalString (config.networking.hostName != "") '' - hostname=${config.networking.hostName} - ''} + ${optionalString (config.networking.hostName != "") + ''hostname=${config.networking.hostName}''} + ${optionalString (cfg.unmanaged != []) + ''unmanaged-devices=${lib.concatStringsSep ";" cfg.unmanaged}''} [logging] level=WARN @@ -40,7 +42,6 @@ let polkit.addRule(function(action, subject) { if ( subject.isInGroup("networkmanager") - && subject.active && (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 || action.id.indexOf("org.freedesktop.ModemManager") == 0 )) @@ -97,6 +98,16 @@ in { ''; }; + unmanaged = mkOption { + type = types.listOf types.string; + default = []; + description = '' + List of interfaces that will not be managed by NetworkManager. + Interface name can be specified here, but if you need more fidelity + see "Device List Format" in NetworkManager.conf man page. + ''; + }; + # Ugly hack for using the correct gnome3 packageSet basePackages = mkOption { type = types.attrsOf types.path; @@ -206,10 +217,16 @@ in { environment.systemPackages = cfg.packages; - users.extraGroups = singleton { + users.extraGroups = [{ name = "networkmanager"; gid = config.ids.gids.networkmanager; - }; + } + { + name = "nm-openvpn"; + }]; + users.extraUsers = [{ + name = "nm-openvpn"; + }]; systemd.packages = cfg.packages; diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix index 005eb7bd7614..52c7ac8e6893 100644 --- a/nixos/modules/services/networking/quassel.nix +++ b/nixos/modules/services/networking/quassel.nix @@ -23,11 +23,11 @@ in ''; }; - interface = mkOption { - default = "127.0.0.1"; + interfaces = mkOption { + default = [ "127.0.0.1" ]; description = '' - The interface the Quassel daemon will be listening to. If `127.0.0.1', - only clients on the local host can connect to it; if `0.0.0.0', clients + The interfaces the Quassel daemon will be listening to. If `[ 127.0.0.1 ]', + only clients on the local host can connect to it; if `[ 0.0.0.0 ]', clients can access it from any network interface. ''; }; @@ -78,7 +78,8 @@ in { description = "Quassel IRC client daemon"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + after = [ "network.target" ] ++ optional config.services.postgresql.enable "postgresql.service" + ++ optional config.services.mysql.enable "mysql.service"; preStart = '' mkdir -p ${cfg.dataDir} @@ -87,7 +88,7 @@ in serviceConfig = { - ExecStart = "${quassel}/bin/quasselcore --listen=${cfg.interface} --port=${toString cfg.portNumber} --configdir=${cfg.dataDir}"; + ExecStart = "${quassel}/bin/quasselcore --listen=${concatStringsSep '','' cfg.interfaces} --port=${toString cfg.portNumber} --configdir=${cfg.dataDir}"; User = user; PermissionsStartOnly = true; }; diff --git a/nixos/modules/services/networking/supplicant.nix b/nixos/modules/services/networking/supplicant.nix new file mode 100644 index 000000000000..502a0468787f --- /dev/null +++ b/nixos/modules/services/networking/supplicant.nix @@ -0,0 +1,249 @@ +{ config, lib, utils, pkgs, ... }: + +with lib; + +let + + cfg = config.networking.supplicant; + + # We must escape interfaces due to the systemd interpretation + subsystemDevice = interface: + "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device"; + + serviceName = iface: "supplicant-${if (iface=="WLAN") then "wlan@" else ( + if (iface=="LAN") then "lan@" else ( + if (iface=="DBUS") then "dbus" + else (replaceChars [" "] ["-"] iface)))}"; + + # TODO: Use proper privilege separation for wpa_supplicant + supplicantService = iface: suppl: + let + deps = (if (iface=="WLAN"||iface=="LAN") then ["sys-subsystem-net-devices-%i.device"] else ( + if (iface=="DBUS") then ["dbus.service"] + else (map subsystemDevice (splitString " " iface)))) + ++ optional (suppl.bridge!="") (subsystemDevice suppl.bridge); + + ifaceArg = concatStringsSep " -N " (map (i: "-i${i}") (splitString " " iface)); + driverArg = optionalString (suppl.driver != null) "-D${suppl.driver}"; + bridgeArg = optionalString (suppl.bridge!="") "-b${suppl.bridge}"; + confFileArg = optionalString (suppl.configFile.path!=null) "-c${suppl.configFile.path}"; + extraConfFile = pkgs.writeText "supplicant-extra-conf-${replaceChars [" "] ["-"] iface}" '' + ${optionalString suppl.userControlled.enable "ctrl_interface=DIR=${suppl.userControlled.socketDir} GROUP=${suppl.userControlled.group}"} + ${optionalString suppl.configFile.writable "update_config=1"} + ${suppl.extraConf} + ''; + in + { description = "Supplicant ${iface}${optionalString (iface=="WLAN"||iface=="LAN") " %I"}"; + wantedBy = [ "network.target" ]; + bindsTo = deps; + after = deps; + before = [ "network.target" ]; + # Receive restart event after resume + partOf = [ "post-resume.target" ]; + + path = [ pkgs.coreutils ]; + + preStart = '' + ${optionalString (suppl.configFile.path!=null) '' + touch -a ${suppl.configFile.path} + chmod 600 ${suppl.configFile.path} + ''} + ${optionalString suppl.userControlled.enable '' + if ! test -e ${suppl.userControlled.socketDir}; then + mkdir -m 0770 -p ${suppl.userControlled.socketDir} + chgrp ${suppl.userControlled.group} ${suppl.userControlled.socketDir} + fi + + if test "$(stat --printf '%G' ${suppl.userControlled.socketDir})" != "${suppl.userControlled.group}"; then + echo "ERROR: bad ownership on ${suppl.userControlled.socketDir}" >&2 + exit 1 + fi + ''} + ''; + + serviceConfig.ExecStart = "${pkgs.wpa_supplicant}/bin/wpa_supplicant -s ${driverArg} ${confFileArg} -I${extraConfFile} ${bridgeArg} ${suppl.extraCmdArgs} ${if (iface=="WLAN"||iface=="LAN") then "-i%I" else (if (iface=="DBUS") then "-u" else ifaceArg)}"; + + }; + + +in + +{ + + ###### interface + + options = { + + networking.supplicant = mkOption { + type = types.attrsOf types.optionSet; + + default = { }; + + example = { + "wlan0 wlan1" = { + configFile = "/etc/wpa_supplicant"; + userControlled.group = "network"; + extraConf = '' + ap_scan=1 + p2p_disabled=1 + ''; + extraCmdArgs = "-u -W"; + bridge = "br0"; + }; + }; + + description = '' + Interfaces for which to start <command>wpa_supplicant</command>. + The supplicant is used to scan for and associate with wireless networks, + or to authenticate with 802.1x capable network switches. + + The value of this option is an attribute set. Each attribute configures a + <command>wpa_supplicant</command> service, where the attribute name specifies + the name of the interface that <command>wpa_supplicant</command> operates on. + The attribute name can be a space separated list of interfaces. + The attribute names <literal>WLAN</literal>, <literal>LAN</literal> and <literal>DBUS</literal> + have a special meaning. <literal>WLAN</literal> and <literal>LAN</literal> are + configurations for universal <command>wpa_supplicant</command> service that is + started for each WLAN interface or for each LAN interface, respectively. + <literal>DBUS</literal> defines a device-unrelated <command>wpa_supplicant</command> + service that can be accessed through <literal>D-Bus</literal>. + ''; + + options = { + + configFile = { + + path = mkOption { + type = types.path; + example = "/etc/wpa_supplicant.conf"; + description = '' + External <literal>wpa_supplicant.conf</literal> configuration file. + The configuration options defined declaratively within <literal>networking.supplicant</literal> have + precedence over options defined in <literal>configFile</literal>. + ''; + }; + + writable = mkOption { + type = types.bool; + default = false; + description = '' + Whether the configuration file at <literal>configFile.path</literal> should be written to by + <literal>wpa_supplicant</literal>. + ''; + }; + + }; + + extraConf = mkOption { + type = types.lines; + default = ""; + example = '' + ap_scan=1 + device_name=My-NixOS-Device + device_type=1-0050F204-1 + driver_param=use_p2p_group_interface=1 + disable_scan_offload=1 + p2p_listen_reg_class=81 + p2p_listen_channel=1 + p2p_oper_reg_class=81 + p2p_oper_channel=1 + manufacturer=NixOS + model_name=NixOS_Unstable + model_number=2015 + ''; + description = '' + Configuration options for <literal>wpa_supplicant.conf</literal>. + Options defined here have precedence over options in <literal>configFile</literal>. + NOTE: Do not write sensitive data into <literal>extraConf</literal> as it will + be world-readable in the <literal>nix-store</literal>. For sensitive information + use the <literal>configFile</literal> instead. + ''; + }; + + extraCmdArgs = mkOption { + type = types.str; + default = ""; + example = "-e/var/run/wpa_supplicant/entropy.bin"; + description = + "Command line arguments to add when executing <literal>wpa_supplicant</literal>."; + }; + + driver = mkOption { + type = types.nullOr types.str; + default = "nl80211,wext"; + description = "Force a specific wpa_supplicant driver."; + }; + + bridge = mkOption { + type = types.str; + default = ""; + description = "Name of the bridge interface that wpa_supplicant should listen at."; + }; + + userControlled = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli. + This is useful for laptop users that switch networks a lot and don't want + to depend on a large package such as NetworkManager just to pick nearby + access points. + ''; + }; + + socketDir = mkOption { + type = types.str; + default = "/var/run/wpa_supplicant"; + description = "Directory of sockets for controlling wpa_supplicant."; + }; + + group = mkOption { + type = types.str; + default = "wheel"; + example = "network"; + description = "Members of this group can control wpa_supplicant."; + }; + + }; + + }; + + }; + + }; + + + ###### implementation + + config = mkIf (cfg != {}) { + + environment.systemPackages = [ pkgs.wpa_supplicant ]; + + services.dbus.packages = [ pkgs.wpa_supplicant ]; + + systemd.services = mapAttrs' (n: v: nameValuePair (serviceName n) (supplicantService n v)) cfg; + + services.udev.packages = [ + (pkgs.writeTextFile { + name = "99-zzz-60-supplicant.rules"; + destination = "/etc/udev/rules.d/99-zzz-60-supplicant.rules"; + text = '' + ${flip (concatMapStringsSep "\n") (filter (n: n!="WLAN" && n!="LAN" && n!="DBUS") (attrNames cfg)) (iface: + flip (concatMapStringsSep "\n") (splitString " " iface) (i: '' + ACTION=="add", SUBSYSTEM=="net", ENV{INTERFACE}=="${i}", TAG+="systemd", ENV{SYSTEMD_WANTS}+="supplicant-${replaceChars [" "] ["-"] iface}.service", TAG+="SUPPLICANT_ASSIGNED"''))} + + ${optionalString (hasAttr "WLAN" cfg) '' + ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", TAG!="SUPPLICANT_ASSIGNED", TAG+="systemd", PROGRAM="${pkgs.systemd}/bin/systemd-escape -p %E{INTERFACE}", ENV{SYSTEMD_WANTS}+="supplicant-wlan@$result.service" + ''} + ${optionalString (hasAttr "LAN" cfg) '' + ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="lan", TAG!="SUPPLICANT_ASSIGNED", TAG+="systemd", PROGRAM="${pkgs.systemd}/bin/systemd-escape -p %E{INTERFACE}", ENV{SYSTEMD_WANTS}+="supplicant-lan@$result.service" + ''} + ''; + })]; + + }; + +} + diff --git a/nixos/modules/services/networking/tlsdated.nix b/nixos/modules/services/networking/tlsdated.nix index f2d0c9f35c9c..ff7d0178a81a 100644 --- a/nixos/modules/services/networking/tlsdated.nix +++ b/nixos/modules/services/networking/tlsdated.nix @@ -63,7 +63,7 @@ in }); default = [ { - host = "www.ptb.de"; + host = "encrypted.google.com"; port = 443; proxy = null; } diff --git a/nixos/modules/services/networking/wakeonlan.nix b/nixos/modules/services/networking/wakeonlan.nix index 11bb7e925255..ebfba263cd8f 100644 --- a/nixos/modules/services/networking/wakeonlan.nix +++ b/nixos/modules/services/networking/wakeonlan.nix @@ -40,7 +40,7 @@ in ]; description = '' Interfaces where to enable Wake-On-LAN, and how. Two methods available: - "magickey" and "password". The password has the shape of six bytes + "magicpacket" and "password". The password has the shape of six bytes in hexadecimal separated by a colon each. For more information, check the ethtool manual. ''; diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix index 02d80a77da50..1b5e83173e8f 100644 --- a/nixos/modules/services/scheduling/cron.nix +++ b/nixos/modules/services/scheduling/cron.nix @@ -100,7 +100,7 @@ in environment.systemPackages = [ cronNixosPkg ]; environment.etc.crontab = - { source = pkgs.runCommand "crontabs" { inherit allFiles; } + { source = pkgs.runCommand "crontabs" { inherit allFiles; preferLocalBuild = true; } '' touch $out for i in $allFiles; do diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix index 2c662c0aead9..171503db4eec 100644 --- a/nixos/modules/services/web-servers/lighttpd/default.nix +++ b/nixos/modules/services/web-servers/lighttpd/default.nix @@ -44,7 +44,6 @@ let "mod_flv_streaming" "mod_magnet" "mod_mysql_vhost" - "mod_rewrite" "mod_scgi" "mod_setenv" "mod_trigger_b4_dl" diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 0fc255c4d64c..e32d6669b046 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -104,6 +104,7 @@ in { services.xserver.desktopManager.session = singleton { name = "gnome3"; + bgSupport = true; start = '' # Set GTK_DATA_PREFIX so that GTK+ can find the themes export GTK_DATA_PREFIX=${config.system.path} diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 5061d59b7c7f..6fdd5b4fa36d 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -8,38 +8,9 @@ let cfg = xcfg.desktopManager.kde5; xorg = pkgs.xorg; - phononBackends = { - gstreamer = [ - pkgs.phonon_backend_gstreamer - pkgs.gst_all.gstreamer - pkgs.gst_all.gstPluginsBase - pkgs.gst_all.gstPluginsGood - pkgs.gst_all.gstPluginsUgly - pkgs.gst_all.gstPluginsBad - pkgs.gst_all.gstFfmpeg # for mp3 playback - pkgs.phonon_qt5_backend_gstreamer - pkgs.gst_all_1.gstreamer - pkgs.gst_all_1.gst-plugins-base - pkgs.gst_all_1.gst-plugins-good - pkgs.gst_all_1.gst-plugins-ugly - pkgs.gst_all_1.gst-plugins-bad - pkgs.gst_all_1.gst-libav # for mp3 playback - ]; - - vlc = [ - pkgs.phonon_qt5_backend_vlc - pkgs.phonon_backend_vlc - ]; - }; - - phononBackendPackages = flip concatMap cfg.phononBackends - (name: attrByPath [name] (throw "unknown phonon backend `${name}'") phononBackends); - kf5 = pkgs.kf5_stable; - - plasma5 = pkgs.plasma5_stable.override { inherit kf5; }; - - kdeApps = pkgs.kdeApps_stable.override { inherit kf5; }; + plasma5 = pkgs.plasma5_stable; + kdeApps = pkgs.kdeApps_stable; in @@ -53,14 +24,24 @@ in description = "Enable the Plasma 5 (KDE 5) desktop environment."; }; - phononBackends = mkOption { - type = types.listOf types.str; - default = ["gstreamer"]; - example = ["gstreamer" "vlc"]; - description = '' - Phonon backends to use in KDE. Only the VLC and GStreamer backends are - available. The GStreamer backend is preferred by upstream. - ''; + phonon = { + + gstreamer = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable the GStreamer Phonon backend (recommended)."; + }; + }; + + vlc = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable the VLC Phonon backend."; + }; + }; + }; }; @@ -88,23 +69,77 @@ in }; environment.systemPackages = - filter isDerivation (builtins.attrValues plasma5) - ++ filter isDerivation (builtins.attrValues kf5) - ++ [ + [ pkgs.qt4 # qtconfig is the only way to set Qt 4 theme - kdeApps.kde-baseapps - kdeApps.kde-base-artwork - kdeApps.kmix + kf5.frameworkintegration + kf5.kinit + + plasma5.breeze + plasma5.kde-cli-tools + plasma5.kdeplasma-addons + plasma5.kgamma5 + plasma5.khelpcenter + plasma5.khotkeys + plasma5.kinfocenter + plasma5.kmenuedit + plasma5.kscreen + plasma5.ksysguard + plasma5.kwayland + plasma5.kwin + plasma5.kwrited + plasma5.milou + plasma5.oxygen + plasma5.polkit-kde-agent + plasma5.systemsettings + + plasma5.plasma-desktop + plasma5.plasma-workspace + plasma5.plasma-workspace-wallpapers + + kdeApps.ark + kdeApps.dolphin + kdeApps.dolphin-plugins + kdeApps.ffmpegthumbs + kdeApps.gwenview + kdeApps.kate + kdeApps.kdegraphics-thumbnailers kdeApps.konsole - kdeApps.oxygen-icons - - kdeApps.kde-runtime + kdeApps.okular + kdeApps.print-manager + kdeApps.oxygen-icons pkgs.hicolor_icon_theme + plasma5.kde-gtk-config pkgs.orion # GTK theme, nearly identical to Breeze - ] ++ phononBackendPackages; + ] + ++ lib.optional config.hardware.bluetooth.enable plasma5.bluedevil + ++ lib.optional config.networking.networkmanager.enable plasma5.plasma-nm + ++ lib.optional config.hardware.pulseaudio.enable plasma5.plasma-pa + ++ lib.optional config.powerManagement.enable plasma5.powerdevil + ++ lib.optionals cfg.phonon.gstreamer.enable + [ + pkgs.phonon_backend_gstreamer + pkgs.gst_all.gstreamer + pkgs.gst_all.gstPluginsBase + pkgs.gst_all.gstPluginsGood + pkgs.gst_all.gstPluginsUgly + pkgs.gst_all.gstPluginsBad + pkgs.gst_all.gstFfmpeg # for mp3 playback + pkgs.phonon_qt5_backend_gstreamer + pkgs.gst_all_1.gstreamer + pkgs.gst_all_1.gst-plugins-base + pkgs.gst_all_1.gst-plugins-good + pkgs.gst_all_1.gst-plugins-ugly + pkgs.gst_all_1.gst-plugins-bad + pkgs.gst_all_1.gst-libav # for mp3 playback + ] + ++ lib.optionals cfg.phonon.vlc.enable + [ + pkgs.phonon_qt5_backend_vlc + pkgs.phonon_backend_vlc + ]; environment.pathsToLink = [ "/share" ]; @@ -114,7 +149,7 @@ in }; environment.profileRelativeEnvVars = - mkIf (lib.elem "gstreamer" cfg.phononBackends) + mkIf cfg.phonon.gstreamer.enable { GST_PLUGIN_SYSTEM_PATH = [ "/lib/gstreamer-0.10" ]; GST_PLUGIN_SYSTEM_PATH_1_0 = [ "/lib/gstreamer-1.0" ]; diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index c9a563768323..58eb6f050131 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -20,7 +20,9 @@ in enable = mkEnableOption '' GDM as the display manager. - <emphasis>GDM is very experimental and may render system unusable.</emphasis> + <emphasis>GDM in NixOS is not well-tested with desktops other + than GNOME, so use with caution, as it could render the + system unusable.</emphasis> ''; debug = mkEnableOption '' diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix index 3f1d190ae66b..16a0d1b6d963 100644 --- a/nixos/modules/services/x11/display-managers/sddm.nix +++ b/nixos/modules/services/x11/display-managers/sddm.nix @@ -35,8 +35,23 @@ let SessionCommand=${dmcfg.session.script} SessionDir=${dmcfg.session.desktops} XauthPath=${pkgs.xorg.xauth}/bin/xauth + + ${optionalString cfg.autoLogin.enable '' + [Autologin] + User=${cfg.autoLogin.user} + Session=${defaultSessionName}.desktop + Relogin=${if cfg.autoLogin.relogin then "true" else "false"} + ''} + + ${cfg.extraConfig} ''; + defaultSessionName = + let + dm = xcfg.desktopManager.default; + wm = xcfg.windowManager.default; + in dm + optionalString (wm != "none") (" + " + wm); + in { options = { @@ -50,6 +65,19 @@ in ''; }; + extraConfig = mkOption { + type = types.str; + default = ""; + example = '' + [Autologin] + User=john + Session=plasma.desktop + ''; + description = '' + Extra lines appended to the configuration of SDDM. + ''; + }; + theme = mkOption { type = types.str; default = "maui"; @@ -57,12 +85,62 @@ in Greeter theme to use. ''; }; + + autoLogin = mkOption { + default = {}; + description = '' + Configuration for automatic login. + ''; + + type = types.submodule { + options = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Automatically log in as the sepecified <option>autoLogin.user</option>. + ''; + }; + + user = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User to be used for the autologin. + ''; + }; + + relogin = mkOption { + type = types.bool; + default = false; + description = '' + If true automatic login will kick in again on session exit, otherwise it + will work only the first time. + ''; + }; + }; + }; + }; + }; }; config = mkIf cfg.enable { + assertions = [ + { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null; + message = "SDDM auto-login requires services.xserver.displayManager.sddm.autoLogin.user to be set"; + } + { assertion = cfg.autoLogin.enable -> elem defaultSessionName dmcfg.session.names; + message = '' + SDDM auto-login requires that services.xserver.desktopManager.default and + services.xserver.windowMananger.default are set to valid values. The current + default session: ${defaultSessionName} is not valid. + ''; + } + ]; + services.xserver.displayManager.slim.enable = false; services.xserver.displayManager.job = { @@ -93,6 +171,18 @@ in session optional pam_keyinit.so force revoke session optional pam_permit.so ''; + + sddm-autologin.text = '' + auth requisite pam_nologin.so + auth required pam_succeed_if.so uid >= 1000 quiet + auth required pam_permit.so + + account include sddm + + password include sddm + + session include sddm + ''; }; users.extraUsers.sddm = { diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix index ffae22d2d670..d40373ec2e55 100644 --- a/nixos/modules/services/x11/redshift.nix +++ b/nixos/modules/services/x11/redshift.nix @@ -22,14 +22,16 @@ in { latitude = mkOption { type = types.str; description = '' - Your current latitude. + Your current latitude, between + <literal>-90.0</literal> and <literal>90.0</literal>. ''; }; longitude = mkOption { type = types.str; description = '' - Your current longitude. + Your current longitude, between + between <literal>-180.0</literal> and <literal>180.0</literal>. ''; }; @@ -38,14 +40,16 @@ in { type = types.int; default = 5500; description = '' - Colour temperature to use during the day. + Colour temperature to use during the day, between + <literal>1000</literal> and <literal>25000</literal> K. ''; }; night = mkOption { type = types.int; default = 3700; description = '' - Colour temperature to use at night. + Colour temperature to use at night, between + <literal>1000</literal> and <literal>25000</literal> K. ''; }; }; diff --git a/nixos/modules/services/x11/window-managers/clfswm.nix b/nixos/modules/services/x11/window-managers/clfswm.nix new file mode 100644 index 000000000000..9d8eecb56c77 --- /dev/null +++ b/nixos/modules/services/x11/window-managers/clfswm.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.clfswm; +in + +{ + options = { + services.xserver.windowManager.clfswm = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable the clfswm tiling window manager."; + }; + }; + }; + + config = mkIf cfg.enable { + services.xserver.windowManager.session = singleton { + name = "clfswm"; + start = '' + ${pkgs.clfswm}/bin/clfswm & + waitPID=$! + ''; + }; + environment.systemPackages = [ pkgs.clfswm ]; + }; +} diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 4751de07a15d..31f42f5ffb9f 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -10,6 +10,7 @@ in imports = [ ./afterstep.nix ./bspwm.nix + ./clfswm.nix ./compiz.nix ./fluxbox.nix ./herbstluftwm.nix diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix index c922ca7848d1..288800d514d3 100644 --- a/nixos/modules/services/x11/window-managers/xmonad.nix +++ b/nixos/modules/services/x11/window-managers/xmonad.nix @@ -20,9 +20,9 @@ in }; haskellPackages = mkOption { - default = pkgs.haskellngPackages; - defaultText = "pkgs.haskellngPackages"; - example = literalExample "pkgs.haskell-ng.packages.ghc784"; + default = pkgs.haskellPackages; + defaultText = "pkgs.haskellPackages"; + example = literalExample "pkgs.haskell.packages.ghc784"; description = '' haskellPackages used to build Xmonad and other packages. This can be used to change the GHC version used to build |