diff options
Diffstat (limited to 'nixpkgs/nixos/modules')
82 files changed, 1797 insertions, 815 deletions
diff --git a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix index e72d4a5b4910..b84096861f56 100644 --- a/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix +++ b/nixpkgs/nixos/modules/installer/cd-dvd/system-tarball.nix @@ -68,7 +68,7 @@ in # Create the tarball system.build.tarball = import ../../../lib/make-system-tarball.nix { - inherit (pkgs) stdenv perl xz pathsFromGraph; + inherit (pkgs) stdenv closureInfo pixz; inherit (config.tarball) contents storeContents; }; diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix index 5012a3a303c9..5fb559d2e6ef 100644 --- a/nixpkgs/nixos/modules/module-list.nix +++ b/nixpkgs/nixos/modules/module-list.nix @@ -188,6 +188,7 @@ ./services/audio/snapserver.nix ./services/audio/squeezelite.nix ./services/audio/ympd.nix + ./services/backup/automysqlbackup.nix ./services/backup/bacula.nix ./services/backup/borgbackup.nix ./services/backup/duplicati.nix @@ -673,6 +674,7 @@ ./services/networking/syncthing-relay.nix ./services/networking/tcpcrypt.nix ./services/networking/teamspeak3.nix + ./services/networking/tedicross.nix ./services/networking/tinc.nix ./services/networking/tinydns.nix ./services/networking/tftpd.nix @@ -685,6 +687,7 @@ ./services/networking/vsftpd.nix ./services/networking/wakeonlan.nix ./services/networking/websockify.nix + ./services/networking/wg-quick.nix ./services/networking/wicd.nix ./services/networking/wireguard.nix ./services/networking/wpa_supplicant.nix @@ -706,6 +709,7 @@ ./services/search/hound.nix ./services/search/kibana.nix ./services/search/solr.nix + ./services/security/bitwarden_rs/default.nix ./services/security/certmgr.nix ./services/security/cfssl.nix ./services/security/clamav.nix diff --git a/nixpkgs/nixos/modules/security/misc.nix b/nixpkgs/nixos/modules/security/misc.nix index 4506a67487d4..ecf22bf81c59 100644 --- a/nixpkgs/nixos/modules/security/misc.nix +++ b/nixpkgs/nixos/modules/security/misc.nix @@ -12,14 +12,24 @@ with lib; type = types.bool; default = true; description = '' - Whether to allow creation of user namespaces. A recurring problem - with user namespaces is the presence of code paths where the kernel's - permission checking logic fails to account for namespacing, instead - permitting a namespaced process to act outside the namespace with the - same privileges as it would have inside it. This is particularly + Whether to allow creation of user namespaces. + </para> + + <para> + The motivation for disabling user namespaces is the potential + presence of code paths where the kernel's permission checking + logic fails to account for namespacing, instead permitting a + namespaced process to act outside the namespace with the same + privileges as it would have inside it. This is particularly damaging in the common case of running as root within the namespace. - When user namespace creation is disallowed, attempting to create - a user namespace fails with "no space left on device" (ENOSPC). + </para> + + <para> + When user namespace creation is disallowed, attempting to create a + user namespace fails with "no space left on device" (ENOSPC). + root may re-enable user namespace creation at runtime. + </para> + <para> ''; }; diff --git a/nixpkgs/nixos/modules/services/admin/oxidized.nix b/nixpkgs/nixos/modules/services/admin/oxidized.nix index 70f7dd9e3647..687cdfb5ba57 100644 --- a/nixpkgs/nixos/modules/services/admin/oxidized.nix +++ b/nixpkgs/nixos/modules/services/admin/oxidized.nix @@ -7,7 +7,7 @@ let in { options.services.oxidized = { - enable = mkEnableOption "the oxidized configuation backup service."; + enable = mkEnableOption "the oxidized configuration backup service"; user = mkOption { type = types.str; diff --git a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix index 7373be2a9b0b..302b94de1965 100644 --- a/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix +++ b/nixpkgs/nixos/modules/services/amqp/rabbitmq.nix @@ -179,11 +179,11 @@ in { } // optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; }; serviceConfig = { - PermissionsStartOnly = true; # preStart must be run as root ExecStart = "${cfg.package}/sbin/rabbitmq-server"; ExecStop = "${cfg.package}/sbin/rabbitmqctl shutdown"; User = "rabbitmq"; Group = "rabbitmq"; + LogsDirectory = "rabbitmq"; WorkingDirectory = cfg.dataDir; Type = "notify"; NotifyAccess = "all"; @@ -197,11 +197,8 @@ in { preStart = '' ${optionalString (cfg.cookie != "") '' echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie - chown rabbitmq:rabbitmq ${cfg.dataDir}/.erlang.cookie chmod 600 ${cfg.dataDir}/.erlang.cookie ''} - mkdir -p /var/log/rabbitmq - chown rabbitmq:rabbitmq /var/log/rabbitmq ''; }; diff --git a/nixpkgs/nixos/modules/services/audio/liquidsoap.nix b/nixpkgs/nixos/modules/services/audio/liquidsoap.nix index 66f84ef20762..3a047d10a631 100644 --- a/nixpkgs/nixos/modules/services/audio/liquidsoap.nix +++ b/nixpkgs/nixos/modules/services/audio/liquidsoap.nix @@ -14,15 +14,10 @@ let description = "${name} liquidsoap stream"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.wget ]; - preStart = - '' - mkdir -p /var/log/liquidsoap - chown liquidsoap -R /var/log/liquidsoap - ''; serviceConfig = { - PermissionsStartOnly="true"; ExecStart = "${pkgs.liquidsoap}/bin/liquidsoap ${stream}"; User = "liquidsoap"; + LogsDirectory = "liquidsoap"; }; }; }; diff --git a/nixpkgs/nixos/modules/services/audio/mpd.nix b/nixpkgs/nixos/modules/services/audio/mpd.nix index 5bfe2b6a22ad..0df8f9688d25 100644 --- a/nixpkgs/nixos/modules/services/audio/mpd.nix +++ b/nixpkgs/nixos/modules/services/audio/mpd.nix @@ -158,18 +158,18 @@ in { }; }; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -" + "d '${cfg.playlistDirectory}' - ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.mpd = { after = [ "network.target" "sound.target" ]; description = "Music Player Daemon"; wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; - preStart = '' - mkdir -p "${cfg.dataDir}" && chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" - mkdir -p "${cfg.playlistDirectory}" && chown -R ${cfg.user}:${cfg.group} "${cfg.playlistDirectory}" - ''; serviceConfig = { User = "${cfg.user}"; - PermissionsStartOnly = true; ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}"; Type = "notify"; LimitRTPRIO = 50; diff --git a/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix new file mode 100644 index 000000000000..b845f370fb70 --- /dev/null +++ b/nixpkgs/nixos/modules/services/backup/automysqlbackup.nix @@ -0,0 +1,115 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (lib) concatMapStringsSep concatStringsSep isInt isList literalExample; + inherit (lib) mapAttrs mapAttrsToList mkDefault mkEnableOption mkIf mkOption optional types; + + cfg = config.services.automysqlbackup; + pkg = pkgs.automysqlbackup; + user = "automysqlbackup"; + group = "automysqlbackup"; + + toStr = val: + if isList val then "( ${concatMapStringsSep " " (val: "'${val}'") val} )" + else if isInt val then toString val + else if true == val then "'yes'" + else if false == val then "'no'" + else "'${toString val}'"; + + configFile = pkgs.writeText "automysqlbackup.conf" '' + #version=${pkg.version} + # DONT'T REMOVE THE PREVIOUS VERSION LINE! + # + ${concatStringsSep "\n" (mapAttrsToList (name: value: "CONFIG_${name}=${toStr value}") cfg.config)} + ''; + +in +{ + # interface + options = { + services.automysqlbackup = { + + enable = mkEnableOption "AutoMySQLBackup"; + + calendar = mkOption { + type = types.str; + default = "01:15:00"; + description = '' + Configured when to run the backup service systemd unit (DayOfWeek Year-Month-Day Hour:Minute:Second). + ''; + }; + + config = mkOption { + type = with types; attrsOf (either (either str (either int bool)) (listOf str)); + default = {}; + description = '' + automysqlbackup configuration. Refer to + <filename>''${pkgs.automysqlbackup}/etc/automysqlbackup.conf</filename> + for details on supported values. + ''; + example = literalExample '' + { + db_names = [ "nextcloud" "matomo" ]; + table_exclude = [ "nextcloud.oc_users" "nextcloud.oc_whats_new" ]; + mailcontent = "log"; + mail_address = "admin@example.org"; + } + ''; + }; + + }; + }; + + # implementation + config = mkIf cfg.enable { + + assertions = [ + { assertion = !config.services.mysqlBackup.enable; + message = "Please choose one of services.mysqlBackup or services.automysqlbackup."; + } + ]; + + services.automysqlbackup.config = mapAttrs (name: mkDefault) { + mysql_dump_username = user; + mysql_dump_host = "localhost"; + backup_dir = "/var/backup/mysql"; + db_exclude = [ "information_schema" "performance_schema" ]; + mailcontent = "stdout"; + mysql_dump_single_transaction = true; + }; + + systemd.timers.automysqlbackup = { + description = "automysqlbackup timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.calendar; + AccuracySec = "5m"; + }; + }; + + systemd.services.automysqlbackup = { + description = "automysqlbackup service"; + serviceConfig = { + User = user; + Group = group; + ExecStart = "${pkg}/bin/automysqlbackup ${configFile}"; + }; + }; + + environment.systemPackages = [ pkg ]; + + users.users.${user}.group = group; + users.groups.${group} = { }; + + systemd.tmpfiles.rules = [ + "d '${cfg.config.backup_dir}' 0750 ${user} ${group} - -" + ]; + + services.mysql.ensureUsers = optional (config.services.mysql.enable && cfg.config.mysql_dump_host == "localhost") { + name = user; + ensurePermissions = { "*.*" = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES"; }; + }; + + }; +} diff --git a/nixpkgs/nixos/modules/services/backup/mysql-backup.nix b/nixpkgs/nixos/modules/services/backup/mysql-backup.nix index f0c273ffebf1..ba6e154f6b3d 100644 --- a/nixpkgs/nixos/modules/services/backup/mysql-backup.nix +++ b/nixpkgs/nixos/modules/services/backup/mysql-backup.nix @@ -117,14 +117,12 @@ in enable = true; serviceConfig = { User = cfg.user; - PermissionsStartOnly = true; }; - preStart = '' - mkdir -m 0700 -p ${cfg.location} - chown -R ${cfg.user} ${cfg.location} - ''; script = backupScript; }; + tmpfiles.rules = [ + "d ${cfg.location} 0700 ${cfg.user} - - -" + ]; }; }; diff --git a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix index 11efa47ec5b2..17b410a97f3e 100644 --- a/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix +++ b/nixpkgs/nixos/modules/services/backup/postgresql-backup.nix @@ -14,11 +14,6 @@ let requires = [ "postgresql.service" ]; - preStart = '' - mkdir -m 0700 -p ${cfg.location} - chown postgres ${cfg.location} - ''; - script = '' umask 0077 # ensure backup is only readable by postgres user @@ -32,7 +27,6 @@ let serviceConfig = { Type = "oneshot"; - PermissionsStartOnly = "true"; User = "postgres"; }; @@ -107,6 +101,11 @@ in { message = "config.services.postgresqlBackup.backupAll cannot be used together with config.services.postgresqlBackup.databases"; }]; } + (mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.location}' 0700 postgres - - -" + ]; + }) (mkIf (cfg.enable && cfg.backupAll) { systemd.services.postgresqlBackup = postgresqlBackupService "all" "${config.services.postgresql.package}/bin/pg_dumpall"; diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix index 17f2dde31a71..ad7d17c9c283 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/addon-manager.nix @@ -62,19 +62,50 @@ in ''; }; - enable = mkEnableOption "Whether to enable Kubernetes addon manager."; + enable = mkEnableOption "Kubernetes addon manager"; + + kubeconfig = top.lib.mkKubeConfigOptions "Kubernetes addon manager"; + bootstrapAddonsKubeconfig = top.lib.mkKubeConfigOptions "Kubernetes addon manager bootstrap"; }; ###### implementation - config = mkIf cfg.enable { + config = let + + addonManagerPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + ]; + bootstrapAddonsPaths = filter (a: a != null) [ + cfg.bootstrapAddonsKubeconfig.caFile + cfg.bootstrapAddonsKubeconfig.certFile + cfg.bootstrapAddonsKubeconfig.keyFile + ]; + + in mkIf cfg.enable { environment.etc."kubernetes/addons".source = "${addons}/"; + #TODO: Get rid of kube-addon-manager in the future for the following reasons + # - it is basically just a shell script wrapped around kubectl + # - it assumes that it is clusterAdmin or can gain clusterAdmin rights through serviceAccount + # - it is designed to be used with k8s system components only + # - it would be better with a more Nix-oriented way of managing addons systemd.services.kube-addon-manager = { description = "Kubernetes addon manager"; wantedBy = [ "kubernetes.target" ]; - after = [ "kube-apiserver.service" ]; - environment.ADDON_PATH = "/etc/kubernetes/addons/"; - path = [ pkgs.gawk ]; + after = [ "kube-node-online.target" ]; + before = [ "kubernetes.target" ]; + environment = { + ADDON_PATH = "/etc/kubernetes/addons/"; + KUBECONFIG = top.lib.mkKubeConfig "kube-addon-manager" cfg.kubeconfig; + }; + path = with pkgs; [ gawk kubectl ]; + preStart = '' + until kubectl -n kube-system get serviceaccounts/default 2>/dev/null; do + echo kubectl -n kube-system get serviceaccounts/default: exit status $? + sleep 2 + done + ''; serviceConfig = { Slice = "kubernetes.slice"; ExecStart = "${top.package}/bin/kube-addons"; @@ -84,8 +115,52 @@ in Restart = "on-failure"; RestartSec = 10; }; + unitConfig.ConditionPathExists = addonManagerPaths; }; + systemd.paths.kube-addon-manager = { + wantedBy = [ "kube-addon-manager.service" ]; + pathConfig = { + PathExists = addonManagerPaths; + PathChanged = addonManagerPaths; + }; + }; + + services.kubernetes.addonManager.kubeconfig.server = mkDefault top.apiserverAddress; + + systemd.services.kube-addon-manager-bootstrap = mkIf (top.apiserver.enable && top.addonManager.bootstrapAddons != {}) { + wantedBy = [ "kube-control-plane-online.target" ]; + after = [ "kube-apiserver.service" ]; + before = [ "kube-control-plane-online.target" ]; + path = [ pkgs.kubectl ]; + environment = { + KUBECONFIG = top.lib.mkKubeConfig "kube-addon-manager-bootstrap" cfg.bootstrapAddonsKubeconfig; + }; + preStart = with pkgs; let + files = mapAttrsToList (n: v: writeText "${n}.json" (builtins.toJSON v)) + cfg.bootstrapAddons; + in '' + until kubectl auth can-i '*' '*' -q 2>/dev/null; do + echo kubectl auth can-i '*' '*': exit status $? + sleep 2 + done + + kubectl apply -f ${concatStringsSep " \\\n -f " files} + ''; + script = "echo Ok"; + unitConfig.ConditionPathExists = bootstrapAddonsPaths; + }; + + systemd.paths.kube-addon-manager-bootstrap = { + wantedBy = [ "kube-addon-manager-bootstrap.service" ]; + pathConfig = { + PathExists = bootstrapAddonsPaths; + PathChanged = bootstrapAddonsPaths; + }; + }; + + services.kubernetes.addonManager.bootstrapAddonsKubeconfig.server = mkDefault top.apiserverAddress; + services.kubernetes.addonManager.bootstrapAddons = mkIf isRBACEnabled (let name = system:kube-addon-manager; diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix index 454e7d35bc01..2295694ffc74 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/addons/dashboard.nix @@ -169,6 +169,23 @@ in { }; }; + kubernetes-dashboard-cm = { + apiVersion = "v1"; + kind = "ConfigMap"; + metadata = { + labels = { + k8s-app = "kubernetes-dashboard"; + # Allows editing resource and makes sure it is created first. + "addonmanager.kubernetes.io/mode" = "EnsureExists"; + }; + name = "kubernetes-dashboard-settings"; + namespace = "kube-system"; + }; + }; + }; + + services.kubernetes.addonManager.bootstrapAddons = mkMerge [{ + kubernetes-dashboard-sa = { apiVersion = "v1"; kind = "ServiceAccount"; @@ -210,20 +227,9 @@ in { }; type = "Opaque"; }; - kubernetes-dashboard-cm = { - apiVersion = "v1"; - kind = "ConfigMap"; - metadata = { - labels = { - k8s-app = "kubernetes-dashboard"; - # Allows editing resource and makes sure it is created first. - "addonmanager.kubernetes.io/mode" = "EnsureExists"; - }; - name = "kubernetes-dashboard-settings"; - namespace = "kube-system"; - }; - }; - } // (optionalAttrs cfg.rbac.enable + } + + (optionalAttrs cfg.rbac.enable (let subjects = [{ kind = "ServiceAccount"; @@ -323,6 +329,6 @@ in { inherit subjects; }; }) - )); + ))]; }; } diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix index 455d02396040..0c04648355b4 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/apiserver.nix @@ -184,6 +184,18 @@ in type = bool; }; + proxyClientCertFile = mkOption { + description = "Client certificate to use for connections to proxy."; + default = null; + type = nullOr path; + }; + + proxyClientKeyFile = mkOption { + description = "Key to use for connections to proxy."; + default = null; + type = nullOr path; + }; + runtimeConfig = mkOption { description = '' Api runtime configuration. See @@ -272,11 +284,32 @@ in ###### implementation config = mkMerge [ - (mkIf cfg.enable { + (let + + apiserverPaths = filter (a: a != null) [ + cfg.clientCaFile + cfg.etcd.caFile + cfg.etcd.certFile + cfg.etcd.keyFile + cfg.kubeletClientCaFile + cfg.kubeletClientCertFile + cfg.kubeletClientKeyFile + cfg.serviceAccountKeyFile + cfg.tlsCertFile + cfg.tlsKeyFile + ]; + etcdPaths = filter (a: a != null) [ + config.services.etcd.trustedCaFile + config.services.etcd.certFile + config.services.etcd.keyFile + ]; + + in mkIf cfg.enable { systemd.services.kube-apiserver = { description = "Kubernetes APIServer Service"; - wantedBy = [ "kubernetes.target" ]; - after = [ "network.target" ]; + wantedBy = [ "kube-control-plane-online.target" ]; + after = [ "certmgr.service" ]; + before = [ "kube-control-plane-online.target" ]; serviceConfig = { Slice = "kubernetes.slice"; ExecStart = ''${top.package}/bin/kube-apiserver \ @@ -316,6 +349,10 @@ in "--kubelet-client-certificate=${cfg.kubeletClientCertFile}"} \ ${optionalString (cfg.kubeletClientKeyFile != null) "--kubelet-client-key=${cfg.kubeletClientKeyFile}"} \ + ${optionalString (cfg.proxyClientCertFile != null) + "--proxy-client-cert-file=${cfg.proxyClientCertFile}"} \ + ${optionalString (cfg.proxyClientKeyFile != null) + "--proxy-client-key-file=${cfg.proxyClientKeyFile}"} \ --insecure-bind-address=${cfg.insecureBindAddress} \ --insecure-port=${toString cfg.insecurePort} \ ${optionalString (cfg.runtimeConfig != "") @@ -341,6 +378,15 @@ in Restart = "on-failure"; RestartSec = 5; }; + unitConfig.ConditionPathExists = apiserverPaths; + }; + + systemd.paths.kube-apiserver = mkIf top.apiserver.enable { + wantedBy = [ "kube-apiserver.service" ]; + pathConfig = { + PathExists = apiserverPaths; + PathChanged = apiserverPaths; + }; }; services.etcd = { @@ -354,6 +400,18 @@ in initialAdvertisePeerUrls = mkDefault ["https://${top.masterAddress}:2380"]; }; + systemd.services.etcd = { + unitConfig.ConditionPathExists = etcdPaths; + }; + + systemd.paths.etcd = { + wantedBy = [ "etcd.service" ]; + pathConfig = { + PathExists = etcdPaths; + PathChanged = etcdPaths; + }; + }; + services.kubernetes.addonManager.bootstrapAddons = mkIf isRBACEnabled { apiserver-kubelet-api-admin-crb = { @@ -389,6 +447,11 @@ in ] ++ cfg.extraSANs; action = "systemctl restart kube-apiserver.service"; }; + apiserverProxyClient = mkCert { + name = "kube-apiserver-proxy-client"; + CN = "front-proxy-client"; + action = "systemctl restart kube-apiserver.service"; + }; apiserverKubeletClient = mkCert { name = "kube-apiserver-kubelet-client"; CN = "system:kube-apiserver"; diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix index 060fd9b78db6..b94e8bd86d4c 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/controller-manager.nix @@ -28,7 +28,7 @@ in type = str; }; - enable = mkEnableOption "Kubernetes controller manager."; + enable = mkEnableOption "Kubernetes controller manager"; extraOpts = mkOption { description = "Kubernetes controller manager extra command line options."; @@ -104,11 +104,31 @@ in }; ###### implementation - config = mkIf cfg.enable { - systemd.services.kube-controller-manager = { + config = let + + controllerManagerPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + cfg.rootCaFile + cfg.serviceAccountKeyFile + cfg.tlsCertFile + cfg.tlsKeyFile + ]; + + in mkIf cfg.enable { + systemd.services.kube-controller-manager = rec { description = "Kubernetes Controller Manager Service"; - wantedBy = [ "kubernetes.target" ]; + wantedBy = [ "kube-control-plane-online.target" ]; after = [ "kube-apiserver.service" ]; + before = [ "kube-control-plane-online.target" ]; + environment.KUBECONFIG = top.lib.mkKubeConfig "kube-controller-manager" cfg.kubeconfig; + preStart = '' + until kubectl auth can-i get /api -q 2>/dev/null; do + echo kubectl auth can-i get /api: exit status $? + sleep 2 + done + ''; serviceConfig = { RestartSec = "30s"; Restart = "on-failure"; @@ -120,7 +140,7 @@ in "--cluster-cidr=${cfg.clusterCidr}"} \ ${optionalString (cfg.featureGates != []) "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \ - --kubeconfig=${top.lib.mkKubeConfig "kube-controller-manager" cfg.kubeconfig} \ + --kubeconfig=${environment.KUBECONFIG} \ --leader-elect=${boolToString cfg.leaderElect} \ ${optionalString (cfg.rootCaFile!=null) "--root-ca-file=${cfg.rootCaFile}"} \ @@ -141,7 +161,16 @@ in User = "kubernetes"; Group = "kubernetes"; }; - path = top.path; + path = top.path ++ [ pkgs.kubectl ]; + unitConfig.ConditionPathExists = controllerManagerPaths; + }; + + systemd.paths.kube-controller-manager = { + wantedBy = [ "kube-controller-manager.service" ]; + pathConfig = { + PathExists = controllerManagerPaths; + PathChanged = controllerManagerPaths; + }; }; services.kubernetes.pki.certs = with top.lib; { diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix index 3e53d18f8bbf..192c893f8a16 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/default.nix @@ -263,6 +263,30 @@ in { wantedBy = [ "multi-user.target" ]; }; + systemd.targets.kube-control-plane-online = { + wantedBy = [ "kubernetes.target" ]; + before = [ "kubernetes.target" ]; + }; + + systemd.services.kube-control-plane-online = rec { + description = "Kubernetes control plane is online"; + wantedBy = [ "kube-control-plane-online.target" ]; + after = [ "kube-scheduler.service" "kube-controller-manager.service" ]; + before = [ "kube-control-plane-online.target" ]; + environment.KUBECONFIG = cfg.lib.mkKubeConfig "default" cfg.kubeconfig; + path = [ pkgs.kubectl ]; + preStart = '' + until kubectl get --raw=/healthz 2>/dev/null; do + echo kubectl get --raw=/healthz: exit status $? + sleep 3 + done + ''; + script = "echo Ok"; + serviceConfig = { + TimeoutSec = "500"; + }; + }; + systemd.tmpfiles.rules = [ "d /opt/cni/bin 0755 root root -" "d /run/kubernetes 0755 kubernetes kubernetes -" @@ -286,6 +310,8 @@ in { services.kubernetes.apiserverAddress = mkDefault ("https://${if cfg.apiserver.advertiseAddress != null then cfg.apiserver.advertiseAddress else "${cfg.masterAddress}:${toString cfg.apiserver.securePort}"}"); + + services.kubernetes.kubeconfig.server = mkDefault cfg.apiserverAddress; }) ]; } diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix index 93ee2fd65eeb..d9437427d6d1 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/flannel.nix @@ -23,17 +23,27 @@ in { ###### interface options.services.kubernetes.flannel = { - enable = mkEnableOption "enable flannel networking"; + enable = mkEnableOption "flannel networking"; + kubeconfig = top.lib.mkKubeConfigOptions "Kubernetes flannel"; }; ###### implementation - config = mkIf cfg.enable { + config = let + + flannelPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + ]; + kubeconfig = top.lib.mkKubeConfig "flannel" cfg.kubeconfig; + + in mkIf cfg.enable { services.flannel = { enable = mkDefault true; network = mkDefault top.clusterCidr; - inherit storageBackend; - nodeName = config.services.kubernetes.kubelet.hostname; + inherit storageBackend kubeconfig; + nodeName = top.kubelet.hostname; }; services.kubernetes.kubelet = { @@ -48,24 +58,66 @@ in }]; }; - systemd.services."mk-docker-opts" = { + systemd.services.mk-docker-opts = { description = "Pre-Docker Actions"; + wantedBy = [ "flannel.target" ]; + before = [ "flannel.target" ]; path = with pkgs; [ gawk gnugrep ]; script = '' ${mkDockerOpts}/mk-docker-opts -d /run/flannel/docker systemctl restart docker ''; + unitConfig.ConditionPathExists = [ "/run/flannel/subnet.env" ]; serviceConfig.Type = "oneshot"; }; - systemd.paths."flannel-subnet-env" = { - wantedBy = [ "flannel.service" ]; + systemd.paths.flannel-subnet-env = { + wantedBy = [ "mk-docker-opts.service" ]; pathConfig = { - PathModified = "/run/flannel/subnet.env"; + PathExists = [ "/run/flannel/subnet.env" ]; + PathChanged = [ "/run/flannel/subnet.env" ]; Unit = "mk-docker-opts.service"; }; }; + systemd.targets.flannel = { + wantedBy = [ "kube-node-online.target" ]; + before = [ "kube-node-online.target" ]; + }; + + systemd.services.flannel = { + wantedBy = [ "flannel.target" ]; + after = [ "kubelet.target" ]; + before = [ "flannel.target" ]; + path = with pkgs; [ iptables kubectl ]; + environment.KUBECONFIG = kubeconfig; + preStart = let + args = [ + "--selector=kubernetes.io/hostname=${top.kubelet.hostname}" + # flannel exits if node is not registered yet, before that there is no podCIDR + "--output=jsonpath={.items[0].spec.podCIDR}" + # if jsonpath cannot be resolved exit with status 1 + "--allow-missing-template-keys=false" + ]; + in '' + until kubectl get nodes ${concatStringsSep " " args} 2>/dev/null; do + echo Waiting for ${top.kubelet.hostname} to be RegisteredNode + sleep 1 + done + ''; + unitConfig.ConditionPathExists = flannelPaths; + }; + + systemd.paths.flannel = { + wantedBy = [ "flannel.service" ]; + pathConfig = { + PathExists = flannelPaths; + PathChanged = flannelPaths; + }; + }; + + services.kubernetes.flannel.kubeconfig.server = mkDefault top.apiserverAddress; + systemd.services.docker = { environment.DOCKER_OPTS = "-b none"; serviceConfig.EnvironmentFile = "-/run/flannel/docker"; @@ -92,7 +144,6 @@ in # give flannel som kubernetes rbac permissions if applicable services.kubernetes.addonManager.bootstrapAddons = mkIf ((storageBackend == "kubernetes") && (elem "RBAC" top.apiserver.authorizationMode)) { - flannel-cr = { apiVersion = "rbac.authorization.k8s.io/v1beta1"; kind = "ClusterRole"; @@ -128,7 +179,6 @@ in name = "flannel-client"; }]; }; - }; }; } diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix index c94bb28bf7fb..2a4a0624555d 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix @@ -241,21 +241,28 @@ in ###### implementation config = mkMerge [ - (mkIf cfg.enable { + (let + + kubeletPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + cfg.clientCaFile + cfg.tlsCertFile + cfg.tlsKeyFile + ]; + + in mkIf cfg.enable { services.kubernetes.kubelet.seedDockerImages = [infraContainer]; systemd.services.kubelet = { description = "Kubernetes Kubelet Service"; - wantedBy = [ "kubernetes.target" ]; - after = [ "network.target" "docker.service" "kube-apiserver.service" ]; + wantedBy = [ "kubelet.target" ]; + after = [ "kube-control-plane-online.target" ]; + before = [ "kubelet.target" ]; path = with pkgs; [ gitMinimal openssh docker utillinux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path; preStart = '' - ${concatMapStrings (img: '' - echo "Seeding docker image: ${img}" - docker load <${img} - '') cfg.seedDockerImages} - - rm /opt/cni/bin/* || true + rm -f /opt/cni/bin/* || true ${concatMapStrings (package: '' echo "Linking cni package: ${package}" ln -fs ${package}/bin/* /opt/cni/bin @@ -308,6 +315,56 @@ in ''; WorkingDirectory = top.dataDir; }; + unitConfig.ConditionPathExists = kubeletPaths; + }; + + systemd.paths.kubelet = { + wantedBy = [ "kubelet.service" ]; + pathConfig = { + PathExists = kubeletPaths; + PathChanged = kubeletPaths; + }; + }; + + systemd.services.docker.before = [ "kubelet.service" ]; + + systemd.services.docker-seed-images = { + wantedBy = [ "docker.service" ]; + after = [ "docker.service" ]; + before = [ "kubelet.service" ]; + path = with pkgs; [ docker ]; + preStart = '' + ${concatMapStrings (img: '' + echo "Seeding docker image: ${img}" + docker load <${img} + '') cfg.seedDockerImages} + ''; + script = "echo Ok"; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + serviceConfig.Slice = "kubernetes.slice"; + }; + + systemd.services.kubelet-online = { + wantedBy = [ "kube-node-online.target" ]; + after = [ "flannel.target" "kubelet.target" ]; + before = [ "kube-node-online.target" ]; + # it is complicated. flannel needs kubelet to run the pause container before + # it discusses the node CIDR with apiserver and afterwards configures and restarts + # dockerd. Until then prevent creating any pods because they have to be recreated anyway + # because the network of docker0 has been changed by flannel. + script = let + docker-env = "/run/flannel/docker"; + flannel-date = "stat --print=%Y ${docker-env}"; + docker-date = "systemctl show --property=ActiveEnterTimestamp --value docker"; + in '' + until test -f ${docker-env} ; do sleep 1 ; done + while test `${flannel-date}` -gt `date +%s --date="$(${docker-date})"` ; do + sleep 1 + done + ''; + serviceConfig.Type = "oneshot"; + serviceConfig.Slice = "kubernetes.slice"; }; # Allways include cni plugins @@ -354,5 +411,16 @@ in }; }) + { + systemd.targets.kubelet = { + wantedBy = [ "kube-node-online.target" ]; + before = [ "kube-node-online.target" ]; + }; + + systemd.targets.kube-node-online = { + wantedBy = [ "kubernetes.target" ]; + before = [ "kubernetes.target" ]; + }; + } ]; } diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix index 38deca23a990..32eacad9025f 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/pki.nix @@ -27,12 +27,11 @@ let certmgrAPITokenPath = "${top.secretsPath}/${cfsslAPITokenBaseName}"; cfsslAPITokenLength = 32; - clusterAdminKubeconfig = with cfg.certs.clusterAdmin; - top.lib.mkKubeConfig "cluster-admin" { - server = top.apiserverAddress; - certFile = cert; - keyFile = key; - }; + clusterAdminKubeconfig = with cfg.certs.clusterAdmin; { + server = top.apiserverAddress; + certFile = cert; + keyFile = key; + }; remote = with config.services; "https://${kubernetes.masterAddress}:${toString cfssl.port}"; in @@ -40,7 +39,7 @@ in ###### interface options.services.kubernetes.pki = with lib.types; { - enable = mkEnableOption "Whether to enable easyCert issuer service."; + enable = mkEnableOption "easyCert issuer service"; certs = mkOption { description = "List of certificate specs to feed to cert generator."; @@ -119,6 +118,12 @@ in cfsslCertPathPrefix = "${config.services.cfssl.dataDir}/cfssl"; cfsslCert = "${cfsslCertPathPrefix}.pem"; cfsslKey = "${cfsslCertPathPrefix}-key.pem"; + cfsslPort = toString config.services.cfssl.port; + + certmgrPaths = [ + top.caFile + certmgrAPITokenPath + ]; in { @@ -168,13 +173,40 @@ in chown cfssl "${cfsslAPITokenPath}" && chmod 400 "${cfsslAPITokenPath}" '')]); + systemd.targets.cfssl-online = { + wantedBy = [ "network-online.target" ]; + after = [ "cfssl.service" "network-online.target" "cfssl-online.service" ]; + }; + + systemd.services.cfssl-online = { + description = "Wait for ${remote} to be reachable."; + wantedBy = [ "cfssl-online.target" ]; + before = [ "cfssl-online.target" ]; + path = [ pkgs.curl ]; + preStart = '' + until curl --fail-early -fskd '{}' ${remote}/api/v1/cfssl/info -o /dev/null; do + echo curl ${remote}/api/v1/cfssl/info: exit status $? + sleep 2 + done + ''; + script = "echo Ok"; + serviceConfig = { + TimeoutSec = "300"; + }; + }; + systemd.services.kube-certmgr-bootstrap = { description = "Kubernetes certmgr bootstrapper"; - wantedBy = [ "certmgr.service" ]; - after = [ "cfssl.target" ]; + wantedBy = [ "cfssl-online.target" ]; + after = [ "cfssl-online.target" ]; + before = [ "certmgr.service" ]; + path = with pkgs; [ curl cfssl ]; script = concatStringsSep "\n" ['' set -e + mkdir -p $(dirname ${certmgrAPITokenPath}) + mkdir -p $(dirname ${top.caFile}) + # If there's a cfssl (cert issuer) running locally, then don't rely on user to # manually paste it in place. Just symlink. # otherwise, create the target file, ready for users to insert the token @@ -186,15 +218,18 @@ in fi '' (optionalString (cfg.pkiTrustOnBootstrap) '' - if [ ! -f "${top.caFile}" ] || [ $(cat "${top.caFile}" | wc -c) -lt 1 ]; then - ${pkgs.curl}/bin/curl --fail-early -f -kd '{}' ${remote}/api/v1/cfssl/info | \ - ${pkgs.cfssl}/bin/cfssljson -stdout >${top.caFile} + if [ ! -s "${top.caFile}" ]; then + until test -s ${top.caFile}.json; do + sleep 2 + curl --fail-early -fskd '{}' ${remote}/api/v1/cfssl/info -o ${top.caFile}.json + done + cfssljson -f ${top.caFile}.json -stdout >${top.caFile} + rm ${top.caFile}.json fi '') ]; serviceConfig = { - RestartSec = "10s"; - Restart = "on-failure"; + TimeoutSec = "500"; }; }; @@ -230,35 +265,28 @@ in mapAttrs mkSpec cfg.certs; }; - #TODO: Get rid of kube-addon-manager in the future for the following reasons - # - it is basically just a shell script wrapped around kubectl - # - it assumes that it is clusterAdmin or can gain clusterAdmin rights through serviceAccount - # - it is designed to be used with k8s system components only - # - it would be better with a more Nix-oriented way of managing addons - systemd.services.kube-addon-manager = mkIf top.addonManager.enable (mkMerge [{ - environment.KUBECONFIG = with cfg.certs.addonManager; - top.lib.mkKubeConfig "addon-manager" { - server = top.apiserverAddress; - certFile = cert; - keyFile = key; - }; - } - - (optionalAttrs (top.addonManager.bootstrapAddons != {}) { - serviceConfig.PermissionsStartOnly = true; - preStart = with pkgs; - let - files = mapAttrsToList (n: v: writeText "${n}.json" (builtins.toJSON v)) - top.addonManager.bootstrapAddons; - in - '' - export KUBECONFIG=${clusterAdminKubeconfig} - ${kubectl}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files} - ''; - })]); + systemd.services.certmgr = { + wantedBy = [ "cfssl-online.target" ]; + after = [ "cfssl-online.target" "kube-certmgr-bootstrap.service" ]; + preStart = '' + while ! test -s ${certmgrAPITokenPath} ; do + sleep 1 + echo Waiting for ${certmgrAPITokenPath} + done + ''; + unitConfig.ConditionPathExists = certmgrPaths; + }; + + systemd.paths.certmgr = { + wantedBy = [ "certmgr.service" ]; + pathConfig = { + PathExists = certmgrPaths; + PathChanged = certmgrPaths; + }; + }; environment.etc.${cfg.etcClusterAdminKubeconfig}.source = mkIf (!isNull cfg.etcClusterAdminKubeconfig) - clusterAdminKubeconfig; + (top.lib.mkKubeConfig "cluster-admin" clusterAdminKubeconfig); environment.systemPackages = mkIf (top.kubelet.enable || top.proxy.enable) [ (pkgs.writeScriptBin "nixos-kubernetes-node-join" '' @@ -284,38 +312,22 @@ in exit 1 fi + do_restart=$(test -s ${certmgrAPITokenPath} && echo -n y || echo -n n) + echo $token > ${certmgrAPITokenPath} chmod 600 ${certmgrAPITokenPath} - echo "Restarting certmgr..." >&1 - systemctl restart certmgr - - echo "Waiting for certs to appear..." >&1 - - ${optionalString top.kubelet.enable '' - while [ ! -f ${cfg.certs.kubelet.cert} ]; do sleep 1; done - echo "Restarting kubelet..." >&1 - systemctl restart kubelet - ''} - - ${optionalString top.proxy.enable '' - while [ ! -f ${cfg.certs.kubeProxyClient.cert} ]; do sleep 1; done - echo "Restarting kube-proxy..." >&1 - systemctl restart kube-proxy - ''} - - ${optionalString top.flannel.enable '' - while [ ! -f ${cfg.certs.flannelClient.cert} ]; do sleep 1; done - echo "Restarting flannel..." >&1 - systemctl restart flannel - ''} + if [ y = $do_restart ]; then + echo "Restarting certmgr..." >&1 + systemctl restart certmgr + fi - echo "Node joined succesfully" + echo "Node joined succesfully" >&1 '')]; # isolate etcd on loopback at the master node # easyCerts doesn't support multimaster clusters anyway atm. - services.etcd = with cfg.certs.etcd; { + services.etcd = mkIf top.apiserver.enable (with cfg.certs.etcd; { listenClientUrls = ["https://127.0.0.1:2379"]; listenPeerUrls = ["https://127.0.0.1:2380"]; advertiseClientUrls = ["https://etcd.local:2379"]; @@ -324,19 +336,11 @@ in certFile = mkDefault cert; keyFile = mkDefault key; trustedCaFile = mkDefault caCert; - }; + }); networking.extraHosts = mkIf (config.services.etcd.enable) '' 127.0.0.1 etcd.${top.addons.dns.clusterDomain} etcd.local ''; - services.flannel = with cfg.certs.flannelClient; { - kubeconfig = top.lib.mkKubeConfig "flannel" { - server = top.apiserverAddress; - certFile = cert; - keyFile = key; - }; - }; - services.kubernetes = { apiserver = mkIf top.apiserver.enable (with cfg.certs.apiServer; { @@ -353,7 +357,16 @@ in kubeletClientCaFile = mkDefault caCert; kubeletClientCertFile = mkDefault cfg.certs.apiserverKubeletClient.cert; kubeletClientKeyFile = mkDefault cfg.certs.apiserverKubeletClient.key; + proxyClientCertFile = mkDefault cfg.certs.apiserverProxyClient.cert; + proxyClientKeyFile = mkDefault cfg.certs.apiserverProxyClient.key; }); + addonManager = mkIf top.addonManager.enable { + kubeconfig = with cfg.certs.addonManager; { + certFile = mkDefault cert; + keyFile = mkDefault key; + }; + bootstrapAddonsKubeconfig = clusterAdminKubeconfig; + }; controllerManager = mkIf top.controllerManager.enable { serviceAccountKeyFile = mkDefault cfg.certs.serviceAccount.key; rootCaFile = cfg.certs.controllerManagerClient.caCert; @@ -362,6 +375,12 @@ in keyFile = mkDefault key; }; }; + flannel = mkIf top.flannel.enable { + kubeconfig = with cfg.certs.flannelClient; { + certFile = cert; + keyFile = key; + }; + }; scheduler = mkIf top.scheduler.enable { kubeconfig = with cfg.certs.schedulerClient; { certFile = mkDefault cert; diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix index 83cd3e231000..23f4d97b7030 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/proxy.nix @@ -17,7 +17,7 @@ in type = str; }; - enable = mkEnableOption "Whether to enable Kubernetes proxy."; + enable = mkEnableOption "Kubernetes proxy"; extraOpts = mkOption { description = "Kubernetes proxy extra command line options."; @@ -45,12 +45,28 @@ in }; ###### implementation - config = mkIf cfg.enable { - systemd.services.kube-proxy = { + config = let + + proxyPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + ]; + + in mkIf cfg.enable { + systemd.services.kube-proxy = rec { description = "Kubernetes Proxy Service"; - wantedBy = [ "kubernetes.target" ]; - after = [ "kube-apiserver.service" ]; - path = with pkgs; [ iptables conntrack_tools ]; + wantedBy = [ "kube-node-online.target" ]; + after = [ "kubelet-online.service" ]; + before = [ "kube-node-online.target" ]; + environment.KUBECONFIG = top.lib.mkKubeConfig "kube-proxy" cfg.kubeconfig; + path = with pkgs; [ iptables conntrack_tools kubectl ]; + preStart = '' + until kubectl auth can-i get nodes/${top.kubelet.hostname} -q 2>/dev/null; do + echo kubectl auth can-i get nodes/${top.kubelet.hostname}: exit status $? + sleep 2 + done + ''; serviceConfig = { Slice = "kubernetes.slice"; ExecStart = ''${top.package}/bin/kube-proxy \ @@ -59,7 +75,7 @@ in "--cluster-cidr=${top.clusterCidr}"} \ ${optionalString (cfg.featureGates != []) "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \ - --kubeconfig=${top.lib.mkKubeConfig "kube-proxy" cfg.kubeconfig} \ + --kubeconfig=${environment.KUBECONFIG} \ ${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \ ${cfg.extraOpts} ''; @@ -67,6 +83,15 @@ in Restart = "on-failure"; RestartSec = 5; }; + unitConfig.ConditionPathExists = proxyPaths; + }; + + systemd.paths.kube-proxy = { + wantedBy = [ "kube-proxy.service" ]; + pathConfig = { + PathExists = proxyPaths; + PathChanged = proxyPaths; + }; }; services.kubernetes.pki.certs = { diff --git a/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix b/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix index 0305b9aefe59..a0e484542951 100644 --- a/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix +++ b/nixpkgs/nixos/modules/services/cluster/kubernetes/scheduler.nix @@ -16,7 +16,7 @@ in type = str; }; - enable = mkEnableOption "Whether to enable Kubernetes scheduler."; + enable = mkEnableOption "Kubernetes scheduler"; extraOpts = mkOption { description = "Kubernetes scheduler extra command line options."; @@ -56,18 +56,35 @@ in }; ###### implementation - config = mkIf cfg.enable { - systemd.services.kube-scheduler = { + config = let + + schedulerPaths = filter (a: a != null) [ + cfg.kubeconfig.caFile + cfg.kubeconfig.certFile + cfg.kubeconfig.keyFile + ]; + + in mkIf cfg.enable { + systemd.services.kube-scheduler = rec { description = "Kubernetes Scheduler Service"; - wantedBy = [ "kubernetes.target" ]; + wantedBy = [ "kube-control-plane-online.target" ]; after = [ "kube-apiserver.service" ]; + before = [ "kube-control-plane-online.target" ]; + environment.KUBECONFIG = top.lib.mkKubeConfig "kube-scheduler" cfg.kubeconfig; + path = [ pkgs.kubectl ]; + preStart = '' + until kubectl auth can-i get /api -q 2>/dev/null; do + echo kubectl auth can-i get /api: exit status $? + sleep 2 + done + ''; serviceConfig = { Slice = "kubernetes.slice"; ExecStart = ''${top.package}/bin/kube-scheduler \ --address=${cfg.address} \ ${optionalString (cfg.featureGates != []) "--feature-gates=${concatMapStringsSep "," (feature: "${feature}=true") cfg.featureGates}"} \ - --kubeconfig=${top.lib.mkKubeConfig "kube-scheduler" cfg.kubeconfig} \ + --kubeconfig=${environment.KUBECONFIG} \ --leader-elect=${boolToString cfg.leaderElect} \ --port=${toString cfg.port} \ ${optionalString (cfg.verbosity != null) "--v=${toString cfg.verbosity}"} \ @@ -79,6 +96,15 @@ in Restart = "on-failure"; RestartSec = 5; }; + unitConfig.ConditionPathExists = schedulerPaths; + }; + + systemd.paths.kube-scheduler = { + wantedBy = [ "kube-scheduler.service" ]; + pathConfig = { + PathExists = schedulerPaths; + PathChanged = schedulerPaths; + }; }; services.kubernetes.pki.certs = { diff --git a/nixpkgs/nixos/modules/services/databases/clickhouse.nix b/nixpkgs/nixos/modules/services/databases/clickhouse.nix index 21e0cee34151..dbabcae43ee5 100644 --- a/nixpkgs/nixos/modules/services/databases/clickhouse.nix +++ b/nixpkgs/nixos/modules/services/databases/clickhouse.nix @@ -1,8 +1,6 @@ { config, lib, pkgs, ... }: let cfg = config.services.clickhouse; - confDir = "/etc/clickhouse-server"; - stateDir = "/var/lib/clickhouse"; in with lib; { @@ -43,20 +41,13 @@ with lib; after = [ "network.target" ]; - preStart = '' - mkdir -p ${stateDir} - chown clickhouse:clickhouse ${confDir} ${stateDir} - ''; - - script = '' - cd "${confDir}" - exec ${pkgs.clickhouse}/bin/clickhouse-server - ''; - serviceConfig = { User = "clickhouse"; Group = "clickhouse"; - PermissionsStartOnly = true; + ConfigurationDirectory = "clickhouse-server"; + StateDirectory = "clickhouse"; + LogsDirectory = "clickhouse"; + ExecStart = "${pkgs.clickhouse}/bin/clickhouse-server --config-file=${pkgs.clickhouse}/etc/clickhouse-server/config.xml"; }; }; diff --git a/nixpkgs/nixos/modules/services/databases/couchdb.nix b/nixpkgs/nixos/modules/services/databases/couchdb.nix index 84d108d9c747..5ddf8ba4bfbd 100644 --- a/nixpkgs/nixos/modules/services/databases/couchdb.nix +++ b/nixpkgs/nixos/modules/services/databases/couchdb.nix @@ -158,27 +158,21 @@ in { services.couchdb.configFile = mkDefault (if useVersion2 then "/var/lib/couchdb/local.ini" else "/var/lib/couchdb/couchdb.ini"); + systemd.tmpfiles.rules = [ + "d '${dirOf cfg.uriFile}' - ${cfg.user} ${cfg.group} - -" + "d '${dirOf cfg.logFile}' - ${cfg.user} ${cfg.group} - -" + "d '${cfg.databaseDir}' - ${cfg.user} ${cfg.group} - -" + "d '${cfg.viewIndexDir}' - ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.couchdb = { description = "CouchDB Server"; wantedBy = [ "multi-user.target" ]; preStart = '' - mkdir -p `dirname ${cfg.uriFile}`; - mkdir -p `dirname ${cfg.logFile}`; - mkdir -p ${cfg.databaseDir}; - mkdir -p ${cfg.viewIndexDir}; touch ${cfg.configFile} touch -a ${cfg.logFile} - - if [ "$(id -u)" = 0 ]; then - chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`; - (test -f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true - chown ${cfg.user}:${cfg.group} ${cfg.databaseDir} - chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir} - chown ${cfg.user}:${cfg.group} ${cfg.configFile} - chown ${cfg.user}:${cfg.group} ${cfg.logFile} - fi ''; environment = mkIf useVersion2 { @@ -191,7 +185,6 @@ in { }; serviceConfig = { - PermissionsStartOnly = true; User = cfg.user; Group = cfg.group; ExecStart = executable; diff --git a/nixpkgs/nixos/modules/services/databases/influxdb.nix b/nixpkgs/nixos/modules/services/databases/influxdb.nix index 888bf13c3df8..6868050c8446 100644 --- a/nixpkgs/nixos/modules/services/databases/influxdb.nix +++ b/nixpkgs/nixos/modules/services/databases/influxdb.nix @@ -157,20 +157,19 @@ in config = mkIf config.services.influxdb.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.influxdb = { description = "InfluxDB Server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { ExecStart = ''${cfg.package}/bin/influxd -config "${configFile}"''; - User = "${cfg.user}"; - Group = "${cfg.group}"; - PermissionsStartOnly = true; + User = cfg.user; + Group = cfg.group; }; - preStart = '' - mkdir -m 0770 -p ${cfg.dataDir} - if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi - ''; postStart = let scheme = if configOptions.http.https-enabled then "-k https" else "http"; diff --git a/nixpkgs/nixos/modules/services/databases/memcached.nix b/nixpkgs/nixos/modules/services/databases/memcached.nix index 7af452e4dced..052ff1f308eb 100644 --- a/nixpkgs/nixos/modules/services/databases/memcached.nix +++ b/nixpkgs/nixos/modules/services/databases/memcached.nix @@ -78,11 +78,6 @@ in after = [ "network.target" ]; serviceConfig = { - PermissionsStartOnly = true; - ExecStartPre = optionals cfg.enableUnixSocket [ - "${pkgs.coreutils}/bin/install -d -o ${cfg.user} /run/memcached/" - "${pkgs.coreutils}/bin/chown -R ${cfg.user} /run/memcached/" - ]; ExecStart = let networking = if cfg.enableUnixSocket @@ -91,12 +86,13 @@ in in "${memcached}/bin/memcached ${networking} -m ${toString cfg.maxMemory} -c ${toString cfg.maxConnections} ${concatStringsSep " " cfg.extraOptions}"; User = cfg.user; + RuntimeDirectory = "memcached"; }; }; }; imports = [ (mkRemovedOptionModule ["services" "memcached" "socket"] '' - This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memached.enableUnixSocket. + This option was replaced by a fixed unix socket path at /run/memcached/memcached.sock enabled using services.memcached.enableUnixSocket. '') ]; diff --git a/nixpkgs/nixos/modules/services/databases/stanchion.nix b/nixpkgs/nixos/modules/services/databases/stanchion.nix index 9fe49f51edd2..97e55bc70c47 100644 --- a/nixpkgs/nixos/modules/services/databases/stanchion.nix +++ b/nixpkgs/nixos/modules/services/databases/stanchion.nix @@ -98,7 +98,7 @@ in type = types.path; default = "/var/log/stanchion"; description = '' - Log directory for Stanchino. + Log directory for Stanchion. ''; }; @@ -152,6 +152,11 @@ in users.groups.stanchion.gid = config.ids.gids.stanchion; + systemd.tmpfiles.rules = [ + "d '${cfg.logDir}' - stanchion stanchion --" + "d '${cfg.dataDir}' 0700 stanchion stanchion --" + ]; + systemd.services.stanchion = { description = "Stanchion Server"; @@ -168,25 +173,12 @@ in environment.STANCHION_LOG_DIR = "${cfg.logDir}"; environment.STANCHION_ETC_DIR = "/etc/stanchion"; - preStart = '' - if ! test -e ${cfg.logDir}; then - mkdir -m 0755 -p ${cfg.logDir} - chown -R stanchion:stanchion ${cfg.logDir} - fi - - if ! test -e ${cfg.dataDir}; then - mkdir -m 0700 -p ${cfg.dataDir} - chown -R stanchion:stanchion ${cfg.dataDir} - fi - ''; - serviceConfig = { ExecStart = "${cfg.package}/bin/stanchion console"; ExecStop = "${cfg.package}/bin/stanchion stop"; StandardInput = "tty"; User = "stanchion"; Group = "stanchion"; - PermissionsStartOnly = true; # Give Stanchion a decent amount of time to clean up. TimeoutStopSec = 120; LimitNOFILE = 65536; diff --git a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix index dbf0f4e9b118..7f7adcf26acf 100644 --- a/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix +++ b/nixpkgs/nixos/modules/services/desktops/gnome3/gnome-settings-daemon.nix @@ -18,7 +18,7 @@ in services.gnome3.gnome-settings-daemon = { - enable = mkEnableOption "GNOME Settings Daemon."; + enable = mkEnableOption "GNOME Settings Daemon"; # There are many forks of gnome-settings-daemon package = mkOption { diff --git a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix index 2a8dfe4a66c9..c5f9d1f9b725 100644 --- a/nixpkgs/nixos/modules/services/hardware/bluetooth.nix +++ b/nixpkgs/nixos/modules/services/hardware/bluetooth.nix @@ -13,7 +13,7 @@ in { options = { hardware.bluetooth = { - enable = mkEnableOption "support for Bluetooth."; + enable = mkEnableOption "support for Bluetooth"; powerOnBoot = mkOption { type = types.bool; diff --git a/nixpkgs/nixos/modules/services/hardware/vdr.nix b/nixpkgs/nixos/modules/services/hardware/vdr.nix index 4822506a899b..6e246f70f515 100644 --- a/nixpkgs/nixos/modules/services/hardware/vdr.nix +++ b/nixpkgs/nixos/modules/services/hardware/vdr.nix @@ -12,7 +12,7 @@ in { options = { services.vdr = { - enable = mkEnableOption "enable VDR. Please put config into ${libDir}."; + enable = mkEnableOption "VDR. Please put config into ${libDir}"; package = mkOption { type = types.package; @@ -34,7 +34,7 @@ in { description = "Additional command line arguments to pass to VDR."; }; - enableLirc = mkEnableOption "enable LIRC"; + enableLirc = mkEnableOption "LIRC"; }; }; diff --git a/nixpkgs/nixos/modules/services/mail/mailcatcher.nix b/nixpkgs/nixos/modules/services/mail/mailcatcher.nix index 2c6aadadce9d..fa8d41e918d3 100644 --- a/nixpkgs/nixos/modules/services/mail/mailcatcher.nix +++ b/nixpkgs/nixos/modules/services/mail/mailcatcher.nix @@ -11,7 +11,7 @@ in options = { services.mailcatcher = { - enable = mkEnableOption "Enable MailCatcher."; + enable = mkEnableOption "MailCatcher"; http.ip = mkOption { type = types.str; diff --git a/nixpkgs/nixos/modules/services/mail/nullmailer.nix b/nixpkgs/nixos/modules/services/mail/nullmailer.nix index 418c02af4b7f..9997d287013e 100644 --- a/nixpkgs/nixos/modules/services/mail/nullmailer.nix +++ b/nixpkgs/nixos/modules/services/mail/nullmailer.nix @@ -212,6 +212,10 @@ with lib; }; }; + systemd.tmpfiles.rules = [ + "d /var/spool/nullmailer - ${cfg.user} - - -" + ]; + systemd.services.nullmailer = { description = "nullmailer"; wantedBy = [ "multi-user.target" ]; @@ -220,13 +224,11 @@ with lib; preStart = '' mkdir -p /var/spool/nullmailer/{queue,tmp} rm -f /var/spool/nullmailer/trigger && mkfifo -m 660 /var/spool/nullmailer/trigger - chown ${cfg.user} /var/spool/nullmailer/* ''; serviceConfig = { User = cfg.user; Group = cfg.group; - PermissionsStartOnly=true; ExecStart = "${pkgs.nullmailer}/bin/nullmailer-send"; Restart = "always"; }; diff --git a/nixpkgs/nixos/modules/services/mail/offlineimap.nix b/nixpkgs/nixos/modules/services/mail/offlineimap.nix index 4b24bd8d0813..294e3806f94a 100644 --- a/nixpkgs/nixos/modules/services/mail/offlineimap.nix +++ b/nixpkgs/nixos/modules/services/mail/offlineimap.nix @@ -7,7 +7,7 @@ let in { options.services.offlineimap = { - enable = mkEnableOption "Offlineimap, a software to dispose your mailbox(es) as a local Maildir(s)."; + enable = mkEnableOption "OfflineIMAP, a software to dispose your mailbox(es) as a local Maildir(s)"; install = mkOption { type = types.bool; diff --git a/nixpkgs/nixos/modules/services/mail/rss2email.nix b/nixpkgs/nixos/modules/services/mail/rss2email.nix index 5f3b2877008f..a123736005ab 100644 --- a/nixpkgs/nixos/modules/services/mail/rss2email.nix +++ b/nixpkgs/nixos/modules/services/mail/rss2email.nix @@ -94,6 +94,10 @@ in { services.rss2email.config.to = cfg.to; + systemd.tmpfiles.rules = [ + "d /var/rss2email 0700 rss2email rss2email - -" + ]; + systemd.services.rss2email = let conf = pkgs.writeText "rss2email.cfg" (lib.generators.toINI {} ({ DEFAULT = cfg.config; @@ -105,22 +109,16 @@ in { in { preStart = '' - mkdir -p /var/rss2email - chmod 700 /var/rss2email - cp ${conf} /var/rss2email/conf.cfg if [ ! -f /var/rss2email/db.json ]; then echo '{"version":2,"feeds":[]}' > /var/rss2email/db.json fi - - chown -R rss2email:rss2email /var/rss2email ''; path = [ pkgs.system-sendmail ]; serviceConfig = { ExecStart = "${pkgs.rss2email}/bin/r2e -c /var/rss2email/conf.cfg -d /var/rss2email/db.json run"; User = "rss2email"; - PermissionsStartOnly = "true"; }; }; diff --git a/nixpkgs/nixos/modules/services/misc/beanstalkd.nix b/nixpkgs/nixos/modules/services/misc/beanstalkd.nix index 8a3e0ab1949a..06e881406b52 100644 --- a/nixpkgs/nixos/modules/services/misc/beanstalkd.nix +++ b/nixpkgs/nixos/modules/services/misc/beanstalkd.nix @@ -12,7 +12,7 @@ in options = { services.beanstalkd = { - enable = mkEnableOption "Enable the Beanstalk work queue."; + enable = mkEnableOption "the Beanstalk work queue"; listen = { port = mkOption { diff --git a/nixpkgs/nixos/modules/services/misc/etcd.nix b/nixpkgs/nixos/modules/services/misc/etcd.nix index 2d1893dae64b..e4d5322f9b5f 100644 --- a/nixpkgs/nixos/modules/services/misc/etcd.nix +++ b/nixpkgs/nixos/modules/services/misc/etcd.nix @@ -142,6 +142,10 @@ in { }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 etcd - - -" + ]; + systemd.services.etcd = { description = "etcd key-value store"; wantedBy = [ "multi-user.target" ]; @@ -176,14 +180,8 @@ in { Type = "notify"; ExecStart = "${pkgs.etcd.bin}/bin/etcd"; User = "etcd"; - PermissionsStartOnly = true; LimitNOFILE = 40000; }; - - preStart = '' - mkdir -m 0700 -p ${cfg.dataDir} - if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi - ''; }; environment.systemPackages = [ pkgs.etcdctl ]; diff --git a/nixpkgs/nixos/modules/services/misc/jackett.nix b/nixpkgs/nixos/modules/services/misc/jackett.nix index b18ce2b1f81a..a07f20e5c24b 100644 --- a/nixpkgs/nixos/modules/services/misc/jackett.nix +++ b/nixpkgs/nixos/modules/services/misc/jackett.nix @@ -38,24 +38,19 @@ in }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.jackett = { description = "Jackett"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - test -d ${cfg.dataDir} || { - echo "Creating jackett data directory in ${cfg.dataDir}" - mkdir -p ${cfg.dataDir} - } - chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} - chmod 0700 ${cfg.dataDir} - ''; serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = "true"; ExecStart = "${pkgs.jackett}/bin/Jackett --NoUpdates --DataFolder '${cfg.dataDir}'"; Restart = "on-failure"; }; diff --git a/nixpkgs/nixos/modules/services/misc/lidarr.nix b/nixpkgs/nixos/modules/services/misc/lidarr.nix index 627f22334fe8..f466402abfc7 100644 --- a/nixpkgs/nixos/modules/services/misc/lidarr.nix +++ b/nixpkgs/nixos/modules/services/misc/lidarr.nix @@ -17,20 +17,15 @@ in description = "Lidarr"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - [ ! -d /var/lib/lidarr ] && mkdir -p /var/lib/lidarr - chown -R lidarr:lidarr /var/lib/lidarr - ''; serviceConfig = { Type = "simple"; User = "lidarr"; Group = "lidarr"; - PermissionsStartOnly = "true"; ExecStart = "${pkgs.lidarr}/bin/Lidarr"; Restart = "on-failure"; - StateDirectory = "/var/lib/lidarr/"; + StateDirectory = "lidarr"; StateDirectoryMode = "0770"; }; }; diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix index 5e465926b832..00c8e7408030 100644 --- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix @@ -554,7 +554,10 @@ in { }; trusted_third_party_id_servers = mkOption { type = types.listOf types.str; - default = ["matrix.org"]; + default = [ + "matrix.org" + "vector.im" + ]; description = '' The list of identity servers trusted to verify third party identifiers by this server. ''; diff --git a/nixpkgs/nixos/modules/services/misc/mesos-master.nix b/nixpkgs/nixos/modules/services/misc/mesos-master.nix index 0523c6549ed6..572a9847e46c 100644 --- a/nixpkgs/nixos/modules/services/misc/mesos-master.nix +++ b/nixpkgs/nixos/modules/services/misc/mesos-master.nix @@ -95,6 +95,9 @@ in { config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.workDir}' 0700 - - - -" + ]; systemd.services.mesos-master = { description = "Mesos Master"; wantedBy = [ "multi-user.target" ]; @@ -114,11 +117,7 @@ in { ${toString cfg.extraCmdLineOptions} ''; Restart = "on-failure"; - PermissionsStartOnly = true; }; - preStart = '' - mkdir -m 0700 -p ${cfg.workDir} - ''; }; }; diff --git a/nixpkgs/nixos/modules/services/misc/mesos-slave.nix b/nixpkgs/nixos/modules/services/misc/mesos-slave.nix index 468c7f36ecc5..170065d0065e 100644 --- a/nixpkgs/nixos/modules/services/misc/mesos-slave.nix +++ b/nixpkgs/nixos/modules/services/misc/mesos-slave.nix @@ -184,6 +184,9 @@ in { }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.workDir}' 0701 - - - -" + ]; systemd.services.mesos-slave = { description = "Mesos Slave"; wantedBy = [ "multi-user.target" ]; @@ -210,11 +213,7 @@ in { --executor_environment_variables=${lib.escapeShellArg (builtins.toJSON cfg.executorEnvironmentVariables)} \ ${toString cfg.extraCmdLineOptions} ''; - PermissionsStartOnly = true; }; - preStart = '' - mkdir -m 0701 -p ${cfg.workDir} - ''; }; }; diff --git a/nixpkgs/nixos/modules/services/misc/plex.nix b/nixpkgs/nixos/modules/services/misc/plex.nix index fce9b29011f1..7efadf1b9bb1 100644 --- a/nixpkgs/nixos/modules/services/misc/plex.nix +++ b/nixpkgs/nixos/modules/services/misc/plex.nix @@ -10,35 +10,38 @@ in services.plex = { enable = mkEnableOption "Plex Media Server"; - # FIXME: In order for this config option to work, symlinks in the Plex - # package in the Nix store have to be changed to point to this directory. dataDir = mkOption { type = types.str; default = "/var/lib/plex"; - description = "The directory where Plex stores its data files."; + description = '' + The directory where Plex stores its data files. + ''; }; openFirewall = mkOption { type = types.bool; default = false; description = '' - Open ports in the firewall for the media server + Open ports in the firewall for the media server. ''; }; user = mkOption { type = types.str; default = "plex"; - description = "User account under which Plex runs."; + description = '' + User account under which Plex runs. + ''; }; group = mkOption { type = types.str; default = "plex"; - description = "Group under which Plex runs."; + description = '' + Group under which Plex runs. + ''; }; - managePlugins = mkOption { type = types.bool; default = true; @@ -80,73 +83,48 @@ in description = "Plex Media Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - test -d "${cfg.dataDir}/Plex Media Server" || { - echo "Creating initial Plex data directory in \"${cfg.dataDir}\"." - mkdir -p "${cfg.dataDir}/Plex Media Server" - chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" - } - - # Copy the database skeleton files to /var/lib/plex/.skeleton - # See the the Nix expression for Plex's package for more information on - # why this is done. - install --owner ${cfg.user} --group ${cfg.group} -d "${cfg.dataDir}/.skeleton" - for db in "com.plexapp.plugins.library.db"; do - if [ ! -e "${cfg.dataDir}/.skeleton/$db" ]; then - cp "${cfg.package}/usr/lib/plexmediaserver/Resources/base_$db" "${cfg.dataDir}/.skeleton/$db" - fi - chmod u+w "${cfg.dataDir}/.skeleton/$db" - chown ${cfg.user}:${cfg.group} "${cfg.dataDir}/.skeleton/$db" - done - - # If managePlugins is enabled, setup symlinks for plugins. - ${optionalString cfg.managePlugins '' - echo "Preparing plugin directory." - PLUGINDIR="${cfg.dataDir}/Plex Media Server/Plug-ins" - test -d "$PLUGINDIR" || { - mkdir -p "$PLUGINDIR"; - chown ${cfg.user}:${cfg.group} "$PLUGINDIR"; - } - - echo "Removing old symlinks." - # First, remove all of the symlinks in the directory. - for f in `ls "$PLUGINDIR/"`; do - if [[ -L "$PLUGINDIR/$f" ]]; then - echo "Removing plugin symlink $PLUGINDIR/$f." - rm "$PLUGINDIR/$f" - fi - done - - echo "Symlinking plugins." - for path in ${toString cfg.extraPlugins}; do - dest="$PLUGINDIR/$(basename $path)" - if [[ ! -d "$path" ]]; then - echo "Error symlinking plugin from $path: no such directory." - elif [[ -d "$dest" || -L "$dest" ]]; then - echo "Error symlinking plugin from $path to $dest: file or directory already exists." - else - echo "Symlinking plugin at $path..." - ln -s "$path" "$dest" - fi - done - ''} - ''; + serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = "true"; - ExecStart = "\"${cfg.package}/usr/lib/plexmediaserver/Plex Media Server\""; + + # Run the pre-start script with full permissions (the "!" prefix) so it + # can create the data directory if necessary. + ExecStartPre = let + preStartScript = pkgs.writeScript "plex-run-prestart" '' + #!${pkgs.bash}/bin/bash + + # Create data directory if it doesn't exist + if ! test -d "$PLEX_DATADIR"; then + echo "Creating initial Plex data directory in: $PLEX_DATADIR" + install -d -m 0755 -o "${cfg.user}" -g "${cfg.group}" "$PLEX_DATADIR" + fi + ''; + in + "!${preStartScript}"; + + ExecStart = "${cfg.package}/bin/plexmediaserver"; KillSignal = "SIGQUIT"; Restart = "on-failure"; }; + environment = { - PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=cfg.dataDir; - PLEX_MEDIA_SERVER_HOME="${cfg.package}/usr/lib/plexmediaserver"; + # Configuration for our FHS userenv script + PLEX_DATADIR=cfg.dataDir; + PLEX_PLUGINS=concatMapStringsSep ":" builtins.toString cfg.extraPlugins; + + # The following variables should be set by the FHS userenv script: + # PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR + # PLEX_MEDIA_SERVER_HOME + + # Allow access to GPU acceleration; the Plex LD_LIBRARY_PATH is added + # by the FHS userenv script. + LD_LIBRARY_PATH="/run/opengl-driver/lib"; + PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS="6"; PLEX_MEDIA_SERVER_TMPDIR="/tmp"; PLEX_MEDIA_SERVER_USE_SYSLOG="true"; - LD_LIBRARY_PATH="/run/opengl-driver/lib:${cfg.package}/usr/lib/plexmediaserver/lib"; LC_ALL="en_US.UTF-8"; LANG="en_US.UTF-8"; }; diff --git a/nixpkgs/nixos/modules/services/misc/radarr.nix b/nixpkgs/nixos/modules/services/misc/radarr.nix index 9ab26d848325..74444e24043f 100644 --- a/nixpkgs/nixos/modules/services/misc/radarr.nix +++ b/nixpkgs/nixos/modules/services/misc/radarr.nix @@ -38,24 +38,19 @@ in }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.radarr = { description = "Radarr"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - test -d ${cfg.dataDir} || { - echo "Creating radarr data directory in ${cfg.dataDir}" - mkdir -p ${cfg.dataDir} - } - chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} - chmod 0700 ${cfg.dataDir} - ''; serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = "true"; ExecStart = "${pkgs.radarr}/bin/Radarr -nobrowser -data='${cfg.dataDir}'"; Restart = "on-failure"; }; diff --git a/nixpkgs/nixos/modules/services/misc/sonarr.nix b/nixpkgs/nixos/modules/services/misc/sonarr.nix index a99445a268d7..77c7f0582d0b 100644 --- a/nixpkgs/nixos/modules/services/misc/sonarr.nix +++ b/nixpkgs/nixos/modules/services/misc/sonarr.nix @@ -39,24 +39,19 @@ in }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.sonarr = { description = "Sonarr"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - test -d ${cfg.dataDir} || { - echo "Creating sonarr data directory in ${cfg.dataDir}" - mkdir -p ${cfg.dataDir} - } - chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} - chmod 0700 ${cfg.dataDir} - ''; serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = "true"; ExecStart = "${pkgs.sonarr}/bin/NzbDrone -nobrowser -data='${cfg.dataDir}'"; Restart = "on-failure"; }; diff --git a/nixpkgs/nixos/modules/services/misc/sssd.nix b/nixpkgs/nixos/modules/services/misc/sssd.nix index fe472a6c68e5..6b64045dde88 100644 --- a/nixpkgs/nixos/modules/services/misc/sssd.nix +++ b/nixpkgs/nixos/modules/services/misc/sssd.nix @@ -6,7 +6,7 @@ let in { options = { services.sssd = { - enable = mkEnableOption "the System Security Services Daemon."; + enable = mkEnableOption "the System Security Services Daemon"; config = mkOption { type = types.lines; diff --git a/nixpkgs/nixos/modules/services/misc/zookeeper.nix b/nixpkgs/nixos/modules/services/misc/zookeeper.nix index cb7cc97d5a5c..50c84e3c6b80 100644 --- a/nixpkgs/nixos/modules/services/misc/zookeeper.nix +++ b/nixpkgs/nixos/modules/services/misc/zookeeper.nix @@ -119,6 +119,10 @@ in { config = mkIf cfg.enable { environment.systemPackages = [cfg.package]; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 zookeeper - - -" + ]; + systemd.services.zookeeper = { description = "Zookeeper Daemon"; wantedBy = [ "multi-user.target" ]; @@ -135,11 +139,8 @@ in { ${configDir}/zoo.cfg ''; User = "zookeeper"; - PermissionsStartOnly = true; }; preStart = '' - mkdir -m 0700 -p ${cfg.dataDir} - if [ "$(id -u)" = 0 ]; then chown zookeeper ${cfg.dataDir}; fi echo "${toString cfg.id}" > ${cfg.dataDir}/myid ''; }; diff --git a/nixpkgs/nixos/modules/services/monitoring/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/collectd.nix index 45e3312c0f44..6a4c678eb21f 100644 --- a/nixpkgs/nixos/modules/services/monitoring/collectd.nix +++ b/nixpkgs/nixos/modules/services/monitoring/collectd.nix @@ -79,6 +79,10 @@ in { }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' - ${cfg.user} - - -" + ]; + systemd.services.collectd = { description = "Collectd Monitoring Agent"; after = [ "network.target" ]; @@ -87,16 +91,9 @@ in { serviceConfig = { ExecStart = "${cfg.package}/sbin/collectd -C ${conf} -f"; User = cfg.user; - PermissionsStartOnly = true; Restart = "on-failure"; RestartSec = 3; }; - - preStart = '' - mkdir -p "${cfg.dataDir}" - chmod 755 "${cfg.dataDir}" - chown -R ${cfg.user} "${cfg.dataDir}" - ''; }; users.users = optional (cfg.user == "collectd") { diff --git a/nixpkgs/nixos/modules/services/monitoring/graphite.nix b/nixpkgs/nixos/modules/services/monitoring/graphite.nix index f59bc56962b1..2365142af40e 100644 --- a/nixpkgs/nixos/modules/services/monitoring/graphite.nix +++ b/nixpkgs/nixos/modules/services/monitoring/graphite.nix @@ -123,7 +123,7 @@ in { graphite carbon. For more information visit - <link xlink:href="http://graphite-api.readthedocs.org/en/latest/"/> + <link xlink:href="https://graphite-api.readthedocs.org/en/latest/"/> ''; default = false; type = types.bool; diff --git a/nixpkgs/nixos/modules/services/monitoring/munin.nix b/nixpkgs/nixos/modules/services/monitoring/munin.nix index f67986327245..ffe223fedbe1 100644 --- a/nixpkgs/nixos/modules/services/monitoring/munin.nix +++ b/nixpkgs/nixos/modules/services/monitoring/munin.nix @@ -8,7 +8,7 @@ # spawn-fcgi -s /run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph # spawn-fcgi -s /run/munin/fastcgi-html.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html # https://paste.sh/vofcctHP#-KbDSXVeWoifYncZmLfZzgum -# nginx http://munin.readthedocs.org/en/latest/example/webserver/nginx.html +# nginx https://munin.readthedocs.org/en/latest/example/webserver/nginx.html with lib; diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix index e7ac12c07d33..d8384e0d35b3 100644 --- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix @@ -22,9 +22,6 @@ let workingDir = stateDirBase + stateDir; workingDir2 = stateDirBase + cfg2.stateDir; - # Get a submodule without any embedded metadata: - _filter = x: filterAttrs (k: v: k != "_module") x; - # a wrapper that verifies that the configuration is valid promtoolCheck = what: name: file: pkgs.runCommand "${name}-${what}-checked" { buildInputs = [ cfg.package ]; } '' @@ -50,11 +47,11 @@ let # This becomes the main config file for Prometheus 1 promConfig = { - global = cfg.globalConfig; + global = filterValidPrometheus cfg.globalConfig; rule_files = map (promtoolCheck "check-rules" "rules") (cfg.ruleFiles ++ [ (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules)) ]); - scrape_configs = filterEmpty cfg.scrapeConfigs; + scrape_configs = filterValidPrometheus cfg.scrapeConfigs; }; generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig; @@ -77,11 +74,11 @@ let # This becomes the main config file for Prometheus 2 promConfig2 = { - global = cfg2.globalConfig; + global = filterValidPrometheus cfg2.globalConfig; rule_files = map (prom2toolCheck "check rules" "rules") (cfg2.ruleFiles ++ [ (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg2.rules)) ]); - scrape_configs = filterEmpty cfg2.scrapeConfigs; + scrape_configs = filterValidPrometheus cfg2.scrapeConfigs; alerting = optionalAttrs (cfg2.alertmanagerURL != []) { alertmanagers = [{ static_configs = [{ @@ -108,7 +105,7 @@ let ] ++ optional (cfg2.webExternalUrl != null) "--web.external-url=${cfg2.webExternalUrl}"; - filterEmpty = filterAttrsListRecursive (_n: v: !(v == null || v == [] || v == {})); + filterValidPrometheus = filterAttrsListRecursive (n: v: !(n == "_module" || v == null)); filterAttrsListRecursive = pred: x: if isAttrs x then listToAttrs ( @@ -123,41 +120,37 @@ let map (filterAttrsListRecursive pred) x else x; - promTypes.globalConfig = types.submodule { - options = { - scrape_interval = mkOption { - type = types.str; - default = "1m"; - description = '' - How frequently to scrape targets by default. - ''; - }; + mkDefOpt = type : defaultStr : description : mkOpt type (description + '' - scrape_timeout = mkOption { - type = types.str; - default = "10s"; - description = '' - How long until a scrape request times out. - ''; - }; + Defaults to <literal>${defaultStr}</literal> in prometheus + when set to <literal>null</literal>. + ''); - evaluation_interval = mkOption { - type = types.str; - default = "1m"; - description = '' - How frequently to evaluate rules by default. - ''; - }; + mkOpt = type : description : mkOption { + type = types.nullOr type; + default = null; + inherit description; + }; - external_labels = mkOption { - type = types.attrsOf types.str; - description = '' - The labels to add to any time series or alerts when - communicating with external systems (federation, remote - storage, Alertmanager). - ''; - default = {}; - }; + promTypes.globalConfig = types.submodule { + options = { + scrape_interval = mkDefOpt types.str "1m" '' + How frequently to scrape targets by default. + ''; + + scrape_timeout = mkDefOpt types.str "10s" '' + How long until a scrape request times out. + ''; + + evaluation_interval = mkDefOpt types.str "1m" '' + How frequently to evaluate rules by default. + ''; + + external_labels = mkOpt (types.attrsOf types.str) '' + The labels to add to any time series or alerts when + communicating with external systems (federation, remote + storage, Alertmanager). + ''; }; }; @@ -169,145 +162,127 @@ let The job name assigned to scraped metrics by default. ''; }; - scrape_interval = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - How frequently to scrape targets from this job. Defaults to the - globally configured default. - ''; - }; - scrape_timeout = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Per-target timeout when scraping this job. Defaults to the - globally configured default. - ''; - }; - metrics_path = mkOption { - type = types.str; - default = "/metrics"; - description = '' - The HTTP resource path on which to fetch metrics from targets. - ''; - }; - honor_labels = mkOption { - type = types.bool; - default = false; - description = '' - Controls how Prometheus handles conflicts between labels - that are already present in scraped data and labels that - Prometheus would attach server-side ("job" and "instance" - labels, manually configured target labels, and labels - generated by service discovery implementations). - - If honor_labels is set to "true", label conflicts are - resolved by keeping label values from the scraped data and - ignoring the conflicting server-side labels. - - If honor_labels is set to "false", label conflicts are - resolved by renaming conflicting labels in the scraped data - to "exported_<original-label>" (for example - "exported_instance", "exported_job") and then attaching - server-side labels. This is useful for use cases such as - federation, where all labels specified in the target should - be preserved. - ''; - }; - scheme = mkOption { - type = types.enum ["http" "https"]; - default = "http"; - description = '' - The URL scheme with which to fetch metrics from targets. - ''; - }; - params = mkOption { - type = types.attrsOf (types.listOf types.str); - default = {}; - description = '' - Optional HTTP URL parameters. - ''; - }; - basic_auth = mkOption { - type = types.nullOr (types.submodule { - options = { - username = mkOption { - type = types.str; - description = '' - HTTP username - ''; - }; - password = mkOption { - type = types.str; - description = '' - HTTP password - ''; - }; + scrape_interval = mkOpt types.str '' + How frequently to scrape targets from this job. Defaults to the + globally configured default. + ''; + + scrape_timeout = mkOpt types.str '' + Per-target timeout when scraping this job. Defaults to the + globally configured default. + ''; + + metrics_path = mkDefOpt types.str "/metrics" '' + The HTTP resource path on which to fetch metrics from targets. + ''; + + honor_labels = mkDefOpt types.bool "false" '' + Controls how Prometheus handles conflicts between labels + that are already present in scraped data and labels that + Prometheus would attach server-side ("job" and "instance" + labels, manually configured target labels, and labels + generated by service discovery implementations). + + If honor_labels is set to "true", label conflicts are + resolved by keeping label values from the scraped data and + ignoring the conflicting server-side labels. + + If honor_labels is set to "false", label conflicts are + resolved by renaming conflicting labels in the scraped data + to "exported_<original-label>" (for example + "exported_instance", "exported_job") and then attaching + server-side labels. This is useful for use cases such as + federation, where all labels specified in the target should + be preserved. + ''; + + honor_timestamps = mkDefOpt types.bool "true" '' + honor_timestamps controls whether Prometheus respects the timestamps present + in scraped data. + + If honor_timestamps is set to <literal>true</literal>, the timestamps of the metrics exposed + by the target will be used. + + If honor_timestamps is set to <literal>false</literal>, the timestamps of the metrics exposed + by the target will be ignored. + ''; + + scheme = mkDefOpt (types.enum ["http" "https"]) "http" '' + The URL scheme with which to fetch metrics from targets. + ''; + + params = mkOpt (types.attrsOf (types.listOf types.str)) '' + Optional HTTP URL parameters. + ''; + + basic_auth = mkOpt (types.submodule { + options = { + username = mkOption { + type = types.str; + description = '' + HTTP username + ''; }; - }); - default = null; - apply = x: mapNullable _filter x; - description = '' - Optional http login credentials for metrics scraping. - ''; - }; - tls_config = mkOption { - type = types.nullOr promTypes.tls_config; - default = null; - apply = x: mapNullable _filter x; - description = '' - Configures the scrape request's TLS settings. - ''; - }; - dns_sd_configs = mkOption { - type = types.listOf promTypes.dns_sd_config; - default = []; - apply = x: map _filter x; - description = '' - List of DNS service discovery configurations. - ''; - }; - consul_sd_configs = mkOption { - type = types.listOf promTypes.consul_sd_config; - default = []; - apply = x: map _filter x; - description = '' - List of Consul service discovery configurations. - ''; - }; - file_sd_configs = mkOption { - type = types.listOf promTypes.file_sd_config; - default = []; - apply = x: map _filter x; - description = '' - List of file service discovery configurations. - ''; - }; - static_configs = mkOption { - type = types.listOf promTypes.static_config; - default = []; - apply = x: map _filter x; - description = '' - List of labeled target groups for this job. - ''; - }; - ec2_sd_configs = mkOption { - type = types.listOf promTypes.ec2_sd_config; - default = []; - apply = x: map _filter x; - description = '' - List of EC2 service discovery configurations. - ''; - }; - relabel_configs = mkOption { - type = types.listOf promTypes.relabel_config; - default = []; - apply = x: map _filter x; - description = '' - List of relabel configurations. - ''; - }; + password = mkOption { + type = types.str; + description = '' + HTTP password + ''; + }; + }; + }) '' + Optional http login credentials for metrics scraping. + ''; + + bearer_token = mkOpt types.str '' + Sets the `Authorization` header on every scrape request with + the configured bearer token. It is mutually exclusive with + <option>bearer_token_file</option>. + ''; + + bearer_token_file = mkOpt types.str '' + Sets the `Authorization` header on every scrape request with + the bearer token read from the configured file. It is mutually + exclusive with <option>bearer_token</option>. + ''; + + tls_config = mkOpt promTypes.tls_config '' + Configures the scrape request's TLS settings. + ''; + + proxy_url = mkOpt types.str '' + Optional proxy URL. + ''; + + ec2_sd_configs = mkOpt (types.listOf promTypes.ec2_sd_config) '' + List of EC2 service discovery configurations. + ''; + + dns_sd_configs = mkOpt (types.listOf promTypes.dns_sd_config) '' + List of DNS service discovery configurations. + ''; + + consul_sd_configs = mkOpt (types.listOf promTypes.consul_sd_config) '' + List of Consul service discovery configurations. + ''; + + file_sd_configs = mkOpt (types.listOf promTypes.file_sd_config) '' + List of file service discovery configurations. + ''; + + static_configs = mkOpt (types.listOf promTypes.static_config) '' + List of labeled target groups for this job. + ''; + + relabel_configs = mkOpt (types.listOf promTypes.relabel_config) '' + List of relabel configurations. + ''; + + sample_limit = mkDefOpt types.int "0" '' + Per-scrape limit on number of scraped samples that will be accepted. + If more than this number of samples are present after metric relabelling + the entire scrape will be treated as failed. 0 means no limit. + ''; }; }; @@ -337,66 +312,41 @@ let The AWS Region. ''; }; - endpoint = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Custom endpoint to be used. - ''; - }; - access_key = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The AWS API key id. If blank, the environment variable - <literal>AWS_ACCESS_KEY_ID</literal> is used. - ''; - }; - secret_key = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - The AWS API key secret. If blank, the environment variable - <literal>AWS_SECRET_ACCESS_KEY</literal> is used. - ''; - }; - profile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Named AWS profile used to connect to the API. - ''; - }; - role_arn = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - AWS Role ARN, an alternative to using AWS API keys. - ''; - }; - refresh_interval = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Refresh interval to re-read the instance list. - ''; - }; - port = mkOption { - type = types.int; - default = 80; - description = '' - The port to scrape metrics from. If using the public IP - address, this must instead be specified in the relabeling - rule. - ''; - }; - filters = mkOption { - type = types.nullOr (types.listOf promTypes.filter); - default = null; - description = '' - Filters can be used optionally to filter the instance list by other criteria. - ''; - }; + endpoint = mkOpt types.str '' + Custom endpoint to be used. + ''; + + access_key = mkOpt types.str '' + The AWS API key id. If blank, the environment variable + <literal>AWS_ACCESS_KEY_ID</literal> is used. + ''; + + secret_key = mkOpt types.str '' + The AWS API key secret. If blank, the environment variable + <literal>AWS_SECRET_ACCESS_KEY</literal> is used. + ''; + + profile = mkOpt types.str '' + Named AWS profile used to connect to the API. + ''; + + role_arn = mkOpt types.str '' + AWS Role ARN, an alternative to using AWS API keys. + ''; + + refresh_interval = mkDefOpt types.str "60s" '' + Refresh interval to re-read the instance list. + ''; + + port = mkDefOpt types.int "80" '' + The port to scrape metrics from. If using the public IP + address, this must instead be specified in the relabeling + rule. + ''; + + filters = mkOpt (types.listOf promTypes.filter) '' + Filters can be used optionally to filter the instance list by other criteria. + ''; }; }; @@ -409,6 +359,7 @@ let for the available filters. ''; }; + value = mkOption { type = types.listOf types.str; default = []; @@ -427,56 +378,63 @@ let A list of DNS SRV record names to be queried. ''; }; - refresh_interval = mkOption { - type = types.str; - default = "30s"; - description = '' - The time after which the provided names are refreshed. - ''; - }; + + refresh_interval = mkDefOpt types.str "30s" '' + The time after which the provided names are refreshed. + ''; }; }; promTypes.consul_sd_config = types.submodule { options = { - server = mkOption { - type = types.str; - description = "Consul server to query."; - }; - token = mkOption { - type = types.nullOr types.str; - description = "Consul token"; - }; - datacenter = mkOption { - type = types.nullOr types.str; - description = "Consul datacenter"; - }; - scheme = mkOption { - type = types.nullOr types.str; - description = "Consul scheme"; - }; - username = mkOption { - type = types.nullOr types.str; - description = "Consul username"; - }; - password = mkOption { - type = types.nullOr types.str; - description = "Consul password"; - }; + server = mkDefOpt types.str "localhost:8500" '' + Consul server to query. + ''; - services = mkOption { - type = types.listOf types.str; - description = '' - A list of services for which targets are retrieved. - ''; - }; - tag_separator = mkOption { - type = types.str; - default = ","; - description = '' - The string by which Consul tags are joined into the tag label. - ''; - }; + token = mkOpt types.str "Consul token"; + + datacenter = mkOpt types.str "Consul datacenter"; + + scheme = mkDefOpt types.str "http" "Consul scheme"; + + username = mkOpt types.str "Consul username"; + + password = mkOpt types.str "Consul password"; + + tls_config = mkOpt promTypes.tls_config '' + Configures the Consul request's TLS settings. + ''; + + services = mkOpt (types.listOf types.str) '' + A list of services for which targets are retrieved. + ''; + + tags = mkOpt (types.listOf types.str) '' + An optional list of tags used to filter nodes for a given + service. Services must contain all tags in the list. + ''; + + node_meta = mkOpt (types.attrsOf types.str) '' + Node metadata used to filter nodes for a given service. + ''; + + tag_separator = mkDefOpt types.str "," '' + The string by which Consul tags are joined into the tag label. + ''; + + allow_stale = mkOpt types.bool '' + Allow stale Consul results + (see <link xlink:href="https://www.consul.io/api/index.html#consistency-modes"/>). + + Will reduce load on Consul. + ''; + + refresh_interval = mkDefOpt types.str "30s" '' + The time after which the provided names are refreshed. + + On large setup it might be a good idea to increase this value + because the catalog will change all the time. + ''; }; }; @@ -488,108 +446,74 @@ let Patterns for files from which target groups are extracted. Refer to the Prometheus documentation for permitted filename patterns and formats. - - ''; - }; - refresh_interval = mkOption { - type = types.str; - default = "30s"; - description = '' - Refresh interval to re-read the files. ''; }; + + refresh_interval = mkDefOpt types.str "5m" '' + Refresh interval to re-read the files. + ''; }; }; promTypes.relabel_config = types.submodule { options = { - source_labels = mkOption { - type = with types; nullOr (listOf str); - default = null; - description = '' - The source labels select values from existing labels. Their content - is concatenated using the configured separator and matched against - the configured regular expression. - ''; - }; - separator = mkOption { - type = types.str; - default = ";"; - description = '' - Separator placed between concatenated source label values. - ''; - }; - target_label = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. - ''; - }; - regex = mkOption { - type = types.str; - default = "(.*)"; - description = '' - Regular expression against which the extracted value is matched. - ''; - }; - replacement = mkOption { - type = types.str; - default = "$1"; - description = '' - Replacement value against which a regex replace is performed if the - regular expression matches. - ''; - }; - action = mkOption { - type = types.enum ["replace" "keep" "drop"]; - default = "replace"; - description = '' - Action to perform based on regex matching. - ''; - }; + source_labels = mkOpt (types.listOf types.str) '' + The source labels select values from existing labels. Their content + is concatenated using the configured separator and matched against + the configured regular expression. + ''; + + separator = mkDefOpt types.str ";" '' + Separator placed between concatenated source label values. + ''; + + target_label = mkOpt types.str '' + Label to which the resulting value is written in a replace action. + It is mandatory for replace actions. + ''; + + regex = mkDefOpt types.str "(.*)" '' + Regular expression against which the extracted value is matched. + ''; + + modulus = mkOpt types.int '' + Modulus to take of the hash of the source label values. + ''; + + replacement = mkDefOpt types.str "$1" '' + Replacement value against which a regex replace is performed if the + regular expression matches. + ''; + + action = mkDefOpt (types.enum ["replace" "keep" "drop"]) "replace" '' + Action to perform based on regex matching. + ''; + }; }; promTypes.tls_config = types.submodule { options = { - ca_file = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - CA certificate to validate API server certificate with. - ''; - }; - cert_file = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Certificate file for client cert authentication to the server. - ''; - }; - key_file = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Key file for client cert authentication to the server. - ''; - }; - server_name = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - ServerName extension to indicate the name of the server. - http://tools.ietf.org/html/rfc4366#section-3.1 - ''; - }; - insecure_skip_verify = mkOption { - type = types.bool; - default = false; - description = '' - Disable validation of the server certificate. - ''; - }; + ca_file = mkOpt types.str '' + CA certificate to validate API server certificate with. + ''; + + cert_file = mkOpt types.str '' + Certificate file for client cert authentication to the server. + ''; + + key_file = mkOpt types.str '' + Key file for client cert authentication to the server. + ''; + + server_name = mkOpt types.str '' + ServerName extension to indicate the name of the server. + http://tools.ietf.org/html/rfc4366#section-3.1 + ''; + + insecure_skip_verify = mkOpt types.bool '' + Disable validation of the server certificate. + ''; }; }; @@ -662,7 +586,6 @@ in { globalConfig = mkOption { type = promTypes.globalConfig; default = {}; - apply = _filter; description = '' Parameters that are valid in all configuration contexts. They also serve as defaults for other configuration sections @@ -688,7 +611,6 @@ in { scrapeConfigs = mkOption { type = types.listOf promTypes.scrape_config; default = []; - apply = x: map _filter x; description = '' A list of scrape configurations. ''; @@ -786,7 +708,6 @@ in { globalConfig = mkOption { type = promTypes.globalConfig; default = {}; - apply = _filter; description = '' Parameters that are valid in all configuration contexts. They also serve as defaults for other configuration sections @@ -812,7 +733,6 @@ in { scrapeConfigs = mkOption { type = types.listOf promTypes.scrape_config; default = []; - apply = x: map _filter x; description = '' A list of scrape configurations. ''; diff --git a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix index d4fa1eccdf3b..f19bf9d81396 100644 --- a/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix +++ b/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix @@ -226,18 +226,19 @@ in { ipfs.gid = config.ids.gids.ipfs; }; + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -" + ] ++ optionals cfg.autoMount [ + "d '${cfg.ipfsMountDir}' - ${cfg.user} ${cfg.group} - -" + "d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -" + ]; + systemd.services.ipfs-init = recursiveUpdate commonEnv { description = "IPFS Initializer"; after = [ "local-fs.target" ]; before = [ "ipfs.service" "ipfs-offline.service" "ipfs-norouting.service" ]; - preStart = '' - install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.dataDir} - '' + optionalString cfg.autoMount '' - install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.ipfsMountDir} - install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.ipnsMountDir} - ''; script = '' if [[ ! -f ${cfg.dataDir}/config ]]; then ipfs init ${optionalString cfg.emptyRepo "-e"} \ @@ -253,7 +254,6 @@ in { serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - PermissionsStartOnly = true; }; }; diff --git a/nixpkgs/nixos/modules/services/networking/i2pd.nix b/nixpkgs/nixos/modules/services/networking/i2pd.nix index 0e9b354cfcaf..40478b85b75e 100644 --- a/nixpkgs/nixos/modules/services/networking/i2pd.nix +++ b/nixpkgs/nixos/modules/services/networking/i2pd.nix @@ -470,7 +470,7 @@ in ''; }; - trust.hidden = mkEnableOption "Router concealment."; + trust.hidden = mkEnableOption "Router concealment"; websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666; @@ -478,7 +478,7 @@ in exploratory.outbound = i2cpOpts "exploratory"; ntcp2.enable = mkEnableTrueOption "NTCP2."; - ntcp2.published = mkEnableOption "NTCP2 publication."; + ntcp2.published = mkEnableOption "NTCP2 publication"; ntcp2.port = mkOption { type = types.int; default = 0; diff --git a/nixpkgs/nixos/modules/services/networking/miredo.nix b/nixpkgs/nixos/modules/services/networking/miredo.nix index 8694d08385ca..2c8393fb5b41 100644 --- a/nixpkgs/nixos/modules/services/networking/miredo.nix +++ b/nixpkgs/nixos/modules/services/networking/miredo.nix @@ -20,7 +20,7 @@ in services.miredo = { - enable = mkEnableOption "the Miredo IPv6 tunneling service."; + enable = mkEnableOption "the Miredo IPv6 tunneling service"; package = mkOption { type = types.package; diff --git a/nixpkgs/nixos/modules/services/networking/monero.nix b/nixpkgs/nixos/modules/services/networking/monero.nix index 8241c32bad07..831e4d60d8da 100644 --- a/nixpkgs/nixos/modules/services/networking/monero.nix +++ b/nixpkgs/nixos/modules/services/networking/monero.nix @@ -51,7 +51,7 @@ in services.monero = { - enable = mkEnableOption "Monero node daemon."; + enable = mkEnableOption "Monero node daemon"; mining.enable = mkOption { type = types.bool; diff --git a/nixpkgs/nixos/modules/services/networking/mosquitto.nix b/nixpkgs/nixos/modules/services/networking/mosquitto.nix index 9974cbd89d1e..1d49c137723c 100644 --- a/nixpkgs/nixos/modules/services/networking/mosquitto.nix +++ b/nixpkgs/nixos/modules/services/networking/mosquitto.nix @@ -44,7 +44,7 @@ in options = { services.mosquitto = { - enable = mkEnableOption "Enable the MQTT Mosquitto broker."; + enable = mkEnableOption "the MQTT Mosquitto broker"; host = mkOption { default = "127.0.0.1"; @@ -65,7 +65,7 @@ in }; ssl = { - enable = mkEnableOption "Enable SSL listener."; + enable = mkEnableOption "SSL listener"; cafile = mkOption { type = types.nullOr types.path; diff --git a/nixpkgs/nixos/modules/services/networking/mxisd.nix b/nixpkgs/nixos/modules/services/networking/mxisd.nix index 0aa6d0d9ecd3..0b9824f29fd7 100644 --- a/nixpkgs/nixos/modules/services/networking/mxisd.nix +++ b/nixpkgs/nixos/modules/services/networking/mxisd.nix @@ -116,7 +116,6 @@ in { Group = "mxisd"; ExecStart = "${cfg.package}/bin/mxisd --spring.config.location=${cfg.dataDir}/ --spring.profiles.active=systemd --java.security.egd=file:/dev/./urandom"; WorkingDirectory = cfg.dataDir; - PermissionsStartOnly = true; SuccessExitStatus = 143; Restart = "on-failure"; }; diff --git a/nixpkgs/nixos/modules/services/networking/namecoind.nix b/nixpkgs/nixos/modules/services/networking/namecoind.nix index 8de23b442f93..a569ca87e262 100644 --- a/nixpkgs/nixos/modules/services/networking/namecoind.nix +++ b/nixpkgs/nixos/modules/services/networking/namecoind.nix @@ -1,3 +1,4 @@ + { config, lib, pkgs, ... }: with lib; @@ -43,7 +44,7 @@ in services.namecoind = { - enable = mkEnableOption "namecoind, Namecoin client."; + enable = mkEnableOption "namecoind, Namecoin client"; wallet = mkOption { type = types.path; diff --git a/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix b/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix index 786b5227dbad..b0d338a27941 100644 --- a/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix +++ b/nixpkgs/nixos/modules/services/networking/nullidentdmod.nix @@ -3,7 +3,7 @@ in { options.services.nullidentdmod = with types; { - enable = mkEnableOption "Enable the nullidentdmod identd daemon"; + enable = mkEnableOption "the nullidentdmod identd daemon"; userid = mkOption { type = nullOr str; diff --git a/nixpkgs/nixos/modules/services/networking/smokeping.nix b/nixpkgs/nixos/modules/services/networking/smokeping.nix index 9ba6e48f417c..fab3ed5bb39d 100644 --- a/nixpkgs/nixos/modules/services/networking/smokeping.nix +++ b/nixpkgs/nixos/modules/services/networking/smokeping.nix @@ -285,12 +285,12 @@ in uid = config.ids.uids.smokeping; description = "smokeping daemon user"; home = smokepingHome; + createHome = true; }; systemd.services.smokeping = { wantedBy = [ "multi-user.target"]; serviceConfig = { User = cfg.user; - PermissionsStartOnly = true; Restart = "on-failure"; }; preStart = '' @@ -300,7 +300,6 @@ in cp ${cgiHome} ${smokepingHome}/smokeping.fcgi ${cfg.package}/bin/smokeping --check --config=${configPath} ${cfg.package}/bin/smokeping --static --config=${configPath} - chown -R ${cfg.user} ${smokepingHome} ''; script = ''${cfg.package}/bin/smokeping --config=${configPath} --nodaemon''; }; diff --git a/nixpkgs/nixos/modules/services/networking/syncthing.nix b/nixpkgs/nixos/modules/services/networking/syncthing.nix index 702481ec5177..114a64dfb175 100644 --- a/nixpkgs/nixos/modules/services/networking/syncthing.nix +++ b/nixpkgs/nixos/modules/services/networking/syncthing.nix @@ -151,7 +151,6 @@ in { RestartForceExitStatus="3 4"; User = cfg.user; Group = cfg.group; - PermissionsStartOnly = true; ExecStart = '' ${cfg.package}/bin/syncthing \ -no-browser \ diff --git a/nixpkgs/nixos/modules/services/networking/tedicross.nix b/nixpkgs/nixos/modules/services/networking/tedicross.nix new file mode 100644 index 000000000000..0716975f594a --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/tedicross.nix @@ -0,0 +1,100 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + dataDir = "/var/lib/tedicross"; + cfg = config.services.tedicross; + configJSON = pkgs.writeText "tedicross-settings.json" (builtins.toJSON cfg.config); + configYAML = pkgs.runCommand "tedicross-settings.yaml" { preferLocalBuild = true; } '' + ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out + ''; + +in { + options = { + services.tedicross = { + enable = mkEnableOption "the TediCross Telegram-Discord bridge service"; + + config = mkOption { + type = types.attrs; + # from https://github.com/TediCross/TediCross/blob/master/example.settings.yaml + example = literalExample '' + { + telegram = { + useFirstNameInsteadOfUsername = false; + colonAfterSenderName = false; + skipOldMessages = true; + sendEmojiWithStickers = true; + }; + discord = { + useNickname = false; + skipOldMessages = true; + displayTelegramReplies = "embed"; + replyLength = 100; + }; + bridges = [ + { + name = "Default bridge"; + direction = "both"; + telegram = { + chatId = -123456789; + relayJoinMessages = true; + relayLeaveMessages = true; + sendUsernames = true; + ignoreCommands = true; + }; + discord = { + serverId = "DISCORD_SERVER_ID"; + channelId = "DISCORD_CHANNEL_ID"; + relayJoinMessages = true; + relayLeaveMessages = true; + sendUsernames = true; + crossDeleteOnTelegram = true; + }; + } + ]; + + debug = false; + } + ''; + description = '' + <filename>settings.yaml</filename> configuration as a Nix attribute set. + Secret tokens should be specified using <option>environmentFile</option> + instead of this world-readable file. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + File containing environment variables to be passed to the TediCross service, + in which secret tokens can be specified securely using the + <literal>TELEGRAM_BOT_TOKEN</literal> and <literal>DISCORD_BOT_TOKEN</literal> + keys. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + # from https://github.com/TediCross/TediCross/blob/master/guides/autostart/Linux.md + systemd.services.tedicross = { + description = "TediCross Telegram-Discord bridge service"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.nodePackages.tedicross}/bin/tedicross --config='${configYAML}' --data-dir='${dataDir}'"; + Restart = "always"; + DynamicUser = true; + StateDirectory = baseNameOf dataDir; + EnvironmentFile = cfg.environmentFile; + }; + }; + }; + + meta.maintainers = with maintainers; [ pacien ]; +} + diff --git a/nixpkgs/nixos/modules/services/networking/toxvpn.nix b/nixpkgs/nixos/modules/services/networking/toxvpn.nix index b7655f4bec62..7830dfb1834c 100644 --- a/nixpkgs/nixos/modules/services/networking/toxvpn.nix +++ b/nixpkgs/nixos/modules/services/networking/toxvpn.nix @@ -5,7 +5,7 @@ with lib; { options = { services.toxvpn = { - enable = mkEnableOption "enable toxvpn running on startup"; + enable = mkEnableOption "toxvpn running on startup"; localip = mkOption { type = types.string; diff --git a/nixpkgs/nixos/modules/services/networking/wg-quick.nix b/nixpkgs/nixos/modules/services/networking/wg-quick.nix new file mode 100644 index 000000000000..b770d47d269e --- /dev/null +++ b/nixpkgs/nixos/modules/services/networking/wg-quick.nix @@ -0,0 +1,312 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.networking.wg-quick; + + kernel = config.boot.kernelPackages; + + # interface options + + interfaceOpts = { ... }: { + options = { + address = mkOption { + example = [ "192.168.2.1/24" ]; + default = []; + type = with types; listOf str; + description = "The IP addresses of the interface."; + }; + + dns = mkOption { + example = [ "192.168.2.2" ]; + default = []; + type = with types; listOf str; + description = "The IP addresses of DNS servers to configure."; + }; + + privateKey = mkOption { + example = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk="; + type = with types; nullOr str; + default = null; + description = '' + Base64 private key generated by wg genkey. + + Warning: Consider using privateKeyFile instead if you do not + want to store the key in the world-readable Nix store. + ''; + }; + + privateKeyFile = mkOption { + example = "/private/wireguard_key"; + type = with types; nullOr str; + default = null; + description = '' + Private key file as generated by wg genkey. + ''; + }; + + listenPort = mkOption { + default = null; + type = with types; nullOr int; + example = 51820; + description = '' + 16-bit port for listening. Optional; if not specified, + automatically generated based on interface name. + ''; + }; + + preUp = mkOption { + example = literalExample '' + ${pkgs.iproute}/bin/ip netns add foo + ''; + default = ""; + type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines; + description = '' + Commands called at the start of the interface setup. + ''; + }; + + preDown = mkOption { + example = literalExample '' + ${pkgs.iproute}/bin/ip netns del foo + ''; + default = ""; + type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines; + description = '' + Command called before the interface is taken down. + ''; + }; + + postUp = mkOption { + example = literalExample '' + ${pkgs.iproute}/bin/ip netns add foo + ''; + default = ""; + type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines; + description = '' + Commands called after the interface setup. + ''; + }; + + postDown = mkOption { + example = literalExample '' + ${pkgs.iproute}/bin/ip netns del foo + ''; + default = ""; + type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines; + description = '' + Command called after the interface is taken down. + ''; + }; + + table = mkOption { + example = "main"; + default = null; + type = with types; nullOr str; + description = '' + The kernel routing table to add this interface's + associated routes to. Setting this is useful for e.g. policy routing + ("ip rule") or virtual routing and forwarding ("ip vrf"). Both numeric + table IDs and table names (/etc/rt_tables) can be used. Defaults to + "main". + ''; + }; + + mtu = mkOption { + example = 1248; + default = null; + type = with types; nullOr int; + description = '' + If not specified, the MTU is automatically determined + from the endpoint addresses or the system default route, which is usually + a sane choice. However, to manually specify an MTU to override this + automatic discovery, this value may be specified explicitly. + ''; + }; + + peers = mkOption { + default = []; + description = "Peers linked to the interface."; + type = with types; listOf (submodule peerOpts); + }; + }; + }; + + # peer options + + peerOpts = { + options = { + publicKey = mkOption { + example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg="; + type = types.str; + description = "The base64 public key the peer."; + }; + + presharedKey = mkOption { + default = null; + example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I="; + type = with types; nullOr str; + description = '' + Base64 preshared key generated by wg genpsk. Optional, + and may be omitted. This option adds an additional layer of + symmetric-key cryptography to be mixed into the already existing + public-key cryptography, for post-quantum resistance. + + Warning: Consider using presharedKeyFile instead if you do not + want to store the key in the world-readable Nix store. + ''; + }; + + presharedKeyFile = mkOption { + default = null; + example = "/private/wireguard_psk"; + type = with types; nullOr str; + description = '' + File pointing to preshared key as generated by wg pensk. Optional, + and may be omitted. This option adds an additional layer of + symmetric-key cryptography to be mixed into the already existing + public-key cryptography, for post-quantum resistance. + ''; + }; + + allowedIPs = mkOption { + example = [ "10.192.122.3/32" "10.192.124.1/24" ]; + type = with types; listOf str; + description = ''List of IP (v4 or v6) addresses with CIDR masks from + which this peer is allowed to send incoming traffic and to which + outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may + be specified for matching all IPv4 addresses, and ::/0 may be specified + for matching all IPv6 addresses.''; + }; + + endpoint = mkOption { + default = null; + example = "demo.wireguard.io:12913"; + type = with types; nullOr str; + description = ''Endpoint IP or hostname of the peer, followed by a colon, + and then a port number of the peer.''; + }; + + persistentKeepalive = mkOption { + default = null; + type = with types; nullOr int; + example = 25; + description = ''This is optional and is by default off, because most + users will not need it. It represents, in seconds, between 1 and 65535 + inclusive, how often to send an authenticated empty packet to the peer, + for the purpose of keeping a stateful firewall or NAT mapping valid + persistently. For example, if the interface very rarely sends traffic, + but it might at anytime receive traffic from a peer, and it is behind + NAT, the interface might benefit from having a persistent keepalive + interval of 25 seconds; however, most users will not need this.''; + }; + }; + }; + + writeScriptFile = name: text: ((pkgs.writeShellScriptBin name text) + "/bin/${name}"); + + generateUnit = name: values: + assert assertMsg ((values.privateKey != null) != (values.privateKeyFile != null)) "Only one of privateKey or privateKeyFile may be set"; + let + preUpFile = if values.preUp != "" then writeScriptFile "preUp.sh" values.preUp else null; + postUp = + optional (values.privateKeyFile != null) "wg set ${name} private-key <(cat ${values.privateKeyFile})" ++ + (concatMap (peer: optional (peer.presharedKeyFile != null) "wg set ${name} peer ${peer.publicKey} preshared-key <(cat ${peer.presharedKeyFile})") values.peers) ++ + optional (values.postUp != null) values.postUp; + postUpFile = if postUp != [] then writeScriptFile "postUp.sh" (concatMapStringsSep "\n" (line: line) postUp) else null; + preDownFile = if values.preDown != "" then writeScriptFile "preDown.sh" values.preDown else null; + postDownFile = if values.postDown != "" then writeScriptFile "postDown.sh" values.postDown else null; + configDir = pkgs.writeTextFile { + name = "config-${name}"; + executable = false; + destination = "/${name}.conf"; + text = + '' + [interface] + ${concatMapStringsSep "\n" (address: + "Address = ${address}" + ) values.address} + ${concatMapStringsSep "\n" (dns: + "DNS = ${dns}" + ) values.dns} + '' + + optionalString (values.table != null) "Table = ${values.table}\n" + + optionalString (values.mtu != null) "MTU = ${toString values.mtu}\n" + + optionalString (values.privateKey != null) "PrivateKey = ${values.privateKey}\n" + + optionalString (values.listenPort != null) "ListenPort = ${toString values.listenPort}\n" + + optionalString (preUpFile != null) "PreUp = ${preUpFile}\n" + + optionalString (postUpFile != null) "PostUp = ${postUpFile}\n" + + optionalString (preDownFile != null) "PreDown = ${preDownFile}\n" + + optionalString (postDownFile != null) "PostDown = ${postDownFile}\n" + + concatMapStringsSep "\n" (peer: + assert assertMsg (!((peer.presharedKeyFile != null) && (peer.presharedKey != null))) "Only one of presharedKey or presharedKeyFile may be set"; + "[Peer]\n" + + "PublicKey = ${peer.publicKey}\n" + + optionalString (peer.presharedKey != null) "PresharedKey = ${peer.presharedKey}\n" + + optionalString (peer.endpoint != null) "Endpoint = ${peer.endpoint}\n" + + optionalString (peer.persistentKeepalive != null) "PersistentKeepalive = ${toString peer.persistentKeepalive}\n" + + optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep "," peer.allowedIPs}\n" + ) values.peers; + }; + configPath = "${configDir}/${name}.conf"; + in + nameValuePair "wg-quick-${name}" + { + description = "wg-quick WireGuard Tunnel - ${name}"; + requires = [ "network-online.target" ]; + after = [ "network.target" "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + environment.DEVICE = name; + path = [ pkgs.kmod pkgs.wireguard-tools ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + script = '' + ${optionalString (!config.boot.isContainer) "modprobe wireguard"} + wg-quick up ${configPath} + ''; + + preStop = '' + wg-quick down ${configPath} + ''; + }; +in { + + ###### interface + + options = { + networking.wg-quick = { + interfaces = mkOption { + description = "Wireguard interfaces."; + default = {}; + example = { + wg0 = { + address = [ "192.168.20.4/24" ]; + privateKey = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk="; + peers = [ + { allowedIPs = [ "192.168.20.1/32" ]; + publicKey = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg="; + endpoint = "demo.wireguard.io:12913"; } + ]; + }; + }; + type = with types; attrsOf (submodule interfaceOpts); + }; + }; + }; + + + ###### implementation + + config = mkIf (cfg.interfaces != {}) { + boot.extraModulePackages = [ kernel.wireguard ]; + environment.systemPackages = [ pkgs.wireguard-tools ]; + # This is forced to false for now because the default "--validmark" rpfilter we apply on reverse path filtering + # breaks the wg-quick routing because wireguard packets leave with a fwmark from wireguard. + networking.firewall.checkReversePath = false; + systemd.services = mapAttrs' generateUnit cfg.interfaces; + }; +} diff --git a/nixpkgs/nixos/modules/services/networking/wireguard.nix b/nixpkgs/nixos/modules/services/networking/wireguard.nix index 41aff1480a05..dd3cb1af2716 100644 --- a/nixpkgs/nixos/modules/services/networking/wireguard.nix +++ b/nixpkgs/nixos/modules/services/networking/wireguard.nix @@ -26,19 +26,28 @@ let type = with types; nullOr str; default = null; description = '' - Base64 private key generated by wg genkey. + Base64 private key generated by <command>wg genkey</command>. Warning: Consider using privateKeyFile instead if you do not want to store the key in the world-readable Nix store. ''; }; + generatePrivateKeyFile = mkOption { + default = false; + type = types.bool; + description = '' + Automatically generate a private key with + <command>wg genkey</command>, at the privateKeyFile location. + ''; + }; + privateKeyFile = mkOption { example = "/private/wireguard_key"; type = with types; nullOr str; default = null; description = '' - Private key file as generated by wg genkey. + Private key file as generated by <command>wg genkey</command>. ''; }; @@ -124,8 +133,8 @@ let example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I="; type = with types; nullOr str; description = '' - Base64 preshared key generated by wg genpsk. Optional, - and may be omitted. This option adds an additional layer of + Base64 preshared key generated by <command>wg genpsk</command>. + Optional, and may be omitted. This option adds an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance. @@ -139,8 +148,8 @@ let example = "/private/wireguard_psk"; type = with types; nullOr str; description = '' - File pointing to preshared key as generated by wg pensk. Optional, - and may be omitted. This option adds an additional layer of + File pointing to preshared key as generated by <command>wg pensk</command>. + Optional, and may be omitted. This option adds an additional layer of symmetric-key cryptography to be mixed into the already existing public-key cryptography, for post-quantum resistance. ''; @@ -182,9 +191,48 @@ let }; - generateUnit = name: values: + + generatePathUnit = name: values: + assert (values.privateKey == null); + assert (values.privateKeyFile != null); + nameValuePair "wireguard-${name}" + { + description = "WireGuard Tunnel - ${name} - Private Key"; + requiredBy = [ "wireguard-${name}.service" ]; + before = [ "wireguard-${name}.service" ]; + pathConfig.PathExists = values.privateKeyFile; + }; + + generateKeyServiceUnit = name: values: + assert values.generatePrivateKeyFile; + nameValuePair "wireguard-${name}-key" + { + description = "WireGuard Tunnel - ${name} - Key Generator"; + wantedBy = [ "wireguard-${name}.service" ]; + requiredBy = [ "wireguard-${name}.service" ]; + before = [ "wireguard-${name}.service" ]; + path = with pkgs; [ wireguard ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + script = '' + mkdir --mode 0644 -p "${dirOf values.privateKeyFile}" + if [ ! -f "${values.privateKeyFile}" ]; then + touch "${values.privateKeyFile}" + chmod 0600 "${values.privateKeyFile}" + wg genkey > "${values.privateKeyFile}" + chmod 0400 "${values.privateKeyFile}" + fi + ''; + }; + + + generateSetupServiceUnit = name: values: # exactly one way to specify the private key must be set - assert (values.privateKey != null) != (values.privateKeyFile != null); + #assert (values.privateKey != null) != (values.privateKeyFile != null); let privKey = if values.privateKeyFile != null then values.privateKeyFile else pkgs.writeText "wg-key" values.privateKey; in nameValuePair "wireguard-${name}" @@ -279,10 +327,27 @@ in config = mkIf (cfg.interfaces != {}) { + assertions = (attrValues ( + mapAttrs (name: value: { + assertion = (value.privateKey != null) != (value.privateKeyFile != null); + message = "Either networking.wireguard.interfaces.${name}.privateKey or networking.wireguard.interfaces.${name}.privateKeyFile must be set."; + }) cfg.interfaces)) + ++ (attrValues ( + mapAttrs (name: value: { + assertion = value.generatePrivateKeyFile -> (value.privateKey == null); + message = "networking.wireguard.interfaces.${name}.generatePrivateKey must not be set if networking.wireguard.interfaces.${name}.privateKey is set."; + }) cfg.interfaces)); + + boot.extraModulePackages = [ kernel.wireguard ]; environment.systemPackages = [ pkgs.wireguard-tools ]; - systemd.services = mapAttrs' generateUnit cfg.interfaces; + systemd.services = (mapAttrs' generateSetupServiceUnit cfg.interfaces) + // (mapAttrs' generateKeyServiceUnit + (filterAttrs (name: value: value.generatePrivateKeyFile) cfg.interfaces)); + + systemd.paths = mapAttrs' generatePathUnit + (filterAttrs (name: value: value.privateKeyFile != null) cfg.interfaces); }; diff --git a/nixpkgs/nixos/modules/services/search/kibana.nix b/nixpkgs/nixos/modules/services/search/kibana.nix index ba58630a467a..2a6e8250850c 100644 --- a/nixpkgs/nixos/modules/services/search/kibana.nix +++ b/nixpkgs/nixos/modules/services/search/kibana.nix @@ -31,7 +31,7 @@ let in { options.services.kibana = { - enable = mkEnableOption "enable kibana service"; + enable = mkEnableOption "kibana service"; listenAddress = mkOption { description = "Kibana listening host"; diff --git a/nixpkgs/nixos/modules/services/search/solr.nix b/nixpkgs/nixos/modules/services/search/solr.nix index 6659cc8a2d1e..5ef7d9893a49 100644 --- a/nixpkgs/nixos/modules/services/search/solr.nix +++ b/nixpkgs/nixos/modules/services/search/solr.nix @@ -11,7 +11,7 @@ in { options = { services.solr = { - enable = mkEnableOption "Enables the solr service."; + enable = mkEnableOption "Solr"; # default to the 8.x series not forcing major version upgrade of those on the 7.x series package = mkOption { diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh b/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh new file mode 100644 index 000000000000..264a7da9cbb6 --- /dev/null +++ b/nixpkgs/nixos/modules/services/security/bitwarden_rs/backup.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Based on: https://github.com/dani-garcia/bitwarden_rs/wiki/Backing-up-your-vault +if ! mkdir -p "$BACKUP_FOLDER"; then + echo "Could not create backup folder '$BACKUP_FOLDER'" >&2 + exit 1 +fi + +if [[ ! -f "$DATA_FOLDER"/db.sqlite3 ]]; then + echo "Could not find SQLite database file '$DATA_FOLDER/db.sqlite3'" >&2 + exit 1 +fi + +sqlite3 "$DATA_FOLDER"/db.sqlite3 ".backup '$BACKUP_FOLDER/db.sqlite3'" +cp "$DATA_FOLDER"/rsa_key.{der,pem,pub.der} "$BACKUP_FOLDER" +cp -r "$DATA_FOLDER"/attachments "$BACKUP_FOLDER" +cp -r "$DATA_FOLDER"/icon_cache "$BACKUP_FOLDER" diff --git a/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix b/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix new file mode 100644 index 000000000000..bb036ee020f4 --- /dev/null +++ b/nixpkgs/nixos/modules/services/security/bitwarden_rs/default.nix @@ -0,0 +1,126 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.bitwarden_rs; + user = config.users.users.bitwarden_rs.name; + group = config.users.groups.bitwarden_rs.name; + + # Convert name from camel case (e.g. disable2FARemember) to upper case snake case (e.g. DISABLE_2FA_REMEMBER). + nameToEnvVar = name: + let + parts = builtins.split "([A-Z0-9]+)" name; + partsToEnvVar = parts: foldl' (key: x: let last = stringLength key - 1; in + if isList x then key + optionalString (key != "" && substring last 1 key != "_") "_" + head x + else if key != "" && elem (substring 0 1 x) lowerChars then # to handle e.g. [ "disable" [ "2FAR" ] "emember" ] + substring 0 last key + optionalString (substring (last - 1) 1 key != "_") "_" + substring last 1 key + toUpper x + else key + toUpper x) "" parts; + in if builtins.match "[A-Z0-9_]+" name != null then name else partsToEnvVar parts; + + configFile = pkgs.writeText "bitwarden_rs.env" (concatMapStrings (s: s + "\n") ( + (concatLists (mapAttrsToList (name: value: + if value != null then [ "${nameToEnvVar name}=${if isBool value then boolToString value else toString value}" ] else [] + ) cfg.config)))); + +in { + options.services.bitwarden_rs = with types; { + enable = mkEnableOption "bitwarden_rs"; + + backupDir = mkOption { + type = nullOr str; + default = null; + description = '' + The directory under which bitwarden_rs will backup its persistent data. + ''; + }; + + config = mkOption { + type = attrsOf (nullOr (either (either bool int) str)); + default = {}; + example = literalExample '' + { + domain = https://bw.domain.tld:8443; + signupsAllowed = true; + rocketPort = 8222; + rocketLog = "critical"; + } + ''; + description = '' + The configuration of bitwarden_rs is done through environment variables, + therefore the names are converted from camel case (e.g. disable2FARemember) + to upper case snake case (e.g. DISABLE_2FA_REMEMBER). + In this conversion digits (0-9) are handled just like upper case characters, + so foo2 would be converted to FOO_2. + Names already in this format remain unchanged, so FOO2 remains FOO2 if passed as such, + even though foo2 would have been converted to FOO_2. + This allows working around any potential future conflicting naming conventions. + + Based on the attributes passed to this config option a environment file will be generated + that is passed to bitwarden_rs's systemd service. + + The available configuration options can be found in + <link xlink:href="https://github.com/dani-garcia/bitwarden_rs/blob/1.8.0/.env.template">the environment template file</link>. + ''; + apply = config: optionalAttrs config.webVaultEnabled { + webVaultFolder = "${pkgs.bitwarden_rs-vault}/share/bitwarden_rs/vault"; + } // config; + }; + }; + + config = mkIf cfg.enable { + services.bitwarden_rs.config = { + dataFolder = "/var/lib/bitwarden_rs"; + webVaultEnabled = mkDefault true; + }; + + users.users.bitwarden_rs = { inherit group; }; + users.groups.bitwarden_rs = { }; + + systemd.services.bitwarden_rs = { + after = [ "network.target" ]; + path = with pkgs; [ openssl ]; + serviceConfig = { + User = user; + Group = group; + EnvironmentFile = configFile; + ExecStart = "${pkgs.bitwarden_rs}/bin/bitwarden_rs"; + LimitNOFILE = "1048576"; + LimitNPROC = "64"; + PrivateTmp = "true"; + PrivateDevices = "true"; + ProtectHome = "true"; + ProtectSystem = "strict"; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + StateDirectory = "bitwarden_rs"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + systemd.services.backup-bitwarden_rs = mkIf (cfg.backupDir != null) { + description = "Backup bitwarden_rs"; + environment = { + DATA_FOLDER = "/var/lib/bitwarden_rs"; + BACKUP_FOLDER = cfg.backupDir; + }; + path = with pkgs; [ sqlite ]; + serviceConfig = { + SyslogIdentifier = "backup-bitwarden_rs"; + User = mkDefault user; + Group = mkDefault group; + ExecStart = "${pkgs.bash}/bin/bash ${./backup.sh}"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + systemd.timers.backup-bitwarden_rs = mkIf (cfg.backupDir != null) { + description = "Backup bitwarden_rs on time"; + timerConfig = { + OnCalendar = mkDefault "23:00"; + Persistent = "true"; + Unit = "backup-bitwarden_rs.service"; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/nixpkgs/nixos/modules/services/security/munge.nix b/nixpkgs/nixos/modules/services/security/munge.nix index 504bc66c6d10..1c4f8e20552f 100644 --- a/nixpkgs/nixos/modules/services/security/munge.nix +++ b/nixpkgs/nixos/modules/services/security/munge.nix @@ -49,21 +49,16 @@ in path = [ pkgs.munge pkgs.coreutils ]; - preStart = '' - chmod 0400 ${cfg.password} - mkdir -p /var/lib/munge -m 0711 - chown -R munge:munge /var/lib/munge - mkdir -p /run/munge -m 0755 - chown -R munge:munge /run/munge - ''; - serviceConfig = { + ExecStartPre = "+${pkgs.coreutils}/bin/chmod 0400 ${cfg.password}"; ExecStart = "${pkgs.munge}/bin/munged --syslog --key-file ${cfg.password}"; PIDFile = "/run/munge/munged.pid"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - PermissionsStartOnly = "true"; User = "munge"; Group = "munge"; + StateDirectory = "munge"; + StateDirectoryMode = "0711"; + RuntimeDirectory = "munge"; }; }; diff --git a/nixpkgs/nixos/modules/services/security/vault.nix b/nixpkgs/nixos/modules/services/security/vault.nix index 0b28bc894458..8176c168ca94 100644 --- a/nixpkgs/nixos/modules/services/security/vault.nix +++ b/nixpkgs/nixos/modules/services/security/vault.nix @@ -119,6 +119,10 @@ in }; users.groups.vault.gid = config.ids.gids.vault; + systemd.tmpfiles.rules = optional (cfg.storagePath != null) [ + "d '${cfg.storagePath}' 0700 vault vault - -" + ]; + systemd.services.vault = { description = "Vault server daemon"; @@ -128,14 +132,9 @@ in restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients. - preStart = optionalString (cfg.storagePath != null) '' - install -d -m0700 -o vault -g vault "${cfg.storagePath}" - ''; - serviceConfig = { User = "vault"; Group = "vault"; - PermissionsStartOnly = true; ExecStart = "${cfg.package}/bin/vault server -config ${configFile}"; PrivateDevices = true; PrivateTmp = true; diff --git a/nixpkgs/nixos/modules/services/torrent/peerflix.nix b/nixpkgs/nixos/modules/services/torrent/peerflix.nix index bed6661f84d6..a74f65984328 100644 --- a/nixpkgs/nixos/modules/services/torrent/peerflix.nix +++ b/nixpkgs/nixos/modules/services/torrent/peerflix.nix @@ -39,6 +39,10 @@ in { ###### implementation config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.stateDir}' - peerflix - - -" + ]; + systemd.services.peerflix = { description = "Peerflix Daemon"; wantedBy = [ "multi-user.target" ]; @@ -47,13 +51,11 @@ in { preStart = '' mkdir -p "${cfg.stateDir}"/{torrents,.config/peerflix-server} - if [ "$(id -u)" = 0 ]; then chown -R peerflix "${cfg.stateDir}"; fi ln -fs "${configFile}" "${cfg.stateDir}/.config/peerflix-server/config.json" ''; serviceConfig = { ExecStart = "${pkgs.nodePackages.peerflix-server}/bin/peerflix-server"; - PermissionsStartOnly = true; User = "peerflix"; }; }; diff --git a/nixpkgs/nixos/modules/services/web-apps/codimd.nix b/nixpkgs/nixos/modules/services/web-apps/codimd.nix index ee2fc2b9d857..7ae7cd9c52d8 100644 --- a/nixpkgs/nixos/modules/services/web-apps/codimd.nix +++ b/nixpkgs/nixos/modules/services/web-apps/codimd.nix @@ -899,10 +899,6 @@ in description = "CodiMD Service"; wantedBy = [ "multi-user.target" ]; after = [ "networking.target" ]; - preStart = '' - mkdir -p ${cfg.workDir} - chown -R codimd: ${cfg.workDir} - ''; serviceConfig = { WorkingDirectory = cfg.workDir; ExecStart = "${pkgs.codimd}/bin/codimd"; @@ -912,7 +908,6 @@ in ]; Restart = "always"; User = "codimd"; - PermissionsStartOnly = true; PrivateTmp = true; }; }; diff --git a/nixpkgs/nixos/modules/services/web-apps/nexus.nix b/nixpkgs/nixos/modules/services/web-apps/nexus.nix index 050f8757fa5f..052dbed6d4f8 100644 --- a/nixpkgs/nixos/modules/services/web-apps/nexus.nix +++ b/nixpkgs/nixos/modules/services/web-apps/nexus.nix @@ -83,6 +83,8 @@ in users.users."${cfg.user}" = { isSystemUser = true; group = cfg.group; + home = cfg.home; + createHome = true; }; users.groups."${cfg.group}" = {}; @@ -104,8 +106,6 @@ in preStart = '' mkdir -p ${cfg.home}/nexus3/etc - chown -R ${cfg.user}:${cfg.group} ${cfg.home} - if [ ! -f ${cfg.home}/nexus3/etc/nexus.properties ]; then echo "# Jetty section" > ${cfg.home}/nexus3/etc/nexus.properties echo "application-port=${toString cfg.listenPort}" >> ${cfg.home}/nexus3/etc/nexus.properties @@ -124,7 +124,6 @@ in User = cfg.user; Group = cfg.group; PrivateTmp = true; - PermissionsStartOnly = true; LimitNOFILE = 102642; }; }; diff --git a/nixpkgs/nixos/modules/services/web-servers/minio.nix b/nixpkgs/nixos/modules/services/web-servers/minio.nix index f78a966989b6..cd123000f009 100644 --- a/nixpkgs/nixos/modules/services/web-servers/minio.nix +++ b/nixpkgs/nixos/modules/services/web-servers/minio.nix @@ -72,19 +72,16 @@ in }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.configDir}' - minio minio - -" + "d '${cfg.dataDir}' - minio minio - -" + ]; + systemd.services.minio = { description = "Minio Object Storage"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - preStart = '' - # Make sure directories exist with correct owner - mkdir -p ${cfg.configDir} - chown -R minio:minio ${cfg.configDir} - mkdir -p ${cfg.dataDir} - chown minio:minio ${cfg.dataDir} - ''; serviceConfig = { - PermissionsStartOnly = true; ExecStart = "${cfg.package}/bin/minio server --json --address ${cfg.listenAddress} --config-dir=${cfg.configDir} ${cfg.dataDir}"; Type = "simple"; User = "minio"; diff --git a/nixpkgs/nixos/modules/services/web-servers/traefik.nix b/nixpkgs/nixos/modules/services/web-servers/traefik.nix index 4674ed0177e6..5bac895d43ac 100644 --- a/nixpkgs/nixos/modules/services/web-servers/traefik.nix +++ b/nixpkgs/nixos/modules/services/web-servers/traefik.nix @@ -84,18 +84,16 @@ in { }; config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0700 traefik traefik - -" + ]; + systemd.services.traefik = { description = "Traefik web server"; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - PermissionsStartOnly = true; ExecStart = ''${cfg.package.bin}/bin/traefik --configfile=${configFile}''; - ExecStartPre = [ - ''${pkgs.coreutils}/bin/mkdir -p "${cfg.dataDir}"'' - ''${pkgs.coreutils}/bin/chmod 700 "${cfg.dataDir}"'' - ''${pkgs.coreutils}/bin/chown -R traefik:traefik "${cfg.dataDir}"'' - ]; Type = "simple"; User = "traefik"; Group = cfg.group; diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix index 3d748d4308b7..9bf03a494701 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -75,7 +75,7 @@ in { debug = mkEnableOption "gnome-session debug messages"; flashback = { - enableMetacity = mkEnableOption "Enable the standard GNOME Flashback session with Metacity."; + enableMetacity = mkEnableOption "the standard GNOME Flashback session with Metacity"; customSessions = mkOption { type = types.listOf (types.submodule { diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix index d7bd2fc5eb0c..6a698658bdd6 100644 --- a/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix +++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/maxx.nix @@ -13,6 +13,12 @@ in { config = mkIf (xcfg.enable && cfg.enable) { environment.systemPackages = [ pkgs.maxx ]; + # there is hardcoded path in binaries + system.activationScripts.setup-maxx = '' + mkdir -p /opt + ln -sfn ${pkgs.maxx}/opt/MaXX /opt + ''; + services.xserver.desktopManager.session = [ { name = "MaXX"; start = '' diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix index 15609540a6e7..570469843586 100644 --- a/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix +++ b/nixpkgs/nixos/modules/services/x11/display-managers/startx.nix @@ -20,8 +20,8 @@ in Whether to enable the dummy "startx" pseudo-display manager, which allows users to start X manually via the "startx" command from a vt shell. The X server runs under the user's id, not as root. - The user must provide a ~/.xinintrc file containing session startup - commands, see startx(1). This is not autmatically generated + The user must provide a ~/.xinitrc file containing session startup + commands, see startx(1). This is not automatically generated from the desktopManager and windowManager settings. ''; }; diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix b/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix index 40a1680da537..c23e479140f0 100644 --- a/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix +++ b/nixpkgs/nixos/modules/services/x11/display-managers/xpra.nix @@ -33,7 +33,7 @@ in description = "Authentication to use when connecting to xpra"; }; - pulseaudio = mkEnableOption "pulseaudio audio streaming."; + pulseaudio = mkEnableOption "pulseaudio audio streaming"; extraOptions = mkOption { description = "Extra xpra options"; diff --git a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh index 6dafc6cddde7..67cbe720ddc3 100644 --- a/nixpkgs/nixos/modules/system/boot/stage-1-init.sh +++ b/nixpkgs/nixos/modules/system/boot/stage-1-init.sh @@ -555,7 +555,7 @@ echo /sbin/modprobe > /proc/sys/kernel/modprobe # Start stage 2. `switch_root' deletes all files in the ramfs on the # current root. Note that $stage2Init might be an absolute symlink, # in which case "-e" won't work because we're not in the chroot yet. -if ! test -e "$targetRoot/$stage2Init" -o ! -L "$targetRoot/$stage2Init"; then +if [ ! -e "$targetRoot/$stage2Init" ] && [ ! -L "$targetRoot/$stage2Init" ] ; then echo "stage 2 init script ($targetRoot/$stage2Init) not found" fail fi diff --git a/nixpkgs/nixos/modules/system/boot/stage-1.nix b/nixpkgs/nixos/modules/system/boot/stage-1.nix index 8702abd3df83..788e3f4a2ab1 100644 --- a/nixpkgs/nixos/modules/system/boot/stage-1.nix +++ b/nixpkgs/nixos/modules/system/boot/stage-1.nix @@ -32,7 +32,7 @@ let fileSystems = filter utils.fsNeededForBoot config.system.build.fileSystems; # A utility for enumerating the shared-library dependencies of a program - findLibs = pkgs.writeShellScriptBin "find-libs" '' + findLibs = pkgs.buildPackages.writeShellScriptBin "find-libs" '' set -euo pipefail declare -A seen diff --git a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix index 1384873b6631..48be18c71021 100644 --- a/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix +++ b/nixpkgs/nixos/modules/tasks/filesystems/btrfs.nix @@ -19,7 +19,7 @@ in # One could also do regular btrfs balances, but that shouldn't be necessary # during normal usage and as long as the filesystems aren't filled near capacity services.btrfs.autoScrub = { - enable = mkEnableOption "Enable regular btrfs scrub"; + enable = mkEnableOption "regular btrfs scrub"; fileSystems = mkOption { type = types.listOf types.path; diff --git a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix index aaea06bb9a63..f640bb21b133 100644 --- a/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix +++ b/nixpkgs/nixos/modules/virtualisation/ec2-amis.nix @@ -274,5 +274,22 @@ let self = { "18.09".sa-east-1.hvm-ebs = "ami-0e4a8a47fd6db6112"; "18.09".ap-south-1.hvm-ebs = "ami-0880a678d3f555313"; - latest = self."18.09"; + # 19.03.172286.8ea36d73256 + "19.03".eu-west-1.hvm-ebs = "ami-0fe40176548ff0940"; + "19.03".eu-west-2.hvm-ebs = "ami-03a40fd3a02fe95ba"; + "19.03".eu-west-3.hvm-ebs = "ami-0436f9da0f20a638e"; + "19.03".eu-central-1.hvm-ebs = "ami-0022b8ea9efde5de4"; + "19.03".us-east-1.hvm-ebs = "ami-0efc58fb70ae9a217"; + "19.03".us-east-2.hvm-ebs = "ami-0abf711b1b34da1af"; + "19.03".us-west-1.hvm-ebs = "ami-07d126e8838c40ec5"; + "19.03".us-west-2.hvm-ebs = "ami-03f8a737546e47fb0"; + "19.03".ca-central-1.hvm-ebs = "ami-03f9fd0ef2e035ede"; + "19.03".ap-southeast-1.hvm-ebs = "ami-0cff66114c652c262"; + "19.03".ap-southeast-2.hvm-ebs = "ami-054c73a7f8d773ea9"; + "19.03".ap-northeast-1.hvm-ebs = "ami-00db62688900456a4"; + "19.03".ap-northeast-2.hvm-ebs = "ami-0485cdd1a5fdd2117"; + "19.03".sa-east-1.hvm-ebs = "ami-0c6a43c6e0ad1f4e2"; + "19.03".ap-south-1.hvm-ebs = "ami-0303deb1b5890f878"; + + latest = self."19.03"; }; in self diff --git a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix index 903411799d3e..ab65523592d7 100644 --- a/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixpkgs/nixos/modules/virtualisation/virtualbox-image.nix @@ -100,6 +100,11 @@ in { boot.growPartition = true; boot.loader.grub.device = "/dev/sda"; + swapDevices = [{ + device = "/var/swap"; + size = 2048; + }]; + virtualisation.virtualbox.guest.enable = true; }; |