Setzen Sie scp (1), sftp (1) oder rsync (1) für die Übertragung einer Named Pipe ein

4

Ich beabsichtige, vollständige und inkrementelle Sicherungen meiner btrfs-Subvolumes an einen Bandarchivierungsdienst zu übertragen. Der Dienst macht FTP- und SSH-Endpunkte verfügbar. Wenn ich beliebige Befehle auf dem SSH-Endpunkt ausführen dürfe, würde ich Folgendes tun, um eine Teilsicherung durchzuführen:

btrfs send -p $LAST_SUBVOLUME $NEXT_SUBVOLUME | compress | encrypt |
    ssh -p $PORT $USER@$ENDPOINT "cat > $SUBVOLUME.$YYYYMMDD.btrfs.bz2.gpg"

Das darf ich aber nicht:

$ ssh -p $PORT $USER@$ENDPOINT
Last login: Mon Jan  3 01:23:45 2067 from 123.456.789.123

This account is restricted by rssh.
Allowed commands: scp sftp rsync 

If you believe this is in error, please contact your system administrator.

Connection to some.remote.endpoint closed.

Stattdessen wollte ich das SCP-Protokoll für die Übertragung verwenden. Meine scpBinärdatei weigert sich jedoch, eine Named Pipe zu übertragen:

$ scp -P $PORT <(btrfs send -p $LAST_SUBVOLUME $NEXT_SUBVOLUME | compress | encrypt) \
    $USER@$ENDPOINT:$SUBVOLUME.$YYYYMMDD.btrfs.bz2.gpg
/dev/fd/63: not a regular file

Die Ironie ist, dass man anscheinend scpeinmal das Richtige getan hat . Ich nehme an, nicht jeder hat gedacht, dass das Übertragen von Named Pipes vernünftig / nützlich sein könnte. BEARBEITEN (03.06.2017): Dies war eine falsche Beobachtung. Wie Kenster feststellt, können mit dem SCP-Protokoll keine Dateien unbekannter Größe gesendet werden.

UPDATE (2017-06-04): Ich habe auch versucht, die Daten mit dem SFTP-Protokoll zu übertragen. Offensichtlich erlaubt das FTP-Protokoll das Senden von Dateien unbekannter Größe, was durch die Unterstützung von Piping-Daten in den Binärdateien ftp ( Link ) und ncftpput ( Link , Abschnitt Beschreibung, letzter Absatz) belegt wird. Ich fand keine solche Unterstützung in den SFTP-Clients, die ich ausprobiert habe ( sftp, lftp). Dies könnte ein Hinweis darauf sein, dass SFTP (im Gegensatz zu FTP) das Senden von Dateien unbekannter Größe nicht unterstützt (anders als ich dachte, ist SFTP nicht nur über SSH mit FTP verbunden) es ist ein anderes Protokoll).

UPDATE (2017-06-05): Gemäß dem Internet-Entwurf ( Link ) des SFTP-Protokolls, Version 3 , muss jedes Paket auf Anwendungsebene die Nutzdatenlänge vor der Nutzdaten angeben ( Link , Abschnitt 3). SFTP unterstützt jedoch Suchvorgänge in der geschriebenen Datei ( Link , Abschnitt 6.4) mit expliziter Unterstützung für Schreibvorgänge über das aktuelle Dateiende hinaus. Daher sollte es möglich sein, einen kleinen Puffer auf der Clientseite zu verwenden und eine Datei unbekannter Größe in kleinen, bekannt großen Blöcken zu senden:

#!/bin/bash
# <Exchange SSH_FXP_INIT requests.>
# <Send an SSH_FXP_OPEN request.>
CHUNK_SIZE=32768
OFFSET=0
IFS=''; while read -r -N $CHUNK_SIZE CHUNK; do
  ACTUAL_SIZE=`cat <<<"$CHUNK" | head -c -1 | wc -c`
  # <Send an SSH_FXP_WRITE request with payload $CHUNK of size
  # $ACTUAL_SIZE at offset $OFFSET.>
  OFFSET=$(($OFFSET+$ACTUAL_SIZE))
done < <(command)
# <Send an SSH_FXP_CLOSE request.>

Es wäre jedoch sehr schmerzhaft, die Kommunikation manuell über die Shell durchzuführen. Ich suche einen SFTP-Client, der diese Art von Funktionalität verfügbar macht.

Verweise

Witiko
quelle
Ich sehe nicht, dass scpfrüher Rohre gehandhabt wurden. Der Fehlerbericht, den Sie verknüpfen, zeigt, dass er auf unbestimmte Zeit an Pipes hängt. jetzt warnt es dich stattdessen. Das klingt nach einer besseren Fehlerberichterstattung, nicht nach einer Änderung des zugrunde liegenden Verhaltens.
user4556274
Nun, ich nahm an, dass es genau deshalb hängen geblieben war, weil es anfangen würde, die Named Pipe wie eine normale Datei zu lesen.
Witiko

Antworten:

3

lftp4.6.1 und neuere Versionen sollten dazu in der Lage sein: https://github.com/lavv17/lftp/issues/104

Leider funktioniert der in der verlinkten Ausgabe vorgeschlagene Befehl nicht, ein leicht modifizierter Befehl jedoch:

lftp -p $port sftp://$user:$pass@$host -e "put /dev/stdin -o $filename"

Aufgrund eines Fehlers müssen Sie etwas in das Kennwortfeld eingeben, wenn Sie einen SSH-Agenten verwenden. Aber jede zufällige Zeichenfolge reicht aus.

Dieser Befehl liest aus /dev/stdin. Wenn Sie eine andere Named Pipe verwenden müssen, sollte das meiner Meinung nach auch funktionieren - wenn nicht, können Sie das immer cat named-pipe | lftp ....

Ich habe lftpmit einem Upload von> 100 GB ohne Probleme getestet .


rcloneunterstützt auch SFTP und sollte in der Lage sein, von einer Pipe-Eingabe mit dem rcatBefehl hochzuladen , da dies in 1.38 (nächste Version) veröffentlicht wird.

Bob
quelle
Ich erhalte einen put: /dev/stdin: cannot seek on data sourceFehler mit den lftpvom Debian-Projekt veröffentlichten Binärdateien 4.7.4 und 4.8.1. Ich muss überprüfen, ob dies eine Regression in der Quelle ist oder ob dies ein Build-Problem ist. Ich werde dies zur akzeptierten Antwort machen, nachdem ich es geschafft habe, Ihre Ergebnisse zu reproduzieren.
Witiko
@Witiko Das ist interessant - weil ich den aktuellen lftpauf Debian Stretch getestet habe . Paketversion 4.7.4-1. LFTP-Version 4.7.4, Readline 7.0, GnuTLS 3.5.8, zlib 1.2.8. Der vollständige Befehl , den ich lief ein Rohr aus aufgenommen , openssl encobwohl pvund dann in lftp.
Bob
Sie haben Recht, ich habe den Port falsch angegeben, wodurch lftpdie obige nicht hilfreiche Fehlermeldung ausgegeben wurde . Vielen Dank für den Rat, es wird sehr geschätzt!
Witiko
@Witiko Ich glaube, ich bin genau in der Situation darauf gestoßen, in der Sie sich befanden ( zfs send | compress | encrypt | upload) - es war tatsächlich Ihre Recherche, die mich davon überzeugt hat, den SFTP-Pfad und nicht SCP / rsync zu wählen. Vielen Dank für eine sehr gut geschriebene Frage (und Kenster für seine Analyse von SCP / SFTP). Ist Ihre Gegenstelle aus Neugier auch C14?
Bob
6

SCP eignet sich nicht für Ihren Zweck. Das SCP-Protokoll unterstützt nicht das Senden eines Datenstroms unbekannter Größe an das ferne System, um als Datei gespeichert zu werden. Die SCP-Protokollnachricht zum Senden einer Datei erfordert, dass die Größe der Datei zuerst gesendet wird, gefolgt von den Bytes, aus denen die Datei besteht. Bei einem Stream von Bytes, die aus einer Pipe gelesen werden, würden Sie normalerweise nicht wissen, wie viele Bytes die Pipe produzieren wird, sodass es keine Möglichkeit gibt, eine SCP-Protokollnachricht mit der richtigen Größe zu senden.

(Die einzigen Online-Beschreibungen des SCP-Protokolls, die ich finden konnte, sind hier und hier . Konzentrieren Sie sich auf die Beschreibung der "C" -Meldung.)

Das SFTP-Protokoll kann für solche Dinge verwendet werden. Soweit ich weiß, unterstützt das normale sftpBefehlszeilenprogramm das Lesen und Speichern einer Pipe als Remote-Datei nicht. Es gibt jedoch SSH / SFTP-Bibliotheken für die meisten modernen Programmiersprachen (Perl, Python, Ruby, C #, Java, C usw.). Wenn Sie wissen, wie man eine dieser Sprachen verwendet, sollte es einfach sein, ein Dienstprogramm zu schreiben, das genau das tut, was Sie benötigen.

Wenn Sie mit Shell-Skripten nicht weiterkommen, können Sie das SCP-Protokoll so oft fälschen, dass eine Datei übertragen wird. Hier ist ein Beispiel:

#!/bin/bash
cmd='cat /etc/group'

size=$($cmd | wc -c)    
{
        echo C0644 $size some-file
        $cmd
        echo -n -e '\000'
} | ssh user@host scp -v -p -t /some/directory

Dies erzeugt some-filein /some/directorymit Berechtigungen auf dem Remote - System 644. Der Inhalt der Datei wird , was auch immer $cmdauf die Standardausgabe schreibt. Beachten Sie, dass Sie den Befehl zweimal ausführen, unabhängig vom Ressourcenverbrauch und den damit verbundenen Nebenwirkungen. Und der Befehl muss jedes Mal dieselbe Anzahl von Bytes ausgeben.

Kenster
quelle
Ich würde mehr als glücklich sein, zwei Durchgänge zu machen - der erste, um die Größe herauszufinden, und der zweite, um den Versand über scp zu machen; es ist nicht die eleganteste Lösung, aber die inkrementellen Sicherungen werden alle im RAM zwischengespeichert. Bibliotheken sind eine Option, aber ich hatte gehofft, dass ich dies von der Shell aus tun kann.
Witiko
Vielen Dank für die Recherche, die zum Schreiben dieses Shell-Skripts geführt hat. Für mich ist dies eine zufriedenstellende Antwort auf die ursprüngliche Frage. Ich werde jedoch weiterhin die SFTP-Route untersuchen, da der Geschwindigkeitsunterschied zwischen Single-Pass und Two-Pass bei größeren Backups spürbar sein wird.
Witiko
2

Wenn Sie Perl schreiben können, können Sie versuchen, Net :: SFTP :: Foreign zu verwenden, das Dateien von einem geöffneten Dateideskriptor über SFTP übertragen kann:

#!/usr/bin/perl
# untested!
use Net::SFTP::Foreign;
my $user = ...;
my $host = ...;
my $remote_path = ...;
my $btrfs_cmd = 'btrfs send -p $LAST_SUBVOLUME $NEXT_SUBVOLUME';
my $sftp = Net::SFTP::Foreign->new("$user\@$host", ...);
open my($pipe), "$btrfs_cmd | compress | encrypt |"
    or die $!;
$sftp->put($fh, $remote_path);
salva
quelle