From bc1e478db160059753c4bf4cb28dd50437a76b27 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 3 Feb 2010 15:34:52 +0000 Subject: [PATCH] * nix-copy-closure: start only one SSH connection to the server, or recycle an already existing connection (using OpenSSH's connection sharing feature). --- scripts/Makefile.am | 2 ++ scripts/nix-copy-closure.in | 16 +++++++++++----- scripts/ssh.pm | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 scripts/ssh.pm diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 0e8443e9c2..aa5d6f78c1 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -15,6 +15,7 @@ install-exec-local: readmanifest.pm download-using-manifests.pl copy-from-other- $(INSTALL) -d $(DESTDIR)$(libexecdir)/nix $(INSTALL_DATA) readmanifest.pm $(DESTDIR)$(libexecdir)/nix $(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix + $(INSTALL_DATA) ssh.pm $(DESTDIR)$(libexecdir)/nix $(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix $(INSTALL_PROGRAM) generate-patches.pl $(DESTDIR)$(libexecdir)/nix $(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix @@ -31,6 +32,7 @@ EXTRA_DIST = nix-collect-garbage.in \ nix-channel.in \ readmanifest.pm.in \ readconfig.pm.in \ + ssh.pm \ nix-build.in \ download-using-manifests.pl.in \ copy-from-other-stores.pl.in \ diff --git a/scripts/nix-copy-closure.in b/scripts/nix-copy-closure.in index 4f31953b92..313d6f0192 100644 --- a/scripts/nix-copy-closure.in +++ b/scripts/nix-copy-closure.in @@ -1,4 +1,6 @@ -#! @perl@ -w +#! @perl@ -w -I@libexecdir@/nix + +use ssh; my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@"; @@ -14,7 +16,6 @@ EOF # Get the target host. my $sshHost; -my @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or ""); my $sign = 0; @@ -52,6 +53,9 @@ while (@ARGV) { } +openSSHConnection $sshHost; + + if ($toMode) { # Copy TO the remote machine. my @allStorePaths; @@ -73,7 +77,6 @@ if ($toMode) { # Copy TO the remote machine. my @missing = (); while () { chomp; - print STDERR "target machine needs $_\n"; push @missing, $_; } close READ or die; @@ -81,6 +84,8 @@ if ($toMode) { # Copy TO the remote machine. # Export the store paths and import them on the remote machine. if (scalar @missing > 0) { + print STDERR "copying these missing paths:\n"; + print STDERR " $_\n" foreach @missing; my $extraOpts = ""; $extraOpts .= "--sign" if $sign == 1; system("nix-store --export $extraOpts @missing | $compressor | ssh @sshOpts $sshHost '$decompressor | nix-store --import'") == 0 @@ -114,7 +119,6 @@ else { # Copy FROM the remote machine. my @missing = (); while () { chomp; - print STDERR "local machine needs $_\n"; push @missing, $_; } close READ or die; @@ -122,10 +126,12 @@ else { # Copy FROM the remote machine. # Export the store paths on the remote machine and import them on locally. if (scalar @missing > 0) { + print STDERR "copying these missing paths:\n"; + print STDERR " $_\n" foreach @missing; my $extraOpts = ""; $extraOpts .= "--sign" if $sign == 1; system("ssh @sshOpts $sshHost 'nix-store --export $extraOpts @missing | $compressor' | $decompressor | @bindir@/nix-store --import") == 0 - or die "copying store paths to remote machine `$sshHost' failed: $?"; + or die "copying store paths from remote machine `$sshHost' failed: $?"; } } diff --git a/scripts/ssh.pm b/scripts/ssh.pm new file mode 100644 index 0000000000..0295cef33b --- /dev/null +++ b/scripts/ssh.pm @@ -0,0 +1,36 @@ +use strict; +use File::Temp qw(tempdir); + +our @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or ""); + +my $sshStarted = 0; +my $sshHost; + +# Open a master SSH connection to `host', unless there already is a +# running master connection (as determined by `-O check'). +sub openSSHConnection { + my ($host) = @_; + die if $sshStarted; + $sshHost = $host; + return if system("ssh $sshHost @sshOpts -O check 2> /dev/null") == 0; + + my $tmpDir = tempdir("nix-ssh.XXXXXX", CLEANUP => 1, TMPDIR => 1) + or die "cannot create a temporary directory"; + + push @sshOpts, "-S", "$tmpDir/control"; + system("ssh $sshHost @sshOpts -M -N -f") == 0 + or die "unable to start SSH: $?"; + $sshStarted = 1; +} + +# Tell the master SSH client to exit. +sub closeSSHConnection { + if ($sshStarted) { + system("ssh $sshHost @sshOpts -O exit 2> /dev/null") == 0 + or warn "unable to stop SSH master: $?"; + } +} + +END { closeSSHConnection; } + +return 1;