diff options
Diffstat (limited to 'nixos/modules')
33 files changed, 1171 insertions, 183 deletions
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index 37a9f4d0d314..17aa29425956 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -12,8 +12,7 @@ with lib; default = false; type = types.bool; description = '' - Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu - and iwlwifi. + Turn on this option if you want to enable all the firmware shipped in linux-firmware. ''; }; @@ -26,7 +25,6 @@ with lib; hardware.firmware = [ "${pkgs.firmwareLinuxNonfree}/lib/firmware" "${pkgs.iwlegacy}/lib/firmware" - "${pkgs.iwlwifi}/lib/firmware" ]; }; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 84de7800c2a9..39db7d9b8f72 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -58,8 +58,8 @@ let efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools ]; } '' - #Let's hope 10M is enough - dd bs=2048 count=5120 if=/dev/zero of="$out" + #Let's hope 15M is enough + dd bs=2048 count=7680 if=/dev/zero of="$out" ${pkgs.dosfstools}/sbin/mkfs.vfat "$out" mcopy -svi "$out" ${efiDir}/* :: mmd -i "$out" boot diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 2c796250a982..63d2077fbe19 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -53,46 +53,9 @@ let inherit (config.system) nixosVersion nixosCodeName; }; - /* - nixos-gui = pkgs.xulrunnerWrapper { - launcher = "nixos-gui"; - application = pkgs.stdenv.mkDerivation { - name = "nixos-gui"; - buildCommand = '' - cp -r "$gui" "$out" - - # Do not force the copy if the file exists in the sources (this - # happens for developpers) - test -e "$out/chrome/content/jquery-1.5.2.js" || - cp -f "$jquery" "$out/chrome/content/jquery-1.5.2.js" - ''; - gui = lib.cleanSource "${modulesPath}/../gui"; - jquery = pkgs.fetchurl { - url = http://code.jquery.com/jquery-1.5.2.min.js; - sha256 = "8f0a19ee8c606b35a10904951e0a27da1896eafe33c6e88cb7bcbe455f05a24a"; - }; - }; - }; - */ - in { - /* - options = { - - installer.enableGraphicalTools = mkOption { - default = false; - type = types.bool; - example = true; - description = '' - Enable the installation of graphical tools. - ''; - }; - - }; - */ - config = { environment.systemPackages = [ nixos-build-vms diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 7415af8ab6af..f3cda7b95416 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -177,6 +177,8 @@ cadvisor = 167; nylon = 168; apache-kafka = 169; + panamax = 170; + # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! nixbld = 30000; # start of range of uids @@ -315,6 +317,7 @@ kubernetes = 162; gitlab = 165; nylon = 166; + panamax = 170; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 6c6aab14ee72..0fad59d55717 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -55,6 +55,7 @@ ./programs/atop.nix ./programs/bash/bash.nix ./programs/blcr.nix + ./programs/cdemu.nix ./programs/command-not-found/command-not-found.nix ./programs/dconf.nix ./programs/environment.nix @@ -104,6 +105,7 @@ ./services/backup/tarsnap.nix ./services/cluster/fleet.nix ./services/cluster/kubernetes.nix + ./services/cluster/panamax.nix ./services/computing/torque/server.nix ./services/computing/torque/mom.nix ./services/continuous-integration/jenkins/default.nix @@ -172,6 +174,7 @@ ./services/mail/spamassassin.nix ./services/misc/apache-kafka.nix #./services/misc/autofs.nix + ./services/misc/canto-daemon.nix ./services/misc/cpuminer-cryptonight.nix ./services/misc/cgminer.nix ./services/misc/dictd.nix @@ -189,6 +192,7 @@ ./services/misc/nix-gc.nix ./services/misc/nixos-manual.nix ./services/misc/nix-ssh-serve.nix + ./services/misc/parsoid.nix ./services/misc/phd.nix ./services/misc/redmine.nix ./services/misc/rippled.nix @@ -293,6 +297,7 @@ ./services/networking/syncthing.nix ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix + ./services/networking/tinc.nix ./services/networking/tftpd.nix ./services/networking/tlsdated.nix ./services/networking/tox-bootstrapd.nix @@ -341,6 +346,7 @@ ./services/web-servers/nginx/default.nix ./services/web-servers/phpfpm.nix ./services/web-servers/tomcat.nix + ./services/web-servers/uwsgi.nix ./services/web-servers/varnish/default.nix ./services/web-servers/winstone.nix ./services/web-servers/zope2.nix diff --git a/nixos/modules/programs/cdemu.nix b/nixos/modules/programs/cdemu.nix new file mode 100644 index 000000000000..d1b1915eea91 --- /dev/null +++ b/nixos/modules/programs/cdemu.nix @@ -0,0 +1,49 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.programs.cdemu; +in { + + options = { + programs.cdemu = { + enable = mkOption { + default = false; + description = "Whether to enable cdemu for users of appropriate group (default cdrom)"; + }; + group = mkOption { + default = "cdrom"; + description = "Required group for users of cdemu"; + }; + gui = mkOption { + default = true; + description = "Whether to install cdemu GUI (gCDEmu)"; + }; + image-analyzer = mkOption { + default = true; + description = "Whether to install image analyzer"; + }; + }; + }; + + config = mkIf cfg.enable { + + boot = { + extraModulePackages = [ pkgs.linuxPackages.vhba ]; + kernelModules = [ "vhba" ]; + }; + + services = { + udev.extraRules = '' + KERNEL=="vhba_ctl", MODE="0660", OWNER="root", GROUP="${cfg.group}" + ''; + dbus.packages = [ pkgs.cdemu-daemon ]; + }; + + environment.systemPackages = + [ pkgs.cdemu-daemon pkgs.cdemu-client ] + ++ optional cfg.gui pkgs.gcdemu + ++ optional cfg.image-analyzer pkgs.image-analyzer; + }; + +} diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix index f430a5a6339f..e070ffc95e43 100644 --- a/nixos/modules/security/ca.nix +++ b/nixos/modules/security/ca.nix @@ -4,10 +4,53 @@ with lib; { + options = { + + security.pki.certificateFiles = mkOption { + type = types.listOf types.path; + default = []; + example = literalExample "[ \"\${pkgs.cacert}/etc/ca-bundle.crt\" ]"; + description = '' + A list of files containing trusted root certificates in PEM + format. These are concatenated to form + <filename>/etc/ssl/certs/ca-bundle.crt</filename>, which is + used by many programs that use OpenSSL, such as + <command>curl</command> and <command>git</command>. + ''; + }; + + security.pki.certificates = mkOption { + type = types.listOf types.string; + default = []; + example = singleton '' + NixOS.org + ========= + -----BEGIN CERTIFICATE----- + MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ + TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 + ... + -----END CERTIFICATE----- + ''; + description = '' + A list of trusted root certificates in PEM format. + ''; + }; + + }; + config = { + security.pki.certificateFiles = [ "${pkgs.cacert}/etc/ca-bundle.crt" ]; + environment.etc = - [ { source = "${pkgs.cacert}/etc/ca-bundle.crt"; + [ { source = pkgs.runCommand "ca-bundle.crt" + { files = + config.security.pki.certificateFiles ++ + [ (builtins.toFile "extra.crt" (concatStringsSep "\n" config.security.pki.certificates)) ]; + } + '' + cat $files > $out + ''; target = "ssl/certs/ca-bundle.crt"; } ]; diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index eab7993387de..b79052337597 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -100,6 +100,7 @@ in { script = "exec mpd --no-daemon ${mpdConf}"; serviceConfig = { User = "mpd"; + PermissionsStartOnly = true; }; }; diff --git a/nixos/modules/services/cluster/panamax.nix b/nixos/modules/services/cluster/panamax.nix new file mode 100644 index 000000000000..a7233f23c913 --- /dev/null +++ b/nixos/modules/services/cluster/panamax.nix @@ -0,0 +1,153 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.panamax; + + panamax_api = pkgs.panamax_api.override { dataDir = cfg.dataDir + "/api"; }; + panamax_ui = pkgs.panamax_ui.override { dataDir = cfg.dataDir + "/ui"; }; + +in { + + ##### Interface + options.services.panamax = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable Panamax service. + ''; + }; + + UIPort = mkOption { + type = types.int; + default = 8888; + description = '' + Panamax UI listening port. + ''; + }; + + APIPort = mkOption { + type = types.int; + default = 3000; + description = '' + Panamax UI listening port. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/panamax"; + description = '' + Data dir for Panamax. + ''; + }; + + fleetctlEndpoint = mkOption { + type = types.str; + default = "http://127.0.0.1:4001"; + description = '' + Panamax fleetctl endpoint. + ''; + }; + + journalEndpoint = mkOption { + type = types.str; + default = "http://127.0.0.1:19531"; + description = '' + Panamax journal endpoint. + ''; + }; + + secretKey = mkOption { + type = types.str; + default = "SomethingVeryLong."; + description = '' + Panamax secret key (do change this). + ''; + }; + + }; + + ##### Implementation + config = mkIf cfg.enable { + systemd.services.panamax-api = { + description = "Panamax API"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "fleet.service" "etcd.service" "docker.service" ]; + + path = [ panamax_api ]; + environment = { + RAILS_ENV = "production"; + JOURNAL_ENDPOINT = cfg.journalEndpoint; + FLEETCTL_ENDPOINT = cfg.fleetctlEndpoint; + PANAMAX_DATABASE_PATH = "${cfg.dataDir}/api/db/mnt/db.sqlite3"; + }; + + preStart = '' + rm -rf ${cfg.dataDir}/state/tmp + mkdir -p ${cfg.dataDir}/api/{db/mnt,state/log,state/tmp} + ln -sf ${panamax_api}/share/panamax-api/_db/{schema.rb,seeds.rb,migrate} ${cfg.dataDir}/api/db/ + + if [ ! -f ${cfg.dataDir}/.created ]; then + bundle exec rake db:setup + bundle exec rake db:seed + bundle exec rake panamax:templates:load || true + touch ${cfg.dataDir}/.created + else + bundle exec rake db:migrate + fi + ''; + + serviceConfig = { + ExecStart = "${panamax_api}/bin/bundle exec rails server --binding 127.0.0.1 --port ${toString cfg.APIPort}"; + User = "panamax"; + Group = "panamax"; + }; + }; + + systemd.services.panamax-ui = { + description = "Panamax UI"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "panamax_api.service" ]; + + path = [ panamax_ui ]; + environment = { + RAILS_ENV = "production"; + JOURNAL_ENDPOINT = cfg.journalEndpoint; + PMX_API_PORT_3000_TCP_ADDR = "localhost"; + PMX_API_PORT_3000_TCP_PORT = toString cfg.APIPort; + SECRET_KEY_BASE = cfg.secretKey; + }; + + preStart = '' + rm -rf ${cfg.dataDir}/state/tmp + mkdir -p ${cfg.dataDir}/ui/state/{log,tmp} + ''; + + serviceConfig = { + ExecStart = "${panamax_ui}/bin/bundle exec rails server --binding 127.0.0.1 --port ${toString cfg.UIPort}"; + User = "panamax"; + Group = "panamax"; + }; + }; + + users.extraUsers.panamax = + { uid = config.ids.uids.panamax; + description = "Panamax user"; + createHome = true; + home = cfg.dataDir; + extraGroups = [ "docker" ]; + }; + + services.journald.enableHttpGateway = mkDefault true; + services.fleet.enable = mkDefault true; + virtualisation.docker.enable = mkDefault true; + + environment.systemPackages = [ panamax_api panamax_ui ]; + users.extraGroups.panamax.gid = config.ids.gids.panamax; + }; +} diff --git a/nixos/modules/services/misc/canto-daemon.nix b/nixos/modules/services/misc/canto-daemon.nix new file mode 100644 index 000000000000..db51a263aab5 --- /dev/null +++ b/nixos/modules/services/misc/canto-daemon.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + +cfg = config.services.canto-daemon; + +in { + +##### interface + + options = { + + services.canto-daemon = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the canto RSS daemon."; + }; + }; + + }; + +##### implementation + + config = mkIf cfg.enable { + + systemd.user.services.canto-daemon = { + description = "Canto RSS Daemon"; + after = [ "network.target" ]; + wantedBy = [ "default.target" ]; + serviceConfig.ExecStart = "${pkgs.canto-daemon}/bin/canto-daemon"; + }; + }; + +} diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index ddb0bd671dd1..4505c5ceb84f 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -61,7 +61,7 @@ let --set GITLAB_SHELL_SECRET_PATH "${cfg.stateDir}/config/gitlab_shell_secret"\ --set GITLAB_HOST "${cfg.host}"\ --set GITLAB_PORT "${toString cfg.port}"\ - --set GITLAB_BACKUP_PATH"${cfg.backupPath}"\ + --set GITLAB_BACKUP_PATH "${cfg.backupPath}"\ --set RAILS_ENV "production" ''; }; diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix new file mode 100644 index 000000000000..0844190a5490 --- /dev/null +++ b/nixos/modules/services/misc/parsoid.nix @@ -0,0 +1,100 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.parsoid; + + conf = '' + exports.setup = function( parsoidConfig ) { + ${toString (mapAttrsToList (name: str: "parsoidConfig.setInterwiki('${name}', '${str}');") cfg.interwikis)} + + parsoidConfig.serverInterface = "${cfg.interface}"; + parsoidConfig.serverPort = ${toString cfg.port}; + + parsoidConfig.useSelser = true; + + ${cfg.extraConfig} + }; + ''; + + confFile = builtins.toFile "localsettings.js" conf; + +in +{ + ##### interface + + options = { + + services.parsoid = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable Parsoid -- bidirectional + wikitext parser. + ''; + }; + + interwikis = mkOption { + type = types.attrsOf types.str; + example = { localhost = "http://localhost/api.php"; }; + description = '' + Used MediaWiki API endpoints. + ''; + }; + + workers = mkOption { + type = types.int; + default = 2; + description = '' + Number of Parsoid workers. + ''; + }; + + interface = mkOption { + type = types.str; + default = "127.0.0.1"; + description = '' + Interface to listen on. + ''; + }; + + port = mkOption { + type = types.int; + default = 8000; + description = '' + Port to listen on. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration to add to parsoid configuration. + ''; + }; + + }; + + }; + + ##### implementation + + config = mkIf cfg.enable { + + systemd.services.parsoid = { + description = "Bidirectional wikitext parser"; + 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}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 6fcf89999523..8c79bf663d15 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -6,25 +6,11 @@ let cfg = config.services.samba; - logDir = "/var/log/samba"; - privateDir = "/var/samba/private"; - samba = cfg.package; setupScript = '' - if ! test -d /var/samba ; then - mkdir -p /var/samba/locks /var/samba/cores/nmbd /var/samba/cores/smbd /var/samba/cores/winbindd - fi - - passwdFile="$(${pkgs.gnused}/bin/sed -n 's/^.*smb[ ]\+passwd[ ]\+file[ ]\+=[ ]\+\(.*\)/\1/p' ${configFile})" - if [ -n "$passwdFile" ]; then - echo 'INFO: [samba] creating directory containing passwd file' - mkdir -p "$(dirname "$passwdFile")" - fi - - mkdir -p ${logDir} - mkdir -p ${privateDir} + mkdir -p /var/lock/samba /var/log/samba /var/cache/samba /var/lib/samba/private ''; shareConfig = name: @@ -39,9 +25,10 @@ let (if cfg.configText != null then cfg.configText else '' [ global ] - log file = ${logDir}/log.%m - private dir = ${privateDir} - ${optionalString cfg.syncPasswordsByPam "pam password change = true"} + security = ${cfg.securityType} + passwd program = /var/setuid-wrappers/passwd %u + pam password change = ${toString cfg.syncPasswordsByPam} + invalid users = ${toString cfg.invalidUsers} ${cfg.extraConfig} @@ -83,14 +70,16 @@ in services.samba = { enable = mkOption { + type = types.bool; default = false; - description = " + description = '' Whether to enable Samba, which provides file and print services to Windows clients through the SMB/CIFS protocol. - "; + ''; }; package = mkOption { + type = types.package; default = pkgs.samba; example = pkgs.samba4; description = '' @@ -99,72 +88,47 @@ in }; syncPasswordsByPam = mkOption { + type = types.bool; default = false; - description = " - enabling this will add a line directly after pam_unix.so. + description = '' + Enabling this will add a line directly after pam_unix.so. Whenever a password is changed the samba password will be updated as well. However you still yave to add the samba password once using smbpasswd -a user If you don't want to maintain an extra pwd database you still can send plain text passwords which is not secure. - "; + ''; }; - extraConfig = mkOption { - # !!! Bad default. - default = '' - # [global] continuing global section here, section is started by nix to set pids etc - - smb passwd file = /etc/samba/passwd - - # is this useful ? - domain master = auto - - encrypt passwords = Yes - client plaintext auth = No - - # yes: if you use this you probably also want to enable syncPasswordsByPam - # no: You can still use the pam password database. However - # passwords will be sent plain text on network (discouraged) - - workgroup = Users - server string = %h - comment = Samba - log file = /var/log/samba/log.%m - log level = 10 - max log size = 50000 - security = ${cfg.securityType} - - client lanman auth = Yes - dns proxy = no - invalid users = root - passdb backend = tdbsam - passwd program = /usr/bin/passwd %u + invalidUsers = mkOption { + type = types.listOf types.str; + default = [ "root" ]; + description = '' + List of users who are denied to login via Samba. ''; - - description = " - additional global section and extra section lines go in here. - "; }; - configFile = mkOption { - description = " - internal use to pass filepath to samba pam module - "; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional global section and extra section lines go in here. + ''; }; configText = mkOption { type = types.nullOr types.lines; default = null; - description = " + description = '' Verbatim contents of smb.conf. If null (default), use the autogenerated file from NixOS instead. - "; + ''; }; securityType = mkOption { - description = "Samba security type"; + type = types.str; default = "user"; example = "share"; + description = "Samba security type"; }; nsswins = mkOption { @@ -179,12 +143,11 @@ in shares = mkOption { default = {}; - description = - '' + description = '' A set describing shared resources. See <command>man smb.conf</command> for options. - ''; - type = types.attrsOf (types.attrsOf types.str); + ''; + type = types.attrsOf (types.attrsOf types.unspecified); example = { srv = { path = "/srv"; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index b2d5854fbc0c..3ae010e81070 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -122,6 +122,34 @@ in ''; }; + alerts = { + enable = mkEnableOption "Whether to enable consul-alerts"; + + listenAddr = mkOption { + description = "Api listening address."; + default = "localhost:9000"; + type = types.str; + }; + + consulAddr = mkOption { + description = "Consul api listening adddress"; + default = "localhost:8500"; + type = types.str; + }; + + watchChecks = mkOption { + description = "Whether to enable check watcher."; + default = true; + type = types.bool; + }; + + watchEvents = mkOption { + description = "Whether to enable event watcher."; + default = true; + type = types.bool; + }; + }; + }; }; @@ -204,5 +232,23 @@ in ''; }; + systemd.services.consul-alerts = mkIf (cfg.alerts.enable) { + wantedBy = [ "multi-user.target" ]; + after = [ "consul.service" ]; + + path = [ pkgs.consul ]; + + serviceConfig = { + ExecStart = '' + ${pkgs.consul-alerts}/bin/consul-alerts start \ + --alert-addr=${cfg.alerts.listenAddr} \ + --consul-addr=${cfg.alerts.consulAddr} \ + ${optionalString cfg.alerts.watchChecks "--watch-checks"} \ + ${optionalString cfg.alerts.watchEvents "--watch-events"} + ''; + User = if cfg.dropPrivileges then "consul" else null; + }; + }; + }; } diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 1ad8cbae15cf..0430d31b99a7 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -68,8 +68,10 @@ let # will actually do something: if ntpd cannot resolve the # server hostnames in its config file, then it will never do # anything ever again ("couldn't resolve ..., giving up on - # it"), so we silently lose time synchronisation. + # it"), so we silently lose time synchronisation. This also + # applies to openntpd. ${config.systemd.package}/bin/systemctl try-restart ntpd.service + ${config.systemd.package}/bin/systemctl try-restart openntpd.service ${config.systemd.package}/bin/systemctl start ip-up.target fi diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 26549bfe6f14..d1b5fbedfa6f 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -103,7 +103,7 @@ in ${pkgs.tzdata}/share/zoneinfo/** r, ${dnscrypt-proxy}/share/dnscrypt-proxy/** r, - ${pkgs.gcc.gcc}/lib/libssp.so.* mr, + ${pkgs.gcc.cc}/lib/libssp.so.* mr, ${pkgs.libsodium}/lib/libsodium.so.* mr, } '') diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix index 95b0ae59ff3c..7ee78f01d497 100644 --- a/nixos/modules/services/networking/i2pd.nix +++ b/nixos/modules/services/networking/i2pd.nix @@ -8,7 +8,7 @@ let homeDir = "/var/lib/i2pd"; - extip = "EXTIP=$(${pkgs.curl}/bin/curl -sf "http://jsonip.com" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')"; + extip = "EXTIP=\$(${pkgs.curl}/bin/curl -sf \"http://jsonip.com\" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')"; i2pSh = pkgs.writeScriptBin "i2pd" '' #!/bin/sh diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix index d1c32db49c4c..e53fc574fbea 100644 --- a/nixos/modules/services/networking/openntpd.nix +++ b/nixos/modules/services/networking/openntpd.nix @@ -5,10 +5,7 @@ with lib; let cfg = config.services.openntpd; - package = pkgs.openntpd.override { - privsepUser = "ntp"; - privsepPath = "/var/empty"; - }; + package = pkgs.openntpd_nixos; cfgFile = pkgs.writeText "openntpd.conf" '' ${concatStringsSep "\n" (map (s: "server ${s}") cfg.servers)} @@ -54,6 +51,9 @@ in config = mkIf cfg.enable { services.ntp.enable = mkForce false; + # Add ntpctl to the environment for status checking + environment.systemPackages = [ package ]; + users.extraUsers = singleton { name = "ntp"; uid = config.ids.uids.ntp; @@ -64,6 +64,8 @@ in systemd.services.openntpd = { description = "OpenNTP Server"; wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "dnsmasq.service" "bind.service" "network-online.target" ]; serviceConfig.ExecStart = "${package}/sbin/ntpd -d -f ${cfgFile} ${cfg.extraOptions}"; }; }; diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix index 83db0841b346..77bf64b80d0f 100644 --- a/nixos/modules/services/networking/sabnzbd.nix +++ b/nixos/modules/services/networking/sabnzbd.nix @@ -39,13 +39,14 @@ in } ]; - jobs.sabnzbd = + systemd.services.sabnzbd = { description = "sabnzbd server"; - - startOn = "started network-interfaces"; - stopOn = "stopping network-interfaces"; - - exec = "${sabnzbd}/bin/sabnzbd -d -f ${cfg.configFile}"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Type = "forking"; + ExecStart = "${sabnzbd}/bin/sabnzbd -d -f ${cfg.configFile}"; + }; }; }; diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix new file mode 100644 index 000000000000..f9ca796ea652 --- /dev/null +++ b/nixos/modules/services/networking/tinc.nix @@ -0,0 +1,162 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.tinc; + +in + +{ + + ###### interface + + options = { + + services.tinc = { + + networks = mkOption { + default = { }; + type = types.loaOf types.optionSet; + description = '' + Defines the tinc networks which will be started. + Each network invokes a different daemon. + ''; + options = { + + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + Extra lines to add to the tinc service configuration file. + ''; + }; + + name = mkOption { + default = null; + type = types.nullOr types.str; + description = '' + The name of the node which is used as an identifier when communicating + with the remote nodes in the mesh. If null then the hostname of the system + is used. + ''; + }; + + debugLevel = mkOption { + default = 0; + type = types.addCheck types.int (l: l >= 0 && l <= 5); + description = '' + The amount of debugging information to add to the log. 0 means little + logging while 5 is the most logging. <command>man tincd</command> for + more details. + ''; + }; + + hosts = mkOption { + default = { }; + type = types.loaOf types.lines; + description = '' + The name of the host in the network as well as the configuration for that host. + This name should only contain alphanumerics and underscores. + ''; + }; + + interfaceType = mkOption { + default = "tun"; + type = types.addCheck types.str (n: n == "tun" || n == "tap"); + description = '' + The type of virtual interface used for the network connection + ''; + }; + + package = mkOption { + default = pkgs.tinc_pre; + description = '' + The package to use for the tinc daemon's binary. + ''; + }; + + }; + }; + }; + + }; + + + ###### implementation + + config = mkIf (cfg.networks != { }) { + + environment.etc = fold (a: b: a // b) { } + (flip mapAttrsToList cfg.networks (network: data: + flip mapAttrs' data.hosts (host: text: nameValuePair + ("tinc/${network}/hosts/${host}") + ({ mode = "0444"; inherit text; }) + ) // { + "tinc/${network}/tinc.conf" = { + mode = "0444"; + text = '' + Name = ${if data.name == null then "$HOST" else data.name} + DeviceType = ${data.interfaceType} + Device = /dev/net/tun + Interface = tinc.${network} + ${data.extraConfig} + ''; + }; + } + )); + + networking.interfaces = flip mapAttrs' cfg.networks (network: data: nameValuePair + ("tinc.${network}") + ({ + virtual = true; + virtualType = "${data.interfaceType}"; + }) + ); + + systemd.services = flip mapAttrs' cfg.networks (network: data: nameValuePair + ("tinc.${network}") + ({ + description = "Tinc Daemon - ${network}"; + wantedBy = [ "network.target" ]; + after = [ "network-interfaces.target" ]; + path = [ data.package ]; + restartTriggers = [ config.environment.etc."tinc/${network}/tinc.conf".source ] + ++ mapAttrsToList (host: _ : config.environment.etc."tinc/${network}/hosts/${host}".source) data.hosts; + serviceConfig = { + Type = "simple"; + PIDFile = "/run/tinc.${network}.pid"; + }; + preStart = '' + mkdir -p /etc/tinc/${network}/hosts + + # Determine how we should generate our keys + if type tinc >/dev/null 2>&1; then + # Tinc 1.1+ uses the tinc helper application for key generation + + # Prefer ED25519 keys (only in 1.1+) + [ -f "/etc/tinc/${network}/ed25519_key.priv" ] || tinc -n ${network} generate-ed25519-keys + + # Otherwise use RSA keys + [ -f "/etc/tinc/${network}/rsa_key.priv" ] || tinc -n ${network} generate-rsa-keys 4096 + else + # Tinc 1.0 uses the tincd application + [ -f "/etc/tinc/${network}/rsa_key.priv" ] || tincd -n ${network} -K 4096 + fi + ''; + script = '' + tincd -D -U tinc.${network} -n ${network} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel} + ''; + }) + ); + + users.extraUsers = flip mapAttrs' cfg.networks (network: _: + nameValuePair ("tinc.${network}") ({ + description = "Tinc daemon user for ${network}"; + }) + ); + + }; + +} diff --git a/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix b/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix new file mode 100644 index 000000000000..6f1f67970f6c --- /dev/null +++ b/nixos/modules/services/web-servers/apache-httpd/limesurvey.nix @@ -0,0 +1,196 @@ +{ config, lib, pkgs, serverInfo, php, ... }: + +with lib; + +let + + httpd = serverInfo.serverConfig.package; + + version24 = !versionOlder httpd.version "2.4"; + + allGranted = if version24 then '' + Require all granted + '' else '' + Order allow,deny + Allow from all + ''; + + limesurveyConfig = pkgs.writeText "config.php" '' + <?php + $config = array(); + $config['name'] = "${config.siteName}"; + $config['runtimePath'] = "${config.dataDir}/tmp/runtime"; + $config['components'] = array(); + $config['components']['db'] = array(); + $config['components']['db']['connectionString'] = '${config.dbType}:host=${config.dbHost};port=${toString config.dbPort};user=${config.dbUser};password=${config.dbPassword};dbname=${config.dbName};'; + $config['components']['db']['username'] = '${config.dbUser}'; + $config['components']['db']['password'] = '${config.dbPassword}'; + $config['components']['db']['charset'] = 'utf-8'; + $config['components']['db']['tablePrefix'] = "prefix_"; + $config['components']['assetManager'] = array(); + $config['components']['assetManager']['basePath'] = '${config.dataDir}/tmp/assets'; + $config['config'] = array(); + $config['config']['debug'] = 1; + $config['config']['tempdir'] = "${config.dataDir}/tmp"; + $config['config']['tempdir'] = "${config.dataDir}/tmp"; + $config['config']['uploaddir'] = "${config.dataDir}/upload"; + $config['config']['force_ssl'] = '${if config.forceSSL then "on" else ""}'; + $config['config']['defaultlang'] = '${config.defaultLang}'; + return $config; + ?> + ''; + + limesurveyRoot = "${pkgs.limesurvey}/share/limesurvey/"; + +in rec { + + extraConfig = '' + Alias ${config.urlPrefix}/tmp ${config.dataDir}/tmp + + <Directory ${config.dataDir}/tmp> + ${allGranted} + Options -Indexes +FollowSymlinks + </Directory> + + Alias ${config.urlPrefix}/upload ${config.dataDir}/upload + + <Directory ${config.dataDir}/upload> + ${allGranted} + Options -Indexes + </Directory> + + ${if config.urlPrefix != "" then '' + Alias ${config.urlPrefix} ${limesurveyRoot} + '' else '' + RewriteEngine On + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d + ''} + + <Directory ${limesurveyRoot}> + DirectoryIndex index.php + </Directory> + ''; + + globalEnvVars = [ + { name = "LIMESURVEY_CONFIG"; value = limesurveyConfig; } + ]; + + documentRoot = if config.urlPrefix == "" then limesurveyRoot else null; + + enablePHP = true; + + options = { + + id = mkOption { + default = "main"; + description = '' + A unique identifier necessary to keep multiple owncloud server + instances on the same machine apart. This is used to + disambiguate the administrative scripts, which get names like + mediawiki-$id-change-password. + ''; + }; + + urlPrefix = mkOption { + default = ""; + description = "Url prefix for site."; + type = types.str; + }; + + dbType = mkOption { + default = "pgsql"; + description = "Type of database for limesurvey, for now, only pgsql."; + type = types.enum ["pgsql"]; + }; + + dbName = mkOption { + default = "limesurvey"; + description = "Name of the database that holds the limesurvey data."; + type = types.str; + }; + + dbHost = mkOption { + default = "localhost"; + description = "Limesurvey database host."; + type = types.str; + }; + + dbPort = mkOption { + default = 5432; + description = "Limesurvey database port."; + type = types.int; + }; + + dbUser = mkOption { + default = "limesurvey"; + description = "Limesurvey database user."; + type = types.str; + }; + + dbPassword = mkOption { + example = "foobar"; + description = "Limesurvey database password."; + type = types.str; + }; + + adminUser = mkOption { + description = "Limesurvey admin username."; + default = "admin"; + type = types.str; + }; + + adminPassword = mkOption { + description = "Default limesurvey admin password."; + default = "admin"; + type = types.str; + }; + + adminEmail = mkOption { + description = "Limesurvey admin email."; + default = "admin@admin.com"; + type = types.str; + }; + + forceSSL = mkOption { + default = false; + description = "Force use of HTTPS connection."; + type = types.bool; + }; + + siteName = mkOption { + default = "LimeSurvey"; + description = "LimeSurvey name of the site."; + type = types.str; + }; + + defaultLang = mkOption { + default = "en"; + description = "LimeSurvey default language."; + type = types.str; + }; + + dataDir = mkOption { + default = "/var/lib/limesurvey"; + description = "LimeSurvey data directory."; + type = types.path; + }; + }; + + startupScript = pkgs.writeScript "limesurvey_startup.sh" '' + if [ ! -f ${config.dataDir}/.created ]; then + mkdir -p ${config.dataDir}/{tmp/runtime,tmp/assets,tmp/upload,upload} + chmod -R ug+rw ${config.dataDir} + chmod -R o-rwx ${config.dataDir} + chown -R wwwrun:wwwrun ${config.dataDir} + + ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole "${config.dbUser}" || true + ${pkgs.postgresql}/bin/createdb "${config.dbName}" -O "${config.dbUser}" || true + ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/psql -U postgres -d postgres -c "alter user ${config.dbUser} with password '${config.dbPassword}';" || true + + ${pkgs.limesurvey}/bin/limesurvey-console install '${config.adminUser}' '${config.adminPassword}' '${config.adminUser}' '${config.adminEmail}' + + touch ${config.dataDir}/.created + fi + ''; +} diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix new file mode 100644 index 000000000000..6e454a2dacd7 --- /dev/null +++ b/nixos/modules/services/web-servers/uwsgi.nix @@ -0,0 +1,112 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.uwsgi; + + python2Pkgs = pkgs.python2Packages.override { + python = pkgs.uwsgi.python2; + self = python2Pkgs; + }; + + python3Pkgs = pkgs.python3Packages.override { + python = pkgs.uwsgi.python3; + self = python3Pkgs; + }; + + buildCfg = c: if builtins.typeOf c != "set" then builtins.readFile c else builtins.toJSON { + uwsgi = + if c.type == "normal" + then { + pythonpath = + (if c ? python2Packages + then builtins.map (x: "${x}/${pkgs.uwsgi.python2.sitePackages}") (c.python2Packages python2Pkgs) + else []) + ++ (if c ? python3Packages + then builtins.map (x: "${x}/${pkgs.uwsgi.python3.sitePackages}") (c.python3Packages python3Pkgs) + else []); + plugins = cfg.plugins; + } // removeAttrs c [ "type" "python2Packages" "python3Packages" ] + else if c.type == "emperor" + then { + emperor = if builtins.typeOf c.vassals != "set" then c.vassals + else pkgs.buildEnv { + name = "vassals"; + paths = mapAttrsToList (n: c: pkgs.writeTextDir "${n}.json" (buildCfg c)) c.vassals; + }; + } // removeAttrs c [ "type" "vassals" ] + else abort "type should be either 'normal' or 'emperor'"; + }; + + uwsgi = pkgs.uwsgi.override { + plugins = cfg.plugins; + }; + +in { + + options = { + services.uwsgi = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable uWSGI"; + }; + + instance = mkOption { + type = types.attrs; + default = { + type = "normal"; + }; + example = literalExample '' + { + type = "emperor"; + vassals = { + moin = { + type = "normal"; + python2Packages = self: with self; [ moinmoin ]; + socket = "/run/uwsgi.sock"; + }; + }; + } + ''; + description = '' + uWSGI configuration. This awaits either a path to file or a set which will be made into one. + If given a set, it awaits an attribute <literal>type</literal> which can be either <literal>normal</literal> + or <literal>emperor</literal>. + + For <literal>normal</literal> mode you can specify <literal>python2Packages</literal> and + <literal>python3Packages</literal> as functions from libraries set into lists of libraries. + For <literal>emperor</literal> mode, you should use <literal>vassals</literal> attribute + which should be either a set of names and configurations or a path to a directory. + ''; + }; + + plugins = mkOption { + type = types.listOf types.str; + default = []; + description = "Plugins used with uWSGI"; + }; + + }; + + }; + + config = mkIf cfg.enable { + + systemd.services.uwsgi = { + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "notify"; + ExecStart = "${uwsgi}/bin/uwsgi --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; + NotifyAccess = "main"; + KillSignal = "SIGQUIT"; + }; + + }; + }; +} diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index c4329cd77550..6398a15bfcc8 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -114,6 +114,9 @@ in { # Let nautilus find extensions export NAUTILUS_EXTENSION_DIR=${config.system.path}/lib/nautilus/extensions-3.0/ + # Find the mouse + export XCURSOR_PATH=~/.icons:${config.system.path}/share/icons + # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/ ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index 080588df2472..b3da0cda04a3 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -55,6 +55,8 @@ in GDM_X_SERVER = "${cfg.xserverBin} ${cfg.xserverArgs}"; GDM_SESSIONS_DIR = "${cfg.session.desktops}"; XDG_CONFIG_DIRS = "${gnome3.gnome_settings_daemon}/etc/xdg"; + # Find the mouse + XCURSOR_PATH = "~/.icons:${config.system.path}/share/icons"; }; execCmd = "exec ${gdm}/sbin/gdm"; }; diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 4f2a2309b60c..7ec32fe83b54 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -7,19 +7,19 @@ let in { - imports = - [ ./compiz.nix - ./openbox.nix - ./metacity.nix - ./none.nix - ./twm.nix - ./wmii.nix - ./xmonad.nix - ./i3.nix - ./herbstluftwm.nix - ./bspwm.nix - ./stumpwm.nix - ]; + imports = [ + ./bspwm.nix + ./compiz.nix + ./herbstluftwm.nix + ./i3.nix + ./metacity.nix + ./openbox.nix + ./stumpwm.nix + ./twm.nix + ./windowmaker.nix + ./wmii.nix + ./xmonad.nix + ./none.nix ]; options = { @@ -61,4 +61,4 @@ in config = { services.xserver.displayManager.session = cfg.session; }; -} \ No newline at end of file +} diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix index 74acfc219759..c922ca7848d1 100644 --- a/nixos/modules/services/x11/window-managers/xmonad.nix +++ b/nixos/modules/services/x11/window-managers/xmonad.nix @@ -3,11 +3,12 @@ let inherit (lib) mkOption mkIf optionals literalExample; cfg = config.services.xserver.windowManager.xmonad; - xmonadEnv = cfg.haskellPackages.ghcWithPackages(self: [ - self.xmonad - ] ++ optionals cfg.enableContribAndExtras [ self.xmonadContrib self.xmonadExtras] - ++ optionals (cfg.extraPackages != null) (cfg.extraPackages self)); - xmessage = pkgs.xlibs.xmessage; + xmonad = pkgs.xmonad-with-packages.override { + ghcWithPackages = cfg.haskellPackages.ghcWithPackages; + packages = self: cfg.extraPackages self ++ + optionals cfg.enableContribAndExtras + [ self.xmonad-contrib self.xmonad-extras ]; + }; in { options = { @@ -19,9 +20,9 @@ in }; haskellPackages = mkOption { - default = pkgs.haskellPackages; - defaultText = "pkgs.haskellPackages"; - example = literalExample "pkgs.haskellPackages_ghc701"; + default = pkgs.haskellngPackages; + defaultText = "pkgs.haskellngPackages"; + example = literalExample "pkgs.haskell-ng.packages.ghc784"; description = '' haskellPackages used to build Xmonad and other packages. This can be used to change the GHC version used to build @@ -31,17 +32,17 @@ in }; extraPackages = mkOption { - default = null; + default = self: []; example = literalExample '' haskellPackages: [ - haskellPackages.xmonadContrib - haskellPackages.monadLogger + haskellPackages.xmonad-contrib + haskellPackages.monad-logger ] ''; description = '' Extra packages available to ghc when rebuilding Xmonad. The value must be a function which receives the attrset defined - in <varname>haskellpackages</varname> as the sole argument. + in <varname>haskellPackages</varname> as the sole argument. ''; }; @@ -58,12 +59,12 @@ in session = [{ name = "xmonad"; start = '' - XMONAD_GHC=${xmonadEnv}/bin/ghc XMONAD_XMESSAGE=${xmessage}/bin/xmessage xmonad & + ${xmonad}/bin/xmonad & waitPID=$! ''; }]; }; - environment.systemPackages = [ cfg.haskellPackages.xmonad ]; + environment.systemPackages = [ xmonad ]; }; } diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 79b173a6ead8..0cae9cb844c8 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -193,8 +193,9 @@ in "ohci_hcd" "ohci_pci" "xhci_hcd" + "xhci_pci" "usbhid" - "hid_generic" + "hid_generic" "hid_lenovo" "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" # Unix domain sockets (needed by udev). diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index b16a725aba8e..0cfef7df1972 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -6,6 +6,8 @@ let cfg = config.boot.loader.grub; + efi = config.boot.loader.efi; + realGrub = if cfg.version == 1 then pkgs.grub else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; }; @@ -16,21 +18,31 @@ let then null else realGrub; + grubEfi = + # EFI version of Grub v2 + if (cfg.devices != ["nodev"]) && cfg.efiSupport && (cfg.version == 2) + then pkgs.grub2.override { zfsSupport = cfg.zfsSupport; efiSupport = cfg.efiSupport; } + else null; + f = x: if x == null then "" else "" + x; grubConfig = pkgs.writeText "grub-config.xml" (builtins.toXML { splashImage = f config.boot.loader.grub.splashImage; grub = f grub; + grubTarget = f (grub.grubTarget or ""); shell = "${pkgs.stdenv.shell}"; fullVersion = (builtins.parseDrvName realGrub.name).version; + grubEfi = f grubEfi; + grubTargetEfi = if cfg.efiSupport && (cfg.version == 2) then f grubEfi.grubTarget else ""; + inherit (efi) efiSysMountPoint canTouchEfiVariables; inherit (cfg) version extraConfig extraPerEntryConfig extraEntries extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout - default devices fsIdentifier; - path = (makeSearchPath "bin" [ + default devices fsIdentifier efiSupport; + path = (makeSearchPath "bin" ([ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs - pkgs.utillinux - ]) + ":" + (makeSearchPath "sbin" [ + pkgs.utillinux ] ++ (if cfg.efiSupport && (cfg.version == 2) then [pkgs.efibootmgr ] else []) + )) + ":" + (makeSearchPath "sbin" [ pkgs.mdadm pkgs.utillinux ]); }); @@ -231,6 +243,18 @@ in type = types.bool; description = '' Whether grub should be build against libzfs. + ZFS support is only available for GRUB v2. + This option is ignored for GRUB v1. + ''; + }; + + efiSupport = mkOption { + default = false; + type = types.bool; + description = '' + Whether grub should be build with EFI support. + EFI support is only available for GRUB v2. + This option is ignored for GRUB v1. ''; }; @@ -269,7 +293,7 @@ in if cfg.devices == [] then throw "You must set the option ‘boot.loader.grub.device’ to make the system bootable." else - "PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ])} " + + "PERL5LIB=${makePerlPath (with pkgs.perlPackages; [ FileSlurp XMLLibXML XMLSAX ListCompare ])} " + (if cfg.enableCryptodisk then "GRUB_ENABLE_CRYPTODISK=y " else "") + "${pkgs.perl}/bin/perl ${./install-grub.pl} ${grubConfig}"; diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index ffee0271e93b..74a934c67931 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -7,6 +7,7 @@ use File::Path; use File::stat; use File::Copy; use File::Slurp; +require List::Compare; use POSIX; use Cwd; @@ -39,6 +40,7 @@ sub runCommand { my $grub = get("grub"); my $grubVersion = int(get("version")); +my $grubTarget = get("grubTarget"); my $extraConfig = get("extraConfig"); my $extraPrepareConfig = get("extraPrepareConfig"); my $extraPerEntryConfig = get("extraPerEntryConfig"); @@ -50,6 +52,10 @@ my $copyKernels = get("copyKernels") eq "true"; my $timeout = int(get("timeout")); my $defaultEntry = int(get("default")); my $fsIdentifier = get("fsIdentifier"); +my $grubEfi = get("grubEfi"); +my $grubTargetEfi = get("grubTargetEfi"); +my $canTouchEfiVariables = get("canTouchEfiVariables"); +my $efiSysMountPoint = get("efiSysMountPoint"); $ENV{'PATH'} = get("path"); die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2; @@ -103,6 +109,8 @@ sub GetFs { # Skip the read-only bind-mount on /nix/store. next if $mountPoint eq "/nix/store" && (grep { $_ eq "rw" } @superOptions) && (grep { $_ eq "ro" } @mountOptions); + # Skip mount point generated by systemd-efi-boot-generator? + next if $fsType eq "autofs"; # Ensure this matches the intended directory next unless PathInMount($dir, $mountPoint); @@ -402,16 +410,114 @@ foreach my $fn (glob "/boot/kernels/*") { } -# Install GRUB if the version changed from the last time we installed -# it. FIXME: shouldn't we reinstall if ‘devices’ changed? -my $prevVersion = readFile("/boot/grub/version") // ""; -if (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1" || get("fullVersion") ne $prevVersion) { +# +# Install GRUB if the parameters changed from the last time we installed it. +# + +struct(GrubState => { + version => '$', + efi => '$', + devices => '$', + efiMountPoint => '$', +}); +sub readGrubState { + my $defaultGrubState = GrubState->new(version => "", efi => "", devices => "", efiMountPoint => "" ); + open FILE, "</boot/grub/state" or return $defaultGrubState; + local $/ = "\n"; + my $version = <FILE>; + chomp($version); + my $efi = <FILE>; + chomp($efi); + my $devices = <FILE>; + chomp($devices); + my $efiMountPoint = <FILE>; + chomp($efiMountPoint); + close FILE; + my $grubState = GrubState->new(version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint ); + return $grubState +} + +sub getDeviceTargets { + my @devices = (); foreach my $dev ($dom->findnodes('/expr/attrs/attr[@name = "devices"]/list/string/@value')) { $dev = $dev->findvalue(".") or die; + push(@devices, $dev); + } + return @devices; +} + +# check whether to install GRUB EFI or not +sub getEfiTarget { + if (($grub ne "") && ($grubEfi ne "")) { + # EFI can only be installed when target is set; + # A target is also required then for non-EFI grub + if (($grubTarget eq "") || ($grubTargetEfi eq "")) { die } + else { return "both" } + } elsif (($grub ne "") && ($grubEfi eq "")) { + # TODO: It would be safer to disallow non-EFI grub installation if no taget is given. + # If no target is given, then grub auto-detects the target which can lead to errors. + # E.g. it seems as if grub would auto-detect a EFI target based on the availability + # of a EFI partition. + # However, it seems as auto-detection is currently relied on for non-x86_64 and non-i386 + # architectures in NixOS. That would have to be fixed in the nixos modules first. + return "no" + } elsif (($grub eq "") && ($grubEfi ne "")) { + # EFI can only be installed when target is set; + if ($grubTargetEfi eq "") { die } + else {return "only" } + } else { + # at least one grub target has to be given + die + } +} + +my @deviceTargets = getDeviceTargets(); +my $efiTarget = getEfiTarget(); +my $prevGrubState = readGrubState(); +my @prevDeviceTargets = split/:/, $prevGrubState->devices; + +my $devicesDiffer = scalar (List::Compare->new( '-u', '-a', \@deviceTargets, \@prevDeviceTargets)->get_symmetric_difference() ); +my $versionDiffer = (get("fullVersion") eq \$prevGrubState->version); +my $efiDiffer = ($efiTarget eq \$prevGrubState->efi); +my $efiMountPointDiffer = ($efiSysMountPoint eq \$prevGrubState->efiMountPoint); +my $requireNewInstall = $devicesDiffer || $versionDiffer || $efiDiffer || $efiMountPointDiffer || (($ENV{'NIXOS_INSTALL_GRUB'} // "") eq "1"); + + +# install non-EFI GRUB +if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) { + foreach my $dev (@deviceTargets) { next if $dev eq "nodev"; print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n"; - system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0 - or die "$0: installation of GRUB on $dev failed\n"; + if ($grubTarget eq "") { + system("$grub/sbin/grub-install", "--recheck", Cwd::abs_path($dev)) == 0 + or die "$0: installation of GRUB on $dev failed\n"; + } else { + system("$grub/sbin/grub-install", "--recheck", "--target=$grubTarget", Cwd::abs_path($dev)) == 0 + or die "$0: installation of GRUB on $dev failed\n"; + } } - writeFile("/boot/grub/version", get("fullVersion")); +} + + +# install EFI GRUB +if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) { + print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n"; + if ($canTouchEfiVariables eq "true") { + system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint") == 0 + or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n"; + } else { + system("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--efi-directory=$efiSysMountPoint", "--no-nvram") == 0 + or die "$0: installation of GRUB EFI into $efiSysMountPoint failed\n"; + } +} + + +# update GRUB state file +if ($requireNewInstall != 0) { + open FILE, ">/boot/grub/state" or die "cannot create /boot/grub/state: $!\n"; + print FILE get("fullVersion"), "\n" or die; + print FILE $efiTarget, "\n" or die; + print FILE join( ":", @deviceTargets ), "\n" or die; + print FILE $efiSysMountPoint, "\n" or die; + close FILE or die; } diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 0b7d4de6d205..8f185217c3f8 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -7,6 +7,8 @@ export LD_LIBRARY_PATH=@extraUtils@/lib export PATH=@extraUtils@/bin ln -s @extraUtils@/bin /bin +# Stop LVM complaining about fd3 +export LVM_SUPPRESS_FD_WARNINGS=true fail() { if [ -n "$panicOnFail" ]; then exit 1; fi @@ -347,7 +349,8 @@ while read -u 3 mountPoint; do # that we don't properly recognise. if test -z "$pseudoDevice" -a ! -e $device; then echo -n "waiting for device $device to appear..." - for try in $(seq 1 20); do + try=20 + while [ $try -gt 0 ]; do sleep 1 # also re-try lvm activation now that new block devices might have appeared lvm vgchange -ay @@ -355,8 +358,12 @@ while read -u 3 mountPoint; do udevadm trigger --action=add if test -e $device; then break; fi echo -n "." + try=$((try - 1)) done echo + if [ $try -eq 0 ]; then + echo "Timed out waiting for device $device, trying to mount anyway." + fi fi # Wait once more for the udev queue to empty, just in case it's diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index f0d8b04d0875..16bebe03740a 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -46,7 +46,7 @@ let cp -pv ${pkgs.glibc}/lib/libpthread.so.* $out/lib cp -pv ${pkgs.glibc}/lib/librt.so.* $out/lib cp -pv ${pkgs.glibc}/lib/libdl.so.* $out/lib - cp -pv ${pkgs.gcc.gcc}/lib*/libgcc_s.so.* $out/lib + cp -pv ${pkgs.gcc.cc}/lib*/libgcc_s.so.* $out/lib # Copy BusyBox. cp -pvd ${pkgs.busybox}/bin/* ${pkgs.busybox}/sbin/* $out/bin/ diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 053a85c4c5b9..f853a8f6775c 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -1040,6 +1040,11 @@ in '' # This file is created automatically and should not be modified. # Please change the option ‘systemd.tmpfiles.rules’ instead. + + z /var/log/journal 2755 root systemd-journal - - + z /var/log/journal/%m 2755 root systemd-journal - - + z /var/log/journal/%m/* 0640 root systemd-journal - - + ${concatStringsSep "\n" cfg.tmpfiles.rules} ''; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index ab5942b79453..93782ffa4d58 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -21,11 +21,12 @@ let kernel = config.boot.kernelPackages; - splPkg = if cfgZfs.useGit then kernel.spl_git else kernel.spl; - zfsPkg = if cfgZfs.useGit then kernel.zfs_git else kernel.zfs; + splKernelPkg = if cfgZfs.useGit then kernel.spl_git else kernel.spl; + zfsKernelPkg = if cfgZfs.useGit then kernel.zfs_git else kernel.zfs; + zfsUserPkg = if cfgZfs.useGit then pkgs.zfs_git else pkgs.zfs; autosnapPkg = pkgs.zfstools.override { - zfs = zfsPkg; + zfs = zfsUserPkg; }; zfsAutoSnap = "${autosnapPkg}/bin/zfs-auto-snapshot"; @@ -54,7 +55,8 @@ in boot.zfs = { useGit = mkOption { type = types.bool; - default = false; + # TODO(wkennington): Revert when 0.6.4 is out + default = versionAtLeast config.boot.kernelPackages.kernel.version "3.19"; example = true; description = '' Use the git version of the SPL and ZFS packages. @@ -195,17 +197,17 @@ in boot = { kernelModules = [ "spl" "zfs" ] ; - extraModulePackages = [ splPkg zfsPkg ]; + extraModulePackages = [ splKernelPkg zfsKernelPkg ]; }; boot.initrd = mkIf inInitrd { kernelModules = [ "spl" "zfs" ]; extraUtilsCommands = '' - cp -v ${zfsPkg}/sbin/zfs $out/bin - cp -v ${zfsPkg}/sbin/zdb $out/bin - cp -v ${zfsPkg}/sbin/zpool $out/bin - cp -pdv ${zfsPkg}/lib/lib*.so* $out/lib + cp -v ${zfsUserPkg}/sbin/zfs $out/bin + cp -v ${zfsUserPkg}/sbin/zdb $out/bin + cp -v ${zfsUserPkg}/sbin/zpool $out/bin + cp -pdv ${zfsUserPkg}/lib/lib*.so* $out/lib cp -pdv ${pkgs.zlib}/lib/lib*.so* $out/lib ''; postDeviceCommands = concatStringsSep "\n" (['' @@ -228,12 +230,12 @@ in zfsSupport = true; }; - environment.etc."zfs/zed.d".source = "${zfsPkg}/etc/zfs/zed.d/*"; + environment.etc."zfs/zed.d".source = "${zfsUserPkg}/etc/zfs/zed.d/*"; - system.fsPackages = [ zfsPkg ]; # XXX: needed? zfs doesn't have (need) a fsck - environment.systemPackages = [ zfsPkg ]; - services.udev.packages = [ zfsPkg ]; # to hook zvol naming, etc. - systemd.packages = [ zfsPkg ]; + system.fsPackages = [ zfsUserPkg ]; # XXX: needed? zfs doesn't have (need) a fsck + environment.systemPackages = [ zfsUserPkg ]; + services.udev.packages = [ zfsUserPkg ]; # to hook zvol naming, etc. + systemd.packages = [ zfsUserPkg ]; systemd.services = let getPoolFilesystems = pool: @@ -260,7 +262,7 @@ in RemainAfterExit = true; }; script = '' - zpool_cmd="${zfsPkg}/sbin/zpool" + zpool_cmd="${zfsUserPkg}/sbin/zpool" ("$zpool_cmd" list "${pool}" >/dev/null) || "$zpool_cmd" import -N ${optionalString cfgZfs.forceImportAll "-f"} "${pool}" ''; }; |