Containers: Use nsenter to execute commands in containers

Also remove ‘nixos-container set-root-password’, which is kind of
pointless now.
This commit is contained in:
Eelco Dolstra 2014-08-27 19:31:22 +02:00
parent 9c7a598713
commit 6773babd5b
3 changed files with 23 additions and 95 deletions

View file

@ -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;
};

View file

@ -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";

View file

@ -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 <container-name>
nixos-container root-login <container-name>
nixos-container run <container-name> -- args...
nixos-container set-root-password <container-name> <password>
nixos-container show-ip <container-name>
nixos-container show-host-key <container-name>
EOF
@ -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") {