diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000000..e75fb319980
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*~
+.version-suffix
diff --git a/.version b/.version
index ceab6e11ece..2f4536184bc 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-0.1
\ No newline at end of file
+0.2
\ No newline at end of file
diff --git a/doc/manual/configuration.xml b/doc/manual/configuration.xml
new file mode 100644
index 00000000000..f1f99fb70ed
--- /dev/null
+++ b/doc/manual/configuration.xml
@@ -0,0 +1,173 @@
+
+
+Configuring NixOS
+
+This chapter describes how to configure various aspects of a
+NixOS machine through the configuration file
+/etc/nixos/configuration.nix. As described in
+, changes to that file only take
+effect after you run nixos-rebuild.
+
+
+
+
+Networking
+
+Secure shell access
+
+Secure shell (SSH) access to your machine can be enabled by
+setting:
+
+
+services.openssh.enable = true;
+
+
+By default, root logins using a password are disallowed. They can be
+disabled entirely by setting
+services.openssh.permitRootLogin to
+"no".
+
+You can declaratively specify authorised RSA/DSA public keys for
+a user as follows:
+
+
+
+users.extraUsers.alice.openssh.authorizedKeys.keys =
+ [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ];
+
+
+
+
+
+
+
+IPv4 configuration
+
+By default, NixOS uses DHCP (specifically,
+(dhcpcd)) to automatically configure network
+interfaces. However, you can configure an interface manually as
+follows:
+
+
+networking.interfaces.eth0 = { ipAddress = "192.168.1.2"; prefixLength = 24; };
+
+
+(The network prefix can also be specified using the option
+subnetMask,
+e.g. "255.255.255.0", but this is deprecated.)
+Typically you’ll also want to set a default gateway and set of name
+servers:
+
+
+networking.defaultGateway = "192.168.1.1";
+networking.nameservers = [ "8.8.8.8" ];
+
+
+
+
+Statically configured interfaces are set up by the systemd
+service
+interface-name-cfg.service.
+The default gateway and name server configuration is performed by
+network-setup.service.
+
+The host name is set using :
+
+
+networking.hostName = "cartman";
+
+
+The default host name is nixos. Set it to the
+empty string ("") to allow the DHCP server to
+provide the host name.
+
+
+
+
+IPv6 configuration
+
+IPv6 is enabled by default. Stateless address autoconfiguration
+is used to automatically assign IPv6 addresses to all interfaces. You
+can disable IPv6 support globally by setting:
+
+
+networking.enableIPv6 = false;
+
+
+
+
+
+
+
+Firewall
+
+NixOS has a simple stateful firewall that blocks incoming
+connections and other unexpected packets. The firewall applies to
+both IPv4 and IPv6 traffic. It can be enabled as follows:
+
+
+networking.firewall.enable = true;
+
+
+You can open specific TCP ports to the outside world:
+
+
+networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+
+Note that TCP port 22 (ssh) is opened automatically if the SSH daemon
+is enabled (). UDP
+ports can be opened through
+. Also of
+interest is
+
+
+networking.firewall.allowPing = true;
+
+
+to allow the machine to respond to ping requests. (ICMPv6 pings are
+always allowed.)
+
+
+
+
+Wireless networks
+
+TODO
+
+
+
+
+Ad-hoc configuration
+
+You can use to specify
+shell commands to be run at the end of
+network-setup.service. This is useful for doing
+network configuration not covered by the existing NixOS modules. For
+instance, to statically configure an IPv6 address:
+
+
+networking.localCommands =
+ ''
+ ip -6 addr add 2001:610:685:1::1/64 dev eth0
+ '';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/manual/default.nix b/doc/manual/default.nix
index d3f554c099e..e6edb30985c 100644
--- a/doc/manual/default.nix
+++ b/doc/manual/default.nix
@@ -59,7 +59,7 @@ in rec {
mkdir -p $dst/images/callouts
cp ${pkgs.docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/
-
+
cp ${./style.css} $dst/style.css
ensureDir $out/nix-support
diff --git a/doc/manual/installation.xml b/doc/manual/installation.xml
index 6f19cc1a0b8..1c00dd37d33 100644
--- a/doc/manual/installation.xml
+++ b/doc/manual/installation.xml
@@ -1,7 +1,7 @@
-Installation
+Installing NixOS
@@ -58,7 +58,7 @@ Wiki.
For partitioning:
fdisk.
-
+
For initialising Ext4 partitions:
mkfs.ext4. It is recommended that you assign a
unique symbolic label to the file system using the option
@@ -70,13 +70,13 @@ Wiki.
mkswap. Again it’s recommended to assign a
label to the swap partition: .
-
+
For creating LVM volumes, the LVM commands, e.g.,
$ pvcreate /dev/sda1 /dev/sdb1
$ vgcreate MyVolGroup /dev/sda1 /dev/sdb1
-$ lvcreate --size 2G --name bigdisk MyVolGroup
+$ lvcreate --size 2G --name bigdisk MyVolGroup
$ lvcreate --size 1G --name smalldisk MyVolGroup
@@ -87,7 +87,7 @@ $ lvcreate --size 1G --name smalldisk MyVolGroup
-
+
Mount the target file system on which NixOS should
be installed on /mnt.
@@ -138,7 +138,7 @@ $ nixos-option --install
xlink:href="https://nixos.org/repos/nix/configurations/trunk/"/>.
-
+
If your machine has a limited amount of memory, you
may want to activate swap devices now (swapon
device). The installer (or
@@ -230,15 +230,11 @@ $ reboot
{
boot.loader.grub.device = "/dev/sda";
- fileSystems =
- [ { mountPoint = "/";
- device = "/dev/disk/by-label/nixos";
- }
- ];
+ fileSystems."/".device = "/dev/disk/by-label/nixos";
swapDevices =
[ { device = "/dev/disk/by-label/swap"; } ];
-
+
services.sshd.enable = true;
}
@@ -264,7 +260,7 @@ to build the new configuration, make it the default configuration for
booting, and try to realise the configuration in the running system
(e.g., by restarting system services).
-You can also do
+You can also do
$ nixos-rebuild test
@@ -274,7 +270,7 @@ without making it the boot default. So if (say) the configuration
locks up your machine, you can just reboot to get back to a working
configuration.
-There is also
+There is also
$ nixos-rebuild boot
@@ -283,7 +279,7 @@ to build the configuration and make it the boot default, but not
switch to it now (so it will only take effect after the next
reboot).
-Finally, you can do
+Finally, you can do
$ nixos-rebuild build
@@ -333,7 +329,7 @@ You can then upgrade NixOS to the latest version in the channel by
running
-$ nix-channel --update
+$ nix-channel --update nixos
and running the nixos-rebuild command as described
diff --git a/doc/manual/manual.xml b/doc/manual/manual.xml
index b7e4c6315f9..ce4055a753c 100644
--- a/doc/manual/manual.xml
+++ b/doc/manual/manual.xml
@@ -24,16 +24,16 @@
2007-2012
Eelco Dolstra
-
+
-
+
Preface
This manual describes NixOS, a Linux distribution based on
the purely functional package management system Nix.
-
+
NixOS is rather bleeding edge, and this manual is
correspondingly sketchy and quite possibly out of date. It gives
basic information on how to get NixOS up and running, but since
@@ -45,11 +45,13 @@
mailing list or on the
#nixos channel on Freenode..
-
+
-
+
+
+
diff --git a/doc/manual/running.xml b/doc/manual/running.xml
new file mode 100644
index 00000000000..ea4028b6e9b
--- /dev/null
+++ b/doc/manual/running.xml
@@ -0,0 +1,288 @@
+
+
+Running NixOS
+
+This chapter describes various aspects of managing a running
+NixOS system, such as how to use the systemd
+service manager.
+
+
+
+
+Service management
+
+In NixOS, all system services are started and monitored using
+the systemd program. Systemd is the “init” process of the system
+(i.e. PID 1), the parent of all other processes. It manages a set of
+so-called “units”, which can be things like system services
+(programs), but also mount points, swap files, devices, targets
+(groups of units) and more. Units can have complex dependencies; for
+instance, one unit can require that another unit must be succesfully
+started before the first unit can be started. When the system boots,
+it starts a unit named default.target; the
+dependencies of this unit cause all system services to be started,
+filesystems to be mounted, swap files to be activated, and so
+on.
+
+The command systemctl is the main way to
+interact with systemd. Without any arguments, it
+shows the status of active units:
+
+
+$ systemctl
+-.mount loaded active mounted /
+swapfile.swap loaded active active /swapfile
+sshd.service loaded active running SSH Daemon
+graphical.target loaded active active Graphical Interface
+...
+
+
+
+
+You can ask for detailed status information about a unit, for
+instance, the PostgreSQL database service:
+
+
+$ systemctl status postgresql.service
+postgresql.service - PostgreSQL Server
+ Loaded: loaded (/nix/store/pn3q73mvh75gsrl8w7fdlfk3fq5qm5mw-unit/postgresql.service)
+ Active: active (running) since Mon, 2013-01-07 15:55:57 CET; 9h ago
+ Main PID: 2390 (postgres)
+ CGroup: name=systemd:/system/postgresql.service
+ ├─2390 postgres
+ ├─2418 postgres: writer process
+ ├─2419 postgres: wal writer process
+ ├─2420 postgres: autovacuum launcher process
+ ├─2421 postgres: stats collector process
+ └─2498 postgres: zabbix zabbix [local] idle
+
+Jan 07 15:55:55 hagbard postgres[2394]: [1-1] LOG: database system was shut down at 2013-01-07 15:55:05 CET
+Jan 07 15:55:57 hagbard postgres[2390]: [1-1] LOG: database system is ready to accept connections
+Jan 07 15:55:57 hagbard postgres[2420]: [1-1] LOG: autovacuum launcher started
+Jan 07 15:55:57 hagbard systemd[1]: Started PostgreSQL Server.
+
+
+Note that this shows the status of the unit (active and running), all
+the processes belonging to the service, as well as the most recent log
+messages from the service.
+
+
+
+Units can be stopped, started or restarted:
+
+
+$ systemctl stop postgresql.service
+$ systemctl start postgresql.service
+$ systemctl restart postgresql.service
+
+
+These operations are synchronous: they wait until the service has
+finished starting or stopping (or has failed). Starting a unit will
+cause the dependencies of that unit to be started as well (if
+necessary).
+
+
+
+
+
+
+
+
+Rebooting and shutting down
+
+The system can be shut down (and automatically powered off) by
+doing:
+
+
+$ shutdown
+
+
+This is equivalent to running systemctl poweroff.
+Likewise, reboot (a.k.a. systemctl
+reboot) will reboot the system.
+
+The machine can be suspended to RAM (if supported) using
+systemctl suspend, and suspended to disk using
+systemctl hibernate.
+
+These commands can be run by any user who is logged in locally,
+i.e. on a virtual console or in X11; otherwise, the user is asked for
+authentication.
+
+
+
+
+
+
+User sessions
+
+Systemd keeps track of all users who are logged into the system
+(e.g. on a virtual console or remotely via SSH). The command
+loginctl allows quering and manipulating user
+sessions. For instance, to list all user sessions:
+
+
+$ loginctl
+ SESSION UID USER SEAT
+ c1 500 eelco seat0
+ c3 0 root seat0
+ c4 500 alice
+
+
+This shows that two users are logged in locally, while another is
+logged in remotely. (“Seats” are essentially the combinations of
+displays and input devices attached to the system; usually, there is
+only one seat.) To get information about a session:
+
+
+$ loginctl session-status c3
+c3 - root (0)
+ Since: Tue, 2013-01-08 01:17:56 CET; 4min 42s ago
+ Leader: 2536 (login)
+ Seat: seat0; vc3
+ TTY: /dev/tty3
+ Service: login; type tty; class user
+ State: online
+ CGroup: name=systemd:/user/root/c3
+ ├─ 2536 /nix/store/10mn4xip9n7y9bxqwnsx7xwx2v2g34xn-shadow-4.1.5.1/bin/login --
+ ├─10339 -bash
+ └─10355 w3m nixos.org
+
+
+This shows that the user is logged in on virtual console 3. It also
+lists the processes belonging to this session. Since systemd keeps
+track of this, you can terminate a session in a way that ensures that
+all the session’s processes are gone:
+
+
+$ loginctl terminate-session c3
+
+
+
+
+
+
+
+
+
+Control groups
+
+To keep track of the processes in a running system, systemd uses
+control groups (cgroups). A control group is a
+set of processes used to allocate resources such as CPU, memory or I/O
+bandwidth. There can be multiple control group hierarchies, allowing
+each kind of resource to be managed independently.
+
+The command systemd-cgls lists all control
+groups in the systemd hierarchy, which is what
+systemd uses to keep track of the processes belonging to each service
+or user session:
+
+
+$ systemd-cgls
+├─user
+│ └─eelco
+│ └─c1
+│ ├─ 2567 -:0
+│ ├─ 2682 kdeinit4: kdeinit4 Running...
+│ ├─ ...
+│ └─10851 sh -c less -R
+└─system
+ ├─httpd.service
+ │ ├─2444 httpd -f /nix/store/3pyacby5cpr55a03qwbnndizpciwq161-httpd.conf -DNO_DETACH
+ │ └─...
+ ├─dhcpcd.service
+ │ └─2376 dhcpcd --config /nix/store/f8dif8dsi2yaa70n03xir8r653776ka6-dhcpcd.conf
+ └─ ...
+
+
+Similarly, systemd-cgls cpu shows the cgroups in
+the CPU hierarchy, which allows per-cgroup CPU scheduling priorities.
+By default, every systemd service gets its own CPU cgroup, while all
+user sessions are in the top-level CPU cgroup. This ensures, for
+instance, that a thousand run-away processes in the
+httpd.service cgroup cannot starve the CPU for one
+process in the postgresql.service cgroup. (By
+contrast, it they were in the same cgroup, then the PostgreSQL process
+would get 1/1001 of the cgroup’s CPU time.) You can limit a service’s
+CPU share in configuration.nix:
+
+
+systemd.services.httpd.serviceConfig.CPUShares = 512;
+
+
+By default, every cgroup has 1024 CPU shares, so this will halve the
+CPU allocation of the httpd.service cgroup.
+
+There also is a memory hierarchy that
+controls memory allocation limits; by default, all processes are in
+the top-level cgroup, so any service or session can exhaust all
+available memory. Per-cgroup memory limits can be specified in
+configuration.nix; for instance, to limit
+httpd.service to 512 MiB of RAM (excluding swap)
+and 640 MiB of RAM (including swap):
+
+
+systemd.services.httpd.serviceConfig.MemoryLimit = "512M";
+systemd.services.httpd.serviceConfig.ControlGroupAttribute = [ "memory.memsw.limit_in_bytes 640M" ];
+
+
+
+
+The command systemd-cgtop shows a
+continuously updated list of all cgroups with their CPU and memory
+usage.
+
+
+
+
+
+
+Logging
+
+System-wide logging is provided by systemd’s
+journal, which subsumes traditional logging
+daemons such as syslogd and klogd. Log entries are kept in binary
+files in /var/log/journal/. The command
+journalctl allows you to see the contents of the
+journal. For example,
+
+
+$ journalctl -b
+
+
+shows all journal entries since the last reboot. (The output of
+journalctl is piped into less by
+default.) You can use various options and match operators to restrict
+output to messages of interest. For instance, to get all messages
+from PostgreSQL:
+
+
+$ journalctl _SYSTEMD_UNIT=postgresql.service
+-- Logs begin at Mon, 2013-01-07 13:28:01 CET, end at Tue, 2013-01-08 01:09:57 CET. --
+...
+Jan 07 15:44:14 hagbard postgres[2681]: [2-1] LOG: database system is shut down
+-- Reboot --
+Jan 07 15:45:10 hagbard postgres[2532]: [1-1] LOG: database system was shut down at 2013-01-07 15:44:14 CET
+Jan 07 15:45:13 hagbard postgres[2500]: [1-1] LOG: database system is ready to accept connections
+
+
+Or to get all messages since the last reboot that have at least a
+“critical” severity level:
+
+
+$ journalctl -b -p crit
+Dec 17 21:08:06 mandark sudo[3673]: pam_unix(sudo:auth): auth could not identify password for [alice]
+Dec 29 01:30:22 mandark kernel[6131]: [1053513.909444] CPU6: Core temperature above threshold, cpu clock throttled (total events = 1)
+
+
+
+
+
+
+
+
diff --git a/doc/manual/troubleshooting.xml b/doc/manual/troubleshooting.xml
index ff19607844f..2961f8e1233 100644
--- a/doc/manual/troubleshooting.xml
+++ b/doc/manual/troubleshooting.xml
@@ -4,60 +4,81 @@
Troubleshooting
-
-
-Debugging the boot process
+Boot problems
-To get a Stage 1 shell (i.e., a shell in the initial ramdisk),
-add debug1 to the kernel command line. The shell
-gets started before anything useful has been done. That is, no
-modules have been loaded and no file systems have been mounted, except
-for /proc and /sys.
+If NixOS fails to boot, there are a number of kernel command
+line parameters that may help you to identify or fix the issue. You
+can add these parameters in the GRUB boot menu by pressing “e” to
+modify the selected boot entry and editing the line starting with
+linux. The following are some useful kernel command
+line parameters that are recognised by the NixOS boot scripts or by
+systemd:
-To get a Stage 2 shell (i.e., a shell in the actual root file
-system), add debug2 to the kernel command
-line. This shell is started right after stage 1 calls the stage 2
-init script, so the root file system is there but
-no services have been started.
+
-
+ boot.shell_on_fail
+ Start a root shell if something goes wrong in
+ stage 1 of the boot process (the initial ramdisk). This is
+ disabled by default because there is no authentication for the
+ root shell.
+
+ boot.debug1
+ Start an interactive shell in stage 1 before
+ anything useful has been done. That is, no modules have been
+ loaded and no file systems have been mounted, except for
+ /proc and
+ /sys.
+
+ boot.trace
+ Print every shell command executed by the stage 1
+ and 2 boot scripts.
+
-
-
-Safe mode
+ single
+ Boot into rescue mode (a.k.a. single user mode).
+ This will cause systemd to start nothing but the unit
+ rescue.target, which runs
+ sulogin to prompt for the root password and
+ start a root login shell. Exiting the shell causes the system to
+ continue with the normal boot process.
+
-If the hardware autodetection (in
-upstart-jobs/hardware-scan) causes problems, add
-safemode to the kernel command line. This will
-disable auto-loading of modules for your PCI devices. However, you
-will probably need to explicitly add modules to
- to get network support etc.
+ systemd.log_level=debug systemd.log_target=console
+ Make systemd very verbose and send log messages to
+ the console instead of the journal.
+
+
+
+
+For more parameters recognised by systemd, see
+systemd1.
+
+If no login prompts or X11 login screens appear (e.g. due to
+hanging dependencies), you can press Alt+ArrowUp. If you’re lucky,
+this will start rescue mode (described above). (Also note that since
+most units have a 90-second timeout before systemd gives up on them,
+the agetty login prompts should appear eventually
+unless something is very wrong.)
-
+
Maintenance mode
-You can go to maintenance mode by doing
+You can enter rescue mode by running:
-$ shutdown now
+$ systemctl rescue
-This will eventually give you a single-user root shell.
-
-To get out of maintenance mode, do
-
-
-$ initctl emit startup
-
-
+This will eventually give you a single-user root shell. Systemd will
+stop (almost) all system services. To get out of maintenance mode,
+just exit from the rescue shell.
-
diff --git a/lib/build-vms.nix b/lib/build-vms.nix
index aacd0e99cb1..59f05bfd104 100644
--- a/lib/build-vms.nix
+++ b/lib/build-vms.nix
@@ -2,7 +2,7 @@
let pkgs = import { config = {}; inherit system; }; in
-with pkgs;
+with pkgs.lib;
with import ../lib/qemu-flags.nix;
rec {
@@ -15,7 +15,7 @@ rec {
# hostname and `configX' is a NixOS system configuration. Each
# machine is given an arbitrary IP address in the virtual network.
buildVirtualNetwork =
- nodes: let nodesOut = lib.mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
+ nodes: let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
buildVM =
@@ -27,7 +27,7 @@ rec {
[ ../modules/virtualisation/qemu-vm.nix
../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
{ key = "no-manual"; services.nixosManual.enable = false; }
- ] ++ lib.optional minimal ../modules/testing/minimal-kernel.nix;
+ ] ++ optional minimal ../modules/testing/minimal-kernel.nix;
extraArgs = { inherit nodes; };
};
@@ -39,51 +39,49 @@ rec {
let
- machines = lib.attrNames nodes;
+ machines = attrNames nodes;
- machinesNumbered = lib.zipTwoLists machines (lib.range 1 254);
+ machinesNumbered = zipTwoLists machines (range 1 254);
- nodes_ = lib.flip map machinesNumbered (m: lib.nameValuePair m.first
+ nodes_ = flip map machinesNumbered (m: nameValuePair m.first
[ ( { config, pkgs, nodes, ... }:
let
- interfacesNumbered = lib.zipTwoLists config.virtualisation.vlans (lib.range 1 255);
- interfaces =
- lib.flip map interfacesNumbered ({ first, second }:
- { name = "eth${toString second}";
- ipAddress = "192.168.${toString first}.${toString m.second}";
+ interfacesNumbered = zipTwoLists config.virtualisation.vlans (range 1 255);
+ interfaces = flip map interfacesNumbered ({ first, second }:
+ nameValuePair "eth${toString second}"
+ { ipAddress = "192.168.${toString first}.${toString m.second}";
subnetMask = "255.255.255.0";
- }
- );
+ });
in
{ key = "ip-address";
config =
{ networking.hostName = m.first;
- networking.interfaces = interfaces;
+ networking.interfaces = listToAttrs interfaces;
networking.primaryIPAddress =
- lib.optionalString (interfaces != []) (lib.head interfaces).ipAddress;
+ optionalString (interfaces != []) (head interfaces).value.ipAddress;
# Put the IP addresses of all VMs in this machine's
# /etc/hosts file. If a machine has multiple
# interfaces, use the IP address corresponding to
# the first interface (i.e. the first network in its
# virtualisation.vlans option).
- networking.extraHosts = lib.flip lib.concatMapStrings machines
- (m: let config = (lib.getAttr m nodes).config; in
- lib.optionalString (config.networking.primaryIPAddress != "")
+ networking.extraHosts = flip concatMapStrings machines
+ (m: let config = (getAttr m nodes).config; in
+ optionalString (config.networking.primaryIPAddress != "")
("${config.networking.primaryIPAddress} " +
"${config.networking.hostName}\n"));
virtualisation.qemu.options =
- lib.flip map interfacesNumbered
+ flip map interfacesNumbered
({ first, second }: qemuNICFlags second first m.second);
};
}
)
- (lib.getAttr m.first nodes)
+ (getAttr m.first nodes)
] );
- in lib.listToAttrs nodes_;
+ in listToAttrs nodes_;
}
diff --git a/lib/eval-config.nix b/lib/eval-config.nix
index f99f3fbedbb..c2bbf036af0 100644
--- a/lib/eval-config.nix
+++ b/lib/eval-config.nix
@@ -31,7 +31,7 @@ rec {
inherit pkgs modules baseModules;
modulesPath = ../modules;
pkgs_i686 = import { system = "i686-linux"; };
- utils = {}; # forward compatibility
+ utils = import ./utils.nix pkgs;
};
# Import Nixpkgs, allowing the NixOS option nixpkgs.config to
diff --git a/lib/test-driver/Machine.pm b/lib/test-driver/Machine.pm
index 3e6a1c8d158..1f7533f22f8 100644
--- a/lib/test-driver/Machine.pm
+++ b/lib/test-driver/Machine.pm
@@ -58,6 +58,7 @@ sub new {
stateDir => "$tmpDir/vm-state-$name",
monitor => undef,
log => $args->{log},
+ redirectSerial => $args->{redirectSerial} // 1,
};
mkdir $self->{stateDir}, 0700;
@@ -125,10 +126,12 @@ sub start {
close $serialP;
close $monitorS;
close $shellS;
- open NUL, "{redirectSerial}) {
+ open NUL, "{stateDir};
$ENV{SHARED_DIR} = $sharedDir;
$ENV{USE_TMPDIR} = 1;
@@ -349,18 +352,39 @@ sub mustFail {
}
-# Wait for an Upstart job to reach the "running" state.
-sub waitForJob {
- my ($self, $jobName) = @_;
- $self->nest("waiting for job ‘$jobName’", sub {
+sub getUnitInfo {
+ my ($self, $unit) = @_;
+ my ($status, $lines) = $self->execute("systemctl --no-pager show '$unit'");
+ return undef if $status != 0;
+ my $info = {};
+ foreach my $line (split '\n', $lines) {
+ $line =~ /^([^=]+)=(.*)$/ or next;
+ $info->{$1} = $2;
+ }
+ return $info;
+}
+
+
+# Wait for a systemd unit to reach the "active" state.
+sub waitForUnit {
+ my ($self, $unit) = @_;
+ $self->nest("waiting for unit ‘$unit’", sub {
retry sub {
- my ($status, $out) = $self->execute("initctl status $jobName");
- return 1 if $out =~ /start\/running/;
+ my $info = $self->getUnitInfo($unit);
+ my $state = $info->{ActiveState};
+ die "unit ‘$unit’ reached state ‘$state’\n" if $state eq "failed";
+ return 1 if $state eq "active";
};
});
}
+sub waitForJob {
+ my ($self, $jobName) = @_;
+ return $self->waitForUnit($jobName);
+}
+
+
# Wait until the specified file exists.
sub waitForFile {
my ($self, $fileName) = @_;
@@ -374,16 +398,13 @@ sub waitForFile {
sub startJob {
my ($self, $jobName) = @_;
- $self->execute("initctl start $jobName");
- my ($status, $out) = $self->execute("initctl status $jobName");
- die "failed to start $jobName" unless $out =~ /start\/running/;
+ $self->execute("systemctl stop $jobName");
+ # FIXME: check result
}
sub stopJob {
my ($self, $jobName) = @_;
- $self->execute("initctl stop $jobName");
- my ($status, $out) = $self->execute("initctl status $jobName");
- die "failed to stop $jobName" unless $out =~ /stop\/waiting/;
+ $self->execute("systemctl stop $jobName");
}
@@ -413,7 +434,7 @@ sub shutdown {
my ($self) = @_;
return unless $self->{booted};
- $self->execute("poweroff");
+ print { $self->{socket} } ("poweroff\n");
$self->waitForShutdown;
}
diff --git a/lib/test-driver/test-driver.pl b/lib/test-driver/test-driver.pl
index 6c95f5ba517..c6a707cdf6b 100644
--- a/lib/test-driver/test-driver.pl
+++ b/lib/test-driver/test-driver.pl
@@ -50,7 +50,7 @@ my $context = "";
sub createMachine {
my ($args) = @_;
- my $vm = Machine->new({%{$args}, log => $log});
+ my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"});
$vms{$vm->name} = $vm;
return $vm;
}
diff --git a/lib/testing.nix b/lib/testing.nix
index a27f4344c6a..7c5bb5d50f7 100644
--- a/lib/testing.nix
+++ b/lib/testing.nix
@@ -158,7 +158,8 @@ rec {
wrapProgram $out/bin/nixos-run-vms \
--add-flags "$vms" \
--set tests '"startAll; joinAll;"' \
- --set VLANS '"${toString vlans}"'
+ --set VLANS '"${toString vlans}"' \
+ ${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
''; # "
test = runTests driver;
diff --git a/lib/utils.nix b/lib/utils.nix
new file mode 100644
index 00000000000..35c56e8c32b
--- /dev/null
+++ b/lib/utils.nix
@@ -0,0 +1,10 @@
+pkgs: with pkgs.lib;
+
+rec {
+
+ # Escape a path according to the systemd rules, e.g. /dev/xyzzy
+ # becomes dev-xyzzy. FIXME: slow.
+ escapeSystemdPath = s:
+ replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] (substring 1 (stringLength s) s);
+
+}
diff --git a/maintainers/scripts/ec2/create-ebs-amis.py b/maintainers/scripts/ec2/create-ebs-amis.py
index 4dfaa9f3b12..31613f08962 100755
--- a/maintainers/scripts/ec2/create-ebs-amis.py
+++ b/maintainers/scripts/ec2/create-ebs-amis.py
@@ -32,10 +32,16 @@ f.write('''{{
'''.format(args.region, key_name, ebs_size))
f.close()
-depl = deployment.Deployment("./ebs-creator.json", create=True, nix_exprs=["./ebs-creator.nix", "./ebs-creator-config.nix"])
-depl.load_state()
-if not args.keep: depl.destroy_vms()
-depl.deploy()
+db = deployment.open_database("./ebs-creator.charon")
+try:
+ depl = deployment.open_deployment(db, "ebs-creator")
+except Exception:
+ depl = deployment.create_deployment(db)
+ depl.name = "ebs-creator"
+depl.auto_response = "y"
+depl.nix_exprs = ["./ebs-creator.nix", "./ebs-creator-config.nix"]
+if not args.keep: depl.destroy_resources()
+depl.deploy(allow_reboot=True)
m = depl.machines['machine']
@@ -52,15 +58,23 @@ m.run_command("mkdir -p /mnt")
m.run_command("mount {0} /mnt".format(device))
m.run_command("touch /mnt/.ebs")
m.run_command("mkdir -p /mnt/etc/nixos")
-m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
-m.run_command("nix-channel --update")
+# Kind of hacky until the nixos channel is updated to systemd
+#m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
+#m.run_command("nix-channel --update")
+m.run_command("mkdir unpack")
+m.run_command("cd unpack; (curl -L http://hydra.nixos.org/job/nixos/systemd/channel/latest/download | bzcat | tar xv)")
+m.run_command("mkdir nixos")
+m.run_command("mv unpack/*/* nixos")
+m.run_command("mv nixos unpack/*")
+m.run_command("nix-env -p /nix/var/nix/profiles/per-user/root/channels -i $(nix-store --add unpack/*)")
+m.run_command("rm -fR unpack")
m.run_command("nixos-rebuild switch")
version = m.run_command("nixos-version", capture_stdout=True).replace('"', '').rstrip()
print >> sys.stderr, "NixOS version is {0}".format(version)
m.run_command("cp -f $(nix-instantiate --find-file nixos/modules/virtualisation/amazon-config.nix) /mnt/etc/nixos/configuration.nix")
m.run_command("nixos-install")
if args.hvm:
- m.run_command('cp /nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
+ m.run_command('cp /mnt/nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
m.run_command('sed -i "s|hd0|hd0,0|" /mnt/boot/grub/menu.lst')
m.run_command('echo "(hd1) /dev/xvdg" > device.map')
m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch')
@@ -84,12 +98,12 @@ def check():
return status == '100%'
m.connect()
-volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m._instance_id, 'attachment.device': "/dev/sdg"})[0]
+volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
if args.hvm:
instance = m._conn.run_instances( image_id="ami-6a9e4503"
, instance_type=instance_type
, key_name=key_name
- , placement=m._zone
+ , placement=m.zone
, security_groups=["eelco-test"]).instances[0]
charon.util.check_wait(lambda: instance.update() == 'running', max_tries=120)
instance.stop()
@@ -117,7 +131,7 @@ else:
m._conn.create_tags([snapshot.id], {'Name': ami_name})
- if not args.keep: depl.destroy_vms()
+ if not args.keep: depl.destroy_resources()
# Register the image.
aki = m._conn.get_all_images(filters={'manifest-location': '*pv-grub-hd0_1.03-x86_64*'})[0]
@@ -163,11 +177,15 @@ f.write(
'''.format(args.region, ami_id, instance_type, key_name))
f.close()
-test_depl = deployment.Deployment("./ebs-test.json", create=True, nix_exprs=["./ebs-test.nix"])
-test_depl.load_state()
+test_depl = deployment.create_deployment(db)
+test_depl.auto_response = "y"
+test_depl.name = "ebs-creator-test"
+test_depl.nix_exprs = [ "./ebs-test.nix" ]
test_depl.deploy(create_only=True)
test_depl.machines['machine'].run_command("nixos-version")
-if not args.keep: test_depl.destroy_vms()
+if not args.keep:
+ test_depl.destroy_resources()
+ test_depl.delete()
# Log the AMI ID.
f = open("{0}.ebs.ami-id".format(args.region), "w")
diff --git a/maintainers/scripts/ec2/create-s3-amis.sh b/maintainers/scripts/ec2/create-s3-amis.sh
index ac92c69f5bb..767696cfe55 100755
--- a/maintainers/scripts/ec2/create-s3-amis.sh
+++ b/maintainers/scripts/ec2/create-s3-amis.sh
@@ -1,6 +1,7 @@
#! /bin/sh -e
-revision=$(svnversion "$NIXOS")
+nixos=$(nix-instantiate --find-file nixos)
+revision=$(cd $nixos; git rev-parse --short HEAD)
echo "NixOS revision is $revision"
buildAndUploadFor() {
@@ -8,7 +9,7 @@ buildAndUploadFor() {
arch="$2"
echo "building $system image..."
- NIXOS_CONFIG=$NIXOS/modules/virtualisation/amazon-config.nix nix-build "$NIXOS" \
+ NIXOS_CONFIG=$nixos/modules/virtualisation/amazon-config.nix nix-build "$nixos" \
-A config.system.build.amazonImage --argstr system "$system" -o ec2-ami
ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \
diff --git a/modules/config/i18n.nix b/modules/config/i18n.nix
index c53325ed4e6..e964b9bfb1d 100644
--- a/modules/config/i18n.nix
+++ b/modules/config/i18n.nix
@@ -1,8 +1,10 @@
-{pkgs, config, ...}:
+{ config, pkgs, ... }:
+
+with pkgs.lib;
###### interface
+
let
- inherit (pkgs.lib) mkOption mkIf;
options = {
i18n = {
@@ -45,16 +47,15 @@ let
The keyboard mapping table for the virtual consoles.
";
};
+
};
+
};
-in
###### implementation
-let
-
glibcLocales = pkgs.glibcLocales.override {
- allLocales = pkgs.lib.any (x: x == "all") config.i18n.supportedLocales;
+ allLocales = any (x: x == "all") config.i18n.supportedLocales;
locales = config.i18n.supportedLocales;
};
@@ -63,10 +64,19 @@ in
{
require = options;
- environment.systemPackages = [glibcLocales];
+ environment.systemPackages = [ glibcLocales ];
environment.shellInit =
''
export LANG=${config.i18n.defaultLocale}
'';
+
+ # ‘/etc/locale.conf’ is used by systemd.
+ environment.etc = singleton
+ { target = "locale.conf";
+ source = pkgs.writeText "locale.conf"
+ ''
+ LANG=${config.i18n.defaultLocale}
+ '';
+ };
}
diff --git a/modules/config/networking.nix b/modules/config/networking.nix
index 3905f28b610..6908996db6c 100644
--- a/modules/config/networking.nix
+++ b/modules/config/networking.nix
@@ -3,7 +3,9 @@
{config, pkgs, ...}:
with pkgs.lib;
+
let
+
cfg = config.networking;
options = {
@@ -55,7 +57,9 @@ in
source = pkgs.writeText "hosts"
''
127.0.0.1 localhost
- ::1 localhost
+ ${optionalString cfg.enableIPv6 ''
+ ::1 localhost
+ ''}
${cfg.extraHosts}
'';
target = "hosts";
@@ -71,7 +75,7 @@ in
'' + optionalString config.services.nscd.enable ''
# Invalidate the nscd cache whenever resolv.conf is
# regenerated.
- libc_restart='${pkgs.upstart}/sbin/start invalidate-nscd'
+ libc_restart='${pkgs.systemd}/bin/systemctl reload --no-block nscd.service'
'' + optionalString cfg.dnsSingleRequest ''
# only send one DNS request at a time
resolv_conf_options='single-request'
@@ -82,4 +86,10 @@ in
target = "resolvconf.conf";
}
];
+
+ systemd.units."ip-up.target".text =
+ ''
+ [Unit]
+ Description=Services Requiring IP Connectivity
+ '';
}
diff --git a/modules/config/no-x-libs.nix b/modules/config/no-x-libs.nix
index 93635aa667f..f270a3fa431 100644
--- a/modules/config/no-x-libs.nix
+++ b/modules/config/no-x-libs.nix
@@ -7,7 +7,7 @@
example = true;
description = ''
Switch off the options in the default configuration that require X libraries.
- Currently this includes: ssh X11 forwarding, dbus, hal, fonts.enableCoreFonts,
+ Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts,
fonts.enableFontConfig
'';
};
@@ -16,7 +16,6 @@
programs.ssh.setXAuthLocation = false;
services = {
dbus.enable = false;
- hal.enable = false;
};
fonts = {
enableCoreFonts = false;
diff --git a/modules/config/power-management.nix b/modules/config/power-management.nix
index 553105e83a8..50c7482a372 100644
--- a/modules/config/power-management.nix
+++ b/modules/config/power-management.nix
@@ -6,21 +6,6 @@ let
cfg = config.powerManagement;
- sleepHook = pkgs.writeScript "sleep-hook.sh"
- ''
- #! ${pkgs.stdenv.shell}
- action="$1"
- case "$action" in
- hibernate|suspend)
- ${cfg.powerDownCommands}
- ;;
- thaw|resume)
- ${cfg.resumeCommands}
- ${cfg.powerUpCommands}
- ;;
- esac
- '';
-
in
{
@@ -32,7 +17,7 @@ in
powerManagement = {
enable = mkOption {
- default = false;
+ default = true;
description =
''
Whether to enable power management. This includes support
@@ -79,13 +64,6 @@ in
# Enable the ACPI daemon. Not sure whether this is essential.
services.acpid.enable = true;
- environment.systemPackages = [ pkgs.pmutils ];
-
- environment.etc = singleton
- { source = sleepHook;
- target = "pm/sleep.d/00sleep-hook";
- };
-
boot.kernelModules =
[ "acpi_cpufreq" "powernow-k8" "cpufreq_performance" "cpufreq_powersave" "cpufreq_ondemand"
"cpufreq_conservative"
@@ -93,7 +71,46 @@ in
powerManagement.cpuFreqGovernor = mkDefault "ondemand";
powerManagement.scsiLinkPolicy = mkDefault "min_power";
-
+
+ # Service executed before suspending/hibernating.
+ systemd.services."pre-sleep" =
+ { description = "Pre-Sleep Actions";
+ wantedBy = [ "sleep.target" ];
+ before = [ "sleep.target" ];
+ script =
+ ''
+ ${cfg.powerDownCommands}
+ '';
+ serviceConfig.Type = "oneshot";
+ };
+
+ # Service executed before suspending/hibernating. There doesn't
+ # seem to be a good way to hook in a service to be executed after
+ # both suspend *and* hibernate, so have a separate one for each.
+ systemd.services."post-suspend" =
+ { description = "Post-Suspend Actions";
+ wantedBy = [ "suspend.target" ];
+ after = [ "systemd-suspend.service" ];
+ script =
+ ''
+ ${cfg.resumeCommands}
+ ${cfg.powerUpCommands}
+ '';
+ serviceConfig.Type = "oneshot";
+ };
+
+ systemd.services."post-hibernate" =
+ { description = "Post-Hibernate Actions";
+ wantedBy = [ "hibernate.target" ];
+ after = [ "systemd-hibernate.service" ];
+ script =
+ ''
+ ${cfg.resumeCommands}
+ ${cfg.powerUpCommands}
+ '';
+ serviceConfig.Type = "oneshot";
+ };
+
};
}
diff --git a/modules/config/swap.nix b/modules/config/swap.nix
index 5b20f657e12..222c18d3e62 100644
--- a/modules/config/swap.nix
+++ b/modules/config/swap.nix
@@ -1,6 +1,7 @@
-{ config, pkgs, ... }:
+{ config, pkgs, utils, ... }:
with pkgs.lib;
+with utils;
{
@@ -74,9 +75,39 @@ with pkgs.lib;
};
config = mkIf ((length config.swapDevices) != 0) {
+
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isYes "SWAP")
];
+
+ # Create missing swapfiles.
+ # FIXME: support changing the size of existing swapfiles.
+ systemd.services =
+ let
+
+ createSwapDevice = sw:
+ assert sw.device != "";
+ let device' = escapeSystemdPath sw.device; in
+ nameValuePair "mkswap-${escapeSystemdPath sw.device}"
+ { description = "Initialisation of Swapfile ${sw.device}";
+ wantedBy = [ "${device'}.swap" ];
+ before = [ "${device'}.swap" ];
+ path = [ pkgs.utillinux ];
+ script =
+ ''
+ if [ ! -e "${sw.device}" ]; then
+ fallocate -l ${toString sw.size}M "${sw.device}" ||
+ dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
+ mkswap ${sw.device}
+ fi
+ '';
+ unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
+ unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+ serviceConfig.Type = "oneshot";
+ };
+
+ in listToAttrs (map createSwapDevice (filter (sw: sw.size != null) config.swapDevices));
+
};
}
diff --git a/modules/config/system-path.nix b/modules/config/system-path.nix
index 85b16d50406..3969be68098 100644
--- a/modules/config/system-path.nix
+++ b/modules/config/system-path.nix
@@ -16,9 +16,7 @@ let
'';
requiredPackages =
- [ config.system.sbin.modprobe # must take precedence over module_init_tools
- config.system.build.upstart
- config.environment.nix
+ [ config.environment.nix
pkgs.acl
pkgs.attr
pkgs.bashInteractive # bash with ncurses support
@@ -39,7 +37,6 @@ let
pkgs.less
pkgs.libcap
pkgs.man
- pkgs.module_init_tools
pkgs.nano
pkgs.ncurses
pkgs.netcat
@@ -50,12 +47,10 @@ let
pkgs.procps
pkgs.rsync
pkgs.strace
- pkgs.sysklogd
pkgs.sysvtools
pkgs.time
- pkgs.udev
pkgs.usbutils
- pkgs.utillinuxCurses
+ pkgs.utillinux
extraManpages
];
diff --git a/modules/config/users-groups.nix b/modules/config/users-groups.nix
index 76b6c2854a9..92839106762 100644
--- a/modules/config/users-groups.nix
+++ b/modules/config/users-groups.nix
@@ -8,74 +8,74 @@ let
users = config.users;
userOpts = { name, config, ... }: {
-
+
options = {
-
+
name = mkOption {
type = with types; uniq string;
description = "The name of the user account. If undefined, the name of the attribute set will be used.";
};
-
+
description = mkOption {
type = with types; uniq string;
default = "";
description = "A short description of the user account.";
};
-
+
uid = mkOption {
type = with types; uniq (nullOr int);
default = null;
description = "The account UID. If undefined, NixOS will select a free UID.";
};
-
+
group = mkOption {
type = with types; uniq string;
default = "nogroup";
description = "The user's primary group.";
};
-
+
extraGroups = mkOption {
type = types.listOf types.string;
default = [];
description = "The user's auxiliary groups.";
};
-
+
home = mkOption {
type = with types; uniq string;
default = "/var/empty";
description = "The user's home directory.";
};
-
+
shell = mkOption {
type = with types; uniq string;
default = "/run/current-system/sw/sbin/nologin";
description = "The path to the user's shell.";
};
-
+
createHome = mkOption {
type = types.bool;
default = false;
description = "If true, the home directory will be created automatically.";
};
-
+
useDefaultShell = mkOption {
type = types.bool;
default = false;
description = "If true, the user's shell will be set to users.defaultUserShell.";
};
-
+
password = mkOption {
type = with types; uniq (nullOr string);
default = null;
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
};
-
+
isSystemUser = mkOption {
type = types.bool;
default = true;
description = "Indicates if the user is a system user or not.";
};
-
+
createUser = mkOption {
type = types.bool;
default = true;
@@ -85,7 +85,13 @@ let
then not modify any of the basic properties for the user account.
";
};
-
+
+ isAlias = mkOption {
+ type = types.bool;
+ default = false;
+ description = "If true, the UID of this user is not required to be unique and can thus alias another user.";
+ };
+
};
config = {
@@ -93,41 +99,41 @@ let
uid = mkDefault (attrByPath [name] null ids.uids);
shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
};
-
+
};
groupOpts = { name, config, ... }: {
-
+
options = {
-
+
name = mkOption {
type = with types; uniq string;
description = "The name of the group. If undefined, the name of the attribute set will be used.";
};
-
+
gid = mkOption {
type = with types; uniq (nullOr int);
default = null;
description = "The GID of the group. If undefined, NixOS will select a free GID.";
};
-
+
};
config = {
name = mkDefault name;
gid = mkDefault (attrByPath [name] null ids.gids);
};
-
+
};
# Note: the 'X' in front of the password is to distinguish between
# having an empty password, and not having a password.
- serializedUser = userName: let u = getAttr userName config.users.extraUsers; in "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${if u.createUser then "yes" else "no"}\n";
+ serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n";
- # keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
usersFile = pkgs.writeText "users" (
- concatMapStrings serializedUser (attrNames config.users.extraUsers)
- );
+ let
+ p = partition (u: u.isAlias) (attrValues config.users.extraUsers);
+ in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right));
in
@@ -208,6 +214,7 @@ in
users = { };
nixbld = { };
utmp = { };
+ adm = { }; # expected by journald
};
system.activationScripts.rootPasswd = stringAfter [ "etc" ]
@@ -242,8 +249,9 @@ in
read password
read isSystemUser
read createUser
+ read isAlias
- if ! test "$createUser" = "yes"; then
+ if [ -z "$createUser" ]; then
continue
fi
@@ -256,6 +264,7 @@ in
--home "$home" \
--shell "$shell" \
''${createHome:+--create-home} \
+ ''${isAlias:+--non-unique} \
"$name"
if test "''${password:0:1}" = 'X'; then
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"
diff --git a/modules/installer/cd-dvd/iso-image.nix b/modules/installer/cd-dvd/iso-image.nix
index 4f87f29f2e9..33000a3fbf1 100644
--- a/modules/installer/cd-dvd/iso-image.nix
+++ b/modules/installer/cd-dvd/iso-image.nix
@@ -87,7 +87,7 @@ let
# The Grub image.
grubImage = pkgs.runCommand "grub_eltorito" {}
''
- ${pkgs.grub2}/bin/grub-mkimage -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain vbe png jpeg echo test normal
+ ${pkgs.grub2}/bin/grub-mkimage -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain png jpeg echo gfxmenu reboot
cat ${pkgs.grub2}/lib/grub/*/cdboot.img tmp > $out
''; # */
@@ -184,27 +184,15 @@ in
# Note that /dev/root is a symlink to the actual root device
# specified on the kernel command line, created in the stage 1 init
# script.
- fileSystems =
- [ { mountPoint = "/";
- device = "/dev/root";
- }
- { mountPoint = "/nix/store";
- fsType = "squashfs";
- device = "/nix-store.squashfs";
- options = "loop";
- neededForBoot = true;
- }
- ];
+ fileSystems."/".device = "/dev/root";
- # We need squashfs in the initrd to mount the compressed Nix store,
- # and aufs to make the root filesystem appear writable.
- boot.extraModulePackages =
- if config.boot.kernelPackages.aufs == null then
- abort "This kernel doesn't have aufs enabled"
- else
- [ config.boot.kernelPackages.aufs ];
+ fileSystems."/nix/store" =
+ { fsType = "squashfs";
+ device = "/nix-store.squashfs";
+ options = "loop";
+ };
- boot.initrd.availableKernelModules = [ "aufs" "squashfs" "iso9660" ];
+ boot.initrd.availableKernelModules = [ "squashfs" "iso9660" ];
boot.initrd.kernelModules = [ "loop" ];
@@ -214,16 +202,20 @@ in
# /nix/store (the squashfs image) to make this a live CD.
boot.initrd.postMountCommands =
''
- mkdir /mnt-root-tmpfs
- mount -t tmpfs -o "mode=755" none /mnt-root-tmpfs
+ mkdir -p /unionfs-chroot/ro-root
+ mount --rbind $targetRoot /unionfs-chroot/ro-root
+
+ mkdir /unionfs-chroot/rw-root
+ mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-root
mkdir /mnt-root-union
- mount -t aufs -o dirs=/mnt-root-tmpfs=rw:$targetRoot=ro none /mnt-root-union
+ unionfs -o allow_other,cow,chroot=/unionfs-chroot /rw-root=RW:/ro-root=RO /mnt-root-union
+ oldTargetRoot=$targetRoot
targetRoot=/mnt-root-union
- mkdir /mnt-store-tmpfs
- mount -t tmpfs -o "mode=755" none /mnt-store-tmpfs
- mkdir -p $targetRoot/nix/store
- mount -t aufs -o dirs=/mnt-store-tmpfs=rw:/mnt-root/nix/store=ro none /mnt-root-union/nix/store
+ mkdir /unionfs-chroot/rw-store
+ mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-store
+ mkdir -p $oldTargetRoot/nix/store
+ unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot /rw-store=RW:/ro-root/nix/store=RO /mnt-root-union/nix/store
'';
# Closures to be copied to the Nix store on the CD, namely the init
@@ -315,7 +307,7 @@ in
'';
# Add vfat support to the initrd to enable people to copy the
- # contents of the CD to a bootable USB stick.
- boot.initrd.supportedFilesystems = [ "vfat" ];
+ # contents of the CD to a bootable USB stick. Need unionfs-fuse for union mounts
+ boot.initrd.supportedFilesystems = [ "vfat" "unionfs-fuse" ];
}
diff --git a/modules/installer/tools/get-version-suffix b/modules/installer/tools/get-version-suffix
new file mode 100644
index 00000000000..76cec8d5dae
--- /dev/null
+++ b/modules/installer/tools/get-version-suffix
@@ -0,0 +1,29 @@
+getVersion() {
+ local dir="$1"
+ rev=
+ if [ -e "$dir/.git" ]; then
+ if [ -z "$(type -P git)" ]; then
+ echo "warning: Git not found; cannot figure out revision of $dir" >&2
+ return
+ fi
+ cd "$dir"
+ rev=$(git rev-parse --short HEAD)
+ if git describe --always --dirty | grep -q dirty; then
+ rev+=M
+ fi
+ fi
+}
+
+if nixos=$(nix-instantiate --find-file nixos "$@"); then
+ getVersion $nixos
+ if [ -n "$rev" ]; then
+ suffix="pre-$rev"
+ if nixpkgs=$(nix-instantiate --find-file nixpkgs "$@"); then
+ getVersion $nixpkgs
+ if [ -n "$rev" ]; then
+ suffix+="-$rev"
+ fi
+ fi
+ echo $suffix
+ fi
+fi
diff --git a/modules/installer/tools/nixos-install.sh b/modules/installer/tools/nixos-install.sh
index a968369198e..0739c33e857 100644
--- a/modules/installer/tools/nixos-install.sh
+++ b/modules/installer/tools/nixos-install.sh
@@ -16,7 +16,7 @@ if test -z "$mountPoint"; then
fi
if test -z "$NIXOS_CONFIG"; then
- NIXOS_CONFIG=/mnt/etc/nixos/configuration.nix
+ NIXOS_CONFIG=/etc/nixos/configuration.nix
fi
if ! test -e "$mountPoint"; then
@@ -28,32 +28,41 @@ if ! grep -F -q " $mountPoint " /proc/mounts; then
echo "$mountPoint doesn't appear to be a mount point"
exit 1
fi
-
-if ! test -e "$NIXOS_CONFIG"; then
+
+if ! test -e "$mountPoint/$NIXOS_CONFIG"; then
echo "configuration file $NIXOS_CONFIG doesn't exist"
exit 1
fi
-
+
# Mount some stuff in the target root directory. We bind-mount /etc
# into the chroot because we need networking and the nixbld user
# accounts in /etc/passwd. But we do need the target's /etc/nixos.
-mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/mnt $mountPoint/etc
-mount --rbind /dev $mountPoint/dev
-mount --rbind /proc $mountPoint/proc
-mount --rbind /sys $mountPoint/sys
-mount --rbind / $mountPoint/mnt
+mkdir -m 0755 -p $mountPoint/dev $mountPoint/proc $mountPoint/sys $mountPoint/mnt $mountPoint/mnt2 $mountPoint/etc /etc/nixos
+mount --make-private / # systemd makes / shared, which is annoying
+mount --bind / $mountPoint/mnt
+mount --bind /nix/store $mountPoint/mnt/nix/store
+mount --bind /dev $mountPoint/dev
+mount --bind /dev/shm $mountPoint/dev/shm
+mount --bind /proc $mountPoint/proc
+mount --bind /sys $mountPoint/sys
+mount --bind $mountPoint/etc/nixos $mountPoint/mnt2
mount --bind /etc $mountPoint/etc
-mount --bind $mountPoint/mnt/$mountPoint/etc/nixos $mountPoint/etc/nixos
+mount --bind $mountPoint/mnt2 $mountPoint/etc/nixos
cleanup() {
set +e
- umount -l $mountPoint/mnt
- umount -l $mountPoint/dev
- umount -l $mountPoint/proc
- umount -l $mountPoint/sys
- mountpoint -q $mountPoint/etc && umount -l $mountPoint/etc
+ mountpoint -q $mountPoint/etc/nixos && umount $mountPoint/etc/nixos
+ mountpoint -q $mountPoint/etc && umount $mountPoint/etc
+ umount $mountPoint/mnt2
+ umount $mountPoint/sys
+ umount $mountPoint/proc
+ umount $mountPoint/dev/shm
+ umount $mountPoint/dev
+ umount $mountPoint/mnt/nix/store
+ umount $mountPoint/mnt
+ rmdir $mountPoint/mnt $mountPoint/mnt2
}
trap "cleanup" EXIT
@@ -144,7 +153,7 @@ srcs=$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-nam
# Build the specified Nix expression in the target store and install
# it into the system configuration profile.
echo "building the system configuration..."
-NIX_PATH="/mnt$srcs/nixos:nixos-config=/mnt$NIXOS_CONFIG" NIXOS_CONFIG= \
+NIX_PATH="/mnt$srcs/nixos:nixos-config=$NIXOS_CONFIG" NIXOS_CONFIG= \
chroot $mountPoint @nix@/bin/nix-env \
-p /nix/var/nix/profiles/system -f '' --set -A system --show-trace
diff --git a/modules/installer/tools/nixos-option.sh b/modules/installer/tools/nixos-option.sh
index 656f2a87403..47abac7fddd 100644
--- a/modules/installer/tools/nixos-option.sh
+++ b/modules/installer/tools/nixos-option.sh
@@ -239,17 +239,14 @@ if $generate; then
# Add filesystem entries for each partition that you want to see
# mounted at boot time. This should include at least the root
# filesystem.
- fileSystems =
- [ # { mountPoint = "/";
- # device = "/dev/disk/by-label/nixos";
- # }
- # { mountPoint = "/data"; # where you want to mount the device
- # device = "/dev/sdb"; # the device
- # fsType = "ext3"; # the type of the partition
- # options = "data=journal";
- # }
- ];
+ # fileSystems."/".device = "/dev/disk/by-label/nixos";
+
+ # fileSystems."/data" = # where you want to mount the device
+ # { device = "/dev/sdb"; # the device
+ # fsType = "ext3"; # the type of the partition
+ # options = "data=journal";
+ # };
# List swap partitions activated at boot time.
swapDevices =
diff --git a/modules/installer/tools/nixos-rebuild.sh b/modules/installer/tools/nixos-rebuild.sh
index dba4b731f7c..b9272f31ac6 100644
--- a/modules/installer/tools/nixos-rebuild.sh
+++ b/modules/installer/tools/nixos-rebuild.sh
@@ -44,13 +44,13 @@ EOF
# Parse the command line.
-extraBuildFlags=
+extraBuildFlags=()
action=
buildNix=1
rollback=
upgrade=
-while test "$#" -gt 0; do
+while [ "$#" -gt 0 ]; do
i="$1"; shift 1
case "$i" in
--help)
@@ -72,20 +72,20 @@ while test "$#" -gt 0; do
upgrade=1
;;
--show-trace|--no-build-hook|--keep-failed|-K|--keep-going|-k|--verbose|-v|--fallback)
- extraBuildFlags="$extraBuildFlags $i"
+ extraBuildFlags+=("$i")
;;
--max-jobs|-j|--cores|-I)
j="$1"; shift 1
- extraBuildFlags="$extraBuildFlags $i $j"
+ extraBuildFlags+=("$i" "$j")
;;
--option)
j="$1"; shift 1
k="$1"; shift 1
- extraBuildFlags="$extraBuildFlags $i $j $k"
+ extraBuildFlags+=("$i" "$j" "$k")
;;
--fast)
buildNix=
- extraBuildFlags="$extraBuildFlags --show-trace"
+ extraBuildFlags+=(--show-trace)
;;
*)
echo "$0: unknown option \`$i'"
@@ -94,13 +94,9 @@ while test "$#" -gt 0; do
esac
done
-if test -z "$action"; then showSyntax; fi
+if [ -z "$action" ]; then showSyntax; fi
-if test "$action" = dry-run; then
- extraBuildFlags="$extraBuildFlags --dry-run"
-fi
-
-if test -n "$rollback"; then
+if [ -n "$rollback" ]; then
buildNix=
fi
@@ -115,7 +111,7 @@ trap 'rm -rf "$tmpDir"' EXIT
# This matters if the new Nix in Nixpkgs has a schema change. It
# would upgrade the schema, which should only happen once we actually
# switch to the new configuration.
-if initctl status nix-daemon 2>&1 | grep -q 'running'; then
+if systemctl show nix-daemon.socket nix-daemon.service | grep -q ActiveState=active; then
export NIX_REMOTE=${NIX_REMOTE:-daemon}
fi
@@ -129,42 +125,57 @@ fi
# First build Nix, since NixOS may require a newer version than the
# current one. Of course, the same goes for Nixpkgs, but Nixpkgs is
# more conservative.
-if [ -n "$buildNix" ]; then
+if [ "$action" != dry-run -a -n "$buildNix" ]; then
echo "building Nix..." >&2
- if ! nix-build '' -A config.environment.nix -o $tmpDir/nix $extraBuildFlags > /dev/null; then
- if ! nix-build '' -A nixFallback -o $tmpDir/nix $extraBuildFlags > /dev/null; then
- nix-build '' -A nixUnstable -o $tmpDir/nix $extraBuildFlags > /dev/null
+ if ! nix-build '' -A config.environment.nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
+ if ! nix-build '' -A nixFallback -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then
+ nix-build '' -A nixUnstable -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null
fi
fi
PATH=$tmpDir/nix/bin:$PATH
fi
+# Update the version suffix if we're building from Git (so that
+# nixos-version shows something useful).
+if nixos=$(nix-instantiate --find-file nixos "${extraBuildFlags[@]}"); then
+ suffix=$($SHELL $nixos/modules/installer/tools/get-version-suffix "${extraBuildFlags[@]}")
+ if [ -n "$suffix" ]; then
+ echo -n "$suffix" > "$nixos/.version-suffix"
+ fi
+fi
+
+
+if [ "$action" = dry-run ]; then
+ extraBuildFlags+=(--dry-run)
+fi
+
+
# Either upgrade the configuration in the system profile (for "switch"
# or "boot"), or just build it and create a symlink "result" in the
# current directory (for "build" and "test").
-if test -z "$rollback"; then
+if [ -z "$rollback" ]; then
echo "building the system configuration..." >&2
- if test "$action" = switch -o "$action" = boot; then
- nix-env $extraBuildFlags -p /nix/var/nix/profiles/system -f '' --set -A system
+ if [ "$action" = switch -o "$action" = boot ]; then
+ nix-env "${extraBuildFlags[@]}" -p /nix/var/nix/profiles/system -f '' --set -A system
pathToConfig=/nix/var/nix/profiles/system
- elif test "$action" = test -o "$action" = build -o "$action" = dry-run; then
- nix-build '' -A system -K -k $extraBuildFlags > /dev/null
+ elif [ "$action" = test -o "$action" = build -o "$action" = dry-run ]; then
+ nix-build '' -A system -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
elif [ "$action" = build-vm ]; then
- nix-build '' -A vm -K -k $extraBuildFlags > /dev/null
+ nix-build '' -A vm -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
elif [ "$action" = build-vm-with-bootloader ]; then
- nix-build '' -A vmWithBootLoader -K -k $extraBuildFlags > /dev/null
+ nix-build '' -A vmWithBootLoader -K -k "${extraBuildFlags[@]}" > /dev/null
pathToConfig=./result
else
showSyntax
fi
-else # test -n "$rollback"
- if test "$action" = switch -o "$action" = boot; then
+else # [ -n "$rollback" ]
+ if [ "$action" = switch -o "$action" = boot ]; then
nix-env --rollback -p /nix/var/nix/profiles/system
pathToConfig=/nix/var/nix/profiles/system
- elif test "$action" = test -o "$action" = build; then
+ elif [ "$action" = test -o "$action" = build ]; then
systemNumber=$(
nix-env -p /nix/var/nix/profiles/system --list-generations |
sed -n '/current/ {g; p;}; s/ *\([0-9]*\).*/\1/; h'
@@ -179,7 +190,7 @@ fi
# If we're not just building, then make the new configuration the boot
# default and/or activate it now.
-if test "$action" = switch -o "$action" = boot -o "$action" = test; then
+if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
# Just in case the new configuration hangs the system, do a sync now.
sync
@@ -187,7 +198,7 @@ if test "$action" = switch -o "$action" = boot -o "$action" = test; then
fi
-if test "$action" = build-vm; then
+if [ "$action" = build-vm ]; then
cat >&2 </bin/sh. Please note that NixOS assumes all
+ over the place that shell to be Bash, so override the default
+ setting only if you know exactly what you're doing.
+ '';
+ };
};
@@ -68,6 +96,7 @@ in
# configured properly.
source = pkgs.substituteAll {
src = ./bashrc.sh;
+ inherit (config.environment) promptInit;
inherit initBashCompletion shellAliases;
};
target = "bashrc";
@@ -79,12 +108,12 @@ in
}
];
- environment.shellAliases = {
- ls = "ls --color=tty";
- ll = "ls -l";
- l = "ls -alh";
- which = "type -P";
- };
+ environment.shellAliases =
+ { ls = "ls --color=tty";
+ ll = "ls -l";
+ l = "ls -alh";
+ which = "type -P";
+ };
system.build.binsh = pkgs.bashInteractive;
@@ -93,7 +122,7 @@ in
# Create the required /bin/sh symlink; otherwise lots of things
# (notably the system() function) won't work.
mkdir -m 0755 -p /bin
- ln -sfn ${config.system.build.binsh}/bin/sh /bin/.sh.tmp
+ ln -sfn "${config.environment.binsh}" /bin/.sh.tmp
mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
'';
diff --git a/modules/programs/bash/bashrc.sh b/modules/programs/bash/bashrc.sh
index b1ecb278b93..4615004d47c 100644
--- a/modules/programs/bash/bashrc.sh
+++ b/modules/programs/bash/bashrc.sh
@@ -19,14 +19,6 @@ if [ -z "$PS1" ]; then return; fi
# Check the window size after every command.
shopt -s checkwinsize
-# Provide a nice prompt.
-PROMPT_COLOR="1;31m"
-let $UID && PROMPT_COLOR="1;32m"
-PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
-if test "$TERM" = "xterm"; then
- PS1="\[\033]2;\h:\u:\w\007\]$PS1"
-fi
-
+@promptInit@
@initBashCompletion@
-
@shellAliases@
diff --git a/modules/programs/shadow.nix b/modules/programs/shadow.nix
index a3f837c7367..39359ac4293 100644
--- a/modules/programs/shadow.nix
+++ b/modules/programs/shadow.nix
@@ -1,6 +1,6 @@
# Configuration for the pwdutils suite of tools: passwd, useradd, etc.
-{config, pkgs, ...}:
+{ config, pkgs, ... }:
let
@@ -27,6 +27,7 @@ let
# Uncomment this to allow non-root users to change their account
#information. This should be made configurable.
#CHFN_RESTRICT frwh
+
'';
in
@@ -90,7 +91,7 @@ in
{ name = "groupmod"; rootOK = true; }
{ name = "groupmems"; rootOK = true; }
{ name = "groupdel"; rootOK = true; }
- { name = "login"; ownDevices = true; allowNullPassword = true; }
+ { name = "login"; startSession = true; allowNullPassword = true; showMotd = true; }
];
security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ];
diff --git a/modules/programs/ssh.nix b/modules/programs/ssh.nix
index 6f607c43368..f28de02bb4e 100644
--- a/modules/programs/ssh.nix
+++ b/modules/programs/ssh.nix
@@ -38,7 +38,7 @@ in
};
};
- assertions = [{ assertion = if cfg.forwardX11 then cfg.setXAuthLocation else true;
+ assertions = [{ assertion = if cfg.forwardX11 then cfg.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";}];
config = {
@@ -46,14 +46,11 @@ in
[ { # SSH configuration. Slight duplication of the sshd_config
# generation in the sshd service.
source = pkgs.writeText "ssh_config" ''
+ AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}
${optionalString cfg.setXAuthLocation ''
XAuthLocation ${pkgs.xorg.xauth}/bin/xauth
''}
- ${if cfg.forwardX11 then ''
- ForwardX11 yes
- '' else ''
- ForwardX11 no
- ''}
+ ForwardX11 ${if cfg.forwardX11 then "yes" else "no"}
'';
target = "ssh/ssh_config";
}
diff --git a/modules/programs/virtualbox.nix b/modules/programs/virtualbox.nix
index cb293563dfd..a7c41d915ec 100644
--- a/modules/programs/virtualbox.nix
+++ b/modules/programs/virtualbox.nix
@@ -10,26 +10,32 @@ let virtualbox = config.boot.kernelPackages.virtualbox; in
environment.systemPackages = [ virtualbox ];
users.extraGroups = singleton { name = "vboxusers"; };
-
+
services.udev.extraRules =
''
- KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660"
- KERNEL=="vboxnetctl", OWNER="root", GROUP="root", MODE="0600"
+ KERNEL=="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660", TAG+="systemd"
+ KERNEL=="vboxnetctl", OWNER="root", GROUP="root", MODE="0600", TAG+="systemd"
'';
# Since we lack the right setuid binaries, set up a host-only network by default.
-
- jobs."create-vboxnet0" =
- { task = true;
+
+ jobs."vboxnet0" =
+ { description = "VirtualBox vboxnet0 Interface";
+ requires = [ "dev-vboxnetctl.device" ];
+ after = [ "dev-vboxnetctl.device" ];
+ wantedBy = [ "network.target" "sys-subsystem-net-devices-vboxnet0.device" ];
path = [ virtualbox ];
- startOn = "starting network-interfaces";
- script =
+ preStart =
''
if ! [ -e /sys/class/net/vboxnet0 ]; then
VBoxManage hostonlyif create
fi
'';
+ postStop =
+ ''
+ VBoxManage hostonlyif remove vboxnet0
+ '';
};
- networking.interfaces = [ { name = "vboxnet0"; ipAddress = "192.168.56.1"; subnetMask = "255.255.255.0"; } ];
+ networking.interfaces.vboxnet0 = { ipAddress = "192.168.56.1"; prefixLength = 24; };
}
diff --git a/modules/rename.nix b/modules/rename.nix
index 43566bab22f..534137d4e09 100644
--- a/modules/rename.nix
+++ b/modules/rename.nix
@@ -71,6 +71,11 @@ in zipModules ([]
++ rename obsolete "networking.enableWLAN" "networking.wireless.enable"
++ rename obsolete "networking.enableRT73Firmware" "networking.enableRalinkFirmware"
+# FIXME: Remove these eventually.
+++ rename obsolete "boot.systemd.sockets" "systemd.sockets"
+++ rename obsolete "boot.systemd.targets" "systemd.targets"
+++ rename obsolete "boot.systemd.services" "systemd.services"
+
# Old Grub-related options.
++ rename obsolete "boot.copyKernels" "boot.loader.grub.copyKernels"
++ rename obsolete "boot.extraGrubEntries" "boot.loader.grub.extraEntries"
diff --git a/modules/security/ca.nix b/modules/security/ca.nix
index ef33298f19e..e42f5ffe3b8 100644
--- a/modules/security/ca.nix
+++ b/modules/security/ca.nix
@@ -21,7 +21,6 @@ with pkgs.lib;
''
export OPENSSL_X509_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
- # !!! Remove the following as soon as OpenSSL 1.0.0e is the default.
export CURL_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt
export GIT_SSL_CAINFO=/etc/ssl/certs/ca-bundle.crt
'';
diff --git a/modules/security/consolekit.nix b/modules/security/consolekit.nix
deleted file mode 100644
index 28e1fec0601..00000000000
--- a/modules/security/consolekit.nix
+++ /dev/null
@@ -1,60 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-let
-
- # `pam_console' maintains the set of locally logged in users in
- # /var/run/console. This is obsolete, but D-Bus still uses it for
- # its `at_console' feature. So maintain it using a ConsoleKit
- # session script. Borrowed from
- # http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/sys-auth/consolekit/files/pam-foreground-compat.ck
- updateVarRunConsole = pkgs.writeTextFile {
- name = "var-run-console.ck";
- destination = "/etc/ConsoleKit/run-session.d/var-run-console.ck";
- executable = true;
-
- text =
- ''
- #! ${pkgs.stdenv.shell} -e
- PATH=${pkgs.coreutils}/bin:${pkgs.gnused}/bin:${pkgs.glibc}/bin
- TAGDIR=/var/run/console
-
- [ -n "$CK_SESSION_USER_UID" ] || exit 1
-
- TAGFILE="$TAGDIR/`getent passwd $CK_SESSION_USER_UID | cut -f 1 -d:`"
-
- if [ "$1" = "session_added" ]; then
- mkdir -p "$TAGDIR"
- echo "$CK_SESSION_ID" >> "$TAGFILE"
- fi
-
- if [ "$1" = "session_removed" ] && [ -e "$TAGFILE" ]; then
- sed -i "\%^$CK_SESSION_ID\$%d" "$TAGFILE"
- [ -s "$TAGFILE" ] || rm -f "$TAGFILE"
- fi
- '';
- };
-
-in
-
-{
-
- config = {
-
- environment.systemPackages = [ pkgs.consolekit ];
-
- services.dbus.packages = [ pkgs.consolekit ];
-
- environment.etc = singleton
- { source = (pkgs.buildEnv {
- name = "consolekit-config";
- pathsToLink = [ "/etc/ConsoleKit" ];
- paths = [ pkgs.consolekit pkgs.udev updateVarRunConsole ];
- }) + "/etc/ConsoleKit";
- target = "ConsoleKit";
- };
-
- };
-
-}
diff --git a/modules/security/pam.nix b/modules/security/pam.nix
index d3dd4ef9ac0..32721205b99 100644
--- a/modules/security/pam.nix
+++ b/modules/security/pam.nix
@@ -31,6 +31,8 @@ let
concatStringsSep " " [ domain type item value ])
limits));
+ motd = pkgs.writeText "motd" config.users.motd;
+
makePAMService =
{ name
, # If set, root doesn't need to authenticate (e.g. for the "chsh"
@@ -43,9 +45,10 @@ let
# against the keys in the calling user's ~/.ssh/authorized_keys.
# This is useful for "sudo" on password-less remote systems.
sshAgentAuth ? false
- , # If set, use ConsoleKit's PAM connector module to claim
- # ownership of audio devices etc.
- ownDevices ? false
+ , # If set, the service will register a new session with systemd's
+ # login manager. If the service is running locally, this will
+ # give the user ownership of audio devices etc.
+ startSession ? false
, # Whether to forward XAuth keys between users. Mostly useful
# for "su".
forwardXAuth ? false
@@ -59,6 +62,8 @@ let
allowNullPassword ? false
, # The limits, as per limits.conf(5).
limits ? config.security.pam.loginLimits
+ , # Whether to show the message of the day.
+ showMotd ? false
}:
{ source = pkgs.writeText "${name}.pam"
@@ -77,7 +82,7 @@ let
${optionalString rootOK
"auth sufficient pam_rootok.so"}
${optionalString (config.security.pam.enableSSHAgentAuth && sshAgentAuth)
- "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys"}
+ "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
${optionalString usbAuth
"auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
auth sufficient pam_unix.so ${optionalString allowNullPassword "nullok"} likeauth
@@ -105,12 +110,14 @@ let
"session optional ${pam_ldap}/lib/security/pam_ldap.so"}
${optionalString config.krb5.enable
"session optional ${pam_krb5}/lib/security/pam_krb5.so"}
- ${optionalString ownDevices
- "session optional ${pkgs.consolekit}/lib/security/pam_ck_connector.so"}
+ ${optionalString startSession
+ "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
${optionalString forwardXAuth
"session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"}
${optionalString (limits != [])
"session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf limits}"}
+ ${optionalString (showMotd && config.users.motd != null)
+ "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
'';
target = "pam.d/${name}";
};
@@ -152,7 +159,7 @@ in
default = [];
example = [
{ name = "chsh"; rootOK = true; }
- { name = "login"; ownDevices = true; allowNullPassword = true;
+ { name = "login"; startSession = true; allowNullPassword = true;
limits = [
{ domain = "ftp";
type = "hard";
@@ -173,13 +180,13 @@ in
the name of the service. The attribute
rootOK specifies whether the root user is
allowed to use this service without authentication. The
- attribute ownDevices specifies whether
- ConsoleKit's PAM connector module should be used to give the
- user ownership of devices such as audio and CD-ROM drives.
- The attribute forwardXAuth specifies
- whether X authentication keys should be passed from the
- calling user to the target user (e.g. for
- su).
+ attribute startSession specifies whether
+ systemd's PAM connector module should be used to start a new
+ session; for local sessions, this will give the user
+ ownership of devices such as audio and CD-ROM drives. The
+ attribute forwardXAuth specifies whether
+ X authentication keys should be passed from the calling user
+ to the target user (e.g. for su).
The attribute limits defines resource limits
that should apply to users or groups for the service. Each item in
@@ -202,6 +209,13 @@ in
'';
};
+ users.motd = mkOption {
+ default = null;
+ example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178.";
+ type = types.nullOr types.string;
+ description = "Message of the day shown to users when they log in.";
+ };
+
};
@@ -238,7 +252,6 @@ in
{ name = "lshd"; }
{ name = "samba"; }
{ name = "screen"; }
- { name = "sshd"; }
{ name = "vlock"; }
{ name = "xlock"; }
{ name = "xscreensaver"; }
diff --git a/modules/security/policykit.nix b/modules/security/policykit.nix
deleted file mode 100644
index 5aa02950f74..00000000000
--- a/modules/security/policykit.nix
+++ /dev/null
@@ -1,80 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-let
-
- conf = pkgs.writeText "PolicyKit.conf"
- ''
-
-
-
-
-
-
- '';
-
-in
-
-{
-
- options = {
-
- security.policykit.enable = mkOption {
- default = false;
- description = "Enable PolicyKit (obsolete).";
- };
-
- };
-
-
- config = mkIf config.security.policykit.enable {
-
- environment.systemPackages = [ pkgs.policykit ];
-
- services.dbus.packages = [ pkgs.policykit ];
-
- security.pam.services = [ { name = "polkit"; } ];
-
- users.extraUsers = singleton
- { name = "polkituser";
- uid = config.ids.uids.polkituser;
- description = "PolicyKit user";
- };
-
- users.extraGroups = singleton
- { name = "polkituser";
- gid = config.ids.gids.polkituser;
- };
-
- environment.etc =
- [ { source = conf;
- target = "PolicyKit/PolicyKit.conf";
- }
- { source = (pkgs.buildEnv {
- name = "PolicyKit-policies";
- pathsToLink = [ "/share/PolicyKit/policy" ];
- paths = [ pkgs.policykit pkgs.consolekit pkgs.hal ];
- }) + "/share/PolicyKit/policy";
- target = "PolicyKit/policy";
- }
- ];
-
- system.activationScripts.policyKit = stringAfter [ "users" ]
- ''
- mkdir -m 0770 -p /var/run/PolicyKit
- chown root:polkituser /var/run/PolicyKit
-
- mkdir -m 0770 -p /var/lib/PolicyKit
- chown root:polkituser /var/lib/PolicyKit
-
- mkdir -p /var/lib/misc
- touch /var/lib/misc/PolicyKit.reload
- chmod 0664 /var/lib/misc/PolicyKit.reload
- chown polkituser:polkituser /var/lib/misc/PolicyKit.reload
- '';
-
- };
-
-}
diff --git a/modules/security/rngd.nix b/modules/security/rngd.nix
new file mode 100644
index 00000000000..dd251fe69d3
--- /dev/null
+++ b/modules/security/rngd.nix
@@ -0,0 +1,37 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+ options = {
+ security.rngd.enable = mkOption {
+ default = true;
+ description = ''
+ Whether to enable the rng daemon, which adds entropy from
+ hardware sources of randomness to the kernel entropy pool when
+ available.
+ '';
+ };
+ };
+
+ config = mkIf config.security.rngd.enable {
+ services.udev.extraRules = ''
+ KERNEL=="random", TAG+="systemd"
+ SUBSYSTEM=="cpu", ENV{MODALIAS}=="x86cpu:*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
+ KERNEL=="hw_random", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
+ KERNEL=="tmp0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
+ '';
+
+ systemd.services.rngd = {
+ bindsTo = [ "dev-random.device" ];
+
+ after = [ "dev-random.device" ];
+
+ description = "Hardware RNG Entropy Gatherer Daemon";
+
+ serviceConfig.ExecStart = "${pkgs.rng_tools}/sbin/rngd -f";
+
+ restartTriggers = [ pkgs.rng_tools ];
+ };
+ };
+}
diff --git a/modules/security/sudo.nix b/modules/security/sudo.nix
index 211ff8a9609..d2db9ee993f 100644
--- a/modules/security/sudo.nix
+++ b/modules/security/sudo.nix
@@ -37,25 +37,6 @@ in
security.sudo.configFile = mkOption {
# Note: if syntax errors are detected in this file, the NixOS
# configuration will fail to build.
- default =
- ''
- # Don't edit this file. Set the NixOS option ‘security.sudo.configFile’ instead.
-
- # Environment variables to keep for root and %wheel.
- Defaults:root,%wheel env_keep+=LOCALE_ARCHIVE
- Defaults:root,%wheel env_keep+=NIX_CONF_DIR
- Defaults:root,%wheel env_keep+=NIX_PATH
- Defaults:root,%wheel env_keep+=TERMINFO_DIRS
-
- # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
- Defaults env_keep+=SSH_AUTH_SOCK
-
- # "root" is allowed to do anything.
- root ALL=(ALL) SETENV: ALL
-
- # Users in the "wheel" group can do anything.
- %wheel ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
- '';
description =
''
This string contains the contents of the
@@ -69,6 +50,26 @@ in
config = mkIf cfg.enable {
+ security.sudo.configFile =
+ ''
+ # Don't edit this file. Set the NixOS option ‘security.sudo.configFile’ instead.
+
+ # Environment variables to keep for root and %wheel.
+ Defaults:root,%wheel env_keep+=LOCALE_ARCHIVE
+ Defaults:root,%wheel env_keep+=NIX_CONF_DIR
+ Defaults:root,%wheel env_keep+=NIX_PATH
+ Defaults:root,%wheel env_keep+=TERMINFO_DIRS
+
+ # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
+ Defaults env_keep+=SSH_AUTH_SOCK
+
+ # "root" is allowed to do anything.
+ root ALL=(ALL) SETENV: ALL
+
+ # Users in the "wheel" group can do anything.
+ %wheel ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL
+ '';
+
security.setuidPrograms = [ "sudo" ];
environment.systemPackages = [ sudo ];
diff --git a/modules/services/audio/alsa.nix b/modules/services/audio/alsa.nix
index 4d622428976..ead53c3dc3a 100644
--- a/modules/services/audio/alsa.nix
+++ b/modules/services/audio/alsa.nix
@@ -29,9 +29,9 @@ in
enableOSSEmulation = mkOption {
default = true;
- description = ''
- Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).
- '';
+ description = ''
+ Whether to enable ALSA OSS emulation (with certain cards sound mixing may not work!).
+ '';
};
};
@@ -45,25 +45,18 @@ in
environment.systemPackages = [ alsaUtils ];
+ # ALSA provides a udev rule for restoring volume settings.
+ services.udev.packages = [ alsaUtils ];
+
boot.kernelModules = optional config.sound.enableOSSEmulation "snd_pcm_oss";
- jobs.alsa =
- { startOn = "stopped udevtrigger";
-
- preStart =
- ''
- mkdir -m 0755 -p $(dirname ${soundState})
-
- # Try to restore the sound state.
- ${alsaUtils}/sbin/alsactl --ignore init || true
- ${alsaUtils}/sbin/alsactl --ignore -f ${soundState} restore || true
- '';
-
- postStop =
- ''
- # Save the sound state.
- ${alsaUtils}/sbin/alsactl --ignore -f ${soundState} store
- '';
+ systemd.services."alsa-store" =
+ { description = "Store Sound Card State";
+ wantedBy = [ "shutdown.target" ];
+ before = [ "shutdown.target" ];
+ unitConfig.DefaultDependencies = "no";
+ serviceConfig.Type = "oneshot";
+ serviceConfig.ExecStart = "${alsaUtils}/sbin/alsactl store --ignore";
};
};
diff --git a/modules/services/databases/mongodb.nix b/modules/services/databases/mongodb.nix
index c676d3e96e4..887f1f0529f 100644
--- a/modules/services/databases/mongodb.nix
+++ b/modules/services/databases/mongodb.nix
@@ -97,17 +97,16 @@ in
users.extraUsers = singleton
{ name = cfg.user;
- shell = "/bin/sh";
description = "MongoDB server user";
};
- environment.systemPackages = [mongodb];
+ environment.systemPackages = [ mongodb ];
- jobs.mongodb =
+ systemd.services.mongodb =
{ description = "MongoDB server";
- daemonType = "daemon";
- startOn = "filesystem";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
preStart =
''
@@ -117,11 +116,10 @@ in
fi
'';
- path = [mongodb];
- exec = "mongod --config ${mongoCnf} --fork";
- setuid = cfg.user;
-
- extraConfig = "kill timeout 10";
+ serviceConfig = {
+ ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf}";
+ User = cfg.user;
+ };
};
};
diff --git a/modules/services/databases/mysql.nix b/modules/services/databases/mysql.nix
index 2c35c13255e..7bf7a77aa85 100644
--- a/modules/services/databases/mysql.nix
+++ b/modules/services/databases/mysql.nix
@@ -91,6 +91,7 @@ in
description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
};
+ # FIXME: remove this option; it's a really bad idea.
rootPassword = mkOption {
default = null;
description = "Path to a file containing the root password, modified on the first startup. Not specifying a root password will leave the root password empty.";
@@ -140,10 +141,12 @@ in
environment.systemPackages = [mysql];
- jobs.mysql =
- { description = "MySQL server";
+ systemd.services.mysql =
+ { description = "MySQL Server";
- startOn = "filesystem";
+ wantedBy = [ "multi-user.target" ];
+
+ unitConfig.RequiresMountsFor = "${cfg.dataDir}";
preStart =
''
@@ -156,9 +159,12 @@ in
mkdir -m 0700 -p ${cfg.pidDir}
chown -R ${cfg.user} ${cfg.pidDir}
-
- ${mysql}/libexec/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions} &
+ '';
+ serviceConfig.ExecStart = "${mysql}/libexec/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
+
+ postStart =
+ ''
# Wait until the MySQL server is available for use
count=0
while [ ! -e /tmp/mysql.sock ]
@@ -183,7 +189,7 @@ in
echo "Creating initial database: ${database.name}"
( echo "create database ${database.name};"
echo "use ${database.name};"
-
+
if [ -f "${database.schema}" ]
then
cat ${database.schema}
@@ -204,7 +210,7 @@ in
${optionalString (cfg.rootPassword != null)
''
# Change root password
-
+
( echo "use mysql;"
echo "update user set Password=password('$(cat ${cfg.rootPassword})') where User='root';"
echo "flush privileges;"
@@ -213,14 +219,10 @@ in
rm /tmp/mysql_init
fi
- '';
+ ''; # */
- postStop = "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
-
- # !!! Need a postStart script to wait until mysqld is ready to
- # accept connections.
-
- extraConfig = "kill timeout 60";
+ serviceConfig.ExecStop =
+ "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
};
};
diff --git a/modules/services/databases/mysql55.nix b/modules/services/databases/mysql55.nix
index a37f1d38831..37cab395677 100644
--- a/modules/services/databases/mysql55.nix
+++ b/modules/services/databases/mysql55.nix
@@ -84,6 +84,7 @@ in
description = "A file containing SQL statements to be executed on the first startup. Can be used for granting certain permissions on the database";
};
+ # FIXME: remove this option; it's a really bad idea.
rootPassword = mkOption {
default = null;
description = "Path to a file containing the root password, modified on the first startup. Not specifying a root password will leave the root password empty.";
@@ -133,10 +134,12 @@ in
environment.systemPackages = [mysql];
- jobs.mysql =
- { description = "MySQL server";
+ systemd.services.mysql =
+ { description = "MySQL Server";
- startOn = "filesystem";
+ wantedBy = [ "multi-user.target" ];
+
+ unitConfig.RequiresMountsFor = "${cfg.dataDir}";
preStart =
''
@@ -149,9 +152,12 @@ in
mkdir -m 0700 -p ${cfg.pidDir}
chown -R ${cfg.user} ${cfg.pidDir}
-
- ${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions} &
+ '';
+ serviceConfig.ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
+
+ postStart =
+ ''
# Wait until the MySQL server is available for use
count=0
while [ ! -e /tmp/mysql.sock ]
@@ -176,7 +182,7 @@ in
echo "Creating initial database: ${database.name}"
( echo "create database ${database.name};"
echo "use ${database.name};"
-
+
if [ -f "${database.schema}" ]
then
cat ${database.schema}
@@ -207,7 +213,7 @@ in
${optionalString (cfg.rootPassword != null)
''
# Change root password
-
+
( echo "use mysql;"
echo "update user set Password=password('$(cat ${cfg.rootPassword})') where User='root';"
echo "flush privileges;"
@@ -216,14 +222,10 @@ in
rm /tmp/mysql_init
fi
- '';
+ ''; # */
- postStop = "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
-
- # !!! Need a postStart script to wait until mysqld is ready to
- # accept connections.
-
- extraConfig = "kill timeout 60";
+ serviceConfig.ExecStop =
+ "${mysql}/bin/mysqladmin ${optionalString (cfg.rootPassword != null) "--user=root --password=\"$(cat ${cfg.rootPassword})\""} shutdown";
};
};
diff --git a/modules/services/databases/postgresql.nix b/modules/services/databases/postgresql.nix
index 398fdbd8611..a33fdaab423 100644
--- a/modules/services/databases/postgresql.nix
+++ b/modules/services/databases/postgresql.nix
@@ -22,8 +22,6 @@ let
postgresql = postgresqlAndPlugins cfg.package;
- run = "su -s ${pkgs.stdenv.shell} postgres";
-
flags = optional cfg.enableTCPIP "-i";
# The main PostgreSQL configuration file.
@@ -36,7 +34,7 @@ let
'';
pre84 = versionOlder (builtins.parseDrvName postgresql.name).version "8.4";
-
+
in
{
@@ -146,7 +144,7 @@ in
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'';
-
+
users.extraUsers = singleton
{ name = "postgres";
description = "PostgreSQL server user";
@@ -157,10 +155,11 @@ in
environment.systemPackages = [postgresql];
- jobs.postgresql =
- { description = "PostgreSQL server";
+ systemd.services.postgresql =
+ { description = "PostgreSQL Server";
- startOn = "started network-interfaces and filesystem";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
environment =
{ TZ = config.time.timeZone;
@@ -175,34 +174,38 @@ in
if ! test -e ${cfg.dataDir}; then
mkdir -m 0700 -p ${cfg.dataDir}
chown -R postgres ${cfg.dataDir}
- ${run} -c 'initdb -U root'
+ su -s ${pkgs.stdenv.shell} postgres -c 'initdb -U root'
rm -f ${cfg.dataDir}/*.conf
fi
ln -sfn ${configFile} ${cfg.dataDir}/postgresql.conf
''; # */
- exec = "${run} -c 'postgres ${toString flags}'";
+ serviceConfig =
+ { ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}";
+ User = "postgres";
+ Group = "postgres";
+ PermissionsStartOnly = true;
+
+ # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See
+ # http://www.postgresql.org/docs/current/static/server-shutdown.html
+ KillSignal = "SIGINT";
+
+ # Give Postgres a decent amount of time to clean up after
+ # receiving systemd's SIGINT.
+ TimeoutSec = 60;
+ };
# Wait for PostgreSQL to be ready to accept connections.
postStart =
''
- while ! psql postgres -c ""; do
- stop_check
- sleep 1
+ while ! psql postgres -c "" 2> /dev/null; do
+ if ! kill -0 "$MAINPID"; then exit 1; fi
+ sleep 0.1
done
'';
- extraConfig =
- ''
- # Shut down Postgres using SIGINT ("Fast Shutdown mode"). See
- # http://www.postgresql.org/docs/current/static/server-shutdown.html
- kill signal INT
-
- # Give Postgres a decent amount of time to clean up after
- # receiving Upstart's SIGINT.
- kill timeout 60
- '';
+ unitConfig.RequiresMountsFor = "${cfg.dataDir}";
};
};
diff --git a/modules/services/hardware/acpid.nix b/modules/services/hardware/acpid.nix
index 26c600092db..b61c8020bca 100644
--- a/modules/services/hardware/acpid.nix
+++ b/modules/services/hardware/acpid.nix
@@ -95,15 +95,18 @@ in
config = mkIf config.services.acpid.enable {
jobs.acpid =
- { description = "ACPI daemon";
+ { description = "ACPI Daemon";
- startOn = "stopped udevtrigger and started syslogd";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "systemd-udev-settle.service" ];
path = [ pkgs.acpid ];
daemonType = "fork";
exec = "acpid --confdir ${acpiConfDir}";
+
+ unitConfig.ConditionPathExists = [ "/proc/acpi" ];
};
};
diff --git a/modules/services/hardware/hal.nix b/modules/services/hardware/hal.nix
deleted file mode 100644
index f9fb2dfecef..00000000000
--- a/modules/services/hardware/hal.nix
+++ /dev/null
@@ -1,117 +0,0 @@
-# HAL daemon.
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-let
-
- cfg = config.services.hal;
-
- inherit (pkgs) hal;
-
- fdi = pkgs.buildEnv {
- name = "hal-fdi";
- pathsToLink = [ "/share/hal/fdi" ];
- paths = cfg.packages;
- };
-
-in
-
-{
-
- ###### interface
-
- options = {
-
- services.hal = {
-
- enable = mkOption {
- default = false;
- description = ''
- Whether to start the HAL daemon.
- '';
- };
-
- packages = mkOption {
- default = [];
- description = ''
- Packages containing additional HAL configuration data.
- '';
- };
-
- };
-
- };
-
-
- ###### implementation
-
- config = mkIf cfg.enable {
-
- environment.systemPackages = [ hal ];
-
- services.hal.packages = [ hal pkgs.hal_info ];
-
- security.policykit.enable = true;
-
- users.extraUsers = singleton
- { name = "haldaemon";
- uid = config.ids.uids.haldaemon;
- description = "HAL daemon user";
- };
-
- users.extraGroups = singleton
- { name = "haldaemon";
- gid = config.ids.gids.haldaemon;
- };
-
- jobs.hal =
- { description = "HAL daemon";
-
- startOn = "started dbus" + optionalString config.services.acpid.enable " and started acpid";
-
- environment =
- { # !!! HACK? These environment variables manipulated inside
- # 'src'/hald/mmap_cache.c are used for testing the daemon.
- HAL_FDI_SOURCE_PREPROBE = "${fdi}/share/hal/fdi/preprobe";
- HAL_FDI_SOURCE_INFORMATION = "${fdi}/share/hal/fdi/information";
- HAL_FDI_SOURCE_POLICY = "${fdi}/share/hal/fdi/policy";
-
- # Stuff needed by the shell scripts run by HAL (in particular pm-utils).
- HALD_RUNNER_PATH = concatStringsSep ":"
- [ "${pkgs.coreutils}/bin"
- "${pkgs.gnugrep}/bin"
- "${pkgs.dbus_tools}/bin"
- "${pkgs.procps}/bin"
- "${pkgs.procps}/sbin"
- "${config.system.sbin.modprobe}/sbin"
- "${pkgs.module_init_tools}/bin"
- "${pkgs.module_init_tools}/sbin"
- "${pkgs.kbd}/bin"
- ];
- };
-
- preStart =
- ''
- mkdir -m 0755 -p /var/cache/hald
- mkdir -m 0755 -p /var/run/hald
-
- rm -f /var/cache/hald/fdi-cache
- '';
-
- daemonType = "fork";
-
- # The `PATH=' works around a bug in HAL: it concatenates
- # its libexec directory to $PATH, but using a 512-byte
- # buffer. So if $PATH is too long it fails.
- script = "PATH= exec ${hal}/sbin/hald --use-syslog";
- };
-
- services.udev.packages = [hal];
-
- services.dbus.enable = true;
- services.dbus.packages = [hal];
-
- };
-
-}
diff --git a/modules/services/hardware/udev.nix b/modules/services/hardware/udev.nix
index 174d31c6c00..e1a338d6ad8 100644
--- a/modules/services/hardware/udev.nix
+++ b/modules/services/hardware/udev.nix
@@ -4,7 +4,9 @@ with pkgs.lib;
let
- inherit (pkgs) stdenv writeText udev procps;
+ inherit (pkgs) stdenv writeText procps;
+
+ udev = config.systemd.package;
cfg = config.services.udev;
@@ -24,20 +26,16 @@ let
udevRules = stdenv.mkDerivation {
name = "udev-rules";
buildCommand = ''
- ensureDir $out
+ mkdir -p $out
shopt -s nullglob
# Set a reasonable $PATH for programs called by udev rules.
echo 'ENV{PATH}="${udevPath}/bin:${udevPath}/sbin"' > $out/00-path.rules
- # Set the firmware search path so that the firmware.sh helper
- # called by 50-firmware.rules works properly.
- echo 'ENV{FIRMWARE_DIRS}="/root/test-firmware ${toString config.hardware.firmware}"' >> $out/00-path.rules
-
# Add the udev rules from other packages.
for i in ${toString cfg.packages}; do
echo "Adding rules for package $i"
- for j in $i/*/udev/rules.d/*; do
+ for j in $i/{etc,lib}/udev/rules.d/*; do
echo "Copying $j to $out/$(basename $j)"
echo "# Copied from $j" > $out/$(basename $j)
cat $j >> $out/$(basename $j)
@@ -53,12 +51,7 @@ let
--replace \"/bin/mount \"${pkgs.utillinux}/bin/mount
done
- # If auto-configuration is disabled, then remove
- # udev's 80-drivers.rules file, which contains rules for
- # automatically calling modprobe.
- ${if !config.boot.hardwareScan then "rm $out/80-drivers.rules" else ""}
-
- echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev ... "
+ echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... "
import_progs=$(grep 'IMPORT{program}="[^/$]' $out/* |
sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="[^/$]' |
@@ -72,7 +65,7 @@ let
done
echo "OK"
- echo -n "Checking that all programs call by absolute paths in udev rules exist ... "
+ echo -n "Checking that all programs called by absolute paths in udev rules exist... "
import_progs=$(grep 'IMPORT{program}="\/' $out/* |
sed -e 's/.*IMPORT{program}="\([^ "]*\)[ "].*/\1/' | uniq)
run_progs=$(grep -v '^[[:space:]]*#' $out/* | grep 'RUN+="/' |
@@ -90,24 +83,9 @@ let
for i in ${toString cfg.packages}; do
grep -l '\(RUN+\|IMPORT{program}\)="\(/usr\)\?/s\?bin' $i/*/udev/rules.d/* || true
done
-
- # Use the persistent device rules (naming for CD/DVD and
- # network devices) stored in
- # /var/lib/udev/rules.d/70-persistent-{cd,net}.rules. These are
- # modified by the write_{cd,net}_rules helpers called from
- # 75-cd-aliases-generator.rules and
- # 75-persistent-net-generator.rules.
- ln -sv /var/lib/udev/rules.d/70-persistent-cd.rules $out/
- ln -sv /var/lib/udev/rules.d/70-persistent-net.rules $out/
''; # */
};
- # The udev configuration file.
- conf = writeText "udev.conf" ''
- udev_rules="${udevRules}"
- #udev_log="debug"
- '';
-
# Udev has a 512-character limit for ENV{PATH}, so create a symlink
# tree to work around this.
udevPath = pkgs.buildEnv {
@@ -207,61 +185,15 @@ in
services.udev.extraRules = nixosRules;
- services.udev.packages = [ pkgs.udev extraUdevRules ];
+ services.udev.packages = [ extraUdevRules ];
- services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux pkgs.udev ];
+ services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ];
- jobs.udev =
- { startOn = "startup";
-
- environment = { UDEV_CONFIG_FILE = conf; };
-
- path = [ udev ];
-
- preStart =
- ''
- echo "" > /proc/sys/kernel/hotplug || true
-
- mkdir -p /var/lib/udev/rules.d
- touch /var/lib/udev/rules.d/70-persistent-cd.rules /var/lib/udev/rules.d/70-persistent-net.rules
-
- mkdir -p /dev/.udev # !!! bug in udev?
- '';
-
- daemonType = "fork";
-
- exec = "udevd --daemon";
-
- postStart =
- ''
- # Do the loading of additional stage 2 kernel modules.
- # This needs to be done while udevd is running, because
- # the modules may call upon udev's firmware loading rule.
- for i in ${toString config.boot.kernelModules}; do
- echo "loading kernel module ‘$i’..."
- ${config.system.sbin.modprobe}/sbin/modprobe $i || true
- done
- '';
- };
-
- jobs.udevtrigger =
- { startOn = "started udev";
-
- task = true;
-
- path = [ udev ];
-
- script =
- ''
- # Let udev create device nodes for all modules that have already
- # been loaded into the kernel (or for which support is built into
- # the kernel).
- udevadm trigger --action=add
- udevadm settle || true # wait for udev to finish
-
- initctl emit -n new-devices
- '';
- };
+ environment.etc =
+ [ { source = udevRules;
+ target = "udev/rules.d";
+ }
+ ];
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isEnabled "UNIX")
diff --git a/modules/services/hardware/upower.nix b/modules/services/hardware/upower.nix
index 1fdaee202d3..5d1658adb75 100644
--- a/modules/services/hardware/upower.nix
+++ b/modules/services/hardware/upower.nix
@@ -35,11 +35,30 @@ with pkgs.lib;
services.udev.packages = [ pkgs.upower ];
+ systemd.services.upower =
+ { description = "Power Management Daemon";
+ path = [ pkgs.glib ]; # needed for gdbus
+ serviceConfig =
+ { Type = "dbus";
+ BusName = "org.freedesktop.UPower";
+ ExecStart = "@${pkgs.upower}/libexec/upowerd upowerd";
+ };
+ };
+
system.activationScripts.upower =
''
mkdir -m 0755 -p /var/lib/upower
'';
+ # The upower daemon seems to get stuck after doing a suspend
+ # (i.e. subsequent suspend requests will say "Sleep has already
+ # been requested and is pending"). So as a workaround, restart
+ # the daemon.
+ powerManagement.resumeCommands =
+ ''
+ ${config.systemd.package}/bin/systemctl try-restart upower
+ '';
+
};
}
diff --git a/modules/services/logging/klogd.nix b/modules/services/logging/klogd.nix
index 907d83c7a6a..d7d0bbf89a5 100644
--- a/modules/services/logging/klogd.nix
+++ b/modules/services/logging/klogd.nix
@@ -1,19 +1,42 @@
{ config, pkgs, ... }:
-###### implementation
+with pkgs.lib;
{
+ ###### interface
- jobs.klogd =
- { description = "Kernel log daemon";
+ options = {
- startOn = "started syslogd";
-
- path = [ pkgs.sysklogd ];
-
- exec =
- "klogd -c 1 -2 -n " +
- "-k $(dirname $(readlink -f /run/booted-system/kernel))/System.map";
+ services.klogd.enable = mkOption {
+ type = types.bool;
+ default = versionOlder (getVersion config.boot.kernelPackages.kernel) "3.5";
+ description = ''
+ Whether to enable klogd, the kernel log message processing
+ daemon. Since systemd handles logging of kernel messages on
+ Linux 3.5 and later, this is only useful if you're running an
+ older kernel.
+ '';
};
+ };
+
+
+ ###### implementation
+
+ config = mkIf config.services.klogd.enable {
+
+ jobs.klogd =
+ { description = "Kernel Log Daemon";
+
+ wantedBy = [ "multi-user.target" ];
+
+ path = [ pkgs.sysklogd ];
+
+ exec =
+ "klogd -c 1 -2 -n " +
+ "-k $(dirname $(readlink -f /run/booted-system/kernel))/System.map";
+ };
+
+ };
+
}
diff --git a/modules/services/logging/logstash.nix b/modules/services/logging/logstash.nix
index f4c226ac349..b535a942a9e 100644
--- a/modules/services/logging/logstash.nix
+++ b/modules/services/logging/logstash.nix
@@ -136,12 +136,11 @@ in
mkNameValuePairs = mergeConfigs;
};
} ( mkIf cfg.enable {
- # Always log to stdout
- services.logstash.outputConfig = { stdout = {}; };
-
- jobs.logstash = with pkgs; {
+ systemd.services.logstash = with pkgs; {
description = "Logstash daemon";
- startOn = "started networking and filesystem";
+
+ wantedBy = [ "multi-user.target" ];
+ environment.TZ = config.time.timeZone;
path = [ jre ];
@@ -157,7 +156,7 @@ in
output {
${exprToConfig cfg.outputConfig}
}
- ''}";
+ ''} &> /var/log/logstash.log";
};
})];
}
diff --git a/modules/services/logging/syslogd.nix b/modules/services/logging/syslogd.nix
index 715cfc0f9e6..886669606b4 100644
--- a/modules/services/logging/syslogd.nix
+++ b/modules/services/logging/syslogd.nix
@@ -36,6 +36,15 @@ in
services.syslogd = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable syslogd. Note that systemd also logs
+ syslog messages, so you normally don't need to run syslogd.
+ '';
+ };
+
tty = mkOption {
type = types.uniq types.string;
default = "tty10";
@@ -89,22 +98,27 @@ in
###### implementation
- config = {
+ config = mkIf cfg.enable {
+
+ environment.systemPackages = [ pkgs.sysklogd ];
services.syslogd.extraParams = optional cfg.enableNetworkInput "-r";
- jobs.syslogd =
- { description = "Syslog daemon";
+ # FIXME: restarting syslog seems to break journal logging.
+ systemd.services.syslog =
+ { description = "Syslog Daemon";
- startOn = "started udev";
+ requires = [ "syslog.socket" ];
- environment = { TZ = config.time.timeZone; };
+ wantedBy = [ "multi-user.target" "syslog.target" ];
- daemonType = "fork";
+ environment.TZ = config.time.timeZone;
- path = [ pkgs.sysklogd ];
-
- exec = "syslogd ${toString cfg.extraParams} -f ${syslogConf}";
+ serviceConfig =
+ { ExecStart = "${pkgs.sysklogd}/sbin/syslogd ${toString cfg.extraParams} -f ${syslogConf} -n";
+ # Prevent syslogd output looping back through journald.
+ StandardOutput = "null";
+ };
};
};
diff --git a/modules/services/mail/postfix.nix b/modules/services/mail/postfix.nix
index ea887ea8e19..6b141e7e24e 100644
--- a/modules/services/mail/postfix.nix
+++ b/modules/services/mail/postfix.nix
@@ -364,22 +364,13 @@ in
# accurate way is unlikely to be better.
{ description = "Postfix mail server";
- startOn = "started networking and filesystem";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
- daemonType = "none";
-
- respawn = true;
+ daemonType = "fork";
environment.TZ = config.time.timeZone;
- script = ''
- while ${pkgs.procps}/bin/ps `${pkgs.coreutils}/bin/cat /var/postfix/queue/pid/master.pid` |
- grep -q postfix
- do
- ${pkgs.coreutils}/bin/sleep 1m
- done
- '';
-
preStart =
''
if ! [ -d /var/spool/postfix ]; then
@@ -402,11 +393,11 @@ in
${pkgs.postfix}/sbin/postalias -c /var/postfix/conf /var/postfix/conf/aliases
${pkgs.postfix}/sbin/postmap -c /var/postfix/conf /var/postfix/conf/virtual
- exec ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
+ ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf start
'';
preStop = ''
- exec ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
+ ${pkgs.postfix}/sbin/postfix -c /var/postfix/conf stop
'';
};
diff --git a/modules/services/misc/nix-daemon.nix b/modules/services/misc/nix-daemon.nix
index 92e3b627f85..a2ec899a593 100644
--- a/modules/services/misc/nix-daemon.nix
+++ b/modules/services/misc/nix-daemon.nix
@@ -4,6 +4,8 @@ with pkgs.lib;
let
+ cfg = config.nix;
+
inherit (config.environment) nix;
makeNixBuildUser = nr:
@@ -74,9 +76,7 @@ in
gc-keep-outputs = true
gc-keep-derivations = true
";
- description = "
- This option allows to append lines to nix.conf.
- ";
+ description = "Additional text appended to nix.conf.";
};
distributedBuilds = mkOption {
@@ -169,11 +169,9 @@ in
# actually a shell script.
envVars = mkOption {
internal = true;
- default = "";
- type = types.string;
- description = "
- Environment variables used by Nix.
- ";
+ default = {};
+ type = types.attrs;
+ description = "Environment variables used by Nix.";
};
nrBuildUsers = mkOption {
@@ -186,6 +184,16 @@ in
'';
};
+ readOnlyStore = mkOption {
+ default = false;
+ description = ''
+ If set, NixOS will enforce the immutability of the Nix store
+ by making /nix/store a read-only bind
+ mount. Nix will automatically make the store writable when
+ needed.
+ '';
+ };
+
binaryCaches = mkOption {
default = [ http://nixos.org/binary-cache ];
type = types.list types.string;
@@ -231,16 +239,16 @@ in
# /bin/sh won't work.
binshDeps = pkgs.writeReferencesToFile config.system.build.binsh;
in
- pkgs.runCommand "nix.conf" {extraOptions = config.nix.extraOptions; } ''
+ pkgs.runCommand "nix.conf" {extraOptions = cfg.extraOptions; } ''
extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done)
cat > $out < /dev/null 2>&1
- '';
+ environment = cfg.envVars;
- extraConfig =
- ''
- limit nofile 4096 4096
- '';
+ serviceConfig =
+ { ExecStart = "@${nix}/bin/nix-daemon nix-daemon";
+ KillMode = "process";
+ Nice = cfg.daemonNiceLevel;
+ IOSchedulingPriority = cfg.daemonIONiceLevel;
+ LimitNOFILE = 4096;
+ };
+ };
+
+ nix.envVars =
+ { NIX_CONF_DIR = "/etc/nix";
+
+ # Enable the copy-from-other-stores substituter, which allows builds
+ # to be sped up by copying build results from remote Nix stores. To
+ # do this, mount the remote file system on a subdirectory of
+ # /var/run/nix/remote-stores.
+ NIX_OTHER_STORES = "/var/run/nix/remote-stores/*/nix";
+ }
+
+ // optionalAttrs cfg.distributedBuilds {
+ NIX_BUILD_HOOK = "${config.environment.nix}/libexec/nix/build-remote.pl";
+ NIX_REMOTE_SYSTEMS = "/etc/nix.machines";
+ NIX_CURRENT_LOAD = "/var/run/nix/current-load";
+ }
+
+ # !!! These should not be defined here, but in some general proxy configuration module!
+ // optionalAttrs (cfg.proxy != "") {
+ http_proxy = cfg.proxy;
+ https_proxy = cfg.proxy;
+ ftp_proxy = cfg.proxy;
};
environment.shellInit =
''
# Set up the environment variables for running Nix.
- ${config.nix.envVars}
+ ${concatMapStrings (n: "export ${n}=\"${getAttr n cfg.envVars}\"\n") (attrNames cfg.envVars)}
# Set up secure multi-user builds: non-root users build through the
# Nix daemon.
@@ -299,36 +331,10 @@ in
fi
'';
- nix.envVars =
- ''
- export NIX_CONF_DIR=/etc/nix
-
- # Enable the copy-from-other-stores substituter, which allows builds
- # to be sped up by copying build results from remote Nix stores. To
- # do this, mount the remote file system on a subdirectory of
- # /var/run/nix/remote-stores.
- export NIX_OTHER_STORES=/var/run/nix/remote-stores/*/nix
- '' # */
- + optionalString config.nix.distributedBuilds ''
- export NIX_BUILD_HOOK=${config.environment.nix}/libexec/nix/build-remote.pl
- export NIX_REMOTE_SYSTEMS=/etc/nix.machines
- export NIX_CURRENT_LOAD=/var/run/nix/current-load
- ''
- # !!! These should not be defined here, but in some general proxy configuration module!
- + optionalString (config.nix.proxy != "") ''
- export http_proxy=${config.nix.proxy}
- export https_proxy=${config.nix.proxy}
- export ftp_proxy=${config.nix.proxy}
- '';
-
- users.extraUsers = map makeNixBuildUser (range 1 config.nix.nrBuildUsers);
+ users.extraUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers);
system.activationScripts.nix = stringAfter [ "etc" "users" ]
''
- # Set up Nix.
- chown root:nixbld /nix/store
- chmod 1775 /nix/store
-
# Nix initialisation.
mkdir -m 0755 -p \
/nix/var/nix/gcroots \
@@ -340,9 +346,10 @@ in
/nix/var/log/nix/drvs \
/nix/var/nix/channel-cache \
/nix/var/nix/chroots
- mkdir -m 1777 -p /nix/var/nix/gcroots/per-user
- mkdir -m 1777 -p /nix/var/nix/profiles/per-user
- mkdir -m 1777 -p /nix/var/nix/gcroots/tmp
+ mkdir -m 1777 -p \
+ /nix/var/nix/gcroots/per-user \
+ /nix/var/nix/profiles/per-user \
+ /nix/var/nix/gcroots/tmp
ln -sf /nix/var/nix/profiles /nix/var/nix/gcroots/
ln -sf /nix/var/nix/manifests /nix/var/nix/gcroots/
diff --git a/modules/services/misc/nix-gc.nix b/modules/services/misc/nix-gc.nix
index 942e7996da0..28045044601 100644
--- a/modules/services/misc/nix-gc.nix
+++ b/modules/services/misc/nix-gc.nix
@@ -3,7 +3,6 @@
with pkgs.lib;
let
- nix = config.environment.nix;
cfg = config.nix.gc;
in
@@ -16,7 +15,7 @@ in
automatic = mkOption {
default = false;
- example = true;
+ type = types.bool;
description = "
Automatically run the garbage collector at specified dates.
";
@@ -24,6 +23,7 @@ in
dates = mkOption {
default = "15 03 * * *";
+ type = types.string;
description = "
Run the garbage collector at specified dates to avoid full
hard-drives.
@@ -33,6 +33,7 @@ in
options = mkOption {
default = "";
example = "--max-freed $((64 * 1024**3))";
+ type = types.string;
description = "
Options given to nix-collect-garbage when the
garbage collector is run automatically.
@@ -45,10 +46,17 @@ in
###### implementation
- config = mkIf cfg.automatic {
- services.cron.systemCronJobs = [
- "${cfg.dates} root ${nix}/bin/nix-collect-garbage ${cfg.options} > /var/log/gc.log 2>&1"
- ];
+ config = {
+
+ services.cron.systemCronJobs = mkIf cfg.automatic (singleton
+ "${cfg.dates} root ${config.systemd.package}/bin/systemctl start nix-gc.service");
+
+ systemd.services."nix-gc" =
+ { description = "Nix Garbage Collector";
+ path = [ config.environment.nix ];
+ script = "exec nix-collect-garbage ${cfg.options}";
+ };
+
};
}
diff --git a/modules/services/misc/nixos-manual.nix b/modules/services/misc/nixos-manual.nix
index 84c39101bb6..108ed2911ce 100644
--- a/modules/services/misc/nixos-manual.nix
+++ b/modules/services/misc/nixos-manual.nix
@@ -16,6 +16,17 @@ let
inherit pkgs options;
};
+ entry = "${manual.manual}/share/doc/nixos/manual.html";
+
+ help = pkgs.writeScriptBin "nixos-help"
+ ''
+ #! ${pkgs.stdenv.shell} -e
+ if ! ''${BROWSER:-w3m} ${entry}; then
+ echo "$0: unable to start a web browser; please set \$BROWSER or install ‘w3m’"
+ exit 1
+ fi
+ '';
+
in
{
@@ -69,23 +80,23 @@ in
system.build.manual = manual;
- environment.systemPackages = [ manual.manpages ];
+ environment.systemPackages = [ manual.manpages help ];
boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"];
- jobs = mkIf cfg.showManual
- { nixosManual =
- { name = "nixos-manual";
-
- description = "NixOS manual";
-
- startOn = "started udev";
-
- exec =
- ''
- ${cfg.browser} ${manual.manual}/share/doc/nixos/manual.html \
- < /dev/tty${toString cfg.ttyNumber} > /dev/tty${toString cfg.ttyNumber} 2>&1
- '';
+ systemd.services = optionalAttrs cfg.showManual
+ { "nixos-manual" =
+ { description = "NixOS Manual";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig =
+ { ExecStart = "${cfg.browser} ${entry}";
+ StandardInput = "tty";
+ StandardOutput = "tty";
+ TTYPath = "/dev/tty${cfg.ttyNumber}";
+ TTYReset = true;
+ TTYVTDisallocate = true;
+ Restart = "always";
+ };
};
};
diff --git a/modules/services/misc/rogue.nix b/modules/services/misc/rogue.nix
index c313de956fc..c5cc8b4050d 100644
--- a/modules/services/misc/rogue.nix
+++ b/modules/services/misc/rogue.nix
@@ -40,14 +40,18 @@ in
boot.extraTTYs = [ cfg.tty ];
- jobs.rogue =
+ systemd.services.rogue =
{ description = "Rogue dungeon crawling game";
-
- startOn = "started udev";
-
- extraConfig = "chdir /root";
-
- exec = "${pkgs.rogue}/bin/rogue < /dev/${cfg.tty} > /dev/${cfg.tty} 2>&1";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig =
+ { ExecStart = "${pkgs.rogue}/bin/rogue";
+ StandardInput = "tty";
+ StandardOutput = "tty";
+ TTYPath = "/dev/${cfg.tty}";
+ TTYReset = true;
+ TTYVTDisallocate = true;
+ Restart = "always";
+ };
};
services.ttyBackgrounds.specificThemes = singleton
diff --git a/modules/services/monitoring/dd-agent.nix b/modules/services/monitoring/dd-agent.nix
new file mode 100644
index 00000000000..c6ab1ca0a3a
--- /dev/null
+++ b/modules/services/monitoring/dd-agent.nix
@@ -0,0 +1,58 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+ cfg = config.services.dd-agent;
+
+ datadog-conf = pkgs.runCommand "datadog.conf" {} ''
+ sed -e 's|^api_key:|api_key: ${cfg.api_key}|' ${optionalString (cfg.hostname != null)
+ "-e 's|^#hostname: mymachine.mydomain|hostname: ${cfg.hostname}|'"
+ } ${pkgs.dd-agent}/etc/dd-agent/datadog.conf.example > $out
+ '';
+in {
+ options.services.dd-agent = {
+ enable = mkOption {
+ description = "Whether to enable the dd-agent montioring service";
+
+ default = false;
+
+ type = types.bool;
+ };
+
+ # !!! This gets stored in the store (world-readable), wish we had https://github.com/NixOS/nix/issues/8
+ api_key = mkOption {
+ description = "The Datadog API key to associate the agent with your account";
+
+ example = "ae0aa6a8f08efa988ba0a17578f009ab";
+
+ type = types.uniq types.string;
+ };
+
+ hostname = mkOption {
+ description = "The hostname to show in the Datadog dashboard (optional)";
+
+ default = null;
+
+ example = "mymachine.mydomain";
+
+ type = types.uniq (types.nullOr types.string);
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc = [ { source = datadog-conf; target = "dd-agent/datadog.conf"; } ];
+
+ systemd.services.dd-agent = {
+ description = "Datadog agent monitor";
+
+ path = [ pkgs.sysstat pkgs.procps ];
+
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig.ExecStart = "${pkgs.dd-agent}/bin/dd-agent foreground";
+
+ restartTriggers = [ pkgs.dd-agent ];
+ };
+ };
+}
diff --git a/modules/services/monitoring/nagios/default.nix b/modules/services/monitoring/nagios/default.nix
index ddb0da21327..c809a3b8457 100644
--- a/modules/services/monitoring/nagios/default.nix
+++ b/modules/services/monitoring/nagios/default.nix
@@ -159,12 +159,7 @@ in
environment.systemPackages = [ pkgs.nagios ];
jobs.nagios =
- { # Run `nagios -v' to check the validity of the configuration file so
- # that a nixos-rebuild fails *before* we kill the running Nagios
- # daemon.
- buildHook = "${pkgs.nagios}/bin/nagios -v ${nagiosCfgFile}";
-
- description = "Nagios monitoring daemon";
+ { description = "Nagios monitoring daemon";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
diff --git a/modules/services/monitoring/smartd.nix b/modules/services/monitoring/smartd.nix
index 7ca5625bfe7..07acab761d0 100644
--- a/modules/services/monitoring/smartd.nix
+++ b/modules/services/monitoring/smartd.nix
@@ -57,7 +57,7 @@ in
description = ''
Additional options for each device that is monitored. The example
turns on SMART Automatic Offline Testing on startup, and schedules short
- self-tests daily, and long self-tests weekly.
+ self-tests daily, and long self-tests weekly.
'';
};
@@ -81,17 +81,15 @@ in
config = mkIf cfg.enable {
- jobs.smartd = {
- description = "S.M.A.R.T. Daemon";
+ systemd.services.smartd = {
+ description = "S.M.A.R.T. Daemon";
- environment.TZ = config.time.timeZone;
+ environment.TZ = config.time.timeZone;
- startOn = "started syslogd";
+ wantedBy = [ "multi-user.target" ];
- path = [ pkgs.smartmontools ];
-
- exec = "smartd --no-fork --pidfile=/var/run/smartd.pid ${smartdFlags}";
- };
+ serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork ${smartdFlags}";
+ };
};
diff --git a/modules/services/monitoring/zabbix-agent.nix b/modules/services/monitoring/zabbix-agent.nix
index ce8e1843d4c..229236c1bbd 100644
--- a/modules/services/monitoring/zabbix-agent.nix
+++ b/modules/services/monitoring/zabbix-agent.nix
@@ -73,15 +73,12 @@ in
description = "Zabbix daemon user";
};
- jobs.zabbix_agent =
- { name = "zabbix-agent";
+ systemd.services."zabbix-agent" =
+ { description = "Zabbix Agent";
- description = "Zabbix agent daemon";
+ wantedBy = [ "multi-user.target" ];
- startOn = "ip-up";
- stopOn = "stopping network-interfaces";
-
- path = [ pkgs.zabbix.agent ];
+ path = [ pkgs.nettools ];
preStart =
''
@@ -89,30 +86,11 @@ in
chown zabbix ${stateDir} ${logDir}
'';
- # Zabbix doesn't have an option not to daemonize, and doesn't
- # daemonize in a way that allows Upstart to track it. So to
- # make sure that we notice when it goes down, we start Zabbix
- # with an open connection to a fifo, with a `cat' on the other
- # side. If Zabbix dies, then `cat' will exit as well, so we
- # just monitor `cat'.
- script =
- ''
- export PATH=${pkgs.nettools}/bin:$PATH
- rm -f ${stateDir}/dummy2
- mkfifo ${stateDir}/dummy2
- cat ${stateDir}/dummy2 &
- pid=$!
- zabbix_agentd --config ${configFile} 100>${stateDir}/dummy2
- wait "$pid"
- '';
-
- postStop =
- ''
- pid=$(cat ${pidFile} 2> /dev/null || true)
- (test -n "$pid" && kill "$pid") || true
- # Wait until they're really gone.
- while ${pkgs.procps}/bin/pgrep -u zabbix zabbix_agentd > /dev/null; do sleep 1; done
- '';
+ serviceConfig.ExecStart = "@${pkgs.zabbix.agent}/sbin/zabbix_agentd zabbix_agentd --config ${configFile}";
+ serviceConfig.Type = "forking";
+ serviceConfig.RemainAfterExit = true;
+ serviceConfig.Restart = "always";
+ serviceConfig.RestartSec = 2;
};
environment.systemPackages = [ pkgs.zabbix.agent ];
diff --git a/modules/services/monitoring/zabbix-server.nix b/modules/services/monitoring/zabbix-server.nix
index 57fc69b3270..df42071ebba 100644
--- a/modules/services/monitoring/zabbix-server.nix
+++ b/modules/services/monitoring/zabbix-server.nix
@@ -73,12 +73,11 @@ in
description = "Zabbix daemon user";
};
- jobs.zabbix_server =
- { name = "zabbix-server";
+ systemd.services."zabbix-server" =
+ { description = "Zabbix Server";
- description = "Zabbix server daemon";
-
- startOn = "filesystem";
+ wantedBy = [ "multi-user.target" ];
+ after = optional (cfg.dbServer == "localhost") "postgresql.service";
preStart =
''
@@ -95,31 +94,12 @@ in
fi
'';
- path = [ pkgs.nettools pkgs.zabbix.server ];
+ path = [ pkgs.nettools ];
- # Zabbix doesn't have an option not to daemonize, and doesn't
- # daemonize in a way that allows Upstart to track it. So to
- # make sure that we notice when it goes down, we start Zabbix
- # with an open connection to a fifo, with a `cat' on the other
- # side. If Zabbix dies, then `cat' will exit as well, so we
- # just monitor `cat'.
- script =
- ''
- rm -f ${stateDir}/dummy
- mkfifo ${stateDir}/dummy
- cat ${stateDir}/dummy &
- pid=$!
- zabbix_server --config ${configFile} 100>${stateDir}/dummy
- wait "$pid"
- '';
-
- postStop =
- ''
- pid=$(cat ${pidFile} 2> /dev/null || true)
- (test -n "$pid" && kill "$pid") || true
- # Wait until they're really gone.
- while ${pkgs.procps}/bin/pkill -u zabbix zabbix_server; do true; done
- '';
+ serviceConfig.ExecStart = "@${pkgs.zabbix.server}/sbin/zabbix_server zabbix_server --config ${configFile}";
+ serviceConfig.Type = "forking";
+ serviceConfig.Restart = "always";
+ serviceConfig.RestartSec = 2;
};
};
diff --git a/modules/services/network-filesystems/nfsd.nix b/modules/services/network-filesystems/nfsd.nix
index b4dc014d68e..ab8e77e2bad 100644
--- a/modules/services/network-filesystems/nfsd.nix
+++ b/modules/services/network-filesystems/nfsd.nix
@@ -80,44 +80,44 @@ in
boot.kernelModules = [ "nfsd" ];
- jobs.nfsd =
- { description = "Kernel NFS server";
+ systemd.services.nfsd =
+ { description = "NFS Server";
- startOn = "started networking";
+ wantedBy = [ "multi-user.target" ];
+
+ requires = [ "rpcbind.service" "mountd.service" ];
+ after = [ "rpcbind.service" "mountd.service" "statd.service" ];
path = [ pkgs.nfsUtils ];
- preStart =
+ script =
''
- ensure rpcbind
- ensure mountd
-
# Create a state directory required by NFSv4.
mkdir -p /var/lib/nfs/v4recovery
rpc.nfsd \
${if cfg.hostName != null then "-H ${cfg.hostName}" else ""} \
${builtins.toString cfg.nproc}
+
+ sm-notify -d
'';
postStop = "rpc.nfsd 0";
- postStart =
- ''
- ensure statd
- ensure idmapd
- '';
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
};
- jobs.mountd =
- { description = "Kernel NFS server - mount daemon";
+ systemd.services.mountd =
+ { description = "NFSv3 Mount Daemon";
+
+ requires = [ "rpcbind.service" ];
+ after = [ "rpcbind.service" ];
path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
preStart =
''
- ensure rpcbind
-
mkdir -p /var/lib/nfs
touch /var/lib/nfs/rmtab
@@ -133,14 +133,14 @@ in
''
}
- # exports file is ${exports}
- # keep this comment so that this job is restarted whenever exports changes!
exportfs -ra
'';
- daemonType = "fork";
+ restartTriggers = [ exports ];
- exec = "rpc.mountd -f /etc/exports";
+ serviceConfig.Type = "forking";
+ serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.mountd rpc.mountd -f /etc/exports";
+ serviceConfig.Restart = "always";
};
};
diff --git a/modules/services/network-filesystems/samba.nix b/modules/services/network-filesystems/samba.nix
index 93c07df7cc6..c4157c647c6 100644
--- a/modules/services/network-filesystems/samba.nix
+++ b/modules/services/network-filesystems/samba.nix
@@ -26,18 +26,14 @@ let
mkdir -p /var/samba/locks /var/samba/cores/nmbd /var/samba/cores/smbd /var/samba/cores/winbindd
fi
- passwdFile="$(sed -n 's/^.*smb[ ]\+passwd[ ]\+file[ ]\+=[ ]\+\(.*\)/\1/p' ${configFile})"
+ passwdFile="$(${pkgs.gnused}/bin/sed -n 's/^.*smb[ ]\+passwd[ ]\+file[ ]\+=[ ]\+\(.*\)/\1/p' ${configFile})"
if [ -n "$passwdFile" ]; then
- echo 'INFO: creating directory containing passwd file'
+ echo 'INFO: [samba] creating directory containing passwd file'
mkdir -p "$(dirname "$passwdFile")"
fi
mkdir -p ${logDir}
mkdir -p ${privateDir}
-
- # The following line is to trigger a restart of the daemons when
- # the configuration changes:
- # ${configFile}
'';
configFile = pkgs.writeText "smb.conf"
@@ -60,12 +56,11 @@ let
# This may include nss_ldap, needed for samba if it has to use ldap.
nssModulesPath = config.system.nssModules.path;
- daemonJob = appName: args:
- { name = "samba-${appName}";
- description = "Samba Service daemon ${appName}";
+ daemonService = appName: args:
+ { description = "Samba Service daemon ${appName}";
- startOn = "started samba";
- stopOn = "stopping samba";
+ wantedBy = [ "samba.target" ];
+ partOf = [ "samba.target" ];
environment = {
LD_LIBRARY_PATH = nssModulesPath;
@@ -73,9 +68,12 @@ let
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};
- daemonType = "fork";
+ serviceConfig = {
+ ExecStart = "${samba}/sbin/${appName} ${args}";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ };
- exec = "${samba}/sbin/${appName} ${args}";
+ restartTriggers = [ configFile ];
};
in
@@ -202,22 +200,26 @@ in
};
- # Dummy job to start the real Samba daemons (nmbd, smbd, winbindd).
- jobs.sambaControl =
- { name = "samba";
+ systemd = {
+ targets.samba = {
description = "Samba server";
-
- startOn = "started network-interfaces";
- stopOn = "stopping network-interfaces";
-
- preStart = setupScript;
+ requires = [ "samba-setup.service" ];
+ after = [ "samba-setup.service" "network.target" ];
+ wantedBy = [ "multi-user.target" ];
};
- jobs.nmbd = daemonJob "nmbd" "-D";
+ services = {
+ "samba-nmbd" = daemonService "nmbd" "-F";
+ "samba-smbd" = daemonService "smbd" "-F";
+ "samba-winbindd" = daemonService "winbindd" "-F";
+ "samba-setup" = {
+ description = "Samba setup task";
+ script = setupScript;
+ unitConfig.RequiresMountsFor = "/home/smbd /var/samba /var/log/samba";
+ };
+ };
+ };
- jobs.smbd = daemonJob "smbd" "-D";
-
- jobs.winbindd = daemonJob "winbindd" "-D";
})
];
diff --git a/modules/services/networking/dhcpcd.nix b/modules/services/networking/dhcpcd.nix
index a6c4ca5433d..342253bac29 100644
--- a/modules/services/networking/dhcpcd.nix
+++ b/modules/services/networking/dhcpcd.nix
@@ -9,7 +9,7 @@ let
# Don't start dhclient on explicitly configured interfaces or on
# interfaces that are part of a bridge.
ignoredInterfaces =
- map (i: i.name) (filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces)
+ map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
++ config.networking.dhcpcd.denyInterfaces;
@@ -52,20 +52,19 @@ let
''}
if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then
- # Restart ntpd. (The "ip-up" event below will trigger the
- # restart.) We need to restart it to make sure that it will
- # actually do something: if ntpd cannot resolve the server
- # hostnames in its config file, then it will never do
+ # Restart ntpd. We need to restart it to make sure that it
+ # will actually do something: if ntpd cannot resolve the
+ # server hostnames in its config file, then it will never do
# anything ever again ("couldn't resolve ..., giving up on
# it"), so we silently lose time synchronisation.
- ${config.system.build.upstart}/sbin/initctl stop ntpd
+ ${config.systemd.package}/bin/systemctl try-restart ntpd.service
- ${config.system.build.upstart}/sbin/initctl emit -n ip-up $params
+ ${config.systemd.package}/bin/systemctl start ip-up.target
fi
- if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
- ${config.system.build.upstart}/sbin/initctl emit -n ip-down $params
- fi
+ #if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
+ # ${config.systemd.package}/bin/systemctl start ip-down.target
+ #fi
'';
in
@@ -93,12 +92,27 @@ in
config = mkIf config.networking.useDHCP {
- jobs.dhcpcd =
- { startOn = "started network-interfaces";
+ systemd.services.dhcpcd =
+ { description = "DHCP Client";
+
+ wantedBy = [ "network.target" ];
+ after = [ "systemd-udev-settle.service" ];
+
+ # Stopping dhcpcd during a reconfiguration is undesirable
+ # because it brings down the network interfaces configured by
+ # dhcpcd. So do a "systemctl restart" instead.
+ stopIfChanged = false;
path = [ dhcpcd pkgs.nettools pkgs.openresolv ];
- exec = "dhcpcd --config ${dhcpcdConf} --nobackground";
+ serviceConfig =
+ { Type = "forking";
+ PIDFile = "/run/dhcpcd.pid";
+ ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --config ${dhcpcdConf}";
+ ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind";
+ StandardError = "null";
+ Restart = "always";
+ };
};
environment.systemPackages = [ dhcpcd ];
@@ -112,8 +126,7 @@ in
powerManagement.resumeCommands =
''
# Tell dhcpcd to rebind its interfaces if it's running.
- status="$(${config.system.build.upstart}/sbin/status dhcpcd)"
- [[ "$status" =~ start/running ]] && ${dhcpcd}/sbin/dhcpcd --rebind
+ ${config.systemd.package}/bin/systemctl reload dhcpcd.service
'';
};
diff --git a/modules/services/networking/firewall.nix b/modules/services/networking/firewall.nix
index 9f7db27c738..7bc09a7b404 100644
--- a/modules/services/networking/firewall.nix
+++ b/modules/services/networking/firewall.nix
@@ -236,14 +236,15 @@ in
];
jobs.firewall =
- { startOn = "started network-interfaces";
+ { description = "Firewall";
+
+ startOn = "started network-interfaces";
path = [ pkgs.iptables ];
preStart =
''
${helpers}
- set -x
# Flush the old firewall rules. !!! Ideally, updating the
# firewall would be atomic. Apparently that's possible
diff --git a/modules/services/networking/gogoclient.nix b/modules/services/networking/gogoclient.nix
index 593f2436a39..07c35e3cb3d 100644
--- a/modules/services/networking/gogoclient.nix
+++ b/modules/services/networking/gogoclient.nix
@@ -56,22 +56,31 @@ in
config = mkIf cfg.enable {
boot.kernelModules = [ "tun" ];
- # environment.systemPackages = [pkgs.gogoclient];
-
networking.enableIPv6 = true;
- jobs.gogoclient = {
- name = "gogoclient";
+ systemd.services.gogoclient = {
description = "ipv6 tunnel";
- startOn = optionalString cfg.autorun "starting networking";
- stopOn = "stopping network-interfaces";
- preStart = ''
- mkdir -p /var/lib/gogoc
- chmod 700 /var/lib/gogoc
- cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | ${pkgs.gnused}/bin/sed -e "s|^userid=|&${cfg.username}|;s|^passwd=|&${if cfg.password == "" then "" else "$(cat ${cfg.password})"}|;s|^server=.*|server=${cfg.server}|;s|^auth_method=.*|auth_method=${if cfg.password == "" then "anonymous" else "any"}|;s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf
+
+ after = [ "network.target" ];
+ requires = [ "network.target" ];
+
+ unitConfig.RequiresMountsFor = "/var/lib/gogoc";
+
+ script = let authMethod = if cfg.password == "" then "anonymous" else "any"; in ''
+ mkdir -p -m 700 /var/lib/gogoc
+ cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | \
+ ${pkgs.gnused}/bin/sed \
+ -e "s|^userid=|&${cfg.username}|" \
+ -e "s|^passwd=|&${optionalString (cfg.password != "") "$(cat ${cfg.password})"}|" \
+ -e "s|^server=.*|server=${cfg.server}|" \
+ -e "s|^auth_method=.*|auth_method=${authMethod}|" \
+ -e "s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf
+ cd /var/lib/gogoc
+ exec ${pkgs.gogoclient}/bin/gogoc -y -f /var/lib/gogoc/gogoc.conf
'';
- script = "cd /var/lib/gogoc; exec gogoc -y -f ./gogoc.conf";
- path = [pkgs.gogoclient];
+ } // optionalAttrs cfg.autorun {
+ wantedBy = [ "ip-up.target" ];
+ partOf = [ "ip-up.target" ];
};
};
diff --git a/modules/services/networking/networkmanager.nix b/modules/services/networking/networkmanager.nix
index 591f34ceee7..74d9992f770 100644
--- a/modules/services/networking/networkmanager.nix
+++ b/modules/services/networking/networkmanager.nix
@@ -1,13 +1,14 @@
{ config, pkgs, ... }:
with pkgs.lib;
+with pkgs;
let
cfg = config.networking.networkmanager;
stateDirs = "/var/lib/NetworkManager /var/lib/dhclient";
- configFile = pkgs.writeText "NetworkManager.conf" ''
+ configFile = writeText "NetworkManager.conf" ''
[main]
plugins=keyfile
@@ -36,10 +37,10 @@ let
ResultActive=yes
'';
- ipUpScript = pkgs.writeScript "01nixos-ip-up" ''
+ ipUpScript = writeScript "01nixos-ip-up" ''
#!/bin/sh
if test "$2" = "up"; then
- ${pkgs.upstart}/sbin/initctl emit ip-up "IFACE=$1"
+ ${config.systemd.package}/bin/systemctl start ip-up.target
fi
'';
@@ -67,7 +68,7 @@ in {
Extra packages that provide NetworkManager plugins.
'';
merge = mergeListOption;
- apply = list: [ pkgs.networkmanager pkgs.modemmanager ] ++ list;
+ apply = list: [ networkmanager modemmanager wpa_supplicant ] ++ list;
};
};
@@ -76,10 +77,14 @@ in {
config = mkIf cfg.enable {
- environment.etc = singleton {
- source = ipUpScript;
- target = "NetworkManager/dispatcher.d/01nixos-ip-up";
- };
+ environment.etc = [
+ { source = ipUpScript;
+ target = "NetworkManager/dispatcher.d/01nixos-ip-up";
+ }
+ { source = configFile;
+ target = "NetworkManager/NetworkManager.conf";
+ }
+ ];
environment.systemPackages = cfg.packages;
@@ -88,24 +93,31 @@ in {
gid = config.ids.gids.networkmanager;
};
- jobs.networkmanager = {
- startOn = "started network-interfaces";
- stopOn = "stopping network-interfaces";
+ systemd.packages = cfg.packages;
- path = [ pkgs.networkmanager ];
-
- preStart = ''
- mkdir -m 755 -p /etc/NetworkManager
+ # Create an initialisation service that both starts
+ # NetworkManager when network.target is reached,
+ # and sets up necessary directories for NM.
+ systemd.services."networkmanager-init" = {
+ description = "NetworkManager initialisation";
+ wantedBy = [ "network.target" ];
+ partOf = [ "NetworkManager.service" ];
+ wants = [ "NetworkManager.service" ];
+ before = [ "NetworkManager.service" ];
+ script = ''
mkdir -m 700 -p /etc/NetworkManager/system-connections
mkdir -m 755 -p ${stateDirs}
'';
-
- exec = "NetworkManager --config=${configFile} --no-daemon";
+ serviceConfig = {
+ Type = "oneshot";
+ };
};
- networking.useDHCP = false;
-
- networking.wireless.enable = true;
+ # Turn off NixOS' network management
+ networking = {
+ useDHCP = false;
+ wireless.enable = false;
+ };
security.polkit.permissions = polkitConf;
diff --git a/modules/services/networking/ntpd.nix b/modules/services/networking/ntpd.nix
index 7d1db8df066..be3fcbd6543 100644
--- a/modules/services/networking/ntpd.nix
+++ b/modules/services/networking/ntpd.nix
@@ -66,9 +66,10 @@ in
};
jobs.ntpd =
- { description = "NTP daemon";
+ { description = "NTP Daemon";
- startOn = "ip-up";
+ wantedBy = [ "ip-up.target" ];
+ partOf = [ "ip-up.target" ];
path = [ ntp ];
diff --git a/modules/services/networking/openvpn.nix b/modules/services/networking/openvpn.nix
index c057bda5033..4ea6fa135b0 100644
--- a/modules/services/networking/openvpn.nix
+++ b/modules/services/networking/openvpn.nix
@@ -11,8 +11,8 @@ let
makeOpenVPNJob = cfg: name:
let
- path = (getAttr "openvpn-${name}" config.jobs).path;
-
+ path = (getAttr "openvpn-${name}" config.systemd.services).path;
+
upScript = ''
#! /bin/sh
exec > /var/log/openvpn-${name}-up 2>&1
@@ -28,17 +28,17 @@ let
fi
fi
done
-
+
${cfg.up}
'';
-
+
downScript = ''
#! /bin/sh
exec > /var/log/openvpn-${name}-down 2>&1
export PATH=${path}
${cfg.down}
'';
-
+
configFile = pkgs.writeText "openvpn-config-${name}"
''
${optionalString (cfg.up != "" || cfg.down != "") "script-security 2"}
@@ -46,7 +46,7 @@ let
${optionalString (cfg.up != "") "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
${optionalString (cfg.down != "") "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
'';
-
+
in {
description = "OpenVPN instance ‘${name}’";
@@ -76,7 +76,7 @@ in
default = {};
example = {
-
+
server = {
config = ''
# Simplest server configuration: http://openvpn.net/index.php/documentation/miscellaneous/static-key-mini-howto.html.
@@ -88,7 +88,7 @@ in
up = "ip route add ...";
down = "ip route del ...";
};
-
+
client = {
config = ''
client
@@ -103,7 +103,7 @@ in
up = "echo nameserver $nameserver | ${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev";
down = "${pkgs.openresolv}/sbin/resolvconf -d $dev";
};
-
+
};
description = ''
@@ -116,7 +116,7 @@ in
'';
type = types.attrsOf types.optionSet;
-
+
options = {
config = mkOption {
@@ -158,9 +158,9 @@ in
jobs = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers);
environment.systemPackages = [ openvpn ];
-
+
boot.kernelModules = [ "tun" ];
-
+
};
}
diff --git a/modules/services/networking/rpcbind.nix b/modules/services/networking/rpcbind.nix
index 5437d221c1e..7180b2cfa14 100644
--- a/modules/services/networking/rpcbind.nix
+++ b/modules/services/networking/rpcbind.nix
@@ -29,6 +29,8 @@ let
'';
};
+ check = mkAssert (!(config.services.rpcbind.enable && config.services.portmap.enable))
+ "Portmap and rpcbind cannot both be enabled.";
in
@@ -57,24 +59,26 @@ in
###### implementation
- config = mkIf config.services.rpcbind.enable {
+ config = mkIf config.services.rpcbind.enable (check {
- environment.etc = [netconfigFile];
+ environment.systemPackages = [ pkgs.rpcbind ];
- jobs.rpcbind =
- { description = "ONC RPC rpcbind";
+ environment.etc = [ netconfigFile ];
- startOn = "started network-interfaces";
- stopOn = "";
+ systemd.services.rpcbind =
+ { description = "ONC RPC Directory Service";
- daemonType = "fork";
+ wantedBy = [ "multi-user.target" ];
- exec =
- ''
- ${pkgs.rpcbind}/bin/rpcbind
- '';
+ requires = [ "basic.target" ];
+ after = [ "basic.target" ];
+
+ unitConfig.DefaultDependencies = false; # don't stop during shutdown
+
+ serviceConfig.Type = "forking";
+ serviceConfig.ExecStart = "@${pkgs.rpcbind}/bin/rpcbind rpcbind";
};
- };
+ });
}
diff --git a/modules/services/networking/ssh/sshd.nix b/modules/services/networking/ssh/sshd.nix
index 14570b76735..e9df8dd3cf6 100644
--- a/modules/services/networking/ssh/sshd.nix
+++ b/modules/services/networking/ssh/sshd.nix
@@ -39,6 +39,7 @@ let
);
userOptions = {
+
openssh.authorizedKeys = {
keys = mkOption {
type = types.listOf types.string;
@@ -63,6 +64,7 @@ let
'';
};
};
+
};
authKeysFiles = let
@@ -114,14 +116,13 @@ in
};
permitRootLogin = mkOption {
- default = "yes";
+ default = "without-password";
check = permitRootLoginCheck;
description = ''
Whether the root user can login using ssh. Valid values are
yes, without-password,
forced-commands-only or
no.
- If without-password doesn't work try yes.
'';
};
@@ -261,20 +262,18 @@ in
}
];
- jobs.sshd = {
+ systemd.services.sshd =
+ { description = "SSH Daemon";
- description = "OpenSSH server";
+ wantedBy = [ "multi-user.target" ];
- startOn = "started network-interfaces";
-
- environment = {
- LD_LIBRARY_PATH = nssModulesPath;
- # Duplicated from bashrc. OpenSSH needs a patch for this.
- LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
- };
+ stopIfChanged = false;
path = [ pkgs.openssh ];
+ environment.LD_LIBRARY_PATH = nssModulesPath;
+ environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
+
preStart =
''
mkdir -m 0755 -p /etc/ssh
@@ -284,22 +283,28 @@ in
fi
'';
- daemonType = "fork";
-
- exec =
- ''
- ${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} \
- -f ${pkgs.writeText "sshd_config" cfg.extraConfig}
- '';
+ serviceConfig =
+ { ExecStart =
+ "${pkgs.openssh}/sbin/sshd -h ${cfg.hostKeyPath} " +
+ "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
+ Restart = "always";
+ Type = "forking";
+ KillMode = "process";
+ PIDFile = "/run/sshd.pid";
+ };
};
networking.firewall.allowedTCPPorts = cfg.ports;
+ security.pam.services = optional cfg.usePAM { name = "sshd"; startSession = true; showMotd = true; };
+
services.openssh.authorizedKeysFiles =
[ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
services.openssh.extraConfig =
''
+ PidFile /run/sshd.pid
+
Protocol 2
UsePAM ${if cfg.usePAM then "yes" else "no"}
@@ -328,11 +333,14 @@ in
PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"}
ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"}
+ PrintMotd no # handled by pam_motd
+
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
'';
assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";}];
+
};
}
diff --git a/modules/services/networking/wpa_supplicant.nix b/modules/services/networking/wpa_supplicant.nix
index 5dc203fd177..20752cdee25 100644
--- a/modules/services/networking/wpa_supplicant.nix
+++ b/modules/services/networking/wpa_supplicant.nix
@@ -45,15 +45,15 @@ in
description = ''
The interfaces wpa_supplicant will use. If empty, it will
automatically use all wireless interfaces. (Note that auto-detection is currently
- broken on Linux 3.4.x kernels. See http://github.com/NixOS/nixos/issues/10 for
- further details.)
+ broken on Linux 3.4.x kernels. See http://github.com/NixOS/nixos/issues/10 for
+ further details.)
'';
};
driver = mkOption {
default = "";
example = "nl80211";
- description = "force a specific wpa_supplicant driver";
+ description = "Force a specific wpa_supplicant driver.";
};
userControlled = {
@@ -66,7 +66,7 @@ in
When you want to use this, make sure ${configFile} doesn't exist.
It will be created for you.
- Currently it is also necesarry to explicitly specify networking.wireless.interfaces
+ Currently it is also necessary to explicitly specify networking.wireless.interfaces.
'';
};
@@ -74,7 +74,7 @@ in
default = "wheel";
example = "network";
type = types.string;
- description = "members of this group can control wpa_supplicant";
+ description = "Members of this group can control wpa_supplicant.";
};
};
};
@@ -90,8 +90,10 @@ in
services.dbus.packages = [ pkgs.wpa_supplicant ];
jobs.wpa_supplicant =
- { startOn = "started network-interfaces";
- stopOn = "stopping network-interfaces";
+ { description = "WPA Supplicant";
+
+ wantedBy = [ "network.target" ];
+ after = [ "systemd-udev-settle.service" ];
path = [ pkgs.wpa_supplicant ];
@@ -122,7 +124,7 @@ in
powerManagement.resumeCommands =
''
- ${config.system.build.upstart}/sbin/restart wpa_supplicant
+ ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant
'';
assertions = [{ assertion = !cfg.userControlled.enable || cfg.interfaces != [];
diff --git a/modules/services/printing/cupsd.nix b/modules/services/printing/cupsd.nix
index 6d31c0050aa..5a6b85810aa 100644
--- a/modules/services/printing/cupsd.nix
+++ b/modules/services/printing/cupsd.nix
@@ -118,7 +118,7 @@ in
boot.blacklistedKernelModules = [ "usblp" ];
jobs.cupsd =
- { description = "CUPS printing daemon";
+ { description = "CUPS Printing Daemon";
startOn = "started network-interfaces";
stopOn = "stopping network-interfaces";
diff --git a/modules/services/scheduling/atd.nix b/modules/services/scheduling/atd.nix
index 6e6eaec1db9..66266e5b570 100644
--- a/modules/services/scheduling/atd.nix
+++ b/modules/services/scheduling/atd.nix
@@ -64,7 +64,7 @@ in
};
jobs.atd =
- { description = "at daemon (atd)";
+ { description = "Job Execution Daemon (atd)";
startOn = "stopped udevtrigger";
diff --git a/modules/services/scheduling/cron.nix b/modules/services/scheduling/cron.nix
index 350d65b476a..cf348793a65 100644
--- a/modules/services/scheduling/cron.nix
+++ b/modules/services/scheduling/cron.nix
@@ -86,7 +86,7 @@ in
environment.systemPackages = [ cronNixosPkg ];
jobs.cron =
- { description = "Cron daemon";
+ { description = "Cron Daemon";
startOn = "startup";
diff --git a/modules/services/system/cgroups.nix b/modules/services/system/cgroups.nix
deleted file mode 100644
index 5d5777909e9..00000000000
--- a/modules/services/system/cgroups.nix
+++ /dev/null
@@ -1,146 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-let
-
- cfg = config.services.cgroups;
-
- cgconfigConf = pkgs.writeText "cgconfig.conf" cfg.groups;
-
- cgrulesConf = pkgs.writeText "cgrules.conf" cfg.rules;
-
-in
-
-{
-
- ###### interface
-
- options = {
-
- services.cgroups.enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to enable support for control groups, a Linux kernel
- feature for resource management. It allows you to assign
- processes to groups that share certain resource limits (e.g.,
- CPU or memory). The cgrulesengd daemon
- automatically assigns processes to the right cgroup depending
- on the rules defined in
- .
- '';
- };
-
- services.cgroups.groups = mkOption {
- type = types.string;
- default =
- ''
- mount {
- cpu = /sys/fs/cgroup/cpu;
- }
- '';
- example =
- ''
- mount {
- cpu = /sys/fs/cgroup/cpu;
- cpuacct = /sys/fs/cgroup/cpuacct;
- }
-
- # Create a "www" cgroup with a lower share of the CPU (the
- # default is 1024).
- group www {
- cpu {
- cpu.shares = "500";
- }
- }
- '';
- description = ''
- The contents of the cgconfig.conf
- configuration file, which defines the cgroups.
- '';
- };
-
- services.cgroups.rules = mkOption {
- type = types.string;
- default = "";
- example =
- ''
- # All processes executed by the "wwwrun" uid should be
- # assigned to the "www" CPU cgroup.
- wwwrun cpu www
- '';
- description = ''
- The contents of the cgrules.conf
- configuration file, which determines to which cgroups
- processes should be assigned by the
- cgrulesengd daemon.
- '';
- };
-
- };
-
-
- ###### implementation
-
- config = mkIf cfg.enable {
-
- environment.systemPackages = [ pkgs.libcgroup ];
-
- environment.etc =
- [ { source = cgconfigConf;
- target = "cgconfig.conf";
- }
- { source = cgrulesConf;
- target = "cgrules.conf";
- }
- ];
-
- # The daemon requires the userspace<->kernelspace netlink
- # connector.
- boot.kernelModules = [ "cn" ];
-
- jobs.cgroups =
- { startOn = "startup";
-
- description = "Control groups daemon";
-
- path = [ pkgs.libcgroup pkgs.procps pkgs.utillinux ];
-
- preStart =
- ''
- if [ -d /sys/fs/cgroup ]; then
- if ! mountpoint -q /sys/fs/cgroup; then
- mount -t tmpfs -o mode=755 /dev/cgroup /sys/fs/cgroup
- fi
- fi
-
- cgclear || true
-
- # Mount the cgroup hierarchies. Note: we refer to the
- # store path of cgconfig.conf here to ensure that the job
- # gets reloaded if the configuration changes.
- cgconfigparser -l ${cgconfigConf}
-
- # Move existing processes to the right cgroup.
- cgclassify --cancel-sticky $(ps --no-headers -eL o tid) || true
-
- # Force a restart if the rules change:
- # ${cgrulesConf}
- '';
-
- # Run the daemon that moves new processes to the right cgroup.
- exec = "cgrulesengd";
-
- daemonType = "fork";
-
- postStop =
- ''
- cgclear
- '';
- };
-
-
- };
-
-}
diff --git a/modules/services/system/dbus.nix b/modules/services/system/dbus.nix
index f7fbb23d0a7..4a9d9a77b57 100644
--- a/modules/services/system/dbus.nix
+++ b/modules/services/system/dbus.nix
@@ -116,6 +116,33 @@ in
gid = config.ids.gids.messagebus;
};
+ # FIXME: these are copied verbatim from the dbus source tree. We
+ # should install and use the originals.
+ systemd.units."dbus.socket".text =
+ ''
+ [Unit]
+ Description=D-Bus System Message Bus Socket
+
+ [Socket]
+ ListenStream=/var/run/dbus/system_bus_socket
+ '';
+
+ systemd.units."dbus.service".text =
+ ''
+ [Unit]
+ Description=D-Bus System Message Bus
+ Requires=dbus.socket
+ After=syslog.target
+
+ [Service]
+ ExecStartPre=${pkgs.dbus_tools}/bin/dbus-uuidgen --ensure
+ ExecStartPre=-${pkgs.coreutils}/bin/rm -f /var/run/dbus/pid
+ ExecStart=${pkgs.dbus_daemon}/bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation
+ ExecReload=${pkgs.dbus_tools}/bin/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
+ OOMScoreAdjust=-900
+ '';
+
+ /*
jobs.dbus =
{ startOn = "started udev and started syslogd";
@@ -138,15 +165,6 @@ in
exec = "dbus-daemon --system";
- /*
- postStart =
- ''
- # Signal Upstart to connect to the system bus. This
- # allows ‘initctl’ to work for non-root users.
- kill -USR1 1
- '';
- */
-
postStop =
''
# !!! Hack: doesn't belong here.
@@ -157,6 +175,7 @@ in
fi
'';
};
+ */
security.setuidOwners = singleton
{ program = "dbus-daemon-launch-helper";
diff --git a/modules/services/system/nscd.nix b/modules/services/system/nscd.nix
index 457be266424..22f507f39d7 100644
--- a/modules/services/system/nscd.nix
+++ b/modules/services/system/nscd.nix
@@ -20,15 +20,14 @@ in
enable = mkOption {
default = true;
- description = "
- Whether to enable the Name Service Cache Daemon.
- ";
+ description = "Whether to enable the Name Service Cache Daemon.";
};
};
};
+
###### implementation
config = mkIf config.services.nscd.enable {
@@ -39,37 +38,31 @@ in
description = "Name service cache daemon user";
};
- jobs.nscd =
+ systemd.services.nscd =
{ description = "Name Service Cache Daemon";
- startOn = "startup";
+ wantedBy = [ "nss-lookup.target" "nss-user-lookup.target" ];
environment = { LD_LIBRARY_PATH = nssModulesPath; };
preStart =
''
- mkdir -m 0755 -p /var/run/nscd
+ mkdir -m 0755 -p /run/nscd
+ rm -f /run/nscd/nscd.pid
mkdir -m 0755 -p /var/db/nscd
'';
- path = [ pkgs.glibc ];
-
- exec = "nscd -f ${./nscd.conf} -d 2> /dev/null";
- };
-
- # Flush nscd's ‘hosts’ database when the network comes up or the
- # system configuration changes to get rid of any negative entries.
- jobs.invalidate_nscd =
- { name = "invalidate-nscd";
- description = "Invalidate NSCD cache";
- startOn = "ip-up or config-changed";
- task = true;
- path = [ pkgs.glibc ];
- script = ''
- nscd --invalidate=passwd
- nscd --invalidate=group
- nscd --invalidate=hosts
- '';
+ serviceConfig =
+ { ExecStart = "@${pkgs.glibc}/sbin/nscd nscd -f ${./nscd.conf}";
+ Type = "forking";
+ PIDFile = "/run/nscd/nscd.pid";
+ Restart = "always";
+ ExecReload =
+ [ "${pkgs.glibc}/sbin/nscd --invalidate passwd"
+ "${pkgs.glibc}/sbin/nscd --invalidate group"
+ "${pkgs.glibc}/sbin/nscd --invalidate hosts"
+ ];
+ };
};
};
diff --git a/modules/services/ttys/agetty.nix b/modules/services/ttys/agetty.nix
new file mode 100644
index 00000000000..f269de6fc2a
--- /dev/null
+++ b/modules/services/ttys/agetty.nix
@@ -0,0 +1,127 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+
+ ###### interface
+
+ options = {
+
+ services.mingetty = {
+
+ greetingLine = mkOption {
+ default = ''<<< Welcome to NixOS ${config.system.nixosVersion} (\m) - \l >>>'';
+ description = ''
+ Welcome line printed by mingetty.
+ '';
+ };
+
+ helpLine = mkOption {
+ default = "";
+ description = ''
+ Help line printed by mingetty below the welcome line.
+ Used by the installation CD to give some hints on
+ how to proceed.
+ '';
+ };
+
+ };
+
+ };
+
+
+ ###### implementation
+
+ config = {
+
+ # FIXME: these are mostly copy/pasted from the systemd sources,
+ # which some small modifications, which is annoying.
+
+ # Generate a separate job for each tty.
+ systemd.units."getty@.service".text =
+ ''
+ [Unit]
+ Description=Getty on %I
+ Documentation=man:agetty(8)
+ After=systemd-user-sessions.service plymouth-quit-wait.service
+
+ # If additional gettys are spawned during boot then we should make
+ # sure that this is synchronized before getty.target, even though
+ # getty.target didn't actually pull it in.
+ Before=getty.target
+ IgnoreOnIsolate=yes
+
+ ConditionPathExists=/dev/tty0
+
+ [Service]
+ Environment=TERM=linux
+ Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
+ ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login %I 38400
+ Type=idle
+ Restart=always
+ RestartSec=0
+ UtmpIdentifier=%I
+ TTYPath=/dev/%I
+ TTYReset=yes
+ TTYVHangup=yes
+ TTYVTDisallocate=yes # set to no to prevent clearing the screen
+ KillMode=process
+ IgnoreSIGPIPE=no
+
+ # Some login implementations ignore SIGTERM, so we send SIGHUP
+ # instead, to ensure that login terminates cleanly.
+ KillSignal=SIGHUP
+
+ X-RestartIfChanged=false
+ '';
+
+ systemd.units."serial-getty@.service".text =
+ ''
+ [Unit]
+ Description=Serial Getty on %I
+ Documentation=man:agetty(8) man:systemd-getty-generator(8)
+ BindsTo=dev-%i.device
+ After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
+
+ # If additional gettys are spawned during boot then we should make
+ # sure that this is synchronized before getty.target, even though
+ # getty.target didn't actually pull it in.
+ Before=getty.target
+ IgnoreOnIsolate=yes
+
+ [Service]
+ Environment=TERM=linux
+ Environment=LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
+ ExecStart=@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login %I 115200,38400,9600
+ Type=idle
+ Restart=always
+ RestartSec=0
+ UtmpIdentifier=%I
+ TTYPath=/dev/%I
+ TTYReset=yes
+ TTYVHangup=yes
+ KillMode=process
+ IgnoreSIGPIPE=no
+
+ # Some login implementations ignore SIGTERM, so we send SIGHUP
+ # instead, to ensure that login terminates cleanly.
+ KillSignal=SIGHUP
+
+ X-RestartIfChanged=false
+ '';
+
+ environment.etc = singleton
+ { # Friendly greeting on the virtual consoles.
+ source = pkgs.writeText "issue" ''
+
+ [1;32m${config.services.mingetty.greetingLine}[0m
+ ${config.services.mingetty.helpLine}
+
+ '';
+ target = "issue";
+ };
+
+ };
+
+}
diff --git a/modules/services/ttys/mingetty.nix b/modules/services/ttys/mingetty.nix
deleted file mode 100644
index ecc4fd4630e..00000000000
--- a/modules/services/ttys/mingetty.nix
+++ /dev/null
@@ -1,90 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-{
-
- ###### interface
-
- options = {
-
- services.mingetty = {
-
- ttys = mkOption {
- default =
- if pkgs.stdenv.isArm
- then [ "ttyS0" ] # presumably an embedded platform such as a plug
- else [ "tty1" "tty2" "tty3" "tty4" "tty5" "tty6" ];
- description = ''
- The list of tty devices on which to start a login prompt.
- '';
- };
-
- waitOnMounts = mkOption {
- default = false;
- description = ''
- Whether the login prompts on the virtual consoles will be
- started before or after all file systems have been mounted. By
- default we don't wait, but if for example your /home is on a
- separate partition, you may want to turn this on.
- '';
- };
-
- greetingLine = mkOption {
- default = ''<<< Welcome to NixOS ${config.system.nixosVersion} (\m) - \l >>>'';
- description = ''
- Welcome line printed by mingetty.
- '';
- };
-
- helpLine = mkOption {
- default = "";
- description = ''
- Help line printed by mingetty below the welcome line.
- Used by the installation CD to give some hints on
- how to proceed.
- '';
- };
-
- };
-
- };
-
-
- ###### implementation
-
- config = {
-
- # Generate a separate job for each tty.
- jobs = listToAttrs (map (tty: nameValuePair tty {
-
- startOn =
- # On tty1 we should always wait for mountall, since it may
- # start an emergency-shell job.
- if config.services.mingetty.waitOnMounts || tty == "tty1"
- then "stopped udevtrigger and filesystem"
- else "stopped udevtrigger"; # !!! should start as soon as the tty device is created
-
- path = [ pkgs.mingetty ];
-
- exec = "mingetty --loginprog=${pkgs.shadow}/bin/login --noclear ${tty}";
-
- restartIfChanged = false;
-
- environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
-
- }) config.services.mingetty.ttys);
-
- environment.etc = singleton
- { # Friendly greeting on the virtual consoles.
- source = pkgs.writeText "issue" ''
-
- [1;32m${config.services.mingetty.greetingLine}[0m
- ${config.services.mingetty.helpLine}
-
- '';
- target = "issue";
- };
- };
-
-}
diff --git a/modules/services/web-servers/apache-httpd/default.nix b/modules/services/web-servers/apache-httpd/default.nix
index 1729850421a..35afacefa16 100644
--- a/modules/services/web-servers/apache-httpd/default.nix
+++ b/modules/services/web-servers/apache-httpd/default.nix
@@ -601,26 +601,12 @@ in
date.timezone = "${config.time.timeZone}"
'';
- jobs.httpd =
- { # Statically verify the syntactic correctness of the generated
- # httpd.conf. !!! this is impure! It doesn't just check for
- # syntax, but also whether the Apache user/group exist,
- # whether SSL keys exist, etc.
- buildHook =
- ''
- echo
- echo '=== Checking the generated Apache configuration file ==='
- ${httpd}/bin/httpd -f ${httpdConf} -t || true
- '';
+ systemd.services.httpd =
+ { description = "Apache HTTPD";
- description = "Apache HTTPD";
-
- startOn = "started networking and filesystem"
- # Hacky. Some subservices depend on Postgres
- # (e.g. Mediawiki), but they don't have a way to declare
- # that dependency. So just start httpd after postgresql if
- # the latter is enabled.
- + optionalString config.services.postgresql.enable " and started postgresql";
+ wantedBy = [ "multi-user.target" ];
+ requires = [ "keys.target" ];
+ after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ];
path =
[ httpd pkgs.coreutils pkgs.gnugrep ]
@@ -632,9 +618,7 @@ in
environment =
{ PHPRC = if enablePHP then phpIni else "";
-
TZ = config.time.timeZone;
-
} // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices));
preStart =
@@ -668,12 +652,9 @@ in
done
'';
- exec = "httpd -f ${httpdConf} -DNO_DETACH";
-
- preStop =
- ''
- ${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop
- '';
+ serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf} -DNO_DETACH";
+ serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
+ serviceConfig.Restart = "always";
};
};
diff --git a/modules/services/x11/desktop-managers/kde4.nix b/modules/services/x11/desktop-managers/kde4.nix
index 2f7f62ce416..f4bf0d3f2c6 100644
--- a/modules/services/x11/desktop-managers/kde4.nix
+++ b/modules/services/x11/desktop-managers/kde4.nix
@@ -158,7 +158,7 @@ in
services.udisks.enable = true;
services.upower = mkIf config.powerManagement.enable { enable = true; };
- security.pam.services = [ { name = "kde"; allowNullPassword = true; } ];
+ security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
};
diff --git a/modules/services/x11/display-managers/auto.nix b/modules/services/x11/display-managers/auto.nix
index cccc6e62a15..33d97e0e07a 100644
--- a/modules/services/x11/display-managers/auto.nix
+++ b/modules/services/x11/display-managers/auto.nix
@@ -41,16 +41,11 @@ in
config = mkIf cfg.enable {
- services.xserver.displayManager.slim.enable = false;
-
- services.xserver.displayManager.job =
- { execCmd =
- ''
- exec ${pkgs.xorg.xinit}/bin/xinit \
- ${pkgs.su}/bin/su -c ${dmcfg.session.script} ${cfg.user} \
- -- ${dmcfg.xserverBin} ${dmcfg.xserverArgs}
- '';
- };
+ services.xserver.displayManager.slim = {
+ enable = true;
+ autoLogin = true;
+ defaultUser = cfg.user;
+ };
};
diff --git a/modules/services/x11/display-managers/default.nix b/modules/services/x11/display-managers/default.nix
index cdfd271ee65..1f842c0c953 100644
--- a/modules/services/x11/display-managers/default.nix
+++ b/modules/services/x11/display-managers/default.nix
@@ -21,6 +21,7 @@ let
''
#! /bin/sh
+ . /etc/profile
cd "$HOME"
# The first argument of this script is the session type.
@@ -31,6 +32,13 @@ let
exec > ~/.xsession-errors 2>&1
''}
+ # Stop systemd from handling the power button and lid switch,
+ # since presumably the desktop environment will handle these.
+ if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then
+ export _INHIBITION_LOCK_TAKEN=1
+ exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key "$0" "$sessionType"
+ fi
+
${optionalString cfg.startOpenSSHAgent ''
if test -z "$SSH_AUTH_SOCK"; then
# Restart this script as a child of the SSH agent. (It is
@@ -53,12 +61,6 @@ let
fi
''}
- # Start a ConsoleKit session so that we get ownership of various
- # devices.
- if test -z "$XDG_SESSION_COOKIE"; then
- exec ${pkgs.consolekit}/bin/ck-launch-session "$0" "$sessionType"
- fi
-
# Handle being called by kdm.
if test "''${1:0:1}" = /; then eval exec "$1"; fi
diff --git a/modules/services/x11/display-managers/kdm.nix b/modules/services/x11/display-managers/kdm.nix
index 838a4ed9033..6a628ec124f 100644
--- a/modules/services/x11/display-managers/kdm.nix
+++ b/modules/services/x11/display-managers/kdm.nix
@@ -12,8 +12,8 @@ let
defaultConfig =
''
[Shutdown]
- HaltCmd=${config.system.build.upstart}/sbin/halt
- RebootCmd=${config.system.build.upstart}/sbin/reboot
+ HaltCmd=${config.systemd.package}/sbin/shutdown -h now
+ RebootCmd=${config.systemd.package}/sbin/shutdown -r now
${optionalString (config.system.boot.loader.id == "grub") ''
BootManager=${if config.boot.loader.grub.version == 2 then "Grub2" else "Grub"}
''}
@@ -111,7 +111,7 @@ in
logsXsession = true;
};
- security.pam.services = [ { name = "kde"; allowNullPassword = true; } ];
+ security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
users.extraUsers = singleton
{ name = "kdm";
diff --git a/modules/services/x11/display-managers/slim.nix b/modules/services/x11/display-managers/slim.nix
index 97c5f1d1b2b..9e8b9391f45 100644
--- a/modules/services/x11/display-managers/slim.nix
+++ b/modules/services/x11/display-managers/slim.nix
@@ -14,10 +14,9 @@ let
xserver_arguments ${dmcfg.xserverArgs}
sessions ${pkgs.lib.concatStringsSep "," (dmcfg.session.names ++ ["custom"])}
login_cmd exec ${pkgs.stdenv.shell} ${dmcfg.session.script} "%session"
- halt_cmd ${config.system.build.upstart}/sbin/shutdown -h now
- reboot_cmd ${config.system.build.upstart}/sbin/shutdown -r now
+ halt_cmd ${config.systemd.package}/sbin/shutdown -h now
+ reboot_cmd ${config.systemd.package}/sbin/shutdown -r now
${optionalString (cfg.defaultUser != "") ("default_user " + cfg.defaultUser)}
- ${optionalString cfg.hideCursor "hidecursor true"}
${optionalString cfg.autoLogin "auto_login yes"}
'';
@@ -76,14 +75,6 @@ in
'';
};
- hideCursor = mkOption {
- default = false;
- example = true;
- description = ''
- Hide the mouse cursor on the login screen.
- '';
- };
-
autoLogin = mkOption {
default = false;
example = true;
@@ -115,7 +106,7 @@ in
# Allow null passwords so that the user can login as root on the
# installation CD.
- security.pam.services = [ { name = "slim"; allowNullPassword = true; } ];
+ security.pam.services = [ { name = "slim"; allowNullPassword = true; startSession = true; } ];
};
diff --git a/modules/services/x11/xserver.nix b/modules/services/x11/xserver.nix
index c1b14940f02..f71e6ea97c4 100644
--- a/modules/services/x11/xserver.nix
+++ b/modules/services/x11/xserver.nix
@@ -434,15 +434,14 @@ in
environment.pathsToLink =
[ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
- jobs."xserver-start-check" =
- { startOn = if cfg.autorun then "filesystem and stopped udevtrigger" else "";
- stopOn = "";
- task = true;
- script = "grep -qv noX11 /proc/cmdline && start xserver || true";
- };
+ systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
- jobs.xserver =
- { restartIfChanged = false;
+ systemd.services."display-manager" =
+ { description = "X11 Server";
+
+ after = [ "systemd-udev-settle.service" "local-fs.target" ];
+
+ restartIfChanged = false;
environment =
{ FONTCONFIG_FILE = "/etc/fonts/fonts.conf"; # !!! cleanup
diff --git a/modules/system/activation/activation-script.nix b/modules/system/activation/activation-script.nix
index 41c3ced1bc2..dc017563217 100644
--- a/modules/system/activation/activation-script.nix
+++ b/modules/system/activation/activation-script.nix
@@ -116,9 +116,8 @@ in
# jobs. Used to determine which jobs need to be restarted
# when switching to a new configuration.
mkdir -m 0700 -p /var/run/upstart-jobs
-
+
mkdir -m 0755 -p /var/log
- mkdir -m 0755 -p /var/log/upstart
touch /var/log/wtmp # must exist
chmod 644 /var/log/wtmp
@@ -146,9 +145,9 @@ in
system.activationScripts.tmpfs =
''
- ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" /dev
- ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" /dev/shm
- ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" /run
+ ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devSize}" none /dev
+ ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.devShmSize}" none /dev/shm
+ ${pkgs.utillinux}/bin/mount -o "remount,size=${config.boot.runSize}" none /run
'';
};
diff --git a/modules/system/activation/switch-to-configuration.pl b/modules/system/activation/switch-to-configuration.pl
new file mode 100644
index 00000000000..032947c3c54
--- /dev/null
+++ b/modules/system/activation/switch-to-configuration.pl
@@ -0,0 +1,345 @@
+#! @perl@
+
+use strict;
+use warnings;
+use File::Basename;
+use File::Slurp;
+use Cwd 'abs_path';
+
+my $startListFile = "/run/systemd/start-list";
+my $restartListFile = "/run/systemd/restart-list";
+my $reloadListFile = "/run/systemd/reload-list";
+
+my $action = shift @ARGV;
+
+if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test")) {
+ print STDERR < 'quiet') // "";
+my $newVersion = read_file("@out@/init-interface-version");
+
+if ($newVersion ne $oldVersion) {
+ print STDERR <{$1} = { load => $2, state => $3, substate => $4 };
+ }
+ return $res;
+}
+
+sub parseFstab {
+ my ($filename) = @_;
+ my ($fss, $swaps);
+ foreach my $line (read_file($filename, err_mode => 'quiet')) {
+ chomp $line;
+ $line =~ s/#.*//;
+ next if $line =~ /^\s*$/;
+ my @xs = split / /, $line;
+ if ($xs[2] eq "swap") {
+ $swaps->{$xs[0]} = { options => $xs[3] // "" };
+ } else {
+ $fss->{$xs[1]} = { device => $xs[0], fsType => $xs[2], options => $xs[3] // "" };
+ }
+ }
+ return ($fss, $swaps);
+}
+
+sub parseUnit {
+ my ($filename) = @_;
+ my $info = {};
+ foreach my $line (read_file($filename)) {
+ # FIXME: not quite correct.
+ $line =~ /^([^=]+)=(.*)$/ or next;
+ $info->{$1} = $2;
+ }
+ return $info;
+}
+
+sub boolIsTrue {
+ my ($s) = @_;
+ return $s eq "yes" || $s eq "true";
+}
+
+# Stop all services that no longer exist or have changed in the new
+# configuration.
+my (@unitsToStop, @unitsToSkip);
+my $activePrev = getActiveUnits;
+while (my ($unit, $state) = each %{$activePrev}) {
+ my $baseUnit = $unit;
+
+ # Recognise template instances.
+ $baseUnit = "$1\@.$2" if $unit =~ /^(.*)@[^\.]*\.(.*)$/;
+ my $prevUnitFile = "/etc/systemd/system/$baseUnit";
+ my $newUnitFile = "@out@/etc/systemd/system/$baseUnit";
+
+ my $baseName = $baseUnit;
+ $baseName =~ s/\.[a-z]*$//;
+
+ if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) {
+ if (! -e $newUnitFile) {
+ push @unitsToStop, $unit;
+ }
+
+ elsif ($unit =~ /\.target$/) {
+ my $unitInfo = parseUnit($newUnitFile);
+
+ # Cause all active target units to be restarted below.
+ # This should start most changed units we stop here as
+ # well as any new dependencies (including new mounts and
+ # swap devices). FIXME: the suspend target is sometimes
+ # active after the system has resumed, which probably
+ # should not be the case. Just ignore it.
+ if ($unit ne "suspend.target" && $unit ne "hibernate.target") {
+ unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) {
+ write_file($startListFile, { append => 1 }, "$unit\n");
+ }
+ }
+
+ # Stop targets that have X-StopOnReconfiguration set.
+ # This is necessary to respect dependency orderings
+ # involving targets: if unit X starts after target Y and
+ # target Y starts after unit Z, then if X and Z have both
+ # changed, then X should be restarted after Z. However,
+ # if target Y is in the "active" state, X and Z will be
+ # restarted at the same time because X's dependency on Y
+ # is already satisfied. Thus, we need to stop Y first.
+ # Stopping a target generally has no effect on other units
+ # (unless there is a PartOf dependency), so this is just a
+ # bookkeeping thing to get systemd to do the right thing.
+ if (boolIsTrue($unitInfo->{'X-StopOnReconfiguration'} // "no")) {
+ push @unitsToStop, $unit;
+ }
+ }
+
+ elsif (abs_path($prevUnitFile) ne abs_path($newUnitFile)) {
+ if ($unit eq "sysinit.target" || $unit eq "basic.target" || $unit eq "multi-user.target" || $unit eq "graphical.target") {
+ # Do nothing. These cannot be restarted directly.
+ } elsif ($unit =~ /\.mount$/) {
+ # Reload the changed mount unit to force a remount.
+ write_file($reloadListFile, { append => 1 }, "$unit\n");
+ } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/) {
+ # FIXME: do something?
+ } else {
+ my $unitInfo = parseUnit($newUnitFile);
+ if (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes")) {
+ push @unitsToSkip, $unit;
+ } else {
+ # If this unit is socket-activated, then stop the
+ # socket unit(s) as well, and restart the
+ # socket(s) instead of the service.
+ my $socketActivated = 0;
+ if ($unit =~ /\.service$/) {
+ my @sockets = split / /, ($unitInfo->{Sockets} // "");
+ if (scalar @sockets == 0) {
+ @sockets = ("$baseName.socket");
+ }
+ foreach my $socket (@sockets) {
+ if (defined $activePrev->{$socket}) {
+ push @unitsToStop, $socket;
+ write_file($startListFile, { append => 1 }, "$socket\n");
+ $socketActivated = 1;
+ }
+ }
+ }
+
+ if (!boolIsTrue($unitInfo->{'X-StopIfChanged'} // "yes")) {
+
+ # This unit should be restarted instead of
+ # stopped and started.
+ write_file($restartListFile, { append => 1 }, "$unit\n");
+
+ } else {
+
+ # If the unit is not socket-activated, record
+ # that this unit needs to be started below.
+ # We write this to a file to ensure that the
+ # service gets restarted if we're interrupted.
+ if (!$socketActivated) {
+ write_file($startListFile, { append => 1 }, "$unit\n");
+ }
+
+ push @unitsToStop, $unit;
+
+ }
+ }
+ }
+ }
+ }
+}
+
+sub pathToUnitName {
+ my ($path) = @_;
+ die unless substr($path, 0, 1) eq "/";
+ return "-" if $path eq "/";
+ $path = substr($path, 1);
+ $path =~ s/\//-/g;
+ # FIXME: handle - and unprintable characters.
+ return $path;
+}
+
+sub unique {
+ my %seen;
+ my @res;
+ foreach my $name (@_) {
+ next if $seen{$name};
+ $seen{$name} = 1;
+ push @res, $name;
+ }
+ return @res;
+}
+
+# Compare the previous and new fstab to figure out which filesystems
+# need a remount or need to be unmounted. New filesystems are mounted
+# automatically by starting local-fs.target. FIXME: might be nicer if
+# we generated units for all mounts; then we could unify this with the
+# unit checking code above.
+my ($prevFss, $prevSwaps) = parseFstab "/etc/fstab";
+my ($newFss, $newSwaps) = parseFstab "@out@/etc/fstab";
+foreach my $mountPoint (keys %$prevFss) {
+ my $prev = $prevFss->{$mountPoint};
+ my $new = $newFss->{$mountPoint};
+ my $unit = pathToUnitName($mountPoint) . ".mount";
+ if (!defined $new) {
+ # Filesystem entry disappeared, so unmount it.
+ push @unitsToStop, $unit;
+ } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) {
+ # Filesystem type or device changed, so unmount and mount it.
+ write_file($startListFile, { append => 1 }, "$unit\n");
+ push @unitsToStop, $unit;
+ } elsif ($prev->{options} ne $new->{options}) {
+ # Mount options changes, so remount it.
+ write_file($reloadListFile, { append => 1 }, "$unit\n");
+ }
+}
+
+# Also handles swap devices.
+foreach my $device (keys %$prevSwaps) {
+ my $prev = $prevSwaps->{$device};
+ my $new = $newSwaps->{$device};
+ if (!defined $new) {
+ # Swap entry disappeared, so turn it off. Can't use
+ # "systemctl stop" here because systemd has lots of alias
+ # units that prevent a stop from actually calling
+ # "swapoff".
+ print STDERR "stopping swap device: $device\n";
+ system("@utillinux@/sbin/swapoff", $device);
+ }
+ # FIXME: update swap options (i.e. its priority).
+}
+
+if (scalar @unitsToStop > 0) {
+ @unitsToStop = unique(@unitsToStop);
+ print STDERR "stopping the following units: ", join(", ", sort(@unitsToStop)), "\n";
+ system("@systemd@/bin/systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors?
+}
+
+print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n"
+ if scalar @unitsToSkip > 0;
+
+# Activate the new configuration (i.e., update /etc, make accounts,
+# and so on).
+my $res = 0;
+print STDERR "activating the configuration...\n";
+system("@out@/activate", "@out@") == 0 or $res = 2;
+
+# Restart systemd if necessary.
+if (abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd")) {
+ print STDERR "restarting systemd...\n";
+ system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2;
+}
+
+# Forget about previously failed services.
+system("@systemd@/bin/systemctl", "reset-failed");
+
+# Make systemd reload its units.
+system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3;
+
+# Restart changed services (those that have to be restarted rather
+# than stopped and started).
+my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // ""));
+if (scalar @restart > 0) {
+ print STDERR "restarting the following units: ", join(", ", sort(@restart)), "\n";
+ system("@systemd@/bin/systemctl", "restart", "--", @restart) == 0 or $res = 4;
+ unlink($restartListFile);
+}
+
+# Start all active targets, as well as changed units we stopped above.
+# The latter is necessary because some may not be dependencies of the
+# targets (i.e., they were manually started). FIXME: detect units
+# that are symlinks to other units. We shouldn't start both at the
+# same time because we'll get a "Failed to add path to set" error from
+# systemd.
+my @start = unique("default.target", split('\n', read_file($startListFile, err_mode => 'quiet') // ""));
+print STDERR "starting the following units: ", join(", ", sort(@start)), "\n";
+system("@systemd@/bin/systemctl", "start", "--", @start) == 0 or $res = 4;
+unlink($startListFile);
+
+# Reload units that need it. This includes remounting changed mount
+# units.
+my @reload = unique(split '\n', read_file($reloadListFile, err_mode => 'quiet') // "");
+if (scalar @reload > 0) {
+ print STDERR "reloading the following units: ", join(", ", sort(@reload)), "\n";
+ system("@systemd@/bin/systemctl", "reload", "--", @reload) == 0 or $res = 4;
+ unlink($reloadListFile);
+}
+
+# Signal dbus to reload its configuration.
+system("@systemd@/bin/systemctl", "reload", "dbus.service");
+
+# Print failed and new units.
+my (@failed, @new, @restarting);
+my $activeNew = getActiveUnits;
+while (my ($unit, $state) = each %{$activeNew}) {
+ push @failed, $unit if $state->{state} eq "failed" || $state->{substate} eq "auto-restart";
+ push @new, $unit if $state->{state} ne "failed" && !defined $activePrev->{$unit};
+}
+
+print STDERR "the following new units were started: ", join(", ", sort(@new)), "\n"
+ if scalar @new > 0;
+
+if (scalar @failed > 0) {
+ print STDERR "warning: the following units failed: ", join(", ", sort(@failed)), "\n";
+ foreach my $unit (@failed) {
+ print STDERR "\n";
+ system("COLUMNS=1000 @systemd@/bin/systemctl status --no-pager '$unit' >&2");
+ }
+ $res = 4;
+}
+
+exit $res;
diff --git a/modules/system/activation/switch-to-configuration.sh b/modules/system/activation/switch-to-configuration.sh
deleted file mode 100644
index 285b095aa3e..00000000000
--- a/modules/system/activation/switch-to-configuration.sh
+++ /dev/null
@@ -1,135 +0,0 @@
-#! @shell@
-
-set -e
-export PATH=/empty
-for i in @path@; do PATH=$PATH:$i/bin:$i/sbin; done
-action="$1"
-
-if ! test -e /etc/NIXOS; then
- echo "This is not a NixOS installation (/etc/NIXOS) is missing!"
- exit 1
-fi
-
-if test -z "$action"; then
- cat < /dev/null || echo 0)
-newVersion=$(cat @out@/upstart-interface-version 2> /dev/null || echo 0)
-
-if test "$oldVersion" -ne "$newVersion"; then
- cat <&2 || true
-}
-
-# Restart all running jobs that have changed. (Here "running" means
-# all jobs that don't have a "stop" goal.) We use the symlinks in
-# /var/run/upstart-jobs (created by each job's pre-start script) to
-# determine if a job has changed.
-for job in @jobs@; do
- status=$(status "$job")
- if ! [[ "$status" =~ start/ ]]; then continue; fi
- if [ "$(readlink -f "$jobsDir/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ]; then continue; fi
- if [ -n "${noRestartIfChanged[$job]}" ]; then
- log "not restarting changed service ‘$job’"
- continue
- fi
- log "restarting changed service ‘$job’..."
- # Note: can't use "restart" here, since that only restarts the
- # job's main process.
- stop --quiet "$job" || true
- start_ "$job" || true
-done
-
-# Start all jobs that are not running but should be. The "should be"
-# criterion is tricky: the intended semantics is that we end up with
-# the same jobs as after a reboot. If it's a task, start it if it
-# differs from the previous instance of the same task; if it wasn't
-# previously run, don't run it. If it's a service, only start it if
-# it has a "start on" condition.
-for job in @jobs@; do
- status=$(status "$job")
- if ! [[ "$status" =~ stop/ ]]; then continue; fi
-
- if [ -n "${tasks[$job]}" ]; then
- if [ ! -e "/var/run/upstart-jobs/$job" -o \
- "$(readlink -f "$jobsDir/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ];
- then continue; fi
- if [ -n "${noRestartIfChanged[$job]}" ]; then continue; fi
- log "starting task ‘$job’..."
- start --quiet "$job" || true
- else
- if ! grep -q "^start on" "$jobsDir/$job.conf"; then continue; fi
- log "starting service ‘$job’..."
- start_ "$job" || true
- fi
-
-done
-
-# Signal dbus to reload its configuration.
-dbusPid=$(initctl status dbus 2> /dev/null | sed -e 's/.*process \([0-9]\+\)/\1/;t;d')
-[ -n "$dbusPid" ] && kill -HUP "$dbusPid"
diff --git a/modules/system/activation/top-level.nix b/modules/system/activation/top-level.nix
index 118a5c6266e..e99b50a0309 100644
--- a/modules/system/activation/top-level.nix
+++ b/modules/system/activation/top-level.nix
@@ -115,12 +115,12 @@ let
ln -s ${config.system.build.etc}/etc $out/etc
ln -s ${config.system.path} $out/sw
- ln -s ${config.system.build.upstart} $out/upstart
+ ln -s "$systemd" $out/systemd
ln -s ${config.hardware.firmware} $out/firmware
echo -n "$kernelParams" > $out/kernel-params
echo -n "$configurationName" > $out/configuration-name
- echo -n "${toString config.system.build.upstart.interfaceVersion}" > $out/upstart-interface-version
+ echo -n "systemd ${toString config.systemd.package.interfaceVersion}" > $out/init-interface-version
echo -n "$nixosVersion" > $out/nixos-version
mkdir $out/fine-tune
@@ -131,7 +131,7 @@ let
done
mkdir $out/bin
- substituteAll ${./switch-to-configuration.sh} $out/bin/switch-to-configuration
+ substituteAll ${./switch-to-configuration.pl} $out/bin/switch-to-configuration
chmod +x $out/bin/switch-to-configuration
${config.system.extraSystemBuilderCmds}
@@ -147,6 +147,10 @@ let
name = "nixos-${config.system.nixosVersion}";
preferLocalBuild = true;
buildCommand = systemBuilder;
+
+ inherit (pkgs) utillinux;
+ systemd = config.systemd.package;
+
inherit children;
kernelParams =
config.boot.kernelParams ++ config.boot.extraKernelParams;
@@ -165,17 +169,10 @@ let
# to the activation script.
noRestartIfChanged = attrValues (mapAttrs (n: v: if v.restartIfChanged then [] else ["[${v.name}]=1"]) config.jobs);
- # Most of these are needed by grub-install.
- path =
- [ pkgs.coreutils
- pkgs.gnused
- pkgs.gnugrep
- pkgs.findutils
- pkgs.diffutils
- config.system.build.upstart # for initctl
- ];
-
configurationName = config.boot.loader.grub.configurationName;
+
+ # Needed by switch-to-configuration.
+ perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl";
};
diff --git a/modules/system/boot/kernel.nix b/modules/system/boot/kernel.nix
index 62b68c560d1..7744fd94a2c 100644
--- a/modules/system/boot/kernel.nix
+++ b/modules/system/boot/kernel.nix
@@ -2,7 +2,16 @@
with pkgs.lib;
-let kernel = config.boot.kernelPackages.kernel; in
+let
+
+ kernel = config.boot.kernelPackages.kernel;
+
+ kernelModulesConf = pkgs.writeText "nixos.conf"
+ ''
+ ${concatStringsSep "\n" config.boot.kernelModules}
+ '';
+
+in
{
@@ -41,7 +50,7 @@ let kernel = config.boot.kernelPackages.kernel; in
boot.extraKernelParams = mkOption {
default = [ ];
- example = [ "debugtrace" ];
+ example = [ "boot.trace" ];
description = "Additional user-defined kernel parameters.";
};
@@ -55,7 +64,7 @@ let kernel = config.boot.kernelPackages.kernel; in
boot.extraModulePackages = mkOption {
default = [];
- # !!! example = [pkgs.aufs pkgs.nvidia_x11];
+ # !!! example = [pkgs.nvidia_x11];
description = "A list of additional packages supplying kernel modules.";
};
@@ -191,6 +200,40 @@ let kernel = config.boot.kernelPackages.kernel; in
# The Linux kernel >= 2.6.27 provides firmware.
hardware.firmware = [ "${kernel}/lib/firmware" ];
+ # Create /etc/modules-load.d/nixos.conf, which is read by
+ # systemd-modules-load.service to load required kernel modules.
+ # FIXME: ensure that systemd-modules-load.service is restarted if
+ # this file changes.
+ environment.etc = singleton
+ { target = "modules-load.d/nixos.conf";
+ source = kernelModulesConf;
+ };
+
+ # Sigh. This overrides systemd's systemd-modules-load.service
+ # just so we can set a restart trigger. Also make
+ # multi-user.target pull it in so that it gets started if it
+ # failed earlier.
+ systemd.services."systemd-modules-load" =
+ { description = "Load Kernel Modules";
+ wantedBy = [ "sysinit.target" "multi-user.target" ];
+ before = [ "sysinit.target" "shutdown.target" ];
+ unitConfig =
+ { DefaultDependencies = "no";
+ Conflicts = "shutdown.target";
+ };
+ serviceConfig =
+ { Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${config.systemd.package}/lib/systemd/systemd-modules-load";
+ # Ignore failed module loads. Typically some of the
+ # modules in ‘boot.kernelModules’ are "nice to have but
+ # not required" (e.g. acpi-cpufreq), so we don't want to
+ # barf on those.
+ SuccessExitStatus = "0 1";
+ };
+ restartTriggers = [ kernelModulesConf ];
+ };
+
lib.kernelConfig = {
isYes = option: {
assertion = config: config.isYes option;
@@ -240,4 +283,5 @@ let kernel = config.boot.kernelPackages.kernel; in
) config.system.requiredKernelConfig;
};
+
}
diff --git a/modules/system/boot/loader/grub/grub.nix b/modules/system/boot/loader/grub/grub.nix
index 70865c3c933..490502c5a36 100644
--- a/modules/system/boot/loader/grub/grub.nix
+++ b/modules/system/boot/loader/grub/grub.nix
@@ -19,6 +19,7 @@ let
version extraConfig extraPerEntryConfig extraEntries
extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout
default devices;
+ path = makeSearchPath "bin" [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils ];
});
in
diff --git a/modules/system/boot/loader/grub/install-grub.pl b/modules/system/boot/loader/grub/install-grub.pl
index 0140a711d72..f06527aaaec 100644
--- a/modules/system/boot/loader/grub/install-grub.pl
+++ b/modules/system/boot/loader/grub/install-grub.pl
@@ -39,6 +39,7 @@ my $configurationLimit = int(get("configurationLimit"));
my $copyKernels = get("copyKernels") eq "true";
my $timeout = int(get("timeout"));
my $defaultEntry = int(get("default"));
+$ENV{'PATH'} = get("path");
die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
diff --git a/modules/system/boot/loader/grub/memtest.nix b/modules/system/boot/loader/grub/memtest.nix
index 4bd4b69101c..b18ff0512f2 100644
--- a/modules/system/boot/loader/grub/memtest.nix
+++ b/modules/system/boot/loader/grub/memtest.nix
@@ -5,7 +5,7 @@
with pkgs.lib;
let
isEnabled = config.boot.loader.grub.memtest86;
- memtest86 = pkgs.memtest86;
+ memtest86 = pkgs.memtest86plus;
in
{
options = {
diff --git a/modules/system/boot/modprobe.nix b/modules/system/boot/modprobe.nix
index 41252e2ba0c..141be71b920 100644
--- a/modules/system/boot/modprobe.nix
+++ b/modules/system/boot/modprobe.nix
@@ -9,7 +9,6 @@ with pkgs.lib;
options = {
system.sbin.modprobe = mkOption {
- # should be moved in module-init-tools
internal = true;
default = pkgs.writeTextFile {
name = "modprobe";
@@ -18,7 +17,7 @@ with pkgs.lib;
text =
''
#! ${pkgs.stdenv.shell}
- export MODULE_DIR=${config.system.modulesTree}/lib/modules/
+ export MODULE_DIR=/run/current-system/kernel-modules/lib/modules
# Fall back to the kernel modules used at boot time if the
# modules in the current configuration don't match the
@@ -27,7 +26,7 @@ with pkgs.lib;
MODULE_DIR=/run/booted-system/kernel-modules/lib/modules/
fi
- exec ${pkgs.module_init_tools}/sbin/modprobe "$@"
+ exec ${pkgs.kmod}/sbin/modprobe "$@"
'';
};
description = ''
@@ -78,6 +77,8 @@ with pkgs.lib;
target = "modprobe.d/nixos.conf";
};
+ environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ];
+
boot.blacklistedKernelModules =
[ # This module is for debugging and generates gigantic amounts
# of log output, so it should never be loaded automatically.
@@ -104,8 +105,8 @@ with pkgs.lib;
environment.shellInit =
''
- export MODULE_DIR=${config.system.modulesTree}/lib/modules/
- '';
+ export MODULE_DIR=/run/current-system/kernel-modules/lib/modules
+ '';
};
diff --git a/modules/system/boot/shutdown.nix b/modules/system/boot/shutdown.nix
new file mode 100644
index 00000000000..23ddf6d0202
--- /dev/null
+++ b/modules/system/boot/shutdown.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+
+ # This unit saves the value of the system clock to the hardware
+ # clock on shutdown.
+ systemd.units."save-hwclock.service" =
+ { wantedBy = [ "shutdown.target" ];
+
+ text =
+ ''
+ [Unit]
+ Description=Save Hardware Clock
+ DefaultDependencies=no
+ Before=shutdown.target
+
+ [Service]
+ Type=oneshot
+ ExecStart=${pkgs.utillinux}/sbin/hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}
+ '';
+ };
+
+}
diff --git a/modules/system/boot/stage-1-init.sh b/modules/system/boot/stage-1-init.sh
index c6fc87bf32a..9bcbe291aad 100644
--- a/modules/system/boot/stage-1-init.sh
+++ b/modules/system/boot/stage-1-init.sh
@@ -1,6 +1,7 @@
#! @shell@
targetRoot=/mnt-root
+console=tty1
export LD_LIBRARY_PATH=@extraUtils@/lib
export PATH=@extraUtils@/bin:@extraUtils@/sbin
@@ -17,37 +18,31 @@ An error occured in stage 1 of the boot process, which must mount the
root filesystem on \`$targetRoot' and then start stage 2. Press one
of the following keys:
- i) to launch an interactive shell;
+EOF
+ if [ -n "$allowShell" ]; then cat </dev/$console 2>/dev/$console" ;;
- i)
- echo "Starting interactive shell..."
- setsid @shell@ -c "@shell@ < /dev/$console >/dev/$console 2>/dev/$console" || fail
- ;;
- *)
- echo "Continuing...";;
- esac
+ if [ -n "$allowShell" -a "$reply" = f ]; then
+ exec setsid @shell@ -c "@shell@ < /dev/$console >/dev/$console 2>/dev/$console"
+ elif [ -n "$allowShell" -a "$reply" = i ]; then
+ echo "Starting interactive shell..."
+ setsid @shell@ -c "@shell@ < /dev/$console >/dev/$console 2>/dev/$console" || fail
+ elif [ "$reply" = r ]; then
+ echo "Rebooting..."
+ reboot -f
+ else
+ echo "Continuing..."
+ fi
}
trap 'fail' 0
@@ -67,40 +62,45 @@ mkdir -p /proc
mount -t proc none /proc
mkdir -p /sys
mount -t sysfs none /sys
-mount -t tmpfs -o "mode=0755,size=@devSize@" none /dev
+mount -t devtmpfs -o "size=@devSize@" none /dev
mkdir -p /run
mount -t tmpfs -o "mode=0755,size=@runSize@" none /run
mount -t securityfs none /sys/kernel/security
-# Some console devices, for the interactivity
-mknod /dev/console c 5 1
-mknod /dev/tty c 5 0
-mknod /dev/tty1 c 4 1
-mknod /dev/ttyS0 c 4 64
-mknod /dev/ttyS1 c 4 65
-
# Process the kernel command line.
export stage2Init=/init
for o in $(cat /proc/cmdline); do
case $o in
+ console=*)
+ set -- $(IFS==; echo $o)
+ params=$2
+ set -- $(IFS=,; echo $params)
+ console=$1
+ ;;
init=*)
set -- $(IFS==; echo $o)
stage2Init=$2
;;
- debugtrace)
+ boot.trace|debugtrace)
# Show each command.
set -x
;;
- debug1) # stop right away
+ boot.shell_on_fail)
+ allowShell=1
+ ;;
+ boot.debug1|debug1) # stop right away
+ allowShell=1
fail
;;
- debug1devices) # stop after loading modules and creating device nodes
+ boot.debug1devices) # stop after loading modules and creating device nodes
+ allowShell=1
debug1devices=1
;;
- debug1mounts) # stop after mounting file systems
+ boot.debug1mounts) # stop after mounting file systems
+ allowShell=1
debug1mounts=1
;;
- stage1panic=1)
+ boot.panic_on_fail|stage1panic=1)
panicOnFail=1
;;
root=*)
@@ -131,16 +131,12 @@ for i in @kernelModules@; do
done
-# Create /dev/null.
-mknod /dev/null c 1 3
-
-
# Create device nodes in /dev.
echo "running udev..."
-export UDEV_CONFIG_FILE=@udevConf@
-mkdir -p /dev/.udev # !!! bug in udev?
+mkdir -p /etc/udev
+ln -sfn @udevRules@ /etc/udev/rules.d
mkdir -p /dev/.mdadm
-udevd --daemon
+systemd-udevd --daemon
udevadm trigger --action=add
udevadm settle || true
modprobe scsi_wait_scan || true
@@ -191,7 +187,7 @@ onACPower() {
checkFS() {
local device="$1"
local fsType="$2"
-
+
# Only check block devices.
if [ ! -b "$device" ]; then return 0; fi
@@ -230,7 +226,7 @@ checkFS() {
if test $(($fsckResult | 2)) = $fsckResult; then
echo "fsck finished, rebooting..."
sleep 3
- reboot
+ reboot -f
fi
if test $(($fsckResult | 4)) = $fsckResult; then
@@ -343,8 +339,8 @@ exec 3>&-
udevadm control --exit || true
# Kill any remaining processes, just to be sure we're not taking any
-# with us into stage 2.
-pkill -9 -v 1
+# with us into stage 2. unionfs-fuse mounts require the unionfs process.
+pkill -9 -v '(1|unionfs)'
if test -n "$debug1mounts"; then fail; fi
diff --git a/modules/system/boot/stage-1.nix b/modules/system/boot/stage-1.nix
index 6f82f3285b9..9743703ffbe 100644
--- a/modules/system/boot/stage-1.nix
+++ b/modules/system/boot/stage-1.nix
@@ -9,6 +9,8 @@ with pkgs.lib;
let
+ udev = config.systemd.package;
+
options = {
boot.resumeDevice = mkOption {
@@ -97,9 +99,12 @@ let
options.neededForBoot = mkOption {
default = false;
type = types.bool;
- description = "
- Mount this file system to boot on NixOS.
- ";
+ description = ''
+ If set, this file system will be mounted in the initial
+ ramdisk. By default, this applies to the root file system
+ and to the file system containing
+ /nix/store.
+ '';
};
};
@@ -167,19 +172,23 @@ let
cp -v ${pkgs.utillinux}/sbin/blkid $out/bin
cp -pdv ${pkgs.utillinux}/lib/libblkid*.so.* $out/lib
cp -pdv ${pkgs.utillinux}/lib/libuuid*.so.* $out/lib
-
+
# Copy dmsetup and lvm.
cp -v ${pkgs.lvm2}/sbin/dmsetup $out/bin/dmsetup
cp -v ${pkgs.lvm2}/sbin/lvm $out/bin/lvm
cp -v ${pkgs.lvm2}/lib/libdevmapper.so.*.* $out/lib
+ cp -v ${pkgs.systemd}/lib/libsystemd-daemon.so.* $out/lib
# Add RAID mdadm tool.
cp -v ${pkgs.mdadm}/sbin/mdadm $out/bin/mdadm
# Copy udev.
- cp -v ${pkgs.udev}/sbin/udevd ${pkgs.udev}/sbin/udevadm $out/bin
- cp -v ${pkgs.udev}/lib/udev/*_id $out/bin
- cp -pdv ${pkgs.udev}/lib/libudev.so.* $out/lib
+ cp -v ${udev}/lib/systemd/systemd-udevd ${udev}/bin/udevadm $out/bin
+ cp -v ${udev}/lib/udev/*_id $out/bin
+ cp -pdv ${udev}/lib/libudev.so.* $out/lib
+ cp -v ${pkgs.kmod}/lib/libkmod.so.* $out/lib
+ cp -v ${pkgs.acl}/lib/libacl.so.* $out/lib
+ cp -v ${pkgs.attr}/lib/libattr.so.* $out/lib
# Copy modprobe.
cp -v ${pkgs.module_init_tools}/sbin/modprobe $out/bin/modprobe
@@ -231,8 +240,8 @@ let
# booting (such as the FS containing /nix/store, or an FS needed for
# mounting /, like / on a loopback).
fileSystems = filter
- (fs: fs.mountPoint == "/" || fs.neededForBoot)
- config.fileSystems;
+ (fs: fs.mountPoint == "/" || fs.mountPoint == "/nix" || fs.mountPoint == "/nix/store" || fs.neededForBoot)
+ (attrValues config.fileSystems);
udevRules = pkgs.stdenv.mkDerivation {
@@ -242,28 +251,22 @@ let
echo 'ENV{LD_LIBRARY_PATH}="${extraUtils}/lib"' > $out/00-env.rules
- cp -v ${pkgs.udev}/lib/udev/rules.d/60-cdrom_id.rules $out/
- cp -v ${pkgs.udev}/lib/udev/rules.d/60-persistent-storage.rules $out/
- cp -v ${pkgs.udev}/lib/udev/rules.d/80-drivers.rules $out/
+ cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/
+ cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/
+ cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/
cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/
cp -v ${pkgs.mdadm}/lib/udev/rules.d/*.rules $out/
for i in $out/*.rules; do
-
substituteInPlace $i \
--replace ata_id ${extraUtils}/bin/ata_id \
- --replace usb_id ${extraUtils}/bin/usb_id \
--replace scsi_id ${extraUtils}/bin/scsi_id \
- --replace path_id ${extraUtils}/bin/path_id \
- --replace vol_id ${extraUtils}/bin/vol_id \
--replace cdrom_id ${extraUtils}/bin/cdrom_id \
--replace ${pkgs.utillinux}/sbin/blkid ${extraUtils}/bin/blkid \
--replace /sbin/blkid ${extraUtils}/bin/blkid \
- --replace /sbin/modprobe ${extraUtils}/bin/modprobe \
--replace ${pkgs.lvm2}/sbin ${extraUtils}/bin \
--replace /sbin/mdadm ${extraUtils}/bin/mdadm
done
- # !!! Remove this after merging the x-updates branch:
# Work around a bug in QEMU, which doesn't implement the "READ
# DISC INFORMATION" SCSI command:
@@ -281,14 +284,7 @@ let
};
- # The udev configuration file for in the initrd.
- udevConf = pkgs.writeText "udev-initrd.conf" ''
- udev_rules="${udevRules}"
- #udev_log="debug"
- '';
-
-
- # the binary keymap for busybox to load at boot
+ # The binary keymap for busybox to load at boot.
busyboxKeymap = pkgs.runCommand "boottime-keymap"
{ preferLocalBuild = true; }
''
@@ -306,7 +302,7 @@ let
isExecutable = true;
- inherit udevConf busyboxKeymap extraUtils modulesClosure;
+ inherit udevRules extraUtils modulesClosure busyboxKeymap;
inherit (config.boot) resumeDevice devSize runSize;
diff --git a/modules/system/boot/stage-2-init.sh b/modules/system/boot/stage-2-init.sh
index 256792460d0..5447ce0c502 100644
--- a/modules/system/boot/stage-2-init.sh
+++ b/modules/system/boot/stage-2-init.sh
@@ -25,9 +25,8 @@ setPath "@path@"
# Normally, stage 1 mounts the root filesystem read/writable.
-# However, in some environments (such as Amazon EC2), stage 2 is
-# executed directly, and the root is read-only. So make it writable
-# here.
+# 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 /
@@ -36,20 +35,22 @@ mount -n -o remount,rw /
if [ ! -e /proc/1 ]; then
mkdir -m 0755 -p /proc
mount -n -t proc none /proc
- mkdir -m 0755 -p /sys
- mount -t sysfs none /sys
mkdir -m 0755 -p /dev
- mount -t tmpfs -o "mode=0755" none /dev
+ mount -t devtmpfs none /dev
+fi
- # Create the minimal device nodes needed for the activation scripts
- # and Upstart.
- mknod -m 0666 /dev/null c 1 3
- mknod -m 0644 /dev/urandom c 1 9 # needed for passwd
- mknod -m 0644 /dev/console c 5 1
- mknod -m 0644 /dev/ptmx c 5 2 # required by upstart
- mknod -m 0644 /dev/tty1 c 4 1
- mknod -m 0644 /dev/ttyS0 c 4 64
- mknod -m 0644 /dev/ttyS1 c 4 65
+
+# Make /nix/store a read-only bind mount to enforce immutability of
+# the Nix store. Note that we can't use "chown root:nixbld" here
+# because users/groups might not exist yet.
+chown 0:30000 /nix/store
+chmod 1775 /nix/store
+if [ -n "@readOnlyStore@" ]; then
+ if ! mountpoint -q /nix/store; then
+ mkdir -p /nix/rw-store
+ mount --bind /nix/store /nix/store
+ mount -o remount,ro,bind /nix/store
+ fi
fi
@@ -57,24 +58,16 @@ fi
mkdir -m 0755 -p /etc
test -e /etc/fstab || touch /etc/fstab # to shut up mount
rm -f /etc/mtab* # not that we care about stale locks
-cat /proc/mounts > /etc/mtab
+ln -s /proc/mounts /etc/mtab
# Process the kernel command line.
-debug2=
for o in $(cat /proc/cmdline); do
case $o in
- debugtrace)
+ boot.debugtrace)
# Show each command.
set -x
;;
- debug2)
- debug2=1
- ;;
- S|s|single)
- # !!! argh, can't pass a startup event to Upstart yet.
- exec @shell@
- ;;
resume=*)
set -- $(IFS==; echo $o)
resumeDevice=$2
@@ -87,19 +80,19 @@ done
mkdir -m 0755 /dev/shm
mount -t tmpfs -o "rw,nosuid,nodev,size=@devShmSize@" tmpfs /dev/shm
mkdir -m 0755 -p /dev/pts
-mount -t devpts -o mode=0600,gid=@ttyGid@ none /dev/pts
[ -e /proc/bus/usb ] && mount -t usbfs none /proc/bus/usb # UML doesn't have USB by default
mkdir -m 01777 -p /tmp
-mkdir -m 0755 -p /var
+mkdir -m 0755 -p /var /var/log
mkdir -m 0755 -p /nix/var
mkdir -m 0700 -p /root
mkdir -m 0755 -p /bin # for the /bin/sh symlink
mkdir -m 0755 -p /home
mkdir -m 0755 -p /etc/nixos
+mkdir -m 0700 -p /var/log/journal
# Miscellaneous boot time cleanup.
-rm -rf /var/run /var/lock /var/log/upstart
+rm -rf /var/run /var/lock
rm -f /etc/resolv.conf
if test -n "@cleanTmpDir@"; then
@@ -167,26 +160,9 @@ ln -sfn /run/booted-system /nix/var/nix/gcroots/booted-system
@shell@ @postBootCommands@
-# For debugging Upstart.
-if [ -n "$debug2" ]; then
- # Get the console from the kernel cmdline
- console=tty1
- for o in $(cat /proc/cmdline); do
- case $o in
- console=*)
- set -- $(IFS==; echo $o)
- params=$2
- set -- $(IFS=,; echo $params)
- console=$1
- ;;
- esac
- done
-
- echo "Debug shell called from @out@"
- setsid @shellDebug@ < /dev/$console >/dev/$console 2>/dev/$console
-fi
-
-
-# Start Upstart's init.
-echo "starting Upstart..."
-PATH=/run/current-system/upstart/sbin exec init --no-sessions ${debug2:+--verbose}
+# Start systemd.
+echo "starting systemd..."
+PATH=/run/current-system/systemd/lib/systemd \
+ MODULE_DIR=/run/booted-system/kernel-modules/lib/modules \
+ LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive \
+ exec systemd --log-target=journal # --log-level=debug --log-target=console --crash-shell
diff --git a/modules/system/boot/stage-2.nix b/modules/system/boot/stage-2.nix
index 02c061dacde..c8ea322eb17 100644
--- a/modules/system/boot/stage-2.nix
+++ b/modules/system/boot/stage-2.nix
@@ -1,53 +1,60 @@
{ config, pkgs, ... }:
+with pkgs.lib;
+
let
options = {
boot = {
- postBootCommands = pkgs.lib.mkOption {
+
+ postBootCommands = mkOption {
default = "";
example = "rm -f /var/log/messages";
- type = with pkgs.lib.types; string;
+ type = types.string;
description = ''
Shell commands to be executed just before Upstart is started.
'';
};
- devSize = pkgs.lib.mkOption {
+ devSize = mkOption {
default = "5%";
example = "32m";
+ type = types.uniq types.string;
description = ''
Size limit for the /dev tmpfs. Look at mount(8), tmpfs size option,
for the accepted syntax.
'';
};
- devShmSize = pkgs.lib.mkOption {
+ devShmSize = mkOption {
default = "50%";
example = "256m";
+ type = types.uniq types.string;
description = ''
Size limit for the /dev/shm tmpfs. Look at mount(8), tmpfs size option,
for the accepted syntax.
'';
};
- runSize = pkgs.lib.mkOption {
+ runSize = mkOption {
default = "25%";
example = "256m";
+ type = types.uniq types.string;
description = ''
Size limit for the /run tmpfs. Look at mount(8), tmpfs size option,
for the accepted syntax.
'';
};
- cleanTmpDir = pkgs.lib.mkOption {
+ cleanTmpDir = mkOption {
default = false;
example = true;
description = ''
Delete all files in /tmp/ during boot.
'';
};
+
};
};
@@ -60,14 +67,13 @@ let
shellDebug = "${pkgs.bashInteractive}/bin/bash";
isExecutable = true;
inherit (config.boot) devShmSize runSize cleanTmpDir;
+ inherit (config.nix) readOnlyStore;
ttyGid = config.ids.gids.tty;
- upstart = config.system.build.upstart;
path =
[ pkgs.coreutils
pkgs.utillinux
- pkgs.udev
pkgs.sysvtools
- ] ++ pkgs.lib.optional config.boot.cleanTmpDir pkgs.findutils;
+ ] ++ optional config.boot.cleanTmpDir pkgs.findutils;
postBootCommands = pkgs.writeText "local-cmds"
''
${config.boot.postBootCommands}
diff --git a/modules/system/boot/systemd-unit-options.nix b/modules/system/boot/systemd-unit-options.nix
new file mode 100644
index 00000000000..1f8097ada1c
--- /dev/null
+++ b/modules/system/boot/systemd-unit-options.nix
@@ -0,0 +1,265 @@
+{ config, pkgs }:
+
+with pkgs.lib;
+
+rec {
+
+ unitOptions = {
+
+ enable = mkOption {
+ default = true;
+ types = types.bool;
+ description = ''
+ If set to false, this unit will be a symlink to
+ /dev/null. This is primarily useful to prevent specific
+ template instances (e.g. serial-getty@ttyS0)
+ from being started.
+ '';
+ };
+
+ description = mkOption {
+ default = "";
+ types = types.uniq types.string;
+ description = "Description of this unit used in systemd messages and progress indicators.";
+ };
+
+ requires = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ Start the specified units when this unit is started, and stop
+ this unit when the specified units are stopped or fail.
+ '';
+ };
+
+ wants = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ Start the specified units when this unit is started.
+ '';
+ };
+
+ after = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ If the specified units are started at the same time as
+ this unit, delay this unit until they have started.
+ '';
+ };
+
+ before = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ If the specified units are started at the same time as
+ this unit, delay them until this unit has started.
+ '';
+ };
+
+ bindsTo = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ Like ‘requires’, but in addition, if the specified units
+ unexpectedly disappear, this unit will be stopped as well.
+ '';
+ };
+
+ partOf = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = ''
+ If the specified units are stopped or restarted, then this
+ unit is stopped or restarted as well.
+ '';
+ };
+
+ wantedBy = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = "Units that want (i.e. depend on) this unit.";
+ };
+
+ unitConfig = mkOption {
+ default = {};
+ example = { RequiresMountsFor = "/data"; };
+ type = types.attrs;
+ description = ''
+ Each attribute in this set specifies an option in the
+ [Unit] section of the unit. See
+ systemd.unit
+ 5 for details.
+ '';
+ };
+
+ restartTriggers = mkOption {
+ default = [];
+ description = ''
+ An arbitrary list of items such as derivations. If any item
+ in the list changes between reconfigurations, the service will
+ be restarted.
+ '';
+ };
+
+ };
+
+
+ serviceOptions = unitOptions // {
+
+ environment = mkOption {
+ default = {};
+ type = types.attrs;
+ example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
+ description = "Environment variables passed to the services's processes.";
+ };
+
+ path = mkOption {
+ default = [];
+ apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
+ description = ''
+ Packages added to the service's PATH
+ environment variable. Both the bin
+ and sbin subdirectories of each
+ package are added.
+ '';
+ };
+
+ serviceConfig = mkOption {
+ default = {};
+ example =
+ { StartLimitInterval = 10;
+ RestartSec = 5;
+ };
+ type = types.attrs;
+ description = ''
+ Each attribute in this set specifies an option in the
+ [Service] section of the unit. See
+ systemd.service
+ 5 for details.
+ '';
+ };
+
+ script = mkOption {
+ type = types.uniq types.string;
+ default = "";
+ description = "Shell commands executed as the service's main process.";
+ };
+
+ preStart = mkOption {
+ type = types.string;
+ default = "";
+ description = ''
+ Shell commands executed before the service's main process
+ is started.
+ '';
+ };
+
+ postStart = mkOption {
+ type = types.string;
+ default = "";
+ description = ''
+ Shell commands executed after the service's main process
+ is started.
+ '';
+ };
+
+ postStop = mkOption {
+ type = types.string;
+ default = "";
+ description = ''
+ Shell commands executed after the service's main process
+ has exited.
+ '';
+ };
+
+ restartIfChanged = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether the service should be restarted during a NixOS
+ configuration switch if its definition has changed.
+ '';
+ };
+
+ stopIfChanged = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ If set, a changed unit is restarted by calling
+ systemctl stop in the old configuration,
+ then systemctl start in the new one.
+ Otherwise, it is restarted in a single step using
+ systemctl restart in the new configuration.
+ The latter is less correct because it runs the
+ ExecStop commands from the new
+ configuration.
+ '';
+ };
+
+ };
+
+
+ socketOptions = unitOptions // {
+
+ socketConfig = mkOption {
+ default = {};
+ example = { ListenStream = "/run/my-socket"; };
+ type = types.attrs;
+ description = ''
+ Each attribute in this set specifies an option in the
+ [Socket] section of the unit. See
+ systemd.socket
+ 5 for details.
+ '';
+ };
+
+ };
+
+ mountOptions = unitOptions // {
+
+ what = mkOption {
+ example = "/dev/sda1";
+ type = types.uniq types.string;
+ description = "Absolute path of device node, file or other resource. (Mandatory)";
+ };
+
+ where = mkOption {
+ example = "/mnt";
+ type = types.uniq types.string;
+ description = ''
+ Absolute path of a directory of the mount point.
+ Will be created if it doesn't exist. (Mandatory)
+ '';
+ };
+
+ type = mkOption {
+ default = "";
+ example = "ext4";
+ type = types.uniq types.string;
+ description = "File system type.";
+ };
+
+ options = mkOption {
+ default = "";
+ example = "noatime";
+ type = types.string;
+ merge = concatStringsSep ",";
+ description = "Options used to mount the file system.";
+ };
+
+ mountConfig = mkOption {
+ default = {};
+ example = { DirectoryMode = "0775"; };
+ type = types.attrs;
+ description = ''
+ Each attribute in this set specifies an option in the
+ [Mount] section of the unit. See
+ systemd.mount
+ 5 for details.
+ '';
+ };
+ };
+
+}
\ No newline at end of file
diff --git a/modules/system/boot/systemd.nix b/modules/system/boot/systemd.nix
new file mode 100644
index 00000000000..b7636702120
--- /dev/null
+++ b/modules/system/boot/systemd.nix
@@ -0,0 +1,531 @@
+{ config, pkgs, utils, ... }:
+
+with pkgs.lib;
+with utils;
+with import ./systemd-unit-options.nix { inherit config pkgs; };
+
+let
+
+ cfg = config.systemd;
+
+ systemd = cfg.package;
+
+ makeUnit = name: unit:
+ pkgs.runCommand "unit" { inherit (unit) text; }
+ (if unit.enable then ''
+ mkdir -p $out
+ echo -n "$text" > $out/${name}
+ '' else ''
+ mkdir -p $out
+ ln -s /dev/null $out/${name}
+ '');
+
+ upstreamUnits =
+ [ # Targets.
+ "basic.target"
+ "sysinit.target"
+ "sockets.target"
+ "graphical.target"
+ "multi-user.target"
+ "getty.target"
+ "network.target"
+ "nss-lookup.target"
+ "nss-user-lookup.target"
+ "syslog.target"
+ "time-sync.target"
+ #"cryptsetup.target"
+ "sigpwr.target"
+
+ # Rescue/emergency.
+ "rescue.target"
+ "rescue.service"
+ "emergency.target"
+ "emergency.service"
+
+ # Udev.
+ "systemd-udevd-control.socket"
+ "systemd-udevd-kernel.socket"
+ "systemd-udevd.service"
+ "systemd-udev-settle.service"
+ "systemd-udev-trigger.service"
+
+ # Hardware (started by udev when a relevant device is plugged in).
+ "sound.target"
+ "bluetooth.target"
+ "printer.target"
+ "smartcard.target"
+
+ # Login stuff.
+ "systemd-logind.service"
+ "autovt@.service"
+ #"systemd-vconsole-setup.service"
+ "systemd-user-sessions.service"
+ "dbus-org.freedesktop.login1.service"
+ "user@.service"
+
+ # Journal.
+ "systemd-journald.socket"
+ "systemd-journald.service"
+ "systemd-journal-flush.service"
+ "syslog.socket"
+
+ # SysV init compatibility.
+ "systemd-initctl.socket"
+ "systemd-initctl.service"
+ "runlevel0.target"
+ "runlevel1.target"
+ "runlevel2.target"
+ "runlevel3.target"
+ "runlevel4.target"
+ "runlevel5.target"
+ "runlevel6.target"
+
+ # Random seed.
+ "systemd-random-seed-load.service"
+ "systemd-random-seed-save.service"
+
+ # Utmp maintenance.
+ "systemd-update-utmp-runlevel.service"
+ "systemd-update-utmp-shutdown.service"
+
+ # Kernel module loading.
+ #"systemd-modules-load.service"
+
+ # Filesystems.
+ "systemd-fsck@.service"
+ "systemd-fsck-root.service"
+ "systemd-remount-fs.service"
+ "local-fs.target"
+ "local-fs-pre.target"
+ "remote-fs.target"
+ "remote-fs-pre.target"
+ "swap.target"
+ "dev-hugepages.mount"
+ "dev-mqueue.mount"
+ "sys-fs-fuse-connections.mount"
+ "sys-kernel-config.mount"
+ "sys-kernel-debug.mount"
+
+ # Hibernate / suspend.
+ "hibernate.target"
+ "suspend.target"
+ "sleep.target"
+ "systemd-hibernate.service"
+ "systemd-suspend.service"
+ "systemd-shutdownd.socket"
+ "systemd-shutdownd.service"
+
+ # Reboot stuff.
+ "reboot.target"
+ "systemd-reboot.service"
+ "poweroff.target"
+ "systemd-poweroff.service"
+ "halt.target"
+ "systemd-halt.service"
+ "ctrl-alt-del.target"
+ "shutdown.target"
+ "umount.target"
+ "final.target"
+ "kexec.target"
+
+ # Password entry.
+ "systemd-ask-password-console.path"
+ "systemd-ask-password-console.service"
+ "systemd-ask-password-wall.path"
+ "systemd-ask-password-wall.service"
+ ];
+
+ upstreamWants =
+ [ "basic.target.wants"
+ "sysinit.target.wants"
+ "sockets.target.wants"
+ "local-fs.target.wants"
+ "multi-user.target.wants"
+ "shutdown.target.wants"
+ ];
+
+ makeJobScript = name: text:
+ let x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${name}"; inherit text; };
+ in "${x}/bin/${name}";
+
+ unitConfig = { name, config, ... }: {
+ config = {
+ unitConfig =
+ { Requires = concatStringsSep " " config.requires;
+ Wants = concatStringsSep " " config.wants;
+ After = concatStringsSep " " config.after;
+ Before = concatStringsSep " " config.before;
+ BindsTo = concatStringsSep " " config.bindsTo;
+ PartOf = concatStringsSep " " config.partOf;
+ "X-Restart-Triggers" = toString config.restartTriggers;
+ } // optionalAttrs (config.description != "") {
+ Description = config.description;
+ };
+ };
+ };
+
+ serviceConfig = { name, config, ... }: {
+ config = {
+ # Default path for systemd services. Should be quite minimal.
+ path =
+ [ pkgs.coreutils
+ pkgs.findutils
+ pkgs.gnugrep
+ pkgs.gnused
+ systemd
+ ];
+ };
+ };
+
+ mountConfig = { name, config, ... }: {
+ config = {
+ mountConfig =
+ { What = config.what;
+ Where = config.where;
+ } // optionalAttrs (config.type != "") {
+ Type = config.type;
+ } // optionalAttrs (config.options != "") {
+ Options = config.options;
+ };
+ };
+ };
+
+ toOption = x:
+ if x == true then "true"
+ else if x == false then "false"
+ else toString x;
+
+ attrsToSection = as:
+ concatStrings (concatLists (mapAttrsToList (name: value:
+ map (x: ''
+ ${name}=${toOption x}
+ '')
+ (if isList value then value else [value]))
+ as));
+
+ targetToUnit = name: def:
+ { inherit (def) wantedBy enable;
+ text =
+ ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+ '';
+ };
+
+ serviceToUnit = name: def:
+ { inherit (def) wantedBy enable;
+ text =
+ ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+
+ [Service]
+ Environment=PATH=${def.path}
+ ${let env = cfg.globalEnvironment // def.environment;
+ in concatMapStrings (n: "Environment=${n}=${getAttr n env}\n") (attrNames env)}
+ ${optionalString (!def.restartIfChanged) "X-RestartIfChanged=false"}
+ ${optionalString (!def.stopIfChanged) "X-StopIfChanged=false"}
+
+ ${optionalString (def.preStart != "") ''
+ ExecStartPre=${makeJobScript "${name}-pre-start" ''
+ #! ${pkgs.stdenv.shell} -e
+ ${def.preStart}
+ ''}
+ ''}
+
+ ${optionalString (def.script != "") ''
+ ExecStart=${makeJobScript "${name}-start" ''
+ #! ${pkgs.stdenv.shell} -e
+ ${def.script}
+ ''}
+ ''}
+
+ ${optionalString (def.postStart != "") ''
+ ExecStartPost=${makeJobScript "${name}-post-start" ''
+ #! ${pkgs.stdenv.shell} -e
+ ${def.postStart}
+ ''}
+ ''}
+
+ ${optionalString (def.postStop != "") ''
+ ExecStopPost=${makeJobScript "${name}-post-stop" ''
+ #! ${pkgs.stdenv.shell} -e
+ ${def.postStop}
+ ''}
+ ''}
+
+ ${attrsToSection def.serviceConfig}
+ '';
+ };
+
+ socketToUnit = name: def:
+ { inherit (def) wantedBy enable;
+ text =
+ ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+
+ [Socket]
+ ${attrsToSection def.socketConfig}
+ '';
+ };
+
+ mountToUnit = name: def:
+ { inherit (def) wantedBy enable;
+ text =
+ ''
+ [Unit]
+ ${attrsToSection def.unitConfig}
+
+ [Mount]
+ ${attrsToSection def.mountConfig}
+ '';
+ };
+
+ nixosUnits = mapAttrsToList makeUnit cfg.units;
+
+ units = pkgs.runCommand "units" { preferLocalBuild = true; }
+ ''
+ mkdir -p $out
+ for i in ${toString upstreamUnits}; do
+ fn=${systemd}/example/systemd/system/$i
+ if ! [ -e $fn ]; then echo "missing $fn"; false; fi
+ if [ -L $fn ]; then
+ cp -pd $fn $out/
+ else
+ ln -s $fn $out/
+ fi
+ done
+
+ for i in ${toString upstreamWants}; do
+ fn=${systemd}/example/systemd/system/$i
+ if ! [ -e $fn ]; then echo "missing $fn"; false; fi
+ x=$out/$(basename $fn)
+ mkdir $x
+ for i in $fn/*; do
+ y=$x/$(basename $i)
+ cp -pd $i $y
+ if ! [ -e $y ]; then rm -v $y; fi
+ done
+ done
+
+ for i in ${toString nixosUnits}; do
+ ln -s $i/* $out/
+ done
+
+ for i in ${toString cfg.packages}; do
+ ln -s $i/etc/systemd/system/* $out/
+ done
+
+ ${concatStrings (mapAttrsToList (name: unit:
+ concatMapStrings (name2: ''
+ mkdir -p $out/${name2}.wants
+ ln -sfn ../${name} $out/${name2}.wants/
+ '') unit.wantedBy) cfg.units)}
+
+ ln -s ${cfg.defaultUnit} $out/default.target
+
+ ln -s rescue.target $out/kbrequest.target
+
+ #ln -s ../getty@tty1.service $out/multi-user.target.wants/
+ ln -s ../local-fs.target ../remote-fs.target ../network.target ../nss-lookup.target \
+ ../nss-user-lookup.target ../swap.target $out/multi-user.target.wants/
+ ''; # */
+
+in
+
+{
+
+ ###### interface
+
+ options = {
+
+ systemd.package = mkOption {
+ default = pkgs.systemd;
+ type = types.package;
+ description = "The systemd package.";
+ };
+
+ systemd.units = mkOption {
+ description = "Definition of systemd units.";
+ default = {};
+ type = types.attrsOf types.optionSet;
+ options = {
+ text = mkOption {
+ types = types.uniq types.string;
+ description = "Text of this systemd unit.";
+ };
+ enable = mkOption {
+ default = true;
+ types = types.bool;
+ description = ''
+ If set to false, this unit will be a symlink to
+ /dev/null. This is primarily useful to prevent specific
+ template instances (e.g. serial-getty@ttyS0)
+ from being started.
+ '';
+ };
+ wantedBy = mkOption {
+ default = [];
+ types = types.listOf types.string;
+ description = "Units that want (i.e. depend on) this unit.";
+ };
+ };
+ };
+
+ systemd.packages = mkOption {
+ default = [];
+ type = types.listOf types.package;
+ description = "Packages providing systemd units.";
+ };
+
+ systemd.targets = mkOption {
+ default = {};
+ type = types.attrsOf types.optionSet;
+ options = [ unitOptions unitConfig ];
+ description = "Definition of systemd target units.";
+ };
+
+ systemd.services = mkOption {
+ default = {};
+ type = types.attrsOf types.optionSet;
+ options = [ serviceOptions unitConfig serviceConfig ];
+ description = "Definition of systemd service units.";
+ };
+
+ systemd.sockets = mkOption {
+ default = {};
+ type = types.attrsOf types.optionSet;
+ options = [ socketOptions unitConfig ];
+ description = "Definition of systemd socket units.";
+ };
+
+ systemd.mounts = mkOption {
+ default = [];
+ type = types.listOf types.optionSet;
+ options = [ mountOptions unitConfig mountConfig ];
+ description = ''
+ Definition of systemd mount units.
+ This is a list instead of an attrSet, because systemd mandates the names to be derived from
+ the 'where' attribute.
+ '';
+ };
+
+ systemd.defaultUnit = mkOption {
+ default = "multi-user.target";
+ type = types.uniq types.string;
+ description = "Default unit started when the system boots.";
+ };
+
+ systemd.globalEnvironment = mkOption {
+ type = types.attrs;
+ default = {};
+ example = { TZ = "CET"; };
+ description = ''
+ Environment variables passed to all systemd units.
+ '';
+ };
+
+ services.journald.console = mkOption {
+ default = "";
+ type = types.uniq types.string;
+ description = "If non-empty, write log messages to the specified TTY device.";
+ };
+
+ services.journald.rateLimitInterval = mkOption {
+ default = "10s";
+ type = types.uniq types.string;
+ description = ''
+ Configures the rate limiting interval that is applied to all
+ messages generated on the system. This rate limiting is applied
+ per-service, so that two services which log do not interfere with
+ each other's limit. The value may be specified in the following
+ units: s, min, h, ms, us. To turn off any kind of rate limiting,
+ set either value to 0.
+ '';
+ };
+
+ services.journald.rateLimitBurst = mkOption {
+ default = 100;
+ type = types.uniq types.int;
+ description = ''
+ Configures the rate limiting burst limit (number of messages per
+ interval) that is applied to all messages generated on the system.
+ This rate limiting is applied per-service, so that two services
+ which log do not interfere with each other's limit.
+ '';
+ };
+
+ };
+
+
+ ###### implementation
+
+ config = {
+
+ system.build.units = units;
+
+ environment.systemPackages = [ systemd ];
+
+ environment.etc =
+ [ { source = units;
+ target = "systemd/system";
+ }
+ { source = pkgs.writeText "systemd.conf"
+ ''
+ [Manager]
+ '';
+ target = "systemd/system.conf";
+ }
+ { source = pkgs.writeText "journald.conf"
+ ''
+ [Journal]
+ RateLimitInterval=${config.services.journald.rateLimitInterval}
+ RateLimitBurst=${toString config.services.journald.rateLimitBurst}
+ ${optionalString (config.services.journald.console != "") ''
+ ForwardToConsole=yes
+ TTYPath=${config.services.journald.console}
+ ''}
+ '';
+ target = "systemd/journald.conf";
+ }
+ ];
+
+ system.activationScripts.systemd =
+ ''
+ mkdir -p /var/lib/udev -m 0755
+
+ # Regenerate the hardware database /var/lib/udev/hwdb.bin
+ # whenever systemd changes.
+ if [ ! -e /var/lib/udev/prev-systemd -o "$(readlink /var/lib/udev/prev-systemd)" != ${systemd} ]; then
+ echo "regenerating udev hardware database..."
+ ${systemd}/bin/udevadm hwdb --update && ln -sfn ${systemd} /var/lib/udev/prev-systemd
+ fi
+ '';
+
+ # Target for ‘charon send-keys’ to hook into.
+ systemd.targets.keys =
+ { description = "Security Keys";
+ };
+
+ systemd.units =
+ mapAttrs' (n: v: nameValuePair "${n}.target" (targetToUnit n v)) cfg.targets
+ // mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.services
+ // mapAttrs' (n: v: nameValuePair "${n}.socket" (socketToUnit n v)) cfg.sockets
+ // listToAttrs (map
+ (v: let n = escapeSystemdPath v.where;
+ in nameValuePair "${n}.mount" (mountToUnit n v)) cfg.mounts);
+
+ system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
+ "CGROUPS" "AUTOFS4_FS" "DEVTMPFS"
+ ];
+
+ environment.shellAliases =
+ { start = "systemctl start";
+ stop = "systemctl stop";
+ restart = "systemctl restart";
+ status = "systemctl status";
+ };
+
+ };
+}
diff --git a/modules/system/etc/make-etc.sh b/modules/system/etc/make-etc.sh
index 6075bdb2673..7cf68db9ddc 100644
--- a/modules/system/etc/make-etc.sh
+++ b/modules/system/etc/make-etc.sh
@@ -26,9 +26,9 @@ for ((i = 0; i < ${#targets_[@]}; i++)); do
if ! [ -e $out/etc/$target ]; then
ln -s $source $out/etc/$target
else
- echo "Duplicate entry $target -> $source"
+ echo "duplicate entry $target -> $source"
if test "$(readlink $out/etc/$target)" != "$source"; then
- echo "Mismatched duplicate entry $(readlink $out/etc/$target) <-> $source"
+ echo "mismatched duplicate entry $(readlink $out/etc/$target) <-> $source"
exit 1
fi
fi
diff --git a/modules/system/upstart-events/control-alt-delete.nix b/modules/system/upstart-events/control-alt-delete.nix
deleted file mode 100644
index f0f146160e5..00000000000
--- a/modules/system/upstart-events/control-alt-delete.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-{ config, pkgs, ... }:
-
-###### implementation
-
-{
- jobs.control_alt_delete =
- { name = "control-alt-delete";
-
- startOn = "control-alt-delete";
-
- task = true;
-
- script =
- ''
- shutdown -r now 'Ctrl-Alt-Delete pressed'
- '';
- };
-
- system.activationScripts.poweroff =
- ''
- # Allow the kernel to find the poweroff command. This is used
- # (for instance) by Xen's "xm shutdown" command to signal a
- # guest to shut down cleanly.
- echo ${config.system.build.upstart}/sbin/poweroff > /proc/sys/kernel/poweroff_cmd
- '';
-}
diff --git a/modules/system/upstart-events/runlevel.nix b/modules/system/upstart-events/runlevel.nix
deleted file mode 100644
index 016217ea3a6..00000000000
--- a/modules/system/upstart-events/runlevel.nix
+++ /dev/null
@@ -1,38 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-{
-
- # After booting, go to runlevel 2. (NixOS doesn't really use
- # runlevels, but this keeps wtmp happy.)
- jobs.boot =
- { name = "boot";
- startOn = "startup";
- task = true;
- restartIfChanged = false;
- script = "telinit 2";
- };
-
- jobs.runlevel =
- { name = "runlevel";
-
- startOn = "runlevel [0123456S]";
-
- task = true;
-
- restartIfChanged = false;
-
- script =
- ''
- case "$RUNLEVEL" in
- 0) initctl start shutdown --no-wait MODE=poweroff;;
- 1) initctl start shutdown --no-wait MODE=maintenance;;
- 2) true;;
- 6) initctl start shutdown --no-wait MODE=reboot;;
- *) echo "Unsupported runlevel: $RUNLEVEL";;
- esac
- '';
- };
-
-}
diff --git a/modules/system/upstart-events/shutdown.nix b/modules/system/upstart-events/shutdown.nix
deleted file mode 100644
index 59fbcc0d878..00000000000
--- a/modules/system/upstart-events/shutdown.nix
+++ /dev/null
@@ -1,162 +0,0 @@
-{ config, pkgs, ... }:
-
-with pkgs.lib;
-
-{
-
- jobs.shutdown =
- { name = "shutdown";
-
- task = true;
-
- stopOn = ""; # must override the default ("starting shutdown")
-
- environment = { MODE = "poweroff"; };
-
- extraConfig = "console owner";
-
- script =
- ''
- set +e # continue in case of errors
-
- ${pkgs.kbd}/bin/chvt 1
-
- exec < /dev/console > /dev/console 2>&1
- echo ""
- if test "$MODE" = maintenance; then
- echo "[1;32m<<< Entering maintenance mode >>>[0m"
- else
- echo "[1;32m<<< System shutdown >>>[0m"
- fi
- echo ""
-
- ${config.powerManagement.powerDownCommands}
-
- export PATH=${pkgs.utillinux}/bin:${pkgs.utillinux}/sbin:$PATH
-
-
- # Do an initial sync just in case.
- sync
-
-
- # Kill all remaining processes except init, this one and any
- # Upstart jobs that don't stop on the "starting shutdown"
- # event, as these are necessary to complete the shutdown.
- omittedPids=$(initctl list | sed -e 's/.*process \([0-9]\+\)/-o \1/;t;d')
- #echo "saved PIDs: $omittedPids"
-
- echo "sending the TERM signal to all processes..."
- ${pkgs.sysvtools}/bin/killall5 -15 $job $omittedPids
-
- sleep 1 # wait briefly
-
- echo "sending the KILL signal to all processes..."
- ${pkgs.sysvtools}/bin/killall5 -9 $job $omittedPids
-
-
- # If maintenance mode is requested, start a root shell, and
- # afterwards emit the "startup" event to bring everything
- # back up.
- if test "$MODE" = maintenance; then
- echo ""
- echo "[1;32m<<< Maintenance shell >>>[0m"
- echo ""
- ${pkgs.shadow}/bin/login root
- initctl emit -n startup
- exit 0
- fi
-
-
- # Write a shutdown record to wtmp while /var/log is still writable.
- reboot --wtmp-only
-
-
- # Set the hardware clock to the system time.
- echo "setting the hardware clock..."
- hwclock --systohc ${if config.time.hardwareClockInLocalTime then "--localtime" else "--utc"}
-
-
- # Stop all swap devices.
- swapoff -a
-
-
- # Unmount file systems. We repeat this until no more file systems
- # can be unmounted. This is to handle loopback devices, file
- # systems mounted on other file systems and so on.
- tryAgain=1
- while test -n "$tryAgain"; do
- tryAgain=
- failed= # list of mount points that couldn't be unmounted/remounted
-
- # Get rid of loopback devices.
- loDevices=$(losetup -a | sed 's#^\(/dev/loop[0-9]\+\).*#\1#')
- if [ -n "$loDevices" ]; then
- echo "removing loopback devices $loDevices..."
- losetup -d $loDevices
- fi
-
- cp /proc/mounts /dev/.mounts # don't read /proc/mounts while it's changing
- exec 4< /dev/.mounts
- while read -u 4 device mp fstype options rest; do
- # Skip various special filesystems. Non-existent
- # mount points are typically tmpfs/aufs mounts from
- # the initrd.
- if [ "$mp" = /proc -o "$mp" = /sys -o "$mp" = /dev -o "$device" = "rootfs" -o "$mp" = /run -o "$mp" = /var/run -o "$mp" = /var/lock -o ! -e "$mp" ]; then continue; fi
-
- echo "unmounting $mp..."
-
- # We need to remount,ro before attempting any
- # umount, or bind mounts may get confused, with
- # the fs not being properly flushed at the end.
-
- # `-i' is to workaround a bug in mount.cifs (it
- # doesn't recognise the `remount' option, and
- # instead mounts the FS again).
- success=
- if mount -t "$fstype" -n -i -o remount,ro "device" "$mp"; then success=1; fi
-
- # Note: don't use `umount -f'; it's very buggy.
- # (For instance, when applied to a bind-mount it
- # unmounts the target of the bind-mount.) !!! But
- # we should use `-f' for NFS.
- if [ "$mp" != / -a "$mp" != /nix -a "$mp" != /nix/store ]; then
- if umount -n "$mp"; then success=1; tryAgain=1; fi
- fi
-
- if [ -z "$success" ]; then failed="$failed $mp"; fi
- done
- done
-
-
- # Warn about filesystems that could not be unmounted or
- # remounted read-only.
- if [ -n "$failed" ]; then
- echo "[1;31mwarning:[0m the following filesystems could not be unmounted:"
- for mp in $failed; do echo " $mp"; done
- echo Enter 'i' to launch a shell, or wait 10 seconds to continue.
- read -t 10 A
- if [ "$A" == "i" ]; then
- ${pkgs.bashInteractive}/bin/bash -i < /dev/console &> /dev/console
- fi
- sleep 5
- fi
-
-
- # Final sync.
- sync
-
-
- # Either reboot or power-off the system.
- if test "$MODE" = reboot; then
- echo "rebooting..."
- sleep 1
- exec reboot -f
- else
- echo "powering off..."
- sleep 1
- exec halt -f -p
- fi
- '';
- };
-
-}
diff --git a/modules/system/upstart/upstart.nix b/modules/system/upstart/upstart.nix
index c5bdd5c66c4..5d5139b7a57 100644
--- a/modules/system/upstart/upstart.nix
+++ b/modules/system/upstart/upstart.nix
@@ -1,184 +1,106 @@
{ config, pkgs, ... }:
with pkgs.lib;
+with import ../boot/systemd-unit-options.nix { inherit config pkgs; };
let
- upstart = pkgs.upstart;
-
userExists = u:
(u == "") || any (uu: uu.name == u) (attrValues config.users.extraUsers);
groupExists = g:
(g == "") || any (gg: gg.name == g) (attrValues config.users.extraGroups);
- # From a job description, generate an Upstart job file.
- makeJob = job:
+ makeJobScript = name: content: "${pkgs.writeScriptBin name content}/bin/${name}";
+
+ # From a job description, generate an systemd unit file.
+ makeUnit = job:
let
hasMain = job.script != "" || job.exec != "";
- env = config.system.upstartEnvironment // job.environment;
+ env = job.environment;
- jobText =
- let log = "/var/log/upstart/${job.name}"; in
+ preStartScript = makeJobScript "${job.name}-pre-start"
''
- # Upstart job `${job.name}'. This is a generated file. Do not edit.
-
- ${optionalString (job.description != "") ''
- description "${job.description}"
- ''}
-
- ${if isList job.startOn then
- "start on ${concatStringsSep " or " job.startOn}"
- else if job.startOn != "" then
- "start on ${job.startOn}"
- else ""
- }
-
- ${optionalString (job.stopOn != "") "stop on ${job.stopOn}"}
-
- env PATH=${job.path}
-
- ${concatMapStrings (n: "env ${n}=\"${getAttr n env}\"\n") (attrNames env)}
-
- ${optionalString (job.console != "") "console ${job.console}"}
-
- pre-start script
- ${optionalString (job.console != "") "echo || "} exec >> ${log} 2>&1
- ln -sfn "$(readlink -f "/etc/init/${job.name}.conf")" /var/run/upstart-jobs/${job.name}
- ${optionalString (job.preStart != "") ''
- source ${jobHelpers}
- ${job.preStart}
- ''}
- end script
-
- ${if job.script != "" && job.exec != "" then
- abort "Job ${job.name} has both a `script' and `exec' attribute."
- else if job.script != "" then
- ''
- script
- ${optionalString (job.console != "") "echo || "} exec >> ${log} 2>&1
- source ${jobHelpers}
- ${job.script}
- end script
- ''
- else if job.exec != "" && job.console == "" then
- ''
- script
- exec >> ${log} 2>&1
- exec ${job.exec}
- end script
- ''
- else if job.exec != "" then
- ''
- exec ${job.exec}
- ''
- else ""
- }
-
- ${optionalString (job.postStart != "") ''
- post-start script
- ${optionalString (job.console != "") "echo || "} exec >> ${log} 2>&1
- source ${jobHelpers}
- ${job.postStart}
- end script
- ''}
-
- ${optionalString job.task "task"}
- ${optionalString (!job.task && job.respawn) "respawn"}
-
- ${ # preStop is run only if there is exec or script.
- # (upstart 0.6.5, job.c:562)
- optionalString (job.preStop != "") (assert hasMain; ''
- pre-stop script
- ${optionalString (job.console != "") "echo || "} exec >> ${log} 2>&1
- source ${jobHelpers}
- ${job.preStop}
- end script
- '')}
-
- ${optionalString (job.postStop != "") ''
- post-stop script
- ${optionalString (job.console != "") "echo || "} exec >> ${log} 2>&1
- source ${jobHelpers}
- ${job.postStop}
- end script
- ''}
-
- ${if job.daemonType == "fork" then "expect fork" else
- if job.daemonType == "daemon" then "expect daemon" else
- if job.daemonType == "stop" then "expect stop" else
- if job.daemonType == "none" then "" else
- throw "invalid daemon type `${job.daemonType}'"}
-
- ${optionalString (job.setuid != "") ''
- setuid ${job.setuid}
- ''}
-
- ${optionalString (job.setgid != "") ''
- setuid ${job.setgid}
- ''}
-
- ${job.extraConfig}
+ #! ${pkgs.stdenv.shell} -e
+ ${job.preStart}
'';
- in
- pkgs.runCommand ("upstart-" + job.name + ".conf")
- { inherit (job) buildHook; inherit jobText; preferLocalBuild = true; }
+ startScript = makeJobScript "${job.name}-start"
''
- eval "$buildHook"
- echo "$jobText" > $out
+ #! ${pkgs.stdenv.shell} -e
+ ${if job.script != "" then job.script else ''
+ exec ${job.exec}
+ ''}
'';
+ postStartScript = makeJobScript "${job.name}-post-start"
+ ''
+ #! ${pkgs.stdenv.shell} -e
+ ${job.postStart}
+ '';
- # Shell functions for use in Upstart jobs.
- jobHelpers = pkgs.writeText "job-helpers.sh"
- ''
- # Ensure that an Upstart service is running.
- ensure() {
- local job="$1"
- local status="$(status "$job")"
+ preStopScript = makeJobScript "${job.name}-pre-stop"
+ ''
+ #! ${pkgs.stdenv.shell} -e
+ ${job.preStop}
+ '';
- # If it's already running, we're happy.
- [[ "$status" =~ start/running ]] && return 0
+ postStopScript = makeJobScript "${job.name}-post-stop"
+ ''
+ #! ${pkgs.stdenv.shell} -e
+ ${job.postStop}
+ '';
+ in {
- # If its current goal is to stop, start it.
- [[ "$status" =~ stop/ ]] && { status="$(start "$job")" || true; }
+ inherit (job) description requires before partOf environment path restartIfChanged unitConfig;
- # The "start" command is synchronous *if* the job is
- # not already starting. So if somebody else started
- # the job in parallel, the "start" above may return
- # while the job is still starting. So wait until it
- # is up or has failed.
- while true; do
- [[ "$status" =~ stop/ ]] && { echo "job $job failed to start"; return 1; }
- [[ "$status" =~ start/running ]] && return 0
- echo "waiting for job $job to start..."
- sleep 1
- status="$(status "$job")"
- done
- }
+ after =
+ (if job.startOn == "stopped udevtrigger" then [ "systemd-udev-settle.service" ] else
+ if job.startOn == "started udev" then [ "systemd-udev.service" ] else
+ if job.startOn == "started network-interfaces" then [ "network-interfaces.target" ] else
+ if job.startOn == "started networking" then [ "network.target" ] else
+ if job.startOn == "ip-up" then [] else
+ if job.startOn == "" || job.startOn == "startup" then [] else
+ builtins.trace "Warning: job ‘${job.name}’ has unknown startOn value ‘${job.startOn}’." []
+ ) ++ job.after;
- # Check whether the current job has been stopped. Used in
- # post-start jobs to determine if they should continue.
- stop_check() {
- local status="$(status)"
- if [[ "$status" =~ stop/ ]]; then
- echo "job asked to stop!"
- return 1
- fi
- if [[ "$status" =~ respawn/ ]]; then
- echo "job respawning unexpectedly!"
- stop
- return 1
- fi
- return 0
- }
- '';
-
+ wants =
+ (if job.startOn == "stopped udevtrigger" then [ "systemd-udev-settle.service" ] else []
+ ) ++ job.wants;
- jobOptions = {
+ wantedBy =
+ (if job.startOn == "" then [] else
+ if job.startOn == "ip-up" then [ "ip-up.target" ] else
+ [ "multi-user.target" ]) ++ job.wantedBy;
+
+ serviceConfig =
+ job.serviceConfig
+ // optionalAttrs (job.preStart != "" && (job.script != "" || job.exec != ""))
+ { ExecStartPre = preStartScript; }
+ // optionalAttrs (job.preStart != "" && job.script == "" && job.exec == "")
+ { ExecStart = preStartScript; }
+ // optionalAttrs (job.script != "" || job.exec != "")
+ { ExecStart = startScript; }
+ // optionalAttrs (job.postStart != "")
+ { ExecStartPost = postStartScript; }
+ // optionalAttrs (job.preStop != "")
+ { ExecStop = preStopScript; }
+ // optionalAttrs (job.postStop != "")
+ { ExecStopPost = postStopScript; }
+ // (if job.script == "" && job.exec == "" then { Type = "oneshot"; RemainAfterExit = true; } else
+ if job.daemonType == "fork" || job.daemonType == "daemon" then { Type = "forking"; GuessMainPID = true; } else
+ if job.daemonType == "none" then { } else
+ throw "invalid daemon type `${job.daemonType}'")
+ // optionalAttrs (!job.task && job.respawn)
+ { Restart = "always"; }
+ // optionalAttrs job.task
+ { Type = "oneshot"; RemainAfterExit = false; };
+ };
+
+
+ jobOptions = serviceOptions // {
name = mkOption {
# !!! The type should ensure that this could be a filename.
@@ -189,25 +111,6 @@ let
'';
};
- buildHook = mkOption {
- type = types.string;
- default = "true";
- description = ''
- Command run while building the Upstart job. Can be used
- to perform simple regression tests (e.g., the Apache
- Upstart job uses it to check the syntax of the generated
- httpd.conf.
- '';
- };
-
- description = mkOption {
- type = types.string;
- default = "";
- description = ''
- A short description of this job.
- '';
- };
-
startOn = mkOption {
# !!! Re-enable this once we're on Upstart >= 0.6.
#type = types.string;
@@ -226,15 +129,6 @@ let
'';
};
- preStart = mkOption {
- type = types.string;
- default = "";
- description = ''
- Shell commands executed before the job is started
- (i.e. before the job's main process is started).
- '';
- };
-
postStart = mkOption {
type = types.string;
default = "";
@@ -275,15 +169,6 @@ let
'';
};
- script = mkOption {
- type = types.string;
- default = "";
- description = ''
- Shell commands executed as the job's main process. Can be
- specified instead of the exec attribute.
- '';
- };
-
respawn = mkOption {
type = types.bool;
default = true;
@@ -293,15 +178,6 @@ let
'';
};
- restartIfChanged = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether the job should be restarted if it has changed after a
- NixOS configuration switch.
- '';
- };
-
task = mkOption {
type = types.bool;
default = false;
@@ -312,15 +188,6 @@ let
'';
};
- environment = mkOption {
- type = types.attrs;
- default = {};
- example = { PATH = "/foo/bar/bin"; LANG = "nl_NL.UTF-8"; };
- description = ''
- Environment variables passed to the job's processes.
- '';
- };
-
daemonType = mkOption {
type = types.string;
default = "none";
@@ -353,18 +220,8 @@ let
'';
};
- extraConfig = mkOption {
- type = types.string;
- default = "";
- example = "limit nofile 4096 4096";
- description = ''
- Additional Upstart stanzas not otherwise supported.
- '';
- };
-
path = mkOption {
- default = [ ];
- apply = ps: "${makeSearchPath "bin" ps}:${makeSearchPath "sbin" ps}";
+ default = [];
description = ''
Packages added to the job's PATH environment variable.
Both the bin and sbin
@@ -372,50 +229,25 @@ let
'';
};
- console = mkOption {
- default = "";
- example = "console";
- description = ''
- If set to output, job output is written to
- the console. If it's owner, additionally
- the job becomes owner of the console. It it's empty (the
- default), output is written to
- /var/log/upstart/jobname
- '';
- };
-
};
- upstartJob = {name, config, ...}: {
+ upstartJob = { name, config, ... }: {
options = {
-
- jobDrv = mkOption {
- default = makeJob config;
- type = types.uniq types.package;
- description = ''
- Derivation that builds the Upstart job file. The default
- value is generated from other options.
- '';
+
+ unit = mkOption {
+ default = makeUnit config;
+ description = "Generated definition of the systemd unit corresponding to this job.";
};
-
+
};
config = {
-
+
# The default name is the name extracted from the attribute path.
name = mkDefaultValue name;
-
- # Default path for Upstart jobs. Should be quite minimal.
- path =
- [ pkgs.coreutils
- pkgs.findutils
- pkgs.gnugrep
- pkgs.gnused
- upstart
- ];
-
+
};
};
@@ -438,25 +270,6 @@ in
options = [ jobOptions upstartJob ];
};
- tests.upstartJobs = mkOption {
- internal = true;
- default = {};
- description = ''
- Make it easier to build individual Upstart jobs. (e.g.,
- nix-build /etc/nixos/nixos -A
- tests.upstartJobs.xserver).
- '';
- };
-
- system.upstartEnvironment = mkOption {
- type = types.attrs;
- default = {};
- example = { TZ = "CET"; };
- description = ''
- Environment variables passed to all Upstart jobs.
- '';
- };
-
};
@@ -464,24 +277,9 @@ in
config = {
- system.build.upstart = upstart;
-
- environment.etc =
- flip map (attrValues config.jobs) (job:
- { source = job.jobDrv;
- target = "init/${job.name}.conf";
- } );
-
- # Upstart can listen on the system bus, allowing normal users to
- # do status queries.
- services.dbus.packages = [ upstart ];
-
- system.activationScripts.chownJobLogs = stringAfter ["var"]
- (concatMapStrings (job: optionalString (job.setuid != "" || job.setgid != "") ''
- touch /var/log/upstart/${job.name}
- ${optionalString (job.setuid != "") "chown ${job.setuid} /var/log/upstart/${job.name}"}
- ${optionalString (job.setgid != "") "chown :${job.setgid} /var/log/upstart/${job.name}"}
- '') (attrValues config.jobs));
+ systemd.services =
+ flip mapAttrs' config.jobs (name: job:
+ nameValuePair job.name job.unit);
};
diff --git a/modules/tasks/cpu-freq.nix b/modules/tasks/cpu-freq.nix
index 0e0fd502a01..59e74fa6660 100644
--- a/modules/tasks/cpu-freq.nix
+++ b/modules/tasks/cpu-freq.nix
@@ -6,7 +6,7 @@ with pkgs.lib;
###### interface
options = {
-
+
powerManagement.cpuFreqGovernor = mkOption {
default = "";
example = "ondemand";
@@ -17,7 +17,7 @@ with pkgs.lib;
"userspace".
'';
};
-
+
};
@@ -30,17 +30,22 @@ with pkgs.lib;
jobs.cpufreq =
{ description = "Initialize CPU frequency governor";
- startOn = "started udev";
+ after = [ "systemd-modules-load.service" ];
+ wantedBy = [ "multi-user.target" ];
- task = true;
+ path = [ pkgs.cpufrequtils ];
- script = ''
+ preStart = ''
for i in $(seq 0 $(($(nproc) - 1))); do
- ${pkgs.cpufrequtils}/bin/cpufreq-set -g ${config.powerManagement.cpuFreqGovernor} -c $i
+ for gov in $(cpufreq-info -c $i -g); do
+ if [ "$gov" = ${config.powerManagement.cpuFreqGovernor} ]; then
+ echo "<6>setting governor on CPU $i to ‘$gov’"
+ cpufreq-set -c $i -g $gov
+ fi
+ done
done
'';
};
-
};
}
diff --git a/modules/tasks/filesystems.nix b/modules/tasks/filesystems.nix
index 5d6e4a4a369..8efc96f7fe4 100644
--- a/modules/tasks/filesystems.nix
+++ b/modules/tasks/filesystems.nix
@@ -1,21 +1,24 @@
-{ config, pkgs, ... }:
+{ config, pkgs, utils, ... }:
with pkgs.lib;
+with utils;
let
+ fileSystems = attrValues config.fileSystems;
+
fstab = pkgs.writeText "fstab"
''
# This is a generated file. Do not edit!
# Filesystems.
- ${flip concatMapStrings config.fileSystems (fs:
+ ${flip concatMapStrings fileSystems (fs:
(if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}")
+ " " + fs.mountPoint
+ " " + fs.fsType
+ " " + fs.options
+ " 0"
- + " " + (if fs.fsType == "none" || fs.fsType == "btrfs" || fs.noCheck then "0" else
+ + " " + (if fs.fsType == "none" || fs.device == "none" || fs.fsType == "btrfs" || fs.fsType == "tmpfs" || fs.noCheck then "0" else
if fs.mountPoint == "/" then "1" else "2")
+ "\n"
)}
@@ -26,8 +29,72 @@ let
)}
'';
+ fileSystemOpts = { name, ... }: {
+
+ options = {
+
+ mountPoint = mkOption {
+ example = "/mnt/usb";
+ type = types.uniq types.string;
+ description = "Location of the mounted the file system.";
+ };
+
+ device = mkOption {
+ default = null;
+ example = "/dev/sda";
+ type = types.uniq (types.nullOr types.string);
+ description = "Location of the device.";
+ };
+
+ label = mkOption {
+ default = null;
+ example = "root-partition";
+ type = types.uniq (types.nullOr types.string);
+ description = "Label of the device (if any).";
+ };
+
+ fsType = mkOption {
+ default = "auto";
+ example = "ext3";
+ type = types.uniq types.string;
+ description = "Type of the file system.";
+ };
+
+ options = mkOption {
+ default = "defaults,relatime";
+ example = "data=journal";
+ type = types.string;
+ merge = pkgs.lib.concatStringsSep ",";
+ description = "Options used to mount the file system.";
+ };
+
+ autoFormat = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ If the device does not currently contain a filesystem (as
+ determined by blkid, then automatically
+ format it with the filesystem type specified in
+ . Use with caution.
+ '';
+ };
+
+ noCheck = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Disable running fsck on this filesystem.";
+ };
+
+ };
+
+ config = {
+ mountPoint = mkDefault name;
+ };
+
+ };
+
in
-
+
{
###### interface
@@ -35,20 +102,17 @@ in
options = {
fileSystems = mkOption {
- example = [
- { mountPoint = "/";
- device = "/dev/hda1";
- }
- { mountPoint = "/data";
+ example = {
+ "/".device = "/dev/hda1";
+ "/data" = {
device = "/dev/hda2";
fsType = "ext3";
options = "data=journal";
- }
- { mountPoint = "/bigdisk";
- label = "bigdisk";
- }
- ];
-
+ };
+ "/bigdisk".label = "bigdisk";
+ };
+ type = types.loaOf types.optionSet;
+ options = [ fileSystemOpts ];
description = ''
The file systems to be mounted. It must include an entry for
the root directory (mountPoint = \"/\"). Each
@@ -64,76 +128,7 @@ in
specify a volume label (label) for file
systems that support it, such as ext2/ext3 (see mke2fs
-L).
-
- autocreate forces mountPoint to be created with
- mkdir -p .
'';
-
- type = types.list types.optionSet;
-
- options = {
-
- mountPoint = mkOption {
- example = "/mnt/usb";
- type = types.uniq types.string;
- description = "Location of the mounted the file system.";
- };
-
- device = mkOption {
- default = null;
- example = "/dev/sda";
- type = types.uniq (types.nullOr types.string);
- description = "Location of the device.";
- };
-
- label = mkOption {
- default = null;
- example = "root-partition";
- type = types.uniq (types.nullOr types.string);
- description = "Label of the device (if any).";
- };
-
- fsType = mkOption {
- default = "auto";
- example = "ext3";
- type = types.uniq types.string;
- description = "Type of the file system.";
- };
-
- options = mkOption {
- default = "defaults,relatime";
- example = "data=journal";
- type = types.string;
- merge = pkgs.lib.concatStringsSep ",";
- description = "Options used to mount the file system.";
- };
-
- autocreate = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Automatically create the mount point defined in
- .
- '';
- };
-
- autoFormat = mkOption {
- default = false;
- type = types.bool;
- description = ''
- If the device does not currently contain a filesystem (as
- determined by blkid, then automatically
- format it with the filesystem type specified in
- . Use with caution.
- '';
- };
-
- noCheck = mkOption {
- default = false;
- type = types.bool;
- description = "Disable running fsck on this filesystem.";
- };
- };
};
system.fsPackages = mkOption {
@@ -156,16 +151,6 @@ in
description = "Names of supported filesystem types in the initial ramdisk.";
};
- boot.ttyEmergency = mkOption {
- default =
- if pkgs.stdenv.isArm
- then "ttyS0" # presumably an embedded platform such as a plug
- else "tty1";
- description = ''
- The tty that will be stopped in case an emergency shell is spawned
- at boot.
- '';
- };
};
@@ -173,18 +158,17 @@ in
config = {
- boot.supportedFilesystems =
- map (fs: fs.fsType) config.fileSystems;
+ boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
boot.initrd.supportedFilesystems =
map (fs: fs.fsType)
- (filter (fs: fs.mountPoint == "/" || fs.neededForBoot) config.fileSystems);
+ (filter (fs: fs.mountPoint == "/" || fs.neededForBoot) fileSystems);
# Add the mount helpers to the system path so that `mount' can find them.
system.fsPackages = [ pkgs.dosfstools ];
-
+
environment.systemPackages =
- [ pkgs.ntfs3g pkgs.cifs_utils pkgs.mountall ]
+ [ pkgs.ntfs3g pkgs.cifs_utils ]
++ config.system.fsPackages;
environment.etc = singleton
@@ -192,133 +176,43 @@ in
target = "fstab";
};
- jobs.mountall =
- { startOn = "started udev or config-changed";
+ # Provide a target that pulls in all filesystems.
+ systemd.targets.fs =
+ { description = "All File Systems";
+ wants = [ "local-fs.target" "remote-fs.target" ];
+ };
- task = true;
+ # Emit systemd services to format requested filesystems.
+ systemd.services =
+ let
- path = [ pkgs.utillinux pkgs.mountall ] ++ config.system.fsPackages;
-
- console = "output";
-
- preStart =
- ''
- # Ensure that this job is restarted when fstab changed:
- # ${fstab}
- echo "mounting filesystems..."
-
- # Format devices.
- ${flip concatMapStrings config.fileSystems (fs: optionalString fs.autoFormat ''
- if [ -e "${fs.device}" ]; then
+ formatDevice = fs:
+ let
+ mountPoint' = escapeSystemdPath fs.mountPoint;
+ device' = escapeSystemdPath fs.device;
+ in nameValuePair "mkfs-${device'}"
+ { description = "Initialisation of Filesystem ${fs.device}";
+ wantedBy = [ "${mountPoint'}.mount" ];
+ before = [ "${mountPoint'}.mount" "systemd-fsck@${device'}.service" ];
+ require = [ "${device'}.device" ];
+ after = [ "${device'}.device" ];
+ path = [ pkgs.utillinux ] ++ config.system.fsPackages;
+ script =
+ ''
+ if ! [ -e "${fs.device}" ]; then exit 1; fi
+ # FIXME: this is scary. The test could be more robust.
type=$(blkid -p -s TYPE -o value "${fs.device}" || true)
if [ -z "$type" ]; then
echo "creating ${fs.fsType} filesystem on ${fs.device}..."
mkfs.${fs.fsType} "${fs.device}"
fi
- fi
- '')}
+ '';
+ unitConfig.RequiresMountsFor = [ "${dirOf fs.device}" ];
+ unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+ serviceConfig.Type = "oneshot";
+ };
- # Create missing mount points. Note that this won't work
- # if the mount point is under another mount point.
- ${flip concatMapStrings config.fileSystems (fs: optionalString fs.autocreate ''
- mkdir -p -m 0755 '${fs.mountPoint}'
- '')}
-
- # Create missing swapfiles.
- # FIXME: support changing the size of existing swapfiles.
- ${flip concatMapStrings config.swapDevices (sw: optionalString (sw.size != null) ''
- if [ ! -e "${sw.device}" -a -e "$(dirname "${sw.device}")" ]; then
- # FIXME: use ‘fallocate’ on filesystems that support it.
- dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
- mkswap ${sw.device}
- fi
- '')}
-
- '';
-
- daemonType = "daemon";
-
- exec = "mountall --daemon";
- };
-
- # The `mount-failed' event is emitted synchronously, but we don't
- # want `mountall' to wait for the emergency shell. So use this
- # intermediate job to make the event asynchronous.
- jobs."mount-failed" =
- { task = true;
- startOn = "mount-failed";
- restartIfChanged = false;
- script =
- ''
- # Don't start the emergency shell if the X server is
- # running. The user won't see it, and the "console owner"
- # stanza breaks VT switching and causes the X server to go
- # to 100% CPU time.
- status="$(status xserver || true)"
- [[ "$status" =~ start/ ]] && exit 0
-
- stop ${config.boot.ttyEmergency} || true
-
- start --no-wait emergency-shell \
- DEVICE="$DEVICE" MOUNTPOINT="$MOUNTPOINT"
- '';
- };
-
- # On an `ip-up' event, notify mountall so that it retries mounting
- # remote filesystems.
- jobs."mountall-ip-up" =
- {
- task = true;
- startOn = "ip-up";
- restartIfChanged = false;
- script =
- ''
- # Send USR1 to the mountall process. Can't use "pkill
- # mountall" here because that has a race condition: we may
- # accidentally send USR1 to children of mountall (such as
- # fsck) just before they do execve().
- status="$(status mountall)"
- if [[ "$status" =~ "start/running, process "([0-9]+) ]]; then
- pid=''${BASH_REMATCH[1]}
- echo "sending USR1 to $pid..."
- kill -USR1 "$pid"
- fi
- '';
- };
-
- jobs."emergency-shell" =
- { task = true;
-
- restartIfChanged = false;
-
- console = "owner";
-
- script =
- ''
- cat <>>[0m
-
- The filesystem \`$DEVICE' could not be mounted on \`$MOUNTPOINT'.
-
- Please do one of the following:
-
- - Repair the filesystem (\`fsck $DEVICE') and exit the emergency
- shell to resume booting.
-
- - Ignore any failed filesystems and continue booting by running
- \`initctl emit filesystem'.
-
- - Remove the failed filesystem from the system configuration in
- /etc/nixos/configuration.nix and run \`nixos-rebuild switch'.
-
- EOF
-
- ${pkgs.shadow}/bin/login root || false
-
- initctl start --no-wait mountall
- '';
- };
+ in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
};
diff --git a/modules/tasks/filesystems/nfs.nix b/modules/tasks/filesystems/nfs.nix
index 491d2de8f24..3d5e1dd51f5 100644
--- a/modules/tasks/filesystems/nfs.nix
+++ b/modules/tasks/filesystems/nfs.nix
@@ -33,50 +33,49 @@ in
config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {
services.rpcbind.enable = true;
-
+
system.fsPackages = [ pkgs.nfsUtils ];
boot.kernelModules = [ "sunrpc" ];
boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
- # Ensure that statd and idmapd are started before mountall.
- jobs.mountall.preStart =
- ''
- ensure statd || true
- ensure idmapd || true
- '';
-
- jobs.statd =
- { description = "Kernel NFS server - Network Status Monitor";
+ systemd.services.statd =
+ { description = "NFSv3 Network Status Monitor";
path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
- stopOn = ""; # needed during shutdown
+ wantedBy = [ "remote-fs-pre.target" "multi-user.target" ];
+ before = [ "remote-fs-pre.target" ];
+ requires = [ "basic.target" "rpcbind.service" ];
+ after = [ "basic.target" "rpcbind.service" "network.target" ];
+
+ unitConfig.DefaultDependencies = false; # don't stop during shutdown
preStart =
''
- ensure rpcbind
mkdir -p ${nfsStateDir}/sm
mkdir -p ${nfsStateDir}/sm.bak
sm-notify -d
'';
- daemonType = "fork";
-
- exec = "rpc.statd --no-notify";
+ serviceConfig.Type = "forking";
+ serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.statd rpc.statd --no-notify";
+ serviceConfig.Restart = "always";
};
- jobs.idmapd =
- { description = "NFS ID mapping daemon";
+ systemd.services.idmapd =
+ { description = "NFSv4 ID Mapping Daemon";
- path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
+ path = [ pkgs.sysvtools pkgs.utillinux ];
- startOn = "started udev";
+ wantedBy = [ "remote-fs-pre.target" "multi-user.target" ];
+ before = [ "remote-fs-pre.target" ];
+ requires = [ "rpcbind.service" ];
+ after = [ "rpcbind.service" ];
preStart =
''
- ensure rpcbind
mkdir -p ${rpcMountpoint}
mount -t rpc_pipefs rpc_pipefs ${rpcMountpoint}
'';
@@ -86,9 +85,9 @@ in
umount ${rpcMountpoint}
'';
- daemonType = "fork";
-
- exec = "rpc.idmapd -v -c ${idmapdConfFile}";
+ serviceConfig.Type = "forking";
+ serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.idmapd rpc.idmapd -c ${idmapdConfFile}";
+ serviceConfig.Restart = "always";
};
};
diff --git a/modules/tasks/filesystems/unionfs-fuse.nix b/modules/tasks/filesystems/unionfs-fuse.nix
new file mode 100644
index 00000000000..48cf798c7f0
--- /dev/null
+++ b/modules/tasks/filesystems/unionfs-fuse.nix
@@ -0,0 +1,19 @@
+{ config, pkgs, ... }:
+
+{
+ config = pkgs.lib.mkIf (pkgs.lib.any (fs: fs == "unionfs-fuse") config.boot.initrd.supportedFilesystems) {
+ boot.initrd.kernelModules = [ "fuse" ];
+
+ boot.initrd.extraUtilsCommands = ''
+ cp -v ${pkgs.fuse}/lib/libfuse* $out/lib
+ cp -v ${pkgs.unionfs-fuse}/bin/unionfs $out/bin
+ '';
+
+ boot.initrd.postDeviceCommands = ''
+ # Hacky!!! fuse hard-codes the path to mount
+ mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+ ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+ ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+ '';
+ };
+}
diff --git a/modules/tasks/kbd.nix b/modules/tasks/kbd.nix
index d9e820ef9e7..e4d22e94c80 100644
--- a/modules/tasks/kbd.nix
+++ b/modules/tasks/kbd.nix
@@ -10,10 +10,15 @@ let
++ config.boot.extraTTYs
++ [ config.services.syslogd.tty ];
ttys = map (dev: "/dev/${dev}") requiredTTYs;
- defaultLocale = config.i18n.defaultLocale;
consoleFont = config.i18n.consoleFont;
consoleKeyMap = config.i18n.consoleKeyMap;
+ vconsoleConf = pkgs.writeText "vconsole.conf"
+ ''
+ KEYMAP=${consoleKeyMap}
+ FONT=${consoleFont}
+ '';
+
in
{
@@ -23,6 +28,7 @@ in
# most options are defined in i18n.nix
+ # FIXME: still needed?
boot.extraTTYs = mkOption {
default = [];
example = ["tty8" "tty9"];
@@ -54,71 +60,34 @@ in
inherit requiredTTYs; # pass it to ./modules/tasks/tty-backgrounds.nix
- environment.systemPackages = [pkgs.kbd];
+ environment.systemPackages = [ pkgs.kbd ];
- jobs.kbd =
- { description = "Keyboard / console initialisation";
+ # Let systemd-vconsole-setup.service do the work of setting up the
+ # virtual consoles. FIXME: trigger a restart of
+ # systemd-vconsole-setup.service if /etc/vconsole.conf changes.
+ environment.etc = singleton
+ { target = "vconsole.conf";
+ source = vconsoleConf;
+ };
- startOn = "started udev";
-
- task = true;
-
- script = ''
- export LANG=${defaultLocale}
- export LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive
- export PATH=${pkgs.gzip}/bin:$PATH # Needed by setfont
-
- set +e # continue in case of errors
-
-
- # Enable or disable UTF-8 mode. This is based on
- # unicode_{start,stop}.
- echo 'Enabling or disabling Unicode mode...'
-
- charMap=$(${pkgs.glibc}/bin/locale charmap)
-
- if test "$charMap" = UTF-8; then
-
- for tty in ${toString ttys}; do
-
- # Tell the console output driver that the bytes arriving are
- # UTF-8 encoded multibyte sequences.
- echo -n -e '\033%G' > $tty
-
- done
-
- # Set the keyboard driver in UTF-8 mode.
- # !!! Commented out because it running this while the X
- # server is running kicks the X server out of raw mode.
- # UTF-8 mode is the default nowadays anyway.
- # ${pkgs.kbd}/bin/kbd_mode -u
-
- else
-
- for tty in ${toString ttys}; do
-
- # Tell the console output driver that the bytes arriving are
- # UTF-8 encoded multibyte sequences.
- echo -n -e '\033%@' > $tty
-
- done
-
- # Set the keyboard driver in ASCII (or any 8-bit character
- # set) mode.
- ${pkgs.kbd}/bin/kbd_mode -a
-
- fi
-
-
- # Set the console font.
- for tty in ${toString ttys}; do
- ${pkgs.kbd}/bin/setfont -C $tty ${consoleFont}
- done
-
-
- # Set the keymap.
- ${pkgs.kbd}/bin/loadkeys '${consoleKeyMap}'
- '';
+ # This is identical to the systemd-vconsole-setup.service unit
+ # shipped with systemd, except that it uses /dev/tty1 instead of
+ # /dev/tty0 to prevent putting the X server in non-raw mode, and
+ # it has a restart trigger.
+ systemd.services."systemd-vconsole-setup" =
+ { description = "Setup Virtual Console";
+ before = [ "sysinit.target" "shutdown.target" ];
+ unitConfig =
+ { DefaultDependencies = "no";
+ Conflicts = "shutdown.target";
+ ConditionPathExists = "/dev/tty1";
+ };
+ serviceConfig =
+ { Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${config.systemd.package}/lib/systemd/systemd-vconsole-setup /dev/tty1";
+ };
+ restartTriggers = [ vconsoleConf ];
};
};
diff --git a/modules/tasks/lvm.nix b/modules/tasks/lvm.nix
index 635146ac889..0e0272388c7 100644
--- a/modules/tasks/lvm.nix
+++ b/modules/tasks/lvm.nix
@@ -6,21 +6,6 @@
config = {
- jobs.lvm =
- { startOn = "started udev or new-devices";
-
- script =
- ''
- # Make all logical volumes on all volume groups available, i.e.,
- # make them appear in /dev.
- ${pkgs.lvm2}/sbin/vgchange --available y
-
- initctl emit -n new-devices
- '';
-
- task = true;
- };
-
environment.systemPackages = [ pkgs.lvm2 ];
services.udev.packages = [ pkgs.lvm2 ];
diff --git a/modules/tasks/network-interfaces.nix b/modules/tasks/network-interfaces.nix
index 4389d6421c5..49dd47251e5 100644
--- a/modules/tasks/network-interfaces.nix
+++ b/modules/tasks/network-interfaces.nix
@@ -5,7 +5,104 @@ with pkgs.lib;
let
cfg = config.networking;
- hasVirtuals = any (i: i.virtual) cfg.interfaces;
+ interfaces = attrValues cfg.interfaces;
+ hasVirtuals = any (i: i.virtual) interfaces;
+
+ interfaceOpts = { name, ... }: {
+
+ options = {
+
+ name = mkOption {
+ example = "eth0";
+ type = types.string;
+ description = "Name of the interface.";
+ };
+
+ ipAddress = mkOption {
+ default = null;
+ example = "10.0.0.1";
+ type = types.nullOr types.string;
+ description = ''
+ IP address of the interface. Leave empty to configure the
+ interface using DHCP.
+ '';
+ };
+
+ prefixLength = mkOption {
+ default = null;
+ example = 24;
+ type = types.nullOr types.int;
+ description = ''
+ Subnet mask of the interface, specified as the number of
+ bits in the prefix (24).
+ '';
+ };
+
+ subnetMask = mkOption {
+ default = "";
+ example = "255.255.255.0";
+ type = types.string;
+ description = ''
+ Subnet mask of the interface, specified as a bitmask.
+ This is deprecated; use
+ instead.
+ '';
+ };
+
+ macAddress = mkOption {
+ default = null;
+ example = "00:11:22:33:44:55";
+ type = types.nullOr types.string;
+ description = ''
+ MAC address of the interface. Leave empty to use the default.
+ '';
+ };
+
+ virtual = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether this interface is virtual and should be created by tunctl.
+ This is mainly useful for creating bridges between a host a virtual
+ network such as VPN or a virtual machine.
+
+ Defaults to tap device, unless interface contains "tun" in its name.
+ '';
+ };
+
+ virtualOwner = mkOption {
+ default = "root";
+ type = types.uniq types.string;
+ description = ''
+ In case of a virtual device, the user who owns it.
+ '';
+ };
+
+ proxyARP = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Turn on proxy_arp for this device (and proxy_ndp for ipv6).
+ This is mainly useful for creating pseudo-bridges between a real
+ interface and a virtual network such as VPN or a virtual machine for
+ interfaces that don't support real bridging (most wlan interfaces).
+ As ARP proxying acts slightly above the link-layer, below-ip traffic
+ isn't bridged, so things like DHCP won't work. The advantage above
+ using NAT lies in the fact that no IP addresses are shared, so all
+ hosts are reachable/routeable.
+
+ WARNING: turns on ip-routing, so if you have multiple interfaces, you
+ should think of the consequence and setup firewall rules to limit this.
+ '';
+ };
+
+ };
+
+ config = {
+ name = mkDefault name;
+ };
+
+ };
in
@@ -38,6 +135,16 @@ in
'';
};
+ networking.defaultGatewayWindowSize = mkOption {
+ default = null;
+ example = 524288;
+ type = types.nullOr types.int;
+ description = ''
+ The window size of the default gateway. It limits maximal data bursts that TCP peers
+ are allowed to send to us.
+ '';
+ };
+
networking.nameservers = mkOption {
default = [];
example = ["130.161.158.4" "130.161.33.17"];
@@ -66,110 +173,20 @@ in
};
networking.interfaces = mkOption {
- default = [];
- example = [
- { name = "eth0";
- ipAddress = "131.211.84.78";
- subnetMask = "255.255.255.128";
- }
- ];
+ default = {};
+ example =
+ { eth0 = {
+ ipAddress = "131.211.84.78";
+ subnetMask = "255.255.255.128";
+ };
+ };
description = ''
The configuration for each network interface. If
is true, then every
interface not listed here will be configured using DHCP.
'';
-
- type = types.list types.optionSet;
-
- options = {
-
- name = mkOption {
- example = "eth0";
- type = types.string;
- description = ''
- Name of the interface.
- '';
- };
-
- ipAddress = mkOption {
- default = "";
- example = "10.0.0.1";
- type = types.string;
- description = ''
- IP address of the interface. Leave empty to configure the
- interface using DHCP.
- '';
- };
-
- subnetMask = mkOption {
- default = "";
- example = "255.255.255.0";
- type = types.string;
- description = ''
- Subnet mask of the interface. Leave empty to use the
- default subnet mask.
- '';
- };
-
- macAddress = mkOption {
- default = "";
- example = "00:11:22:33:44:55";
- type = types.string;
- description = ''
- MAC address of the interface. Leave empty to use the default.
- '';
- };
-
- virtual = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Whether this interface is virtual and should be created by tunctl.
- This is mainly useful for creating bridges between a host a virtual
- network such as VPN or a virtual machine.
-
- Defaults to tap device, unless interface contains "tun" in its name.
- '';
- };
-
- virtualOwner = mkOption {
- default = "root";
- type = types.uniq types.string;
- description = ''
- In case of a virtual device, the user who owns it.
- '';
- };
-
- proxyARP = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Turn on proxy_arp for this device (and proxy_ndp for ipv6).
- This is mainly useful for creating pseudo-bridges between a real
- interface and a virtual network such as VPN or a virtual machine for
- interfaces that don't support real bridging (most wlan interfaces).
- As ARP proxying acts slightly above the link-layer, below-ip traffic
- isn't bridged, so things like DHCP won't work. The advantage above
- using NAT lies in the fact that no IP addresses are shared, so all
- hosts are reachable/routeable.
-
- WARNING: turns on ip-routing, so if you have multiple interfaces, you
- should think of the consequence and setup firewall rules to limit this.
- '';
- };
-
- };
-
- };
-
- networking.ifaces = mkOption {
- default = listToAttrs
- (map (iface: { name = iface.name; value = iface; }) config.networking.interfaces);
- internal = true;
- description = ''
- The network interfaces in
- as an attribute set keyed on the interface name.
- '';
+ type = types.loaOf types.optionSet;
+ options = [ interfaceOpts ];
};
networking.bridges = mkOption {
@@ -235,113 +252,172 @@ in
security.setuidPrograms = [ "ping" "ping6" ];
- jobs.networkInterfaces =
- { name = "network-interfaces";
+ systemd.targets."network-interfaces" =
+ { description = "All Network Interfaces";
+ wantedBy = [ "network.target" ];
+ unitConfig.X-StopOnReconfiguration = true;
+ };
- startOn = "stopped udevtrigger";
+ systemd.services =
+ let
- path = [ pkgs.iproute ];
+ networkSetup =
+ { description = "Networking Setup";
- preStart =
- ''
- set +e # continue in case of errors
+ after = [ "network-interfaces.target" ];
+ before = [ "network.target" ];
+ wantedBy = [ "network.target" ];
- # Create virtual network interfaces
- ${flip concatMapStrings cfg.interfaces (i:
- optionalString i.virtual
+ path = [ pkgs.iproute ];
+
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
+
+ script =
+ ''
+ # Set the static DNS configuration, if given.
+ cat | ${pkgs.openresolv}/sbin/resolvconf -a static < /proc/sys/net/ipv6/conf/all/disable_ipv6
+ fi
+
+ # Set the default gateway.
+ ${optionalString (cfg.defaultGateway != "") ''
+ # FIXME: get rid of "|| true" (necessary to make it idempotent).
+ ip route add default via "${cfg.defaultGateway}" ${
+ optionalString (cfg.defaultGatewayWindowSize != null)
+ "window ${cfg.defaultGatewayWindowSize}"} || true
+ ''}
+
+ # Turn on forwarding if any interface has enabled proxy_arp.
+ ${optionalString (any (i: i.proxyARP) interfaces) ''
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+ ''}
+
+ # Run any user-specified commands.
+ ${cfg.localCommands}
+ '';
+ };
+
+ # For each interface , create a job ‘-cfg.service"
+ # that performs static configuration. It has a "wants"
+ # dependency on ‘.service’, which is supposed to create
+ # the interface and need not exist (i.e. for hardware
+ # interfaces). It has a binds-to dependency on the actual
+ # network device, so it only gets started after the interface
+ # has appeared, and it's stopped when the interface
+ # disappears.
+ configureInterface = i: nameValuePair "${i.name}-cfg"
+ (let mask =
+ if i.prefixLength != null then toString i.prefixLength else
+ if i.subnetMask != "" then i.subnetMask else "32";
+ in
+ { description = "Configuration of ${i.name}";
+ wantedBy = [ "network-interfaces.target" ];
+ bindsTo = [ "sys-subsystem-net-devices-${i.name}.device" ];
+ after = [ "sys-subsystem-net-devices-${i.name}.device" ];
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
+ path = [ pkgs.iproute pkgs.gawk ];
+ script =
+ ''
+ echo "bringing up interface..."
+ ip link set "${i.name}" up
+ ''
+ + optionalString (i.macAddress != null)
''
- echo "Creating virtual network interface ${i.name}..."
- ${pkgs.tunctl}/bin/tunctl -t "${i.name}" -u "${i.virtualOwner}"
- '')
- }
-
- # Set MAC addresses of interfaces, if desired.
- ${flip concatMapStrings cfg.interfaces (i:
- optionalString (i.macAddress != "")
- ''
- echo "Setting MAC address of ${i.name} to ${i.macAddress}..."
+ echo "setting MAC address to ${i.macAddress}..."
ip link set "${i.name}" address "${i.macAddress}"
- '')
- }
+ ''
+ + optionalString (i.ipAddress != null)
+ ''
+ cur=$(ip -4 -o a show dev "${i.name}" | awk '{print $4}')
+ # Only do a flush/add if it's necessary. This is
+ # useful when the Nix store is accessed via this
+ # interface (e.g. in a QEMU VM test).
+ if [ "$cur" != "${i.ipAddress}/${mask}" ]; then
+ echo "configuring interface..."
+ ip -4 addr flush dev "${i.name}"
+ ip -4 addr add "${i.ipAddress}/${mask}" dev "${i.name}"
+ # Ensure that the default gateway remains set.
+ # (Flushing this interface may have removed it.)
+ ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service
+ else
+ echo "skipping configuring interface"
+ fi
+ ${config.systemd.package}/bin/systemctl start ip-up.target
+ ''
+ + optionalString i.proxyARP
+ ''
+ echo 1 > /proc/sys/net/ipv4/conf/${i.name}/proxy_arp
+ ''
+ + optionalString (i.proxyARP && cfg.enableIPv6)
+ ''
+ echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp
+ '';
+ });
- for i in $(cd /sys/class/net && ls -d *); do
- echo "Bringing up network device $i..."
- ip link set "$i" up
- done
+ createTunDevice = i: nameValuePair "${i.name}"
+ { description = "Virtual Network Interface ${i.name}";
+ requires = [ "dev-net-tun.device" ];
+ after = [ "dev-net-tun.device" ];
+ wantedBy = [ "network.target" "sys-subsystem-net-devices-${i.name}.device" ];
+ serviceConfig =
+ { Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${pkgs.tunctl}/bin/tunctl -t '${i.name}' -u '${i.virtualOwner}'";
+ ExecStop = "${pkgs.tunctl}/bin/tunctl -d '${i.name}'";
+ };
+ };
- # Create bridge devices.
- ${concatStrings (attrValues (flip mapAttrs cfg.bridges (n: v: ''
- echo "Creating bridge ${n}..."
- ${pkgs.bridge_utils}/sbin/brctl addbr "${n}"
+ createBridgeDevice = n: v:
+ let
+ deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces;
+ in
+ { description = "Bridge Interface ${n}";
+ wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ];
+ bindsTo = deps;
+ after = deps;
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
+ path = [ pkgs.bridge_utils pkgs.iproute ];
+ script =
+ ''
+ brctl addbr "${n}"
# Set bridge's hello time to 0 to avoid startup delays.
- ${pkgs.bridge_utils}/sbin/brctl setfd "${n}" 0
+ brctl setfd "${n}" 0
${flip concatMapStrings v.interfaces (i: ''
- ${pkgs.bridge_utils}/sbin/brctl addif "${n}" "${i}"
+ brctl addif "${n}" "${i}"
+ ip link set "${i}" up
ip addr flush dev "${i}"
'')}
# !!! Should delete (brctl delif) any interfaces that
# no longer belong to the bridge.
- '')))}
+ '';
+ postStop =
+ ''
+ ip link set "${n}" down
+ brctl delbr "${n}"
+ '';
+ };
- # Configure the manually specified interfaces.
- ${flip concatMapStrings cfg.interfaces (i:
- optionalString (i.ipAddress != "")
- ''
- echo "Configuring interface ${i.name}..."
- ip addr add "${i.ipAddress}""${optionalString (i.subnetMask != "") ("/" + i.subnetMask)}" \
- dev "${i.name}"
- '' +
- optionalString i.proxyARP
- ''
- echo 1 > /proc/sys/net/ipv4/conf/${i.name}/proxy_arp
- '' +
- optionalString (i.proxyARP && cfg.enableIPv6)
- ''
- echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp
- '')
- }
-
- # Set the static DNS configuration, if given.
- cat | ${pkgs.openresolv}/sbin/resolvconf -a static < /proc/sys/net/ipv4/ip_forward
- ''}
-
- # Run any user-specified commands.
- ${pkgs.stdenv.shell} ${pkgs.writeText "local-net-cmds" cfg.localCommands}
-
- ${optionalString (cfg.interfaces != [] || cfg.localCommands != "") ''
- # Emit the ip-up event (e.g. to start ntpd).
- initctl emit -n ip-up
- ''}
- '';
- };
-
- jobs.networking = {
- name = "networking";
- description = "All required interfaces are up";
- startOn = "started network-interfaces";
- stopOn = "stopping network-interfaces";
- task = true;
- exec = "true";
- };
+ in listToAttrs (
+ map configureInterface interfaces ++
+ map createTunDevice (filter (i: i.virtual) interfaces))
+ // mapAttrs createBridgeDevice cfg.bridges
+ // { "network-setup" = networkSetup; };
# Set the host name in the activation script. Don't clear it if
# it's not configured in the NixOS configuration, since it may
@@ -351,6 +427,11 @@ in
hostname "${config.networking.hostName}"
'';
+ services.udev.extraRules =
+ ''
+ KERNEL=="tun", TAG+="systemd"
+ '';
+
};
}
diff --git a/modules/tasks/scsi-link-power-management.nix b/modules/tasks/scsi-link-power-management.nix
index 263acb8f321..13ffbc7a51a 100644
--- a/modules/tasks/scsi-link-power-management.nix
+++ b/modules/tasks/scsi-link-power-management.nix
@@ -6,7 +6,7 @@ with pkgs.lib;
###### interface
options = {
-
+
powerManagement.scsiLinkPolicy = mkOption {
default = "";
example = "min_power";
@@ -16,7 +16,7 @@ with pkgs.lib;
the kernel configures "max_performance".
'';
};
-
+
};
@@ -25,19 +25,20 @@ with pkgs.lib;
config = mkIf (config.powerManagement.scsiLinkPolicy != "") {
jobs."scsi-link-pm" =
- { description = "Set SCSI link power management policy";
+ { description = "SCSI Link Power Management Policy";
- startOn = "started udev";
+ startOn = "stopped udevtrigger";
task = true;
script = ''
+ shopt -s nullglob
for x in /sys/class/scsi_host/host*/link_power_management_policy; do
echo ${config.powerManagement.scsiLinkPolicy} > $x
done
'';
};
-
+
};
}
diff --git a/modules/testing/test-instrumentation.nix b/modules/testing/test-instrumentation.nix
index 9d36538ea08..9c36ac2bbdd 100644
--- a/modules/testing/test-instrumentation.nix
+++ b/modules/testing/test-instrumentation.nix
@@ -5,25 +5,16 @@
with pkgs.lib;
-let
- kernel = config.boot.kernelPackages.kernel;
-
- hasCIFSTimeout = if kernel ? features then kernel.features ? cifsTimeout
- else (filter (p: p.name == "cifs-timeout") kernel.kernelPatches) != [];
-in
+let kernel = config.boot.kernelPackages.kernel; in
{
- config =
- # Require a patch to the kernel to increase the 15s CIFS timeout.
- mkAssert hasCIFSTimeout "
- VM tests require that the kernel has the CIFS timeout patch.
- " {
-
- jobs.backdoor =
- { startOn = "started udev";
- stopOn = "";
+ config = {
+ systemd.services.backdoor =
+ { wantedBy = [ "multi-user.target" ];
+ requires = [ "dev-hvc0.device" "dev-ttyS0.device" ];
+ after = [ "dev-hvc0.device" "dev-ttyS0.device" ];
script =
''
export USER=root
@@ -35,12 +26,17 @@ in
echo "connecting to host..." >&2
stty -F /dev/hvc0 raw -echo # prevent nl -> cr/nl conversion
echo
- PS1= /bin/sh
+ PS1= exec /bin/sh
'';
-
- respawn = false;
+ serviceConfig.KillSignal = "SIGHUP";
};
+ # Prevent agetty from being instantiated on ttyS0, since it
+ # interferes with the backdoor (writes to ttyS0 will randomly fail
+ # with EIO). Likewise for hvc0.
+ systemd.services."serial-getty@ttyS0".enable = false;
+ systemd.services."serial-getty@hvc0".enable = false;
+
boot.initrd.postDeviceCommands =
''
# Using acpi_pm as a clock source causes the guest clock to
@@ -60,10 +56,6 @@ in
# Coverage data is written into /tmp/coverage-data.
mkdir -p /tmp/xchg/coverage-data
-
- # Mount debugfs to gain access to the kernel coverage data (if
- # available).
- mount -t debugfs none /sys/kernel/debug || true
'';
# If the kernel has been built with coverage instrumentation, make
@@ -73,32 +65,26 @@ in
# Panic if an error occurs in stage 1 (rather than waiting for
# user intervention).
boot.kernelParams =
- [ "console=tty1" "console=ttyS0" "panic=1" "stage1panic=1" ];
+ [ "console=tty1" "console=ttyS0" "panic=1" "boot.panic_on_fail" ];
# `xwininfo' is used by the test driver to query open windows.
environment.systemPackages = [ pkgs.xorg.xwininfo ];
- # Send all of /var/log/messages to the serial port.
- services.syslogd.extraConfig = "*.* /dev/ttyS0";
-
- # Disable "-- MARK --" messages. These prevent hanging tests from
- # being killed after 1 hour of silence.
- services.syslogd.extraParams = [ "-m 0" ];
-
- # Don't run klogd. Kernel messages appear on the serial console anyway.
- jobs.klogd.startOn = mkOverride 50 "";
+ # Log everything to the serial console.
+ services.journald.console = "/dev/console";
# Prevent tests from accessing the Internet.
networking.defaultGateway = mkOverride 150 "";
networking.nameservers = mkOverride 150 [ ];
- system.upstartEnvironment.GCOV_PREFIX = "/tmp/xchg/coverage-data";
+ systemd.globalEnvironment.GCOV_PREFIX = "/tmp/xchg/coverage-data";
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isYes "SERIAL_8250_CONSOLE")
(isYes "SERIAL_8250")
(isEnabled "VIRTIO_CONSOLE")
];
+
};
}
diff --git a/modules/virtualisation/amazon-image.nix b/modules/virtualisation/amazon-image.nix
index 9ada2b176fe..38885d12b35 100644
--- a/modules/virtualisation/amazon-image.nix
+++ b/modules/virtualisation/amazon-image.nix
@@ -50,6 +50,10 @@ with pkgs.lib;
mkdir -p /mnt/etc
touch /mnt/etc/NIXOS
+ # `switch-to-configuration' requires a /bin/sh
+ mkdir -p /mnt/bin
+ ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
+
# Install a configuration.nix.
mkdir -p /mnt/etc/nixos
cp ${./amazon-config.nix} /mnt/etc/nixos/configuration.nix
@@ -62,17 +66,11 @@ with pkgs.lib;
''
);
- fileSystems =
- [ { mountPoint = "/";
- device = "/dev/disk/by-label/nixos";
- }
- ];
+ fileSystems."/".device = "/dev/disk/by-label/nixos";
- boot.initrd.kernelModules = [ "xen-blkfront" "aufs" ];
+ boot.initrd.kernelModules = [ "xen-blkfront" ];
boot.kernelModules = [ "xen-netfront" ];
- boot.extraModulePackages = [ config.boot.kernelPackages.aufs ];
-
# Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd.
boot.loader.grub.device = "nodev";
boot.loader.grub.timeout = 0;
@@ -93,12 +91,12 @@ with pkgs.lib;
# while "m1.large" has two ephemeral filesystems and no swap
# devices). Also, put /tmp and /var on /disk0, since it has a lot
# more space than the root device. Similarly, "move" /nix to /disk0
- # by layering an AUFS on top of it so we have a lot more space for
+ # by layering a unionfs-fuse mount on top of it so we have a lot more space for
# Nix operations.
boot.initrd.postMountCommands =
''
diskNr=0
- diskForAufs=
+ diskForUnionfs=
for device in /dev/xvd[abcde]*; do
if [ "$device" = /dev/xvda -o "$device" = /dev/xvda1 ]; then continue; fi
fsType=$(blkid -o value -s TYPE "$device" || true)
@@ -110,25 +108,31 @@ with pkgs.lib;
diskNr=$((diskNr + 1))
echo "mounting $device on $mp..."
if mountFS "$device" "$mp" "" ext3; then
- if [ -z "$diskForAufs" ]; then diskForAufs="$mp"; fi
+ if [ -z "$diskForUnionfs" ]; then diskForUnionfs="$mp"; fi
fi
else
echo "skipping unknown device type $device"
fi
done
- if [ -n "$diskForAufs" ]; then
- mkdir -m 755 -p $targetRoot/$diskForAufs/root
+ if [ -n "$diskForUnionfs" ]; then
+ mkdir -m 755 -p $targetRoot/$diskForUnionfs/root
- mkdir -m 1777 -p $targetRoot/$diskForAufs/root/tmp $targetRoot/tmp
- mount --bind $targetRoot/$diskForAufs/root/tmp $targetRoot/tmp
+ mkdir -m 1777 -p $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp
+ mount --bind $targetRoot/$diskForUnionfs/root/tmp $targetRoot/tmp
if [ ! -e $targetRoot/.ebs ]; then
- mkdir -m 755 -p $targetRoot/$diskForAufs/root/var $targetRoot/var
- mount --bind $targetRoot/$diskForAufs/root/var $targetRoot/var
+ mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/var $targetRoot/var
+ mount --bind $targetRoot/$diskForUnionfs/root/var $targetRoot/var
- mkdir -m 755 -p $targetRoot/$diskForAufs/root/nix
- mount -t aufs -o dirs=$targetRoot/$diskForAufs/root/nix=rw:$targetRoot/nix=rr none $targetRoot/nix
+ mkdir -p /unionfs-chroot/ro-nix
+ mount --rbind $targetRoot/nix /unionfs-chroot/ro-nix
+
+ mkdir -m 755 -p $targetRoot/$diskForUnionfs/root/nix
+ mkdir -p /unionfs-chroot/rw-nix
+ mount --rbind $targetRoot/$diskForUnionfs/root/nix /unionfs-chroot/rw-nix
+
+ unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot /rw-nix=RW:/ro-nix=RO $targetRoot/nix
fi
fi
'';
@@ -153,4 +157,6 @@ with pkgs.lib;
# Always include cryptsetup so that Charon can use it.
environment.systemPackages = [ pkgs.cryptsetup ];
+
+ boot.initrd.supportedFilesystems = [ "unionfs-fuse" ];
}
diff --git a/modules/virtualisation/ec2-data.nix b/modules/virtualisation/ec2-data.nix
index e094ae54093..42c50d857e4 100644
--- a/modules/virtualisation/ec2-data.nix
+++ b/modules/virtualisation/ec2-data.nix
@@ -19,21 +19,21 @@ in
{
require = [options];
- jobs.fetchEC2Data =
- { name = "fetch-ec2-data";
+ systemd.services."fetch-ec2-data" =
+ { description = "Fetch EC2 Data";
- startOn = "ip-up";
-
- task = true;
+ wantedBy = [ "multi-user.target" ];
+ before = [ "sshd.service" ];
+ after = [ "network.target" ];
path = [ pkgs.curl pkgs.iproute ];
script =
''
ip route del blackhole 169.254.169.254/32 || true
-
+
curl="curl --retry 3 --retry-delay 0 --fail"
-
+
echo "setting host name..."
${optionalString (config.networking.hostName == "") ''
${pkgs.nettools}/bin/hostname $($curl http://169.254.169.254/1.0/meta-data/hostname)
@@ -73,12 +73,15 @@ in
ip route add blackhole 169.254.169.254/32
''}
'';
+
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
};
- jobs.printHostKey =
- { name = "print-host-key";
- task = true;
- startOn = "started sshd";
+ systemd.services."print-host-key" =
+ { description = "Print SSH Host Key";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "sshd.service" ];
script =
''
# Print the host public key on the console so that the user
@@ -88,10 +91,8 @@ in
${pkgs.openssh}/bin/ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub > /dev/console
echo "-----END SSH HOST KEY FINGERPRINTS-----" > /dev/console
'';
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
};
- # Only start sshd after we've obtained the host key (if given in the
- # user data), otherwise the sshd job will generate one itself.
- jobs.sshd.startOn = mkOverride 90 "stopped fetch-ec2-data";
-
}
diff --git a/modules/virtualisation/libvirtd.nix b/modules/virtualisation/libvirtd.nix
index 66bbb757c70..757a20f6164 100644
--- a/modules/virtualisation/libvirtd.nix
+++ b/modules/virtualisation/libvirtd.nix
@@ -49,11 +49,11 @@ in
boot.kernelModules = [ "tun" ];
- jobs.libvirtd =
- { description = "Libvirtd virtual machine management daemon";
+ systemd.services.libvirtd =
+ { description = "Libvirt Virtual Machine Management Daemon";
- startOn = "stopped udevtrigger";
- stopOn = "";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "systemd-udev-settle.service" ];
path =
[ pkgs.bridge_utils pkgs.dmidecode pkgs.dnsmasq
@@ -83,7 +83,9 @@ in
done
''; # */
- exec = "${pkgs.libvirt}/sbin/libvirtd --daemon --verbose";
+ serviceConfig.ExecStart = "@${pkgs.libvirt}/sbin/libvirtd libvirtd --daemon --verbose";
+ serviceConfig.Type = "forking";
+ serviceConfig.KillMode = "process"; # when stopping, leave the VMs alone
# Wait until libvirtd is ready to accept requests.
postStart =
@@ -94,18 +96,17 @@ in
done
exit 1 # !!! seems to be ignored
'';
-
- daemonType = "daemon";
};
- # !!! Split this into save and restore tasks.
jobs."libvirt-guests" =
- { description = "Job to save/restore libvirtd VMs";
+ { description = "Libvirt Virtual Machines";
- startOn = "started libvirtd";
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "libvirtd.service" ];
+ after = [ "libvirtd.service" ];
# We want to suspend VMs only on shutdown, but Upstart is broken.
- stopOn = "";
+ #stopOn = "";
restartIfChanged = false;
@@ -119,19 +120,8 @@ in
postStop = "${pkgs.libvirt}/etc/rc.d/init.d/libvirt-guests stop";
- respawn = false;
- };
-
- jobs."stop-libvirt" =
- { description = "Helper task to stop libvirtd and libvirt-guests on shutdown";
- task = true;
- restartIfChanged = false;
- startOn = "starting shutdown";
- script =
- ''
- stop libvirt-guests || true
- stop libvirtd || true
- '';
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
};
};
diff --git a/modules/virtualisation/nova-image.nix b/modules/virtualisation/nova-image.nix
index ea4dbcc4dd4..0ce5d218cdb 100644
--- a/modules/virtualisation/nova-image.nix
+++ b/modules/virtualisation/nova-image.nix
@@ -68,18 +68,10 @@ with pkgs.lib;
''
);
- fileSystems =
- [ { mountPoint = "/";
- device = "/dev/disk/by-label/nixos";
- }
- ];
+ fileSystems."/".device = "/dev/disk/by-label/nixos";
boot.kernelParams = [ "console=ttyS0" ];
- boot.initrd.kernelModules = [ "aufs" ];
-
- boot.extraModulePackages = [ config.boot.kernelPackages.aufs ];
-
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/vda";
boot.loader.grub.timeout = 0;
@@ -87,8 +79,8 @@ with pkgs.lib;
# Put /tmp and /var on /ephemeral0, which has a lot more space.
# Unfortunately we can't do this with the `fileSystems' option
# because it has no support for creating the source of a bind
- # mount. Also, "move" /nix to /ephemeral0 by layering an AUFS
- # on top of it so we have a lot more space for Nix operations.
+ # mount. Also, "move" /nix to /ephemeral0 by layering a unionfs-fuse
+ # mount on top of it so we have a lot more space for Nix operations.
/*
boot.initrd.postMountCommands =
''
@@ -100,9 +92,16 @@ with pkgs.lib;
mkdir -m 755 -p $targetRoot/var
mount --bind $targetRoot/ephemeral0/var $targetRoot/var
+ mkdir -p /unionfs-chroot/ro-nix
+ mount --rbind $targetRoot/nix /unionfs-chroot/ro-nix
+
+ mkdir -p /unionfs-chroot/rw-nix
mkdir -m 755 -p $targetRoot/ephemeral0/nix
- mount -t aufs -o dirs=$targetRoot/ephemeral0/nix=rw:$targetRoot/nix=rr none $targetRoot/nix
+ mount --rbind $targetRoot/ephemeral0/nix /unionfs-chroot/rw-nix
+ unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot /rw-nix=RW:/ro-nix=RO $targetRoot/nix
'';
+
+ boot.initrd.supportedFilesystems = [ "unionfs-fuse" ];
*/
# Since Nova allows VNC access to instances, it's nice to start to
diff --git a/modules/virtualisation/qemu-vm.nix b/modules/virtualisation/qemu-vm.nix
index c30086487a7..b35b311819a 100644
--- a/modules/virtualisation/qemu-vm.nix
+++ b/modules/virtualisation/qemu-vm.nix
@@ -95,7 +95,7 @@ let
description =
''
If enabled, the Nix store in the VM is made writable by
- layering an AUFS/tmpfs filesystem on top of the host's Nix
+ layering a unionfs-fuse/tmpfs filesystem on top of the host's Nix
store.
'';
};
@@ -252,11 +252,9 @@ in
# CIFS. Also use paravirtualised network and block devices for
# performance.
boot.initrd.availableKernelModules =
- [ "cifs" "nls_utf8" "hmac" "md4" "ecb" "des_generic" ]
- ++ optional cfg.writableStore [ "aufs" ];
+ [ "cifs" "nls_utf8" "hmac" "md4" "ecb" "des_generic" ];
- boot.extraModulePackages =
- optional cfg.writableStore config.boot.kernelPackages.aufs;
+ boot.initrd.supportedFilesystems = optional cfg.writableStore "unionfs-fuse";
boot.initrd.extraUtilsCommands =
''
@@ -290,9 +288,12 @@ in
mkdir -p $targetRoot/boot
mount -o remount,ro $targetRoot/nix/store
${optionalString cfg.writableStore ''
- mkdir /mnt-store-tmpfs
- mount -t tmpfs -o "mode=755" none /mnt-store-tmpfs
- mount -t aufs -o dirs=/mnt-store-tmpfs=rw:$targetRoot/nix/store=rr none $targetRoot/nix/store
+ mkdir -p /unionfs-chroot/ro-store
+ mount --rbind $targetRoot/nix/store /unionfs-chroot/ro-store
+
+ mkdir /unionfs-chroot/rw-store
+ mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-store
+ unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot /rw-store=RW:/ro-store=RO $targetRoot/nix/store
''}
'';
@@ -322,35 +323,33 @@ in
# where the regular value for the `fileSystems' attribute should be
# disregarded for the purpose of building a VM test image (since
# those filesystems don't exist in the VM).
- fileSystems = mkOverride 50 (
- [ { mountPoint = "/";
- device = "/dev/vda";
- }
- { mountPoint = "/nix/store";
- device = "//10.0.2.4/store";
- fsType = "cifs";
- options = "guest,sec=none,noperm,noacl";
- neededForBoot = true;
- }
- { mountPoint = "/tmp/xchg";
- device = "//10.0.2.4/xchg";
- fsType = "cifs";
- options = "guest,sec=none,noperm,noacl";
- neededForBoot = true;
- }
- { mountPoint = "/tmp/shared";
- device = "//10.0.2.4/shared";
- fsType = "cifs";
- options = "guest,sec=none,noperm,noacl";
- neededForBoot = true;
- }
- ] ++ optional cfg.useBootLoader
- { mountPoint = "/boot";
- device = "/dev/disk/by-label/boot";
- fsType = "ext4";
- options = "ro";
- noCheck = true; # fsck fails on a r/o filesystem
- });
+ fileSystems =
+ { "/".device = "/dev/vda";
+ "/nix/store" =
+ { device = "//10.0.2.4/store";
+ fsType = "cifs";
+ options = "guest,sec=none,noperm,noacl";
+ };
+ "/tmp/xchg" =
+ { device = "//10.0.2.4/xchg";
+ fsType = "cifs";
+ options = "guest,sec=none,noperm,noacl";
+ neededForBoot = true;
+ };
+ "/tmp/shared" =
+ { device = "//10.0.2.4/shared";
+ fsType = "cifs";
+ options = "guest,sec=none,noperm,noacl";
+ neededForBoot = true;
+ };
+ } // optionalAttrs cfg.useBootLoader
+ { "/boot" =
+ { device = "/dev/disk/by-label/boot";
+ fsType = "ext4";
+ options = "ro";
+ noCheck = true; # fsck fails on a r/o filesystem
+ };
+ };
swapDevices = mkOverride 50 [ ];
@@ -365,6 +364,7 @@ in
networking.interfaces = singleton
{ name = "eth0";
ipAddress = "10.0.2.15";
+ prefixLength = 24;
};
# Don't run ntpd in the guest. It should get the correct time from KVM.
@@ -397,8 +397,6 @@ in
VertRefresh 50-160
'';
- services.mingetty.ttys = ttys ++ optional (!cfg.graphics) "ttyS0";
-
# Wireless won't work in the VM.
networking.wireless.enable = mkOverride 50 false;
diff --git a/modules/virtualisation/virtualbox-guest.nix b/modules/virtualisation/virtualbox-guest.nix
index a204f56b2ee..262afae2cf6 100644
--- a/modules/virtualisation/virtualbox-guest.nix
+++ b/modules/virtualisation/virtualbox-guest.nix
@@ -11,7 +11,7 @@ let
in
-if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then
+optionalAttrs (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) # ugly...
{
###### interface
@@ -41,9 +41,11 @@ if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then
users.extraGroups = singleton { name = "vboxsf"; };
jobs.virtualbox =
- { description = "VirtualBox service";
+ { description = "VirtualBox Guest Services";
- startOn = "started udev";
+ wantedBy = [ "multi-user.target" ];
+ requires = [ "dev-vboxguest.device" ];
+ after = [ "dev-vboxguest.device" ];
exec = "${kernel.virtualboxGuestAdditions}/sbin/VBoxService --foreground";
};
@@ -62,7 +64,7 @@ if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then
''
InputDevice "VBoxMouse"
'';
-
+
services.xserver.displayManager.sessionCommands =
''
PATH=${makeSearchPath "bin" [ pkgs.gnugrep pkgs.which pkgs.xorg.xorgserver ]}:$PATH \
@@ -74,12 +76,14 @@ if (pkgs.stdenv.isi686 || pkgs.stdenv.isx86_64) then
# /dev/vboxuser is necessary for VBoxClient to work. Maybe we
# should restrict this to logged-in users.
KERNEL=="vboxuser", OWNER="root", GROUP="root", MODE="0666"
+
+ # Allow systemd dependencies on vboxguest.
+ KERNEL=="vboxguest", TAG+="systemd"
'';
- # Make the ACPI Shutdown command to do the right thing.
+ # Make the ACPI Shutdown command to do the right thing.
services.acpid.enable = true;
services.acpid.powerEventCommands = "poweroff";
};
}
-else {}
diff --git a/modules/virtualisation/virtualbox-image.nix b/modules/virtualisation/virtualbox-image.nix
index f049c5eb348..373195a9d68 100644
--- a/modules/virtualisation/virtualbox-image.nix
+++ b/modules/virtualisation/virtualbox-image.nix
@@ -63,6 +63,10 @@ with pkgs.lib;
mkdir -p /mnt/etc/nixos
cp ${./nova-config.nix} /mnt/etc/nixos/configuration.nix
+ # `switch-to-configuration' requires a /bin/sh
+ mkdir -p /mnt/bin
+ ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
+
# Generate the GRUB menu.
chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
@@ -71,11 +75,7 @@ with pkgs.lib;
''
);
- fileSystems =
- [ { mountPoint = "/";
- device = "/dev/disk/by-label/nixos";
- }
- ];
+ fileSystems."/".device = "/dev/disk/by-label/nixos";
boot.loader.grub.version = 2;
boot.loader.grub.device = "/dev/sda";
diff --git a/release.nix b/release.nix
index bd740af1c42..2a78031f9a9 100644
--- a/release.nix
+++ b/release.nix
@@ -20,7 +20,7 @@ let
let
versionModule =
- { system.nixosVersion = version + (lib.optionalString (!officialRelease) versionSuffix);
+ { system.nixosVersionSuffix = lib.optionalString (!officialRelease) versionSuffix;
isoImage.isoBaseName = "nixos-${type}";
};
@@ -55,7 +55,7 @@ let
with import {inherit system;};
let
- versionModule = { system.nixosVersion = version + (lib.optionalString (!officialRelease) versionSuffix); };
+ versionModule = { system.nixosVersionSuffix = lib.optionalString (!officialRelease) versionSuffix; };
config = (import lib/eval-config.nix {
inherit system;
@@ -195,10 +195,9 @@ let
*/
- tests =
+ tests = { system ? "x86_64-linux" }:
let
- t = import ./tests { system = "i686-linux"; };
- t_64 = import ./tests { system = "x86_64-linux"; };
+ t = import ./tests { inherit system; };
in {
avahi = t.avahi.test;
bittorrent = t.bittorrent.test;
@@ -209,7 +208,6 @@ let
installer.rebuildCD = t.installer.rebuildCD.test;
installer.separateBoot = t.installer.separateBoot.test;
installer.simple = t.installer.simple.test;
- installer.simple_64 = t_64.installer.simple.test;
installer.swraid = t.installer.swraid.test;
ipv6 = t.ipv6.test;
kde4 = t.kde4.test;
diff --git a/tests/avahi.nix b/tests/avahi.nix
index d29e0ff77c6..d95361dcd83 100644
--- a/tests/avahi.nix
+++ b/tests/avahi.nix
@@ -22,34 +22,34 @@ with pkgs;
'' startAll;
# mDNS.
- $one->waitForJob("network-interfaces");
- $one->mustSucceed("avahi-resolve-host-name one.local | tee out >&2");
- $one->mustSucceed("test \"`cut -f1 < out`\" = one.local");
- $one->mustSucceed("avahi-resolve-host-name two.local | tee out >&2");
- $one->mustSucceed("test \"`cut -f1 < out`\" = two.local");
+ $one->waitForUnit("network.target");
+ $one->succeed("avahi-resolve-host-name one.local | tee out >&2");
+ $one->succeed("test \"`cut -f1 < out`\" = one.local");
+ $one->succeed("avahi-resolve-host-name two.local | tee out >&2");
+ $one->succeed("test \"`cut -f1 < out`\" = two.local");
- $two->waitForJob("network-interfaces");
- $two->mustSucceed("avahi-resolve-host-name one.local | tee out >&2");
- $two->mustSucceed("test \"`cut -f1 < out`\" = one.local");
- $two->mustSucceed("avahi-resolve-host-name two.local | tee out >&2");
- $two->mustSucceed("test \"`cut -f1 < out`\" = two.local");
+ $two->waitForUnit("network.target");
+ $two->succeed("avahi-resolve-host-name one.local | tee out >&2");
+ $two->succeed("test \"`cut -f1 < out`\" = one.local");
+ $two->succeed("avahi-resolve-host-name two.local | tee out >&2");
+ $two->succeed("test \"`cut -f1 < out`\" = two.local");
# Basic DNS-SD.
- $one->mustSucceed("avahi-browse -r -t _workstation._tcp | tee out >&2");
- $one->mustSucceed("test `wc -l < out` -gt 0");
- $two->mustSucceed("avahi-browse -r -t _workstation._tcp | tee out >&2");
- $two->mustSucceed("test `wc -l < out` -gt 0");
+ $one->succeed("avahi-browse -r -t _workstation._tcp | tee out >&2");
+ $one->succeed("test `wc -l < out` -gt 0");
+ $two->succeed("avahi-browse -r -t _workstation._tcp | tee out >&2");
+ $two->succeed("test `wc -l < out` -gt 0");
# More DNS-SD.
$one->execute("avahi-publish -s \"This is a test\" _test._tcp 123 one=1 &");
$one->sleep(5);
- $two->mustSucceed("avahi-browse -r -t _test._tcp | tee out >&2");
- $two->mustSucceed("test `wc -l < out` -gt 0");
+ $two->succeed("avahi-browse -r -t _test._tcp | tee out >&2");
+ $two->succeed("test `wc -l < out` -gt 0");
# NSS-mDNS.
- $one->mustSucceed("getent hosts one.local >&2");
- $one->mustSucceed("getent hosts two.local >&2");
- $two->mustSucceed("getent hosts one.local >&2");
- $two->mustSucceed("getent hosts two.local >&2");
+ $one->succeed("getent hosts one.local >&2");
+ $one->succeed("getent hosts two.local >&2");
+ $two->succeed("getent hosts one.local >&2");
+ $two->succeed("getent hosts two.local >&2");
'';
}
diff --git a/tests/bittorrent.nix b/tests/bittorrent.nix
index 8951e5bad1b..180da8267e0 100644
--- a/tests/bittorrent.nix
+++ b/tests/bittorrent.nix
@@ -16,7 +16,7 @@ let
miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf"
''
ext_ifname=eth1
- listening_ip=${nodes.router.config.networking.ifaces.eth2.ipAddress}/24
+ listening_ip=${nodes.router.config.networking.interfaces.eth2.ipAddress}/24
allow 1024-65535 192.168.2.0/24 1024-65535
'';
@@ -49,7 +49,7 @@ in
{ environment.systemPackages = [ pkgs.transmission ];
virtualisation.vlans = [ 2 ];
networking.defaultGateway =
- nodes.router.config.networking.ifaces.eth2.ipAddress;
+ nodes.router.config.networking.interfaces.eth2.ipAddress;
};
client2 =
@@ -64,7 +64,7 @@ in
startAll;
# Enable NAT on the router and start miniupnpd.
- $router->waitForJob("nat");
+ $router->waitForUnit("nat");
$router->succeed(
"iptables -t nat -N MINIUPNPD",
"iptables -t nat -A PREROUTING -i eth1 -j MINIUPNPD",
@@ -79,7 +79,7 @@ in
$tracker->succeed("chmod 644 /tmp/test.torrent");
# Start the tracker. !!! use a less crappy tracker
- $tracker->waitForJob("network-interfaces");
+ $tracker->waitForUnit("network.target");
$tracker->succeed("bittorrent-tracker --port 6969 --dfile /tmp/dstate >&2 &");
$tracker->waitForOpenPort(6969);
@@ -87,8 +87,8 @@ in
my $pid = $tracker->succeed("transmission-cli /tmp/test.torrent -M -w /tmp/data >&2 & echo \$!");
# Now we should be able to download from the client behind the NAT.
- $tracker->waitForJob("httpd");
- $client1->waitForJob("network-interfaces");
+ $tracker->waitForUnit("httpd");
+ $client1->waitForUnit("network.target");
$client1->succeed("transmission-cli http://tracker/test.torrent -w /tmp >&2 &");
$client1->waitForFile("/tmp/test.tar.bz2");
$client1->succeed("cmp /tmp/test.tar.bz2 ${file}");
@@ -98,7 +98,7 @@ in
# Now download from the second client. This can only succeed if
# the first client created a NAT hole in the router.
- $client2->waitForJob("network-interfaces");
+ $client2->waitForUnit("network.target");
$client2->succeed("transmission-cli http://tracker/test.torrent -M -w /tmp >&2 &");
$client2->waitForFile("/tmp/test.tar.bz2");
$client2->succeed("cmp /tmp/test.tar.bz2 ${file}");
diff --git a/tests/check-filesystems.nix b/tests/check-filesystems.nix
index ed4b365b901..39e8883ee59 100644
--- a/tests/check-filesystems.nix
+++ b/tests/check-filesystems.nix
@@ -59,22 +59,22 @@ rec {
''
startAll;
- $share->waitForJob("checkable");
- $fsCheck->waitForJob("checkable");
+ $share->waitForUnit("checkable");
+ $fsCheck->waitForUnit("checkable");
# check repos1
- $fsCheck->mustSucceed("test -d /repos1");
- $share->mustSucceed("touch /repos1/test1");
- $fsCheck->mustSucceed("test -e /repos1/test1");
+ $fsCheck->succeed("test -d /repos1");
+ $share->succeed("touch /repos1/test1");
+ $fsCheck->succeed("test -e /repos1/test1");
# check repos2 (check after remount)
- $fsCheck->mustSucceed("test -d /repos2");
- $share->mustSucceed("touch /repos2/test2");
- $fsCheck->mustSucceed("test -e /repos2/test2");
+ $fsCheck->succeed("test -d /repos2");
+ $share->succeed("touch /repos2/test2");
+ $fsCheck->succeed("test -e /repos2/test2");
# check without network
$share->block();
- $fsCheck->mustFail("test -e /repos1/test1");
- $fsCheck->mustFail("test -e /repos2/test2");
+ $fsCheck->fail("test -e /repos1/test1");
+ $fsCheck->fail("test -e /repos2/test2");
'';
}
diff --git a/tests/firewall.nix b/tests/firewall.nix
index b38cd988b76..de32b98e5d2 100644
--- a/tests/firewall.nix
+++ b/tests/firewall.nix
@@ -25,9 +25,9 @@
''
startAll;
- $walled->waitForJob("firewall");
- $walled->waitForJob("httpd");
- $attacker->waitForJob("network-interfaces");
+ $walled->waitForUnit("firewall");
+ $walled->waitForUnit("httpd");
+ $attacker->waitForUnit("network.target");
# Local connections should still work.
$walled->succeed("curl -v http://localhost/ >&2");
@@ -41,7 +41,7 @@
$walled->succeed("ping -c 1 attacker >&2");
# If we stop the firewall, then connections should succeed.
- $walled->succeed("stop firewall");
+ $walled->stopJob("firewall");
$attacker->succeed("curl -v http://walled/ >&2");
'';
diff --git a/tests/installer.nix b/tests/installer.nix
index d57cbb6119e..477e5c660af 100644
--- a/tests/installer.nix
+++ b/tests/installer.nix
@@ -49,7 +49,7 @@ let
boot.loader.grub.extraConfig = "serial; terminal_output.serial";
boot.initrd.kernelModules = [ "ext3" "ext4" "xfs" "virtio_console" ];
- fileSystems = [ ${fileSystems} ];
+ ${fileSystems}
swapDevices = [ { label = "swap"; } ];
environment.systemPackages = [ ${optionalString testChannel "pkgs.rlwrap"} ];
@@ -58,16 +58,12 @@ let
rootFS =
''
- { mountPoint = "/";
- device = "/dev/disk/by-label/nixos";
- }
+ fileSystems."/".device = "/dev/disk/by-label/nixos";
'';
bootFS =
''
- { mountPoint = "/boot";
- device = "/dev/disk/by-label/boot";
- }
+ fileSystems."/boot".device = "/dev/disk/by-label/boot";
'';
@@ -110,31 +106,31 @@ let
# Create a channel on the web server containing a few packages
# to simulate the Nixpkgs channel.
$webserver->start;
- $webserver->waitForJob("httpd");
+ $webserver->waitForUnit("httpd");
$webserver->succeed(
"nix-push --bzip2 --dest /tmp/channel --manifest --url-prefix http://nixos.org/channels/nixos-unstable " .
"${toString channelContents} >&2");
''}
# Make sure that we get a login prompt etc.
- $machine->mustSucceed("echo hello");
- $machine->waitForJob("tty1");
- $machine->waitForJob("rogue");
- $machine->waitForJob("nixos-manual");
- $machine->waitForJob("dhcpcd");
+ $machine->succeed("echo hello");
+ #$machine->waitForUnit('getty@tty2');
+ $machine->waitForUnit("rogue");
+ $machine->waitForUnit("nixos-manual");
+ $machine->waitForUnit("dhcpcd");
${optionalString testChannel ''
# Allow the machine to talk to the fake nixos.org.
- $machine->mustSucceed(
+ $machine->succeed(
"rm /etc/hosts",
"echo 192.168.1.1 nixos.org > /etc/hosts",
"ifconfig eth1 up 192.168.1.2",
);
# Test nix-env.
- $machine->mustFail("hello");
- $machine->mustSucceed("nix-env -i hello");
- $machine->mustSucceed("hello") =~ /Hello, world/
+ $machine->fail("hello");
+ $machine->succeed("nix-env -i hello");
+ $machine->succeed("hello") =~ /Hello, world/
or die "bad `hello' output";
''}
@@ -142,12 +138,12 @@ let
${createPartitions}
# Create the NixOS configuration.
- $machine->mustSucceed(
+ $machine->succeed(
"mkdir -p /mnt/etc/nixos",
"nixos-hardware-scan > /mnt/etc/nixos/hardware.nix",
);
- my $cfg = $machine->mustSucceed("cat /mnt/etc/nixos/hardware.nix");
+ my $cfg = $machine->succeed("cat /mnt/etc/nixos/hardware.nix");
print STDERR "Result of the hardware scan:\n$cfg\n";
$machine->copyFileFromHost(
@@ -155,10 +151,10 @@ let
"/mnt/etc/nixos/configuration.nix");
# Perform the installation.
- $machine->mustSucceed("nixos-install >&2");
+ $machine->succeed("nixos-install >&2");
# Do it again to make sure it's idempotent.
- $machine->mustSucceed("nixos-install >&2");
+ $machine->succeed("nixos-install >&2");
$machine->shutdown;
@@ -166,26 +162,25 @@ let
my $machine = createMachine({ hda => "harddisk", hdaInterface => "${iface}" });
# Did /boot get mounted, if appropriate?
- # !!! There is currently no good way to wait for the
- # `filesystems' task to finish.
- $machine->waitForFile("/boot/grub");
+ $machine->waitForUnit("local-fs.target");
+ $machine->succeed("test -e /boot/grub");
# Did the swap device get activated?
- # !!! Idem.
- $machine->waitUntilSucceeds("cat /proc/swaps | grep -q /dev");
+ $machine->waitForUnit("swap.target");
+ $machine->succeed("cat /proc/swaps | grep -q /dev");
- $machine->mustSucceed("nix-env -i coreutils >&2");
- $machine->mustSucceed("type -tP ls | tee /dev/stderr") =~ /.nix-profile/
+ $machine->succeed("nix-env -i coreutils >&2");
+ $machine->succeed("type -tP ls | tee /dev/stderr") =~ /.nix-profile/
or die "nix-env failed";
- $machine->mustSucceed("nixos-rebuild switch >&2");
+ $machine->succeed("nixos-rebuild switch >&2");
$machine->shutdown;
# And just to be sure, check that the machine still boots after
# "nixos-rebuild switch".
my $machine = createMachine({ hda => "harddisk", hdaInterface => "${iface}" });
- $machine->waitForJob("network-interfaces");
+ $machine->waitForUnit("network.target");
$machine->shutdown;
'';
@@ -209,7 +204,7 @@ in {
simple = makeTest
{ createPartitions =
''
- $machine->mustSucceed(
+ $machine->succeed(
"parted /dev/vda mklabel msdos",
"parted /dev/vda -- mkpart primary linux-swap 1M 1024M",
"parted /dev/vda -- mkpart primary ext2 1024M -1s",
@@ -228,7 +223,7 @@ in {
separateBoot = makeTest
{ createPartitions =
''
- $machine->mustSucceed(
+ $machine->succeed(
"parted /dev/vda mklabel msdos",
"parted /dev/vda -- mkpart primary ext2 1M 50MB", # /boot
"parted /dev/vda -- mkpart primary linux-swap 50MB 1024M",
@@ -251,7 +246,7 @@ in {
lvm = makeTest
{ createPartitions =
''
- $machine->mustSucceed(
+ $machine->succeed(
"parted /dev/vda mklabel msdos",
"parted /dev/vda -- mkpart primary 1M 2048M", # first PV
"parted /dev/vda -- set 1 lvm on",
@@ -274,7 +269,7 @@ in {
swraid = makeTest
{ createPartitions =
''
- $machine->mustSucceed(
+ $machine->succeed(
"parted /dev/vda --"
. " mklabel msdos"
. " mkpart primary ext2 1M 30MB" # /boot
@@ -308,7 +303,7 @@ in {
grub1 = makeTest
{ createPartitions =
''
- $machine->mustSucceed(
+ $machine->succeed(
"parted /dev/sda mklabel msdos",
"parted /dev/sda -- mkpart primary linux-swap 1M 1024M",
"parted /dev/sda -- mkpart primary ext2 1024M -1s",
@@ -335,19 +330,19 @@ in {
$machine->start;
# Enable sshd service.
- $machine->mustSucceed(
+ $machine->succeed(
"sed -i 's,^}\$,jobs.sshd.startOn = pkgs.lib.mkOverride 0 \"startup\"; },' /etc/nixos/configuration.nix"
);
- my $cfg = $machine->mustSucceed("cat /etc/nixos/configuration.nix");
+ my $cfg = $machine->succeed("cat /etc/nixos/configuration.nix");
print STDERR "New CD config:\n$cfg\n";
# Apply the new CD configuration.
- $machine->mustSucceed("nixos-rebuild test");
+ $machine->succeed("nixos-rebuild test");
# Connect to it-self.
- #$machine->waitForJob("sshd");
- #$machine->mustSucceed("ssh root@127.0.0.1 echo hello");
+ #$machine->waitForUnit("sshd");
+ #$machine->succeed("ssh root@127.0.0.1 echo hello");
$machine->shutdown;
'';
diff --git a/tests/ipv6.nix b/tests/ipv6.nix
index 4a308416aef..29d675e180a 100644
--- a/tests/ipv6.nix
+++ b/tests/ipv6.nix
@@ -31,12 +31,12 @@
testScript =
''
# Start the router first so that it respond to router solicitations.
- $router->waitForJob("radvd");
+ $router->waitForUnit("radvd");
startAll;
- $client->waitForJob("network-interfaces");
- $server->waitForJob("network-interfaces");
+ $client->waitForUnit("network.target");
+ $server->waitForUnit("network.target");
# Wait until the given interface has a non-tentative address of
# the desired scope (i.e. has completed Duplicate Address
diff --git a/tests/kde4.nix b/tests/kde4.nix
index afdf1754942..f435d983791 100644
--- a/tests/kde4.nix
+++ b/tests/kde4.nix
@@ -31,7 +31,7 @@
$machine->waitForWindow(qr/plasma-desktop/);
# Check that logging in has given the user ownership of devices.
- $machine->mustSucceed("getfacl /dev/snd/timer | grep -q alice");
+ $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
$machine->execute("su - alice -c 'DISPLAY=:0.0 kwrite /var/log/messages &'");
$machine->execute("su - alice -c 'DISPLAY=:0.0 konqueror http://localhost/ &'");
diff --git a/tests/login.nix b/tests/login.nix
index 90987782f8c..cdd6414744a 100644
--- a/tests/login.nix
+++ b/tests/login.nix
@@ -6,14 +6,23 @@
testScript =
''
+ $machine->waitForUnit("default.target");
+ $machine->screenshot("postboot");
+
subtest "create user", sub {
$machine->succeed("useradd -m alice");
$machine->succeed("(echo foobar; echo foobar) | passwd alice");
};
+ # Check whether switching VTs works.
+ subtest "virtual console switching", sub {
+ $machine->sendKeys("alt-f2");
+ $machine->waitUntilSucceeds("[ \$(fgconsole) = 2 ]");
+ $machine->waitForUnit('getty@tty2.service');
+ };
+
# Log in as alice on a virtual console.
subtest "virtual console login", sub {
- $machine->waitForJob("tty1");
$machine->sleep(2); # urgh: wait for username prompt
$machine->sendChars("alice\n");
$machine->waitUntilSucceeds("pgrep login");
@@ -24,28 +33,19 @@
$machine->waitForFile("/home/alice/done");
};
- # Check whether switching VTs works.
- subtest "virtual console switching", sub {
- $machine->sendKeys("alt-f10");
- $machine->waitUntilSucceeds("[ \$(fgconsole) = 10 ]");
- $machine->sleep(2); # allow fbcondecor to catch up (not important)
- $machine->screenshot("syslog");
- };
-
- # Check whether ConsoleKit/udev gives and removes device
- # ownership as needed.
+ # Check whether systemd gives and removes device ownership as
+ # needed.
subtest "device permissions", sub {
+ $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
+ $machine->sendKeys("alt-f1");
+ $machine->waitUntilSucceeds("[ \$(fgconsole) = 1 ]");
$machine->fail("getfacl /dev/snd/timer | grep -q alice");
- $machine->succeed("chvt 1");
- $machine->waitUntilSucceeds("getfacl /dev/snd/timer | grep -q alice");
$machine->succeed("chvt 2");
- $machine->sleep(2); # urgh
- $machine->fail("getfacl /dev/snd/timer | grep -q alice");
+ $machine->waitUntilSucceeds("getfacl /dev/snd/timer | grep -q alice");
};
# Log out.
subtest "virtual console logout", sub {
- $machine->succeed("chvt 1");
$machine->sendChars("exit\n");
$machine->waitUntilFails("pgrep -u alice bash");
$machine->screenshot("mingetty");
diff --git a/tests/misc.nix b/tests/misc.nix
index 8501d6a0979..9f85877e8bb 100644
--- a/tests/misc.nix
+++ b/tests/misc.nix
@@ -30,7 +30,7 @@
# Test that the swap file got created.
subtest "swapfile", sub {
- $machine->waitUntilSucceeds("cat /proc/swaps | grep /root/swapfile");
+ $machine->waitForUnit("root-swapfile.swap");
$machine->succeed("ls -l /root/swapfile | grep 134217728");
};
'';
diff --git a/tests/mpich.nix b/tests/mpich.nix
index 0b81bc1d0de..d57512ebdfe 100644
--- a/tests/mpich.nix
+++ b/tests/mpich.nix
@@ -24,17 +24,17 @@ with pkgs;
''
startAll;
- $master->mustSucceed("echo 'MPD_SECRETWORD=secret' > /etc/mpd.conf");
- $master->mustSucceed("chmod 600 /etc/mpd.conf");
- $master->mustSucceed("mpd --daemon --ifhn=master --listenport=4444");
+ $master->succeed("echo 'MPD_SECRETWORD=secret' > /etc/mpd.conf");
+ $master->succeed("chmod 600 /etc/mpd.conf");
+ $master->succeed("mpd --daemon --ifhn=master --listenport=4444");
- $slave->mustSucceed("echo 'MPD_SECRETWORD=secret' > /etc/mpd.conf");
- $slave->mustSucceed("chmod 600 /etc/mpd.conf");
- $slave->mustSucceed("mpd --daemon --host=master --port=4444");
+ $slave->succeed("echo 'MPD_SECRETWORD=secret' > /etc/mpd.conf");
+ $slave->succeed("chmod 600 /etc/mpd.conf");
+ $slave->succeed("mpd --daemon --host=master --port=4444");
- $master->mustSucceed("mpicc -o example -Wall ${./mpich-example.c}");
- $slave->mustSucceed("mpicc -o example -Wall ${./mpich-example.c}");
+ $master->succeed("mpicc -o example -Wall ${./mpich-example.c}");
+ $slave->succeed("mpicc -o example -Wall ${./mpich-example.c}");
- $master->mustSucceed("mpiexec -n 2 ./example >&2");
+ $master->succeed("mpiexec -n 2 ./example >&2");
'';
}
diff --git a/tests/mysql-replication.nix b/tests/mysql-replication.nix
index 5ac7f0a5097..28a1187dd18 100644
--- a/tests/mysql-replication.nix
+++ b/tests/mysql-replication.nix
@@ -48,10 +48,10 @@ in
testScript = ''
startAll;
- $master->waitForJob("mysql");
- $master->waitForJob("mysql");
- $slave2->waitForJob("mysql");
+ $master->waitForUnit("mysql");
+ $master->waitForUnit("mysql");
+ $slave2->waitForUnit("mysql");
$slave2->sleep(100); # Hopefully this is long enough!!
- $slave2->mustSucceed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
+ $slave2->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
'';
}
diff --git a/tests/mysql.nix b/tests/mysql.nix
index 65785c8fdb5..b48850738b7 100644
--- a/tests/mysql.nix
+++ b/tests/mysql.nix
@@ -15,8 +15,8 @@
testScript = ''
startAll;
- $master->waitForJob("mysql");
+ $master->waitForUnit("mysql");
$master->sleep(10); # Hopefully this is long enough!!
- $master->mustSucceed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
+ $master->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
'';
}
diff --git a/tests/nat.nix b/tests/nat.nix
index 5adbf3ce57d..55d87ed4fa1 100644
--- a/tests/nat.nix
+++ b/tests/nat.nix
@@ -13,7 +13,7 @@
{ config, pkgs, nodes, ... }:
{ virtualisation.vlans = [ 1 ];
networking.defaultGateway =
- nodes.router.config.networking.ifaces.eth2.ipAddress;
+ nodes.router.config.networking.interfaces.eth2.ipAddress;
};
router =
@@ -40,18 +40,19 @@
startAll;
# The router should have access to the server.
- $server->waitForJob("httpd");
- $router->waitForJob("network-interfaces");
+ $server->waitForUnit("network.target");
+ $server->waitForUnit("httpd");
+ $router->waitForUnit("network.target");
$router->succeed("curl --fail http://server/ >&2");
# The client should be also able to connect via the NAT router.
- $router->waitForJob("nat");
- $client->waitForJob("network-interfaces");
+ $router->waitForUnit("nat");
+ $client->waitForUnit("network.target");
$client->succeed("curl --fail http://server/ >&2");
$client->succeed("ping -c 1 server >&2");
# Test whether passive FTP works.
- $server->waitForJob("vsftpd");
+ $server->waitForUnit("vsftpd");
$server->succeed("echo Hello World > /home/ftp/foo.txt");
$client->succeed("curl -v ftp://server/foo.txt >&2");
@@ -63,12 +64,12 @@
$router->succeed("ping -c 1 client >&2");
# If we turn off NAT, the client shouldn't be able to reach the server.
- $router->succeed("stop nat");
+ $router->stopJob("nat");
$client->fail("curl --fail --connect-timeout 5 http://server/ >&2");
$client->fail("ping -c 1 server >&2");
# And make sure that restarting the NAT job works.
- $router->succeed("start nat");
+ $router->succeed("systemctl start nat");
$client->succeed("curl --fail http://server/ >&2");
$client->succeed("ping -c 1 server >&2");
'';
diff --git a/tests/nfs.nix b/tests/nfs.nix
index 7c1ff5e9212..7c10eec310c 100644
--- a/tests/nfs.nix
+++ b/tests/nfs.nix
@@ -8,7 +8,7 @@ let
[ { mountPoint = "/data";
device = "server:/data";
fsType = "nfs";
- options = "bootwait,vers=3";
+ options = "vers=3";
}
];
};
@@ -34,20 +34,21 @@ in
testScript =
''
- $server->waitForJob("nfsd");
+ $server->waitForUnit("nfsd");
+ $server->waitForUnit("network.target");
startAll;
- $client1->waitForJob("tty1"); # depends on filesystems
+ $client1->waitForUnit("data.mount");
$client1->succeed("echo bla > /data/foo");
$server->succeed("test -e /data/foo");
- $client2->waitForJob("tty1"); # depends on filesystems
+ $client2->waitForUnit("data.mount");
$client2->succeed("echo bla > /data/bar");
$server->succeed("test -e /data/bar");
# Test whether restarting ‘nfsd’ works correctly.
- $server->succeed("stop nfsd; start nfsd");
+ $server->succeed("systemctl restart nfsd");
$client2->succeed("echo bla >> /data/bar"); # will take 90 seconds due to the NFS grace period
# Test whether we can get a lock.
@@ -66,7 +67,7 @@ in
$client2->waitForFile("locked");
# Test whether locks survive a reboot of the server.
- $client1->waitForJob("tty1"); # depends on filesystems
+ $client1->waitForUnit("data.mount");
$server->shutdown;
$server->start;
$client1->succeed("touch /data/xyzzy");
diff --git a/tests/openssh.nix b/tests/openssh.nix
index 5818c9d6ceb..16757cf9098 100644
--- a/tests/openssh.nix
+++ b/tests/openssh.nix
@@ -20,16 +20,16 @@
my $key=`${pkgs.openssh}/bin/ssh-keygen -t dsa -f key -N ""`;
- $server->waitForJob("sshd");
+ $server->waitForUnit("sshd");
- $server->mustSucceed("mkdir -m 700 /root/.ssh");
+ $server->succeed("mkdir -m 700 /root/.ssh");
$server->copyFileFromHost("key.pub", "/root/.ssh/authorized_keys");
- $client->mustSucceed("mkdir -m 700 /root/.ssh");
+ $client->succeed("mkdir -m 700 /root/.ssh");
$client->copyFileFromHost("key", "/root/.ssh/id_dsa");
- $client->mustSucceed("chmod 600 /root/.ssh/id_dsa");
+ $client->succeed("chmod 600 /root/.ssh/id_dsa");
- $client->waitForJob("network-interfaces");
- $client->mustSucceed("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world'");
+ $client->waitForUnit("network.target");
+ $client->succeed("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2");
'';
}
diff --git a/tests/portmap.nix b/tests/portmap.nix
index 4ee4eb02890..0d2bf153685 100644
--- a/tests/portmap.nix
+++ b/tests/portmap.nix
@@ -11,7 +11,7 @@
''
# The `portmap' service must be registered once for TCP and once for
# UDP.
- $machine->mustSucceed("test `rpcinfo -p | grep portmapper | wc -l` -eq 2");
+ $machine->succeed("test `rpcinfo -p | grep portmapper | wc -l` -eq 2");
'';
}
diff --git a/tests/proxy.nix b/tests/proxy.nix
index 323b548de74..3b79c16ea2c 100644
--- a/tests/proxy.nix
+++ b/tests/proxy.nix
@@ -62,33 +62,33 @@ in
''
startAll;
- $proxy->waitForJob("httpd");
- $backend1->waitForJob("httpd");
- $backend2->waitForJob("httpd");
+ $proxy->waitForUnit("httpd");
+ $backend1->waitForUnit("httpd");
+ $backend2->waitForUnit("httpd");
# With the back-ends up, the proxy should work.
- $client->mustSucceed("curl --fail http://proxy/");
+ $client->succeed("curl --fail http://proxy/");
- $client->mustSucceed("curl --fail http://proxy/server-status");
+ $client->succeed("curl --fail http://proxy/server-status");
# Block the first back-end.
$backend1->block;
# The proxy should still work.
- $client->mustSucceed("curl --fail http://proxy/");
+ $client->succeed("curl --fail http://proxy/");
- $client->mustSucceed("curl --fail http://proxy/");
+ $client->succeed("curl --fail http://proxy/");
# Block the second back-end.
$backend2->block;
# Now the proxy should fail as well.
- $client->mustFail("curl --fail http://proxy/");
+ $client->fail("curl --fail http://proxy/");
# But if the second back-end comes back, the proxy should start
# working again.
$backend2->unblock;
- $client->mustSucceed("curl --fail http://proxy/");
+ $client->succeed("curl --fail http://proxy/");
'';
}
diff --git a/tests/quake3.nix b/tests/quake3.nix
index fbd0adab2fa..041cfdb29ae 100644
--- a/tests/quake3.nix
+++ b/tests/quake3.nix
@@ -28,9 +28,8 @@ rec {
{ server =
{ config, pkgs, ... }:
- { jobs.quake3Server =
- { name = "quake3-server";
- startOn = "startup";
+ { jobs."quake3-server" =
+ { startOn = "startup";
exec =
"${pkgs.quake3demo}/bin/quake3-server '+set g_gametype 0' " +
"'+map q3dm7' '+addbot grunt' '+addbot daemia' 2> /tmp/log";
@@ -46,7 +45,7 @@ rec {
''
startAll;
- $server->waitForJob("quake3-server");
+ $server->waitForUnit("quake3-server");
$client1->waitForX;
$client2->waitForX;
@@ -74,7 +73,7 @@ rec {
$client1->shutdown();
$client2->shutdown();
- $server->succeed("stop quake3-server");
+ $server->stopJob("quake3-server");
'';
}
diff --git a/tests/subversion.nix b/tests/subversion.nix
index fb8bba93806..309da90c5df 100644
--- a/tests/subversion.nix
+++ b/tests/subversion.nix
@@ -41,7 +41,7 @@ in
services.httpd.enable = true;
services.httpd.adminAddr = "e.dolstra@tudelft.nl";
services.httpd.extraSubservices =
- [ { serviceType = "subversion";
+ [ { function = import ;
urlPrefix = "";
dataDir = "/data/subversion";
userCreationDomain = "192.168.0.0/16";
@@ -66,33 +66,33 @@ in
$webserver->waitForOpenPort(80);
- print STDERR $client->mustSucceed("svn --version");
+ print STDERR $client->succeed("svn --version");
- print STDERR $client->mustSucceed("curl --fail http://webserver/");
+ print STDERR $client->succeed("curl --fail http://webserver/");
# Create a new user through the web interface.
- $client->mustSucceed("curl --fail -F username=alice -F fullname='Alice Lastname' -F address=alice\@example.org -F password=foobar -F password_again=foobar http://webserver/repoman/adduser");
+ $client->succeed("curl --fail -F username=alice -F fullname='Alice Lastname' -F address=alice\@example.org -F password=foobar -F password_again=foobar http://webserver/repoman/adduser");
# Let Alice create a new repository.
- $client->mustSucceed("curl --fail -u alice:foobar --form repo=xyzzy --form description=Xyzzy http://webserver/repoman/create");
+ $client->succeed("curl --fail -u alice:foobar --form repo=xyzzy --form description=Xyzzy http://webserver/repoman/create");
- $client->mustSucceed("curl --fail http://webserver/") =~ /alice/ or die;
+ $client->succeed("curl --fail http://webserver/") =~ /alice/ or die;
# Let Alice do a checkout.
my $svnFlags = "--non-interactive --username alice --password foobar";
- $client->mustSucceed("svn co $svnFlags http://webserver/repos/xyzzy wc");
- $client->mustSucceed("echo hello > wc/world");
- $client->mustSucceed("svn add wc/world");
- $client->mustSucceed("svn ci $svnFlags -m 'Added world.' wc/world");
+ $client->succeed("svn co $svnFlags http://webserver/repos/xyzzy wc");
+ $client->succeed("echo hello > wc/world");
+ $client->succeed("svn add wc/world");
+ $client->succeed("svn ci $svnFlags -m 'Added world.' wc/world");
# Create a new user on the server through the create-user.pl script.
$webserver->execute("svn-server-create-user.pl bob bob\@example.org Bob");
- $webserver->mustSucceed("svn-server-resetpw.pl bob fnord");
- $client->mustSucceed("curl --fail http://webserver/") =~ /bob/ or die;
+ $webserver->succeed("svn-server-resetpw.pl bob fnord");
+ $client->succeed("curl --fail http://webserver/") =~ /bob/ or die;
# Bob should not have access to the repo.
my $svnFlagsBob = "--non-interactive --username bob --password fnord";
- $client->mustFail("svn co $svnFlagsBob http://webserver/repos/xyzzy wc2");
+ $client->fail("svn co $svnFlagsBob http://webserver/repos/xyzzy wc2");
# Bob should not be able change the ACLs of the repo.
# !!! Repoman should really return a 403 here.
@@ -100,15 +100,15 @@ in
=~ /not authorised/ or die;
# Give Bob access.
- $client->mustSucceed("curl --fail -u alice:foobar -F description=Xyzzy -F readers=alice,bob -F writers=alice -F watchers= -F tardirs= http://webserver/repoman/update/xyzzy");
+ $client->succeed("curl --fail -u alice:foobar -F description=Xyzzy -F readers=alice,bob -F writers=alice -F watchers= -F tardirs= http://webserver/repoman/update/xyzzy");
# So now his checkout should succeed.
- $client->mustSucceed("svn co $svnFlagsBob http://webserver/repos/xyzzy wc2");
+ $client->succeed("svn co $svnFlagsBob http://webserver/repos/xyzzy wc2");
# Test ViewVC and WebSVN
- $client->mustSucceed("curl --fail -u alice:foobar http://webserver/viewvc/xyzzy");
- $client->mustSucceed("curl --fail -u alice:foobar http://webserver/websvn/xyzzy");
- $client->mustSucceed("curl --fail -u alice:foobar http://webserver/repos-xml/xyzzy");
+ $client->succeed("curl --fail -u alice:foobar http://webserver/viewvc/xyzzy");
+ $client->succeed("curl --fail -u alice:foobar http://webserver/websvn/xyzzy");
+ $client->succeed("curl --fail -u alice:foobar http://webserver/repos-xml/xyzzy");
# Stop Apache to gather all the coverage data.
$webserver->stopJob("httpd");
diff --git a/tests/test-upstart-job.sh b/tests/test-upstart-job.sh
deleted file mode 100755
index d0fba23d625..00000000000
--- a/tests/test-upstart-job.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#! /bin/sh -e
-
-for i in $*; do
- echo "building job $i..."
- nix-build /etc/nixos/nixos -A "config.jobs.$i" -o $tmpDir/.result
- # !!! Here we assume that the attribute name equals the Upstart
- # job name.
- ln -sfn $(readlink -f $tmpDir/.result) /etc/init/"$i".conf
-done
-
-echo "restarting init..."
-initctl reload-configuration
-
-sleep 1
-
-for i in $*; do
- echo "restarting job $i..."
- initctl stop "$i" || true
- initctl start "$i"
-done
diff --git a/tests/tomcat.nix b/tests/tomcat.nix
index 0726a782250..c25276aa424 100644
--- a/tests/tomcat.nix
+++ b/tests/tomcat.nix
@@ -23,9 +23,9 @@
testScript = ''
startAll;
- $server->waitForJob("tomcat");
+ $server->waitForUnit("tomcat");
$server->sleep(30); # Dirty, but it takes a while before Tomcat handles to requests properly
- $client->waitForJob("network-interfaces");
+ $client->waitForUnit("network.target");
$client->succeed("curl --fail http://server/examples/servlets/servlet/HelloWorldExample");
$client->succeed("curl --fail http://server/examples/jsp/jsp2/simpletag/hello.jsp");
'';
diff --git a/tests/trac.nix b/tests/trac.nix
index 254996c2440..335d9473704 100644
--- a/tests/trac.nix
+++ b/tests/trac.nix
@@ -33,8 +33,7 @@
fileSystems = pkgs.lib.mkOverride 50
[ { mountPoint = "/repos";
device = "storage:/repos";
- fsType = "nfs";
- options = "bootwait";
+ fsType = "nfs";
}
];
@@ -56,15 +55,15 @@
''
startAll;
- $postgresql->waitForJob("postgresql");
- $postgresql->mustSucceed("createdb trac");
+ $postgresql->waitForUnit("postgresql");
+ $postgresql->succeed("createdb trac");
- $webserver->mustSucceed("mkdir -p /repos/trac");
- $webserver->mustSucceed("svnadmin create /repos/trac");
+ $webserver->succeed("mkdir -p /repos/trac");
+ $webserver->succeed("svnadmin create /repos/trac");
$webserver->waitForFile("/var/trac");
- $webserver->mustSucceed("mkdir -p /var/trac/projects/test");
- $webserver->mustSucceed("PYTHONPATH=${pkgs.pythonPackages.psycopg2}/lib/${pkgs.python.libPrefix}/site-packages trac-admin /var/trac/projects/test initenv Test postgres://root\@postgresql/trac svn /repos/trac");
+ $webserver->succeed("mkdir -p /var/trac/projects/test");
+ $webserver->succeed("PYTHONPATH=${pkgs.pythonPackages.psycopg2}/lib/${pkgs.python.libPrefix}/site-packages trac-admin /var/trac/projects/test initenv Test postgres://root\@postgresql/trac svn /repos/trac");
$client->waitForX;
$client->execute("konqueror http://webserver/projects/test &");