From 1ad9a654be1120a6844c9eb7520188e874178ebe Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 Apr 2014 16:02:53 +0200 Subject: Make starting a container synchronous So now "systemctl start container@foo" will only return after the container has reached multi-user.target. --- nixos/modules/virtualisation/container-config.nix | 72 +++++++++++++++++++++++ nixos/modules/virtualisation/container-login.nix | 58 ------------------ nixos/modules/virtualisation/containers.nix | 25 +++++++- 3 files changed, 94 insertions(+), 61 deletions(-) create mode 100644 nixos/modules/virtualisation/container-config.nix delete mode 100644 nixos/modules/virtualisation/container-login.nix diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix new file mode 100644 index 000000000000..3d107899e4fe --- /dev/null +++ b/nixos/modules/virtualisation/container-config.nix @@ -0,0 +1,72 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + + config = mkIf config.boot.isContainer { + + # Provide a login prompt on /var/lib/login.socket. On the host, + # you can connect to it by running ‘socat + # unix:/var/lib/login.socket -,echo=0,raw’. + systemd.sockets.login = + { description = "Login Socket"; + wantedBy = [ "sockets.target" ]; + socketConfig = + { ListenStream = "/var/lib/login.socket"; + SocketMode = "0666"; + Accept = true; + }; + }; + + systemd.services."login@" = + { description = "Login %i"; + environment.TERM = "linux"; + serviceConfig = + { Type = "simple"; + StandardInput = "socket"; + ExecStart = "${pkgs.socat}/bin/socat -t0 - exec:${pkgs.shadow}/bin/login,pty,setsid,setpgid,stderr,ctty"; + TimeoutStopSec = 1; # FIXME + }; + }; + + # Provide a non-interactive login root shell on + # /var/lib/root-shell.socket. On the host, you can connect to it + # by running ‘socat unix:/var/lib/root-shell.socket -’. + systemd.sockets.root-shell = + { description = "Root Shell Socket"; + wantedBy = [ "sockets.target" ]; + socketConfig = + { ListenStream = "/var/lib/root-shell.socket"; + SocketMode = "0600"; # only root can connect, obviously + Accept = true; + }; + }; + + systemd.services."root-shell@" = + { description = "Root Shell %i"; + serviceConfig = + { Type = "simple"; + StandardInput = "socket"; + ExecStart = "${pkgs.bash}/bin/bash --login"; + TimeoutStopSec = 1; # FIXME + }; + }; + + systemd.services.container-startup-done = + { description = "Container Startup Notification"; + wantedBy = [ "multi-user.target" ]; + after = [ "multi-user.target" ]; + script = + '' + if [ -p /var/lib/startup-done ]; then + echo done > /var/lib/startup-done + fi + ''; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + }; + + }; + +} diff --git a/nixos/modules/virtualisation/container-login.nix b/nixos/modules/virtualisation/container-login.nix deleted file mode 100644 index fb5e333b32ab..000000000000 --- a/nixos/modules/virtualisation/container-login.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -{ - - config = mkIf config.boot.isContainer { - - # Provide a login prompt on /var/lib/login.socket. On the host, - # you can connect to it by running ‘socat - # unix:/var/lib/login.socket -,echo=0,raw’. - systemd.sockets.login = - { description = "Login Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/login.socket"; - SocketMode = "0666"; - Accept = true; - }; - }; - - systemd.services."login@" = - { description = "Login %i"; - environment.TERM = "linux"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - ExecStart = "${pkgs.socat}/bin/socat -t0 - exec:${pkgs.shadow}/bin/login,pty,setsid,setpgid,stderr,ctty"; - TimeoutStopSec = 1; # FIXME - }; - }; - - # Provide a non-interactive login root shell on - # /var/lib/root-shell.socket. On the host, you can connect to it - # by running ‘socat unix:/var/lib/root-shell.socket -’. - systemd.sockets.root-shell = - { description = "Root Shell Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/root-shell.socket"; - SocketMode = "0600"; # only root can connect, obviously - Accept = true; - }; - }; - - systemd.services."root-shell@" = - { description = "Root Shell %i"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - ExecStart = "${pkgs.bash}/bin/bash --login"; - TimeoutStopSec = 1; # FIXME - }; - }; - - }; - -} diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 6c8a6f876c8d..9be79cec3695 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -150,11 +150,21 @@ in path = [ pkgs.iproute ]; environment.INSTANCE = "%i"; + environment.root = "/var/lib/containers/%i"; + + preStart = + '' + mkdir -p -m 0755 $root/var/lib + + # Create a named pipe to get a signal when the container + # has finished booting. + rm -f $root/var/lib/startup-done + mkfifo $root/var/lib/startup-done + ''; script = '' - root="/var/lib/containers/$INSTANCE" - mkdir -p -m 0755 "$root/etc" + mkdir -p -m 0755 "$root/etc" "$root/var/lib" if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -209,6 +219,13 @@ in "$SYSTEM_PATH/init" ''; + postStart = + '' + # This blocks until the container-startup-done service + # writes something to this pipe. + read x < $root/var/lib/startup-done + ''; + preStop = '' pid="$(cat /sys/fs/cgroup/systemd/machine/$INSTANCE.nspawn/system/tasks 2> /dev/null)" @@ -238,8 +255,10 @@ in . "/etc/containers/$INSTANCE.conf" fi echo $SYSTEM_PATH/bin/switch-to-configuration test | \ - ${pkgs.socat}/bin/socat unix:/var/lib/containers/$INSTANCE/var/lib/root-shell.socket - + ${pkgs.socat}/bin/socat unix:$root/var/lib/root-shell.socket - ''; + + serviceConfig.SyslogIdentifier = "container %i"; }; # Generate a configuration file in /etc/containers for each -- cgit 1.4.1