diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/configuration.xml | 6 | ||||
-rw-r--r-- | nixos/modules/config/users-groups.nix | 2 | ||||
-rw-r--r-- | nixos/modules/misc/ids.nix | 5 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 3 | ||||
-rw-r--r-- | nixos/modules/profiles/all-hardware.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/databases/neo4j.nix | 143 | ||||
-rw-r--r-- | nixos/modules/services/hardware/thermald.nix | 28 | ||||
-rw-r--r-- | nixos/modules/services/mail/mlmmj.nix | 128 | ||||
-rw-r--r-- | nixos/modules/services/misc/siproxd.nix | 180 | ||||
-rw-r--r-- | nixos/modules/services/networking/dhcpcd.nix | 5 | ||||
-rw-r--r-- | nixos/modules/services/web-servers/apache-httpd/default.nix | 6 | ||||
-rw-r--r-- | nixos/modules/system/boot/kernel.nix | 1 | ||||
-rw-r--r-- | nixos/modules/system/boot/stage-1.nix | 15 | ||||
-rw-r--r-- | nixos/modules/system/boot/stage-2-init.sh | 4 | ||||
-rw-r--r-- | nixos/modules/tasks/network-interfaces.nix | 89 | ||||
-rw-r--r-- | nixos/modules/virtualisation/container-config.nix | 2 | ||||
-rw-r--r-- | nixos/modules/virtualisation/containers.nix | 90 | ||||
-rw-r--r-- | nixos/modules/virtualisation/nixos-container.pl | 49 | ||||
-rw-r--r-- | nixos/release.nix | 52 |
19 files changed, 771 insertions, 41 deletions
diff --git a/nixos/doc/manual/configuration.xml b/nixos/doc/manual/configuration.xml index d35a5fff4aa4..64372f3bbf14 100644 --- a/nixos/doc/manual/configuration.xml +++ b/nixos/doc/manual/configuration.xml @@ -1053,6 +1053,12 @@ a password. However, you can use the <command>passwd</command> program to set a password, which is retained across invocations of <command>nixos-rebuild</command>.</para> +<para>If you set users.mutableUsers to false, then the contents of /etc/passwd +and /etc/group will be congruent to your NixOS configuration. For instance, +if you remove a user from users.extraUsers and run nixos-rebuild, the user +account will cease to exist. Also, imperative commands for managing users +and groups, such as useradd, are no longer available.</para> + <para>A user ID (uid) is assigned automatically. You can also specify a uid manually by adding diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 5de81a773424..7783f13b14b1 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -404,7 +404,7 @@ in { uid = ids.uids.root; description = "System administrator"; home = "/root"; - shell = cfg.defaultUserShell; + shell = mkDefault cfg.defaultUserShell; group = "root"; extraGroups = [ "grsecurity" ]; hashedPassword = mkDefault config.security.initialRootPassword; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index fa81ff8a8398..515105d886ae 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -141,6 +141,9 @@ unifi = 131; gdm = 132; dhcpd = 133; + siproxd = 134; + mlmmj = 135; + neo4j = 136; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -256,6 +259,8 @@ docker = 131; gdm = 132; tss = 133; + siproxd = 134; + mlmmj = 135; # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399! diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 5b1b008a270c..feb590ad2491 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -100,6 +100,7 @@ ./services/databases/monetdb.nix ./services/databases/mongodb.nix ./services/databases/mysql.nix + ./services/databases/neo4j.nix ./services/databases/openldap.nix ./services/databases/postgresql.nix ./services/databases/redis.nix @@ -142,6 +143,7 @@ ./services/mail/dovecot.nix ./services/mail/freepops.nix ./services/mail/mail.nix + ./services/mail/mlmmj.nix ./services/mail/opensmtpd.nix ./services/mail/postfix.nix ./services/mail/spamassassin.nix @@ -159,6 +161,7 @@ ./services/misc/nix-ssh-serve.nix ./services/misc/rippled.nix ./services/misc/rogue.nix + ./services/misc/siproxd.nix ./services/misc/svnserve.nix ./services/misc/synergy.nix ./services/monitoring/apcupsd.nix diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix index 511c118e2bf5..6385ee69500f 100644 --- a/nixos/modules/profiles/all-hardware.nix +++ b/nixos/modules/profiles/all-hardware.nix @@ -8,7 +8,7 @@ { # The initrd has to contain any module that might be necessary for - # mounting the CD/DVD. + # supporting the most important parts of HW like drives. boot.initrd.availableKernelModules = [ # SATA/PATA support. "ahci" @@ -43,7 +43,7 @@ "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "virtio_console" # Keyboards - "hid_apple" + "usbhid" "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" ]; # Include lots of firmware. diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix new file mode 100644 index 000000000000..2ef49a95166e --- /dev/null +++ b/nixos/modules/services/databases/neo4j.nix @@ -0,0 +1,143 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.neo4j; + + serverConfig = pkgs.writeText "neo4j-server.properties" '' + org.neo4j.server.database.location=${cfg.dataDir}/data/graph.db + org.neo4j.server.webserver.address=${cfg.host} + org.neo4j.server.webserver.port=${toString cfg.port} + ${optionalString cfg.enableHttps '' + org.neo4j.server.webserver.https.enabled=true + org.neo4j.server.webserver.https.port=${toString cfg.httpsPort} + org.neo4j.server.webserver.https.cert.location=${cfg.cert} + org.neo4j.server.webserver.https.key.location=${cfg.key} + org.neo4j.server.webserver.https.keystore.location=${cfg.dataDir}/data/keystore + ''} + org.neo4j.server.webadmin.rrdb.location=${cfg.dataDir}/data/rrd + org.neo4j.server.webadmin.data.uri=/db/data/ + org.neo4j.server.webadmin.management.uri=/db/manage/ + org.neo4j.server.db.tuning.properties=${pkgs.neo4j}/share/neo4j/conf/neo4j.properties + org.neo4j.server.manage.console_engines=shell + ${cfg.extraServerConfig} + ''; + + loggingConfig = pkgs.writeText "logging.properties" cfg.loggingConfig; + + wrapperConfig = pkgs.writeText "neo4j-wrapper.conf" '' + wrapper.java.additional=-Dorg.neo4j.server.properties=${serverConfig} + wrapper.java.additional=-Djava.util.logging.config.file=${loggingConfig} + wrapper.java.additional=-XX:+UseConcMarkSweepGC + wrapper.java.additional=-XX:+CMSClassUnloadingEnabled + wrapper.pidfile=${cfg.dataDir}/neo4j-server.pid + wrapper.name=neo4j + ''; + +in { + + ###### interface + + options.services.neo4j = { + enable = mkOption { + description = "Whether to enable neo4j."; + default = false; + type = types.uniq types.bool; + }; + + host = mkOption { + description = "Neo4j listen address."; + default = "127.0.0.1"; + type = types.str; + }; + + port = mkOption { + description = "Neo4j port to listen for HTTP traffic."; + default = 7474; + type = types.int; + }; + + enableHttps = mkOption { + description = "Enable https for Neo4j."; + default = false; + type = types.bool; + }; + + httpsPort = mkOption { + description = "Neo4j port to listen for HTTPS traffic."; + default = 7473; + type = types.int; + }; + + cert = mkOption { + description = "Neo4j https certificate."; + default = "${cfg.dataDir}/conf/ssl/neo4j.cert"; + type = types.path; + }; + + key = mkOption { + description = "Neo4j https certificate key."; + default = "${cfg.dataDir}/conf/ssl/neo4j.key"; + type = types.path; + }; + + dataDir = mkOption { + description = "Neo4j data directory."; + default = "/var/lib/neo4j"; + type = types.path; + }; + + loggingConfig = mkOption { + description = "Neo4j logging configuration."; + default = '' + handlers=java.util.logging.ConsoleHandler + .level=INFO + org.neo4j.server.level=INFO + + java.util.logging.ConsoleHandler.level=INFO + java.util.logging.ConsoleHandler.formatter=org.neo4j.server.logging.SimpleConsoleFormatter + java.util.logging.ConsoleHandler.filter=org.neo4j.server.logging.NeoLogFilter + ''; + type = types.lines; + }; + + extraServerConfig = mkOption { + description = "Extra configuration for neo4j server."; + default = ""; + type = types.lines; + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.neo4j = { + description = "Neo4j Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + environment = { NEO4J_INSTANCE = cfg.dataDir; }; + serviceConfig = { + ExecStart = "${pkgs.neo4j}/bin/neo4j console"; + User = "neo4j"; + PermissionsStartOnly = true; + }; + preStart = '' + mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf} + ln -fs ${wrapperConfig} ${cfg.dataDir}/conf/neo4j-wrapper.conf + if [ "$(id -u)" = 0 ]; then chown -R neo4j ${cfg.dataDir}; fi + ''; + }; + + environment.systemPackages = [ pkgs.neo4j ]; + + users.extraUsers = singleton { + name = "neo4j"; + uid = config.ids.uids.neo4j; + description = "Neo4j daemon user"; + home = cfg.dataDir; + }; + }; + +} diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix new file mode 100644 index 000000000000..5233794a20cc --- /dev/null +++ b/nixos/modules/services/hardware/thermald.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.thermald; +in { + ###### interface + options = { + services.thermald = { + enable = mkOption { + default = false; + description = '' + Whether to enable thermald, the temperature management daemon. + ''; + }; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + systemd.services.thermald = { + description = "Thermal Daemon Service"; + wantedBy = [ "multi-user.target" ]; + script = "exec ${pkgs.thermald}/sbin/thermald --no-daemon --dbus-enable"; + }; + }; +} diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix new file mode 100644 index 000000000000..637974f05cd1 --- /dev/null +++ b/nixos/modules/services/mail/mlmmj.nix @@ -0,0 +1,128 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.mlmmj; + stateDir = "/var/lib/mlmmj"; + spoolDir = "/var/spool/mlmmj"; + listDir = domain: list: "${spoolDir}/${domain}/${list}"; + listCtl = domain: list: "${listDir domain list}/control"; + transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}"; + virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj"; + alias = domain: list: "${list}: \"|${pkgs.mlmmj}/mlmmj-receive -L ${listDir domain list}/\""; + subjectPrefix = list: "[${list}]"; + listAddress = domain: list: "${list}@${domain}"; + customHeaders = list: domain: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ]; + footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}"; + createList = d: l: '' + ${pkgs.coreutils}/bin/mkdir -p ${listCtl d l} + echo ${listAddress d l} > ${listCtl d l}/listadress + echo "${lib.concatStringsSep "\n" (customHeaders d l)}" > ${listCtl d l}/customheaders + echo ${footer d l} > ${listCtl d l}/footer + echo ${subjectPrefix l} > ${listCtl d l}/prefix + ''; +in + +{ + + ###### interface + + options = { + + services.mlmmj = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable mlmmj"; + }; + + user = mkOption { + type = types.str; + default = "mlmmj"; + description = "mailinglist local user"; + }; + + group = mkOption { + type = types.str; + default = "mlmmj"; + description = "mailinglist local group"; + }; + + listDomain = mkOption { + type = types.str; + default = "localhost"; + description = "Set the mailing list domain"; + }; + + mailLists = mkOption { + type = types.listOf types.str; + default = []; + description = "The collection of hosted maillists"; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = cfg.user; + description = "mlmmj user"; + home = stateDir; + createHome = true; + uid = config.ids.uids.mlmmj; + group = cfg.group; + useDefaultShell = true; + }; + + users.extraGroups = singleton { + name = cfg.group; + gid = config.ids.gids.mlmmj; + }; + + services.postfix = { + enable = true; + recipientDelimiter= "+"; + extraMasterConf = '' + mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-recieve -F -L ${spoolDir}/$nextHop + ''; + + extraAliases = concatMapStrings (alias cfg.listDomain) cfg.mailLists; + + extraConfig = '' + transport = hash:${stateDir}/transports + virtual = hash:${stateDir}/virtuals + ''; + }; + + environment.systemPackages = [ pkgs.mlmmj ]; + + system.activationScripts.mlmmj = '' + ${pkgs.coreutils}/bin/mkdir -p ${stateDir} ${spoolDir}/${cfg.listDomain} + ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir} + ${lib.concatMapStrings (createList cfg.listDomain) cfg.mailLists} + echo ${lib.concatMapStrings (virtual cfg.listDomain) cfg.mailLists} > ${stateDir}/virtuals + echo ${cfg.listDomain} mailman: > ${stateDir}/transports + echo ${lib.concatMapStrings (transport cfg.listDomain) cfg.mailLists} >> ${stateDir}/transports + ''; + + systemd.services."mlmmj-maintd" = { + description = "mlmmj maintenance daemon"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/misc/siproxd.nix b/nixos/modules/services/misc/siproxd.nix new file mode 100644 index 000000000000..9e8fb6c228f2 --- /dev/null +++ b/nixos/modules/services/misc/siproxd.nix @@ -0,0 +1,180 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.siproxd; + + conf = '' + daemonize = 0 + rtp_proxy_enable = 1 + user = siproxd + if_inbound = ${cfg.ifInbound} + if_outbound = ${cfg.ifOutbound} + sip_listen_port = ${toString cfg.sipListenPort} + rtp_port_low = ${toString cfg.rtpPortLow} + rtp_port_high = ${toString cfg.rtpPortHigh} + rtp_dscp = ${toString cfg.rtpDscp} + sip_dscp = ${toString cfg.sipDscp} + ${optionalString (cfg.hostsAllowReg != []) "hosts_allow_reg = ${concatStringsSep "," cfg.hostsAllowReg}"} + ${optionalString (cfg.hostsAllowSip != []) "hosts_allow_sip = ${concatStringsSep "," cfg.hostsAllowSip}"} + ${optionalString (cfg.hostsDenySip != []) "hosts_deny_sip = ${concatStringsSep "," cfg.hostsDenySip}"} + ${if (cfg.passwordFile != "") then "proxy_auth_pwfile = ${cfg.passwordFile}" else ""} + ${cfg.extraConfig} + ''; + + confFile = builtins.toFile "siproxd.conf" conf; + +in +{ + ##### interface + + options = { + + services.siproxd = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the Siproxd SIP + proxy/masquerading daemon. + ''; + }; + + ifInbound = mkOption { + type = types.str; + example = "eth0"; + description = "Local network interface"; + }; + + ifOutbound = mkOption { + type = types.str; + example = "ppp0"; + description = "Public network interface"; + }; + + hostsAllowReg = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "192.168.1.0/24" "192.168.2.0/24" ]; + description = '' + Acess control list for incoming SIP registrations. + ''; + }; + + hostsAllowSip = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "123.45.0.0/16" "123.46.0.0/16" ]; + description = '' + Acess control list for incoming SIP traffic. + ''; + }; + + hostsDenySip = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "10.0.0.0/8" "11.0.0.0/8" ]; + description = '' + Acess control list for denying incoming + SIP registrations and traffic. + ''; + }; + + sipListenPort = mkOption { + type = types.int; + default = 5060; + description = '' + Port to listen for incoming SIP messages. + ''; + }; + + rtpPortLow = mkOption { + type = types.int; + default = 7070; + description = '' + Bottom of UDP port range for incoming and outgoing RTP traffic + ''; + }; + + rtpPortHigh = mkOption { + type = types.int; + default = 7089; + description = '' + Top of UDP port range for incoming and outgoing RTP traffic + ''; + }; + + rtpTimeout = mkOption { + type = types.int; + default = 300; + description = '' + Timeout for an RTP stream. If for the specified + number of seconds no data is relayed on an active + stream, it is considered dead and will be killed. + ''; + }; + + rtpDscp = mkOption { + type = types.int; + default = 46; + description = '' + DSCP (differentiated services) value to be assigned + to RTP packets. Allows QOS aware routers to handle + different types traffic with different priorities. + ''; + }; + + sipDscp = mkOption { + type = types.int; + default = 0; + description = '' + DSCP (differentiated services) value to be assigned + to SIP packets. Allows QOS aware routers to handle + different types traffic with different priorities. + ''; + }; + + passwordFile = mkOption { + type = types.str; + default = ""; + description = '' + Path to per-user password file. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration to add to siproxd configuration. + ''; + }; + + }; + + }; + + ##### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = "siproxyd"; + uid = config.ids.uids.siproxd; + }; + + systemd.services.siproxd = { + description = "SIP proxy/masquerading daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ExecStart = "${pkgs.siproxd}/sbin/siproxd -c ${confFile}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 5a353fc0942a..866707c3a913 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -7,9 +7,10 @@ let dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; }; # Don't start dhcpcd on explicitly configured interfaces or on - # interfaces that are part of a bridge. + # interfaces that are part of a bridge, bond or sit device. ignoredInterfaces = map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces)) + ++ mapAttrsToList (i: _: i) config.networking.sits ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) ++ config.networking.dhcpcd.denyInterfaces; @@ -35,7 +36,7 @@ let # Ignore peth* devices; on Xen, they're renamed physical # Ethernet cards used for bridging. Likewise for vif* and tap* # (Xen) and virbr* and vnet* (libvirt). - denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* + denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit* ${config.networking.dhcpcd.extraConfig} ''; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 78f3cf2b7e49..b83cf276ed52 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -130,7 +130,7 @@ let ''; - loggingConf = '' + loggingConf = (if mainCfg.logFormat != "none" then '' ErrorLog ${mainCfg.logDir}/error_log LogLevel notice @@ -141,7 +141,9 @@ let LogFormat "%{User-agent}i" agent CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat} - ''; + '' else '' + ErrorLog /dev/null + ''); browserHacks = '' diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 9beb7fabce12..79b173a6ead8 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -195,6 +195,7 @@ in "xhci_hcd" "usbhid" "hid_generic" + "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" # Unix domain sockets (needed by udev). "unix" diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 6a069c5d0540..1d3878054432 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -199,6 +199,21 @@ let { object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf; symlink = "/etc/mdadm.conf"; } + { object = config.environment.etc."modprobe.d/nixos.conf".source; + symlink = "/etc/modprobe.d/nixos.conf"; + } + { object = pkgs.stdenv.mkDerivation { + name = "initrd-kmod-blacklist-ubuntu"; + builder = pkgs.writeText "builder.sh" '' + source $stdenv/setup + target=$out + + ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out + ''; + src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; + }; + symlink = "/etc/modprobe.d/ubuntu.conf"; + } ]; }; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index fcefdfa88a36..6fff776f8581 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -29,7 +29,9 @@ setPath "@path@" # Normally, stage 1 mounts the root filesystem read/writable. # However, in some environments, stage 2 is executed directly, and the # root is read-only. So make it writable here. -mount -n -o remount,rw none / +if [ "$container" != systemd-nspawn ]; then + mount -n -o remount,rw none / +fi # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 991f9f261450..7dabe70f00c4 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -7,6 +7,7 @@ let cfg = config.networking; interfaces = attrValues cfg.interfaces; hasVirtuals = any (i: i.virtual) interfaces; + hasSits = cfg.sits != { }; hasBonds = cfg.bonds != { }; interfaceOpts = { name, ... }: { @@ -321,6 +322,66 @@ in }; }; + networking.sits = mkOption { + type = types.attrsOf types.optionSet; + default = { }; + example = { + hurricane = { + remote = "10.0.0.1"; + local = "10.0.0.22"; + ttl = 255; + }; + msipv6 = { + remote = "192.168.0.1"; + dev = "enp3s0"; + ttl = 127; + }; + }; + description = '' + This option allows you to define 6-to-4 interfaces which should be automatically created. + ''; + options = { + + remote = mkOption { + type = types.nullOr types.str; + default = null; + example = "10.0.0.1"; + description = '' + The address of the remote endpoint to forward traffic over. + ''; + }; + + local = mkOption { + type = types.nullOr types.str; + default = null; + example = "10.0.0.22"; + description = '' + The address of the local endpoint which the remote + side should send packets to. + ''; + }; + + ttl = mkOption { + type = types.nullOr types.int; + default = null; + example = 255; + description = '' + The time-to-live of the connection to the remote tunnel endpoint. + ''; + }; + + dev = mkOption { + type = types.nullOr types.str; + default = null; + example = "enp4s0f0"; + description = '' + The underlying network device on which the tunnel resides. + ''; + }; + + }; + }; + networking.vlans = mkOption { default = { }; example = { @@ -380,6 +441,7 @@ in boot.kernelModules = [ ] ++ optional cfg.enableIPv6 "ipv6" ++ optional hasVirtuals "tun" + ++ optional hasSits "sit" ++ optional hasBonds "bonding"; boot.extraModprobeConfig = @@ -641,6 +703,32 @@ in ''; }; + createSitDevice = n: v: + let + deps = optional (v.dev != null) "sys-subsystem-net-devices-${v.dev}.device"; + in + { description = "6-to-4 Tunnel Interface ${n}"; + wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; + bindsTo = deps; + after = deps; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + path = [ pkgs.iproute ]; + script = '' + # Remove Dead Interfaces + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" + ip link add "${n}" type sit \ + ${optionalString (v.remote != null) "remote \"${v.remote}\""} \ + ${optionalString (v.local != null) "local \"${v.local}\""} \ + ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \ + ${optionalString (v.dev != null) "dev \"${v.dev}\""} + ip link set "${n}" up + ''; + postStop = '' + ip link delete "${n}" + ''; + }; + createVlanDevice = n: v: let deps = [ "sys-subsystem-net-devices-${v.interface}.device" ]; @@ -668,6 +756,7 @@ in map createTunDevice (filter (i: i.virtual) interfaces)) // mapAttrs createBridgeDevice cfg.bridges // mapAttrs createBondDevice cfg.bonds + // mapAttrs createSitDevice cfg.sits // mapAttrs createVlanDevice cfg.vlans // { "network-setup" = networkSetup; }; diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index b81f97f2b4ec..84e3aa283520 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -89,6 +89,8 @@ with lib; restartIfChanged = false; }; + systemd.services.systemd-remount-fs.enable = false; + }; } diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 7f545a9d3031..292b96e6eb24 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -32,7 +32,10 @@ let fi fi - exec "$1" + # Start the regular stage 1 script, passing the bind-mounted + # notification socket from the host to allow the container + # systemd to signal readiness to the host systemd. + NOTIFY_SOCKET=/var/lib/private/host-notify exec "$1" ''; system = config.nixpkgs.system; @@ -168,17 +171,18 @@ in preStart = '' - mkdir -p -m 0755 $root/var/lib + # Clean up existing machined registration and interfaces. + machinectl terminate "$INSTANCE" 2> /dev/null || true - # Create a named pipe to get a signal when the container - # has finished booting. - rm -f $root/var/lib/startup-done - mkfifo -m 0600 $root/var/lib/startup-done + if [ "$PRIVATE_NETWORK" = 1 ]; then + ip link del dev "ve-$INSTANCE" 2> /dev/null || true + fi ''; script = '' mkdir -p -m 0755 "$root/etc" "$root/var/lib" + mkdir -p -m 0700 "$root/var/lib/private" if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -205,12 +209,16 @@ in fi ''} + # Run systemd-nspawn without startup notification (we'll + # wait for the container systemd to signal readiness). + EXIT_ON_REBOOT=1 NOTIFY_SOCKET= \ exec ${config.systemd.package}/bin/systemd-nspawn \ --keep-unit \ -M "$INSTANCE" -D "$root" $extraFlags \ --bind-ro=/nix/store \ --bind-ro=/nix/var/nix/db \ --bind-ro=/nix/var/nix/daemon-socket \ + --bind=/run/systemd/notify:/var/lib/private/host-notify \ --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \ --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \ --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \ @@ -222,12 +230,6 @@ in postStart = '' - # This blocks until the container-startup-done service - # writes something to this pipe. FIXME: it also hangs - # until the start timeout expires if systemd-nspawn exits. - read x < $root/var/lib/startup-done - rm -f $root/var/lib/startup-done - if [ "$PRIVATE_NETWORK" = 1 ]; then ifaceHost=ve-$INSTANCE ip link set dev $ifaceHost up @@ -242,23 +244,42 @@ in preStop = '' - machinectl poweroff "$INSTANCE" + machinectl poweroff "$INSTANCE" || true ''; restartIfChanged = false; #reloadIfChanged = true; # FIXME - serviceConfig.ExecReload = pkgs.writeScript "reload-container" - '' - #! ${pkgs.stdenv.shell} -e - SYSTEM_PATH=/nix/var/nix/profiles/system - echo $SYSTEM_PATH/bin/switch-to-configuration test | \ - ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket - - ''; + serviceConfig = { + ExecReload = pkgs.writeScript "reload-container" + '' + #! ${pkgs.stdenv.shell} -e + SYSTEM_PATH=/nix/var/nix/profiles/system + echo $SYSTEM_PATH/bin/switch-to-configuration test | \ + ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket - + ''; - serviceConfig.SyslogIdentifier = "container %i"; + SyslogIdentifier = "container %i"; - serviceConfig.EnvironmentFile = "-/etc/containers/%i.conf"; + EnvironmentFile = "-/etc/containers/%i.conf"; + + Type = "notify"; + + NotifyAccess = "all"; + + # Note that on reboot, systemd-nspawn returns 10, so this + # unit will be restarted. On poweroff, it returns 0, so the + # unit won't be restarted. + Restart = "on-failure"; + + # Hack: we don't want to kill systemd-nspawn, since we call + # "machinectl poweroff" in preStop to shut down the + # container cleanly. But systemd requires sending a signal + # (at least if we want remaining processes to be killed + # after the timeout). So send an ignored signal. + KillMode = "mixed"; + KillSignal = "WINCH"; + }; }; # Generate a configuration file in /etc/containers for each @@ -292,5 +313,30 @@ in environment.systemPackages = [ nixos-container ]; + # Start containers at boot time. + systemd.services.all-containers = + { description = "All Containers"; + + wantedBy = [ "multi-user.target" ]; + + unitConfig.ConditionDirectoryNotEmpty = "/etc/containers"; + + serviceConfig.Type = "oneshot"; + + script = + '' + res=0 + shopt -s nullglob + for i in /etc/containers/*.conf; do + AUTO_START= + source "$i" + if [ "$AUTO_START" = 1 ]; then + systemctl start "container@$(basename "$i" .conf).service" || res=1 + fi + done + exit $res + ''; # */ + }; + }; } diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl index c6a5ecde9e32..bf6f16fc6c77 100644 --- a/nixos/modules/virtualisation/nixos-container.pl +++ b/nixos/modules/virtualisation/nixos-container.pl @@ -17,25 +17,31 @@ umask 0022; sub showHelp { print <<EOF; Usage: nixos-container list - nixos-container create <container-name> [--config <string>] [--ensure-unique-name] + nixos-container create <container-name> [--system-path <path>] [--config <string>] [--ensure-unique-name] [--auto-start] nixos-container destroy <container-name> nixos-container start <container-name> nixos-container stop <container-name> + nixos-container status <container-name> nixos-container login <container-name> nixos-container root-login <container-name> nixos-container run <container-name> -- args... nixos-container set-root-password <container-name> <password> nixos-container show-ip <container-name> + nixos-container show-host-key <container-name> EOF exit 0; } +my $systemPath; my $ensureUniqueName = 0; +my $autoStart = 0; my $extraConfig; GetOptions( "help" => sub { showHelp() }, "ensure-unique-name" => \$ensureUniqueName, + "auto-start" => \$autoStart, + "system-path=s" => \$systemPath, "config=s" => \$extraConfig ) or exit 1; @@ -122,17 +128,13 @@ if ($action eq "create") { push @conf, "PRIVATE_NETWORK=1\n"; push @conf, "HOST_ADDRESS=$hostAddress\n"; push @conf, "LOCAL_ADDRESS=$localAddress\n"; + push @conf, "AUTO_START=$autoStart\n"; write_file($confFile, \@conf); close($lock); print STDERR "host IP is $hostAddress, container IP is $localAddress\n"; - mkpath("$root/etc/nixos", 0, 0755); - - my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; - writeNixOSConfig $nixosConfigFile; - # The per-container directory is restricted to prevent users on # the host from messing with guest users who happen to have the # same uid. @@ -141,10 +143,21 @@ if ($action eq "create") { $profileDir = "$profileDir/$containerName"; mkpath($profileDir, 0, 0755); - system("nix-env", "-p", "$profileDir/system", - "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", - "--set", "-A", "system") == 0 - or die "$0: failed to build initial container configuration\n"; + # Build/set the initial configuration. + if (defined $systemPath) { + system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0 + or die "$0: failed to set initial container configuration\n"; + } else { + mkpath("$root/etc/nixos", 0, 0755); + + my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; + writeNixOSConfig $nixosConfigFile; + + system("nix-env", "-p", "$profileDir/system", + "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", + "--set", "-A", "system") == 0 + or die "$0: failed to build initial container configuration\n"; + } print "$containerName\n" if $ensureUniqueName; exit 0; @@ -155,7 +168,11 @@ my $profileDir = "/nix/var/nix/profiles/per-container/$containerName"; my $gcRootsDir = "/nix/var/nix/gcroots/per-container/$containerName"; my $confFile = "/etc/containers/$containerName.conf"; if (!-e $confFile) { - exit 0 if $action eq "destroy"; + if ($action eq "destroy") { + exit 0; + } elsif ($action eq "status") { + print "gone\n"; + } die "$0: container ‘$containerName’ does not exist\n" ; } @@ -190,6 +207,10 @@ elsif ($action eq "stop") { stopContainer; } +elsif ($action eq "status") { + print isContainerRunning() ? "up" : "down", "\n"; +} + elsif ($action eq "update") { my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; @@ -244,6 +265,12 @@ elsif ($action eq "show-ip") { print "$1\n"; } +elsif ($action eq "show-host-key") { + my $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub"; + exit 1 if ! -f $fn; + print read_file($fn); +} + else { die "$0: unknown action ‘$action’\n"; } diff --git a/nixos/release.nix b/nixos/release.nix index ed413d3e928f..0620b46d46ad 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -78,6 +78,16 @@ let }; + makeClosure = module: forAllSystems (system: (import ./lib/eval-config.nix { + inherit system; + modules = [ module ] ++ lib.singleton + ({ config, lib, ... }: + { fileSystems."/".device = lib.mkDefault "/dev/sda1"; + boot.loader.grub.device = lib.mkDefault "/dev/sda"; + }); + }).config.system.build.toplevel); + + in rec { channel = @@ -242,4 +252,46 @@ in rec { tests.udisks2 = callTest tests/udisks2.nix {}; tests.xfce = callTest tests/xfce.nix {}; + + /* Build a bunch of typical closures so that Hydra can keep track of + the evolution of closure sizes. */ + + closures = { + + smallContainer = makeClosure ({ pkgs, ... }: + { boot.isContainer = true; + services.openssh.enable = true; + }); + + tinyContainer = makeClosure ({ pkgs, ... }: + { boot.isContainer = true; + imports = [ modules/profiles/minimal.nix ]; + }); + + ec2 = makeClosure ({ pkgs, ... }: + { imports = [ modules/virtualisation/amazon-image.nix ]; + }); + + kde = makeClosure ({ pkgs, ... }: + { services.xserver.enable = true; + services.xserver.displayManager.kdm.enable = true; + services.xserver.desktopManager.kde4.enable = true; + }); + + xfce = makeClosure ({ pkgs, ... }: + { services.xserver.enable = true; + services.xserver.desktopManager.xfce.enable = true; + }); + + # Linux/Apache/PostgreSQL/PHP stack. + lapp = makeClosure ({ pkgs, ... }: + { services.httpd.enable = true; + services.httpd.adminAddr = "foo@example.org"; + services.postgresql.enable = true; + services.postgresql.package = pkgs.postgresql93; + environment.systemPackages = [ pkgs.php ]; + }); + + }; + } |