From 6773babd5b75d34afa850351fd292310e3dd3fc8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 27 Aug 2014 19:31:22 +0200 Subject: [PATCH] Containers: Use nsenter to execute commands in containers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove ‘nixos-container set-root-password’, which is kind of pointless now. --- .../virtualisation/container-config.nix | 71 ------------------- nixos/modules/virtualisation/containers.nix | 7 +- .../modules/virtualisation/nixos-container.pl | 40 +++++------ 3 files changed, 23 insertions(+), 95 deletions(-) diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index 84e3aa283520..a7e8953827a6 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -18,77 +18,6 @@ with lib; # Shut up warnings about not having a boot loader. system.build.installBootLoader = "${pkgs.coreutils}/bin/true"; - # Provide a root login prompt on /var/lib/root-login.socket that - # doesn't ask for a password. This socket can only be used by root - # on the host. - systemd.sockets.root-login = - { description = "Root Login Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/root-login.socket"; - SocketMode = "0600"; - Accept = true; - }; - }; - - systemd.services."root-login@" = - { description = "Root Login %i"; - environment.TERM = "linux"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - ExecStart = "${pkgs.socat}/bin/socat -t0 - \"exec:${pkgs.shadow}/bin/login -f root,pty,setsid,setpgid,stderr,ctty\""; - TimeoutStopSec = 1; # FIXME - }; - restartIfChanged = false; - }; - - # Provide a daemon on /var/lib/run-command.socket that reads a - # command from stdin and executes it. - systemd.sockets.run-command = - { description = "Run Command Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/run-command.socket"; - SocketMode = "0600"; # only root can connect - Accept = true; - }; - }; - - systemd.services."run-command@" = - { description = "Run Command %i"; - environment.TERM = "linux"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - TimeoutStopSec = 1; # FIXME - }; - script = - '' - #! ${pkgs.stdenv.shell} -e - source /etc/bashrc - read c - eval "command=($c)" - exec "''${command[@]}" - ''; - restartIfChanged = false; - }; - - 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; - restartIfChanged = false; - }; - systemd.services.systemd-remount-fs.enable = false; }; diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 292b96e6eb24..d62340f2c798 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -10,7 +10,7 @@ let isExecutable = true; src = ./nixos-container.pl; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; - inherit (pkgs) socat; + inherit (pkgs) utillinux; }; # The container's init script, a small wrapper around the regular @@ -254,9 +254,8 @@ in ExecReload = pkgs.writeScript "reload-container" '' #! ${pkgs.stdenv.shell} -e - SYSTEM_PATH=/nix/var/nix/profiles/system - echo $SYSTEM_PATH/bin/switch-to-configuration test | \ - ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket - + ${nixos-container}/bin/nixos-container run "$INSTANCE" -- \ + bash --login -c "/nix/var/nix/profiles/system/bin/switch-to-configuration test" ''; SyslogIdentifier = "container %i"; diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl index bf6f16fc6c77..b829eeb05790 100644 --- a/nixos/modules/virtualisation/nixos-container.pl +++ b/nixos/modules/virtualisation/nixos-container.pl @@ -7,7 +7,7 @@ use File::Slurp; use Fcntl ':flock'; use Getopt::Long qw(:config gnu_getopt); -my $socat = '@socat@/bin/socat'; +my $nsenter = "@utillinux@/bin/nsenter"; # Ensure a consistent umask. umask 0022; @@ -25,7 +25,6 @@ Usage: nixos-container list nixos-container login nixos-container root-login nixos-container run -- args... - nixos-container set-root-password nixos-container show-ip nixos-container show-host-key EOF @@ -186,6 +185,23 @@ sub stopContainer { or die "$0: failed to stop container\n"; } +# Return the PID of the init process of the container. +sub getLeader { + my $s = `machinectl show "$containerName" -p Leader`; + chomp $s; + $s =~ /^Leader=(\d+)$/ or die "unable to get container's main PID\n"; + return int($1); +} + +# Run a command in the container. +sub runInContainer { + my @args = @_; + my $leader = getLeader; + # FIXME: initialise the environment properly. + exec($nsenter, "-t", $leader, "-m", "-u", "-i", "-n", "-p", "--", "env", "-i", "--", @args); + die "cannot run ‘nsenter’: $!\n"; +} + if ($action eq "destroy") { die "$0: cannot destroy declarative container (remove it from your configuration.nix instead)\n" unless POSIX::access($confFile, &POSIX::W_OK); @@ -235,28 +251,12 @@ elsif ($action eq "login") { } elsif ($action eq "root-login") { - exec($socat, "unix:$root/var/lib/root-login.socket", "-,echo=0,raw"); + runInContainer("bash", "--login"); } elsif ($action eq "run") { shift @ARGV; shift @ARGV; - my $pid = open(SOCAT, "|-", $socat, "-t0", "-", "unix:$root/var/lib/run-command.socket") or die "$0: cannot start $socat: $!\n"; - print SOCAT join(' ', map { "'$_'" } @ARGV), "\n"; - flush SOCAT; - waitpid($pid, 0); - close(SOCAT); -} - -elsif ($action eq "set-root-password") { - # FIXME: don't get password from the command line. - my $password = $ARGV[2] or die "$0: no password given\n"; - my $pid = open(SOCAT, "|-", $socat, "-t0", "-", "unix:$root/var/lib/run-command.socket") or die "$0: cannot start $socat: $!\n"; - print SOCAT "passwd\n"; - print SOCAT "$password\n"; - print SOCAT "$password\n"; - flush SOCAT; - waitpid($pid, 0); - close(SOCAT); + runInContainer(@ARGV); } elsif ($action eq "show-ip") {