Ép buộc scp (1), sftp (1) hoặc rsync (1) để chuyển một đường ống có tên


4

Tôi dự định chuyển các bản sao lưu đầy đủ và gia tăng của các subvolume btrfs của tôi sang một dịch vụ lưu trữ băng. Dịch vụ này hiển thị các điểm cuối FTP và SSH. Nếu tôi được phép thực thi các lệnh tùy ý trên điểm cuối SSH, thì tôi sẽ làm như sau để thực hiện sao lưu gia tăng:

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

Tôi, tuy nhiên, không được phép làm điều đó:

$ 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.

Vì vậy, những gì tôi nghĩ phải làm thay vào đó là sử dụng giao thức SCP để chuyển. Tuy nhiên, scpnhị phân của tôi từ chối chuyển một đường ống có tên:

$ 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

Điều trớ trêu là rõ ràng, scpđược sử dụng để làm điều đúng một lần . Tôi cho rằng không phải ai cũng nghĩ việc chuyển các ống có tên có thể lành mạnh / hữu ích. EDIT (2017-06-03): Đây là một quan sát không chính xác. Theo ghi nhận của Kenster, giao thức SCP không cho phép gửi các tệp có kích thước không xác định.

CẬP NHẬT (2017-06-04): Tôi cũng đã thử chuyển dữ liệu bằng giao thức SFTP. Rõ ràng, giao thức FTP cho phép gửi các tệp có kích thước không xác định, bằng chứng là sự hỗ trợ cho dữ liệu đường ống trong các nhị phân ftp ( liên kết ) và ncftpput ( liên kết , phần Mô tả, đoạn cuối). Tôi không tìm thấy sự hỗ trợ nào trong các máy khách SFTP mà tôi đã thử ( sftp, lftp), đó có thể là một dấu hiệu cho thấy SFTP (không giống như FTP) không hỗ trợ gửi các tệp có kích thước không xác định (trái với những gì tôi nghĩ, SFTP không chỉ là FTP được điều chỉnh qua SSH ; nó là một giao thức khác nhau).

CẬP NHẬT (2017-06-05): Theo dự thảo ( liên kết ) của giao thức SFTP phiên bản 3 , mỗi gói cấp độ ứng dụng phải chỉ định chiều dài tải trọng trước khi tải trọng ( liên kết , Mục 3). Tuy nhiên, SFTP hỗ trợ tìm kiếm trong tệp bằng văn bản ( liên kết , Mục 6.4) với sự hỗ trợ rõ ràng cho việc ghi vượt quá cuối tệp hiện tại. Do đó, nếu có thể sử dụng một bộ đệm nhỏ ở phía máy khách và gửi một tệp có kích thước không xác định trong các khối nhỏ có kích thước đã biết:

#!/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.>

Tuy nhiên, thực hiện giao tiếp thủ công qua vỏ sẽ khá đau đớn. Tôi đang tìm kiếm một khách hàng SFTP trưng bày loại chức năng này.

Tài liệu tham khảo


Tôi không thấy rằng scpđược sử dụng để xử lý các đường ống. Báo cáo lỗi mà bạn liên kết cho thấy rằng nó được sử dụng để treo vô thời hạn trên các đường ống; bây giờ nó cảnh báo bạn Nghe có vẻ như báo cáo lỗi tốt hơn, không phải là một thay đổi trong hành vi cơ bản.
user4556274

Chà, tôi cho rằng nó đã bị treo chính xác bởi vì nó sẽ bắt đầu đọc đường ống có tên như một tập tin thông thường.
Witiko

Câu trả lời:


3

lftp4.6.1 và mới hơn sẽ có thể làm điều này: https://github.com/lavv17/lftp/issues/104

Thật không may, lệnh được đề xuất trong vấn đề được liên kết không hoạt động, nhưng một lệnh được sửa đổi một chút sẽ:

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

Do một lỗi , bạn phải cung cấp một cái gì đó trong trường mật khẩu nếu bạn sử dụng tác nhân SSH. Nhưng bất kỳ chuỗi ngẫu nhiên sẽ làm.

Lệnh này đọc từ /dev/stdin. Nếu bạn phải sử dụng một đường ống có tên khác, tôi tưởng tượng rằng nó cũng hoạt động - nếu không, bạn luôn có thể cat named-pipe | lftp ....

Tôi đã thử nghiệm lftpvới tải lên> 100 GB mà không gặp sự cố nào.


rclonecũng hỗ trợ SFTP và có thể tải lên từ đầu vào có đường dẫn bằng rcatlệnh, do được phát hành trong 1.38 (phiên bản tiếp theo).


Tôi đang gặp put: /dev/stdin: cannot seek on data sourcelỗi với các lftptệp nhị phân 4.7.4 và 4.8.1 do dự án Debian phát hành. Tôi cần kiểm tra xem đây có phải là hồi quy trong nguồn không, hoặc nếu đây là vấn đề xây dựng. Tôi sẽ làm cho câu trả lời được chấp nhận sau khi tôi đã quản lý để tái tạo kết quả của bạn.
Witiko

@Witiko Điều đó thật thú vị - vì tôi đã thử nghiệm dòng điện lftptrên Debian Stretch. Phiên bản trọn gói 4.7.4-1. Phiên bản LFTP 4.7.4, Readline 7.0, GnuTLS 3.5.8, zlib 1.2.8. Lệnh đầy đủ tôi chạy bao gồm một đường ống từ openssl encmặc dù pvvà sau đó vào lftp.
Bob


Bạn nói đúng, tôi đã sai chính tả cổng, điều này lftpphát ra thông báo lỗi không hữu ích ở trên. Cảm ơn bạn đã cho lời khuyên, nó được nhiều đánh giá cao!
Witiko

@Witiko Tôi nghĩ rằng tôi đã vấp phải điều này trong tình huống chính xác giống như bạn đang ở ( zfs send | compress | encrypt | upload) - thực sự nghiên cứu của bạn đã thuyết phục tôi đi xuống con đường SFTP thay vì SCP / rsync. Vì vậy, cảm ơn bạn về một câu hỏi được viết rất tốt (và Kenster cho phân tích về SCP / SFTP của anh ấy). Chỉ tò mò thôi, có phải từ xa của bạn cũng là C14?
Bob

6

SCP không phù hợp với mục đích của bạn. Giao thức SCP không hỗ trợ gửi một luồng byte có kích thước không xác định đến hệ thống từ xa để được lưu dưới dạng tệp. Thông báo giao thức SCP để gửi tệp yêu cầu kích thước của tệp được gửi trước, theo sau là các byte tạo nên tệp. Với một luồng byte được đọc từ một đường ống, thông thường bạn sẽ không biết đường ống sẽ tạo ra bao nhiêu byte nên không có cách nào để gửi một thông điệp giao thức SCP bao gồm kích thước chính xác.

(Các mô tả trực tuyến duy nhất về giao thức SCP mà tôi có thể tìm thấy ở đâyđây . Tập trung vào mô tả của thông báo "C".)

Giao thức SFTP có thể được sử dụng cho loại điều này. Theo như tôi biết, sftptiện ích dòng lệnh thông thường không hỗ trợ đọc một đường ống và lưu trữ nó dưới dạng tệp từ xa. Nhưng có thư viện SSH / SFTP cho hầu hết các ngôn ngữ lập trình hiện đại (perl, python, ruby, C #, Java, C, v.v.). Nếu bạn biết cách sử dụng một trong những ngôn ngữ này, việc viết một tiện ích thực hiện những gì bạn cần là điều đơn giản.

Nếu bạn bị mắc kẹt với kịch bản shell, có thể giả mạo đủ giao thức SCP để truyền tệp. Đây là một ví dụ:

#!/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

Điều này sẽ tạo ra some-filetrong /some/directorytrên hệ thống từ xa với các điều khoản 644. Nội dung tập tin sẽ được bất cứ điều gì $cmdghi vào đầu ra tiêu chuẩn của nó. Lưu ý rằng bạn đang chạy lệnh hai lần, với bất kỳ mức tiêu thụ tài nguyên và tác dụng phụ nào. Và lệnh phải xuất cùng số byte mỗi lần.


Tôi sẽ rất hạnh phúc khi thực hiện hai lần vượt qua - lần đầu tiên tìm ra kích thước và lần thứ hai thực hiện việc gửi qua scp; nó không phải là giải pháp tao nhã nhất, nhưng các bản sao lưu gia tăng sẽ được lưu trong bộ nhớ cache. Thư viện là một lựa chọn, nhưng tôi đã hy vọng tôi có thể làm điều này từ trình bao.
Witiko

Cảm ơn bạn đã nghiên cứu để viết kịch bản shell đó. Đối với tôi, đây là một câu trả lời thỏa đáng cho câu hỏi ban đầu. Tuy nhiên, tôi vẫn sẽ khám phá tuyến SFTP, bởi vì sự khác biệt về tốc độ giữa một lượt và hai lượt sẽ đáng chú ý đối với các bản sao lưu lớn hơn.
Witiko

2

Nếu bạn có thể viết perl, bạn có thể thử sử dụng Net :: SFTP :: Foreign có thể chuyển tệp từ một mô tả tệp đang mở thông qua SFTP:

#!/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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.