[pve-devel] [RFC PATCH storage] pvesm export: convert dd's \r in status=progress output to \n
Dominik Csapak
d.csapak at proxmox.com
Thu Jan 16 09:13:05 CET 2025
On 1/15/25 12:28, Thomas Lamprecht wrote:
> Am 15.01.25 um 10:59 schrieb Dominik Csapak:
>> pvesm export is mostly used for (remote) migrations, where the
>> status progress output lands in a task log. For task logs we want to
>> have line based output (since it's not a terminal), but dd uses \r
>> to overwrite the same line which does not work in every situation, e.g.
>> browsers sometimes simply don't show them, making the dd output a long
>> line instead of separate ones.
>>
>> To fix this, use run_command's `errfunc` to log the lines. run_command
>> will split also on \r, but with warn we print a \n so this does the
>> conversion.
>>
>> This fixes an issue where the remote migration task log on PDM does not
>> display that part in new lines. (ExtJS works because it does things
>> differently and some browser quirks convert \r to \n)
>>
>> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
>> ---
>> Not sure if we want to take this approach because we lose the
>> functionalty of overwriting progress on the terminal.
>
> FWIW, you could test with `-t STDERR` if the std error FD is a terminal
> and differ between replacing \r or not.
>
not sure if that would work here since we do quite some redirection for
the worker task (to be able to display + putting it in the task log at
the same time), but yes, I'll try that
>>
>> AFAICS there is no easy way to only do this for the task log, since
>> we simply pipe the output fh of the worker task to the task log fh.
>>
>> Alternatively we could patch the task log api to parse \r as newlines or
>> patch the yew widget toolkit to replace \r with \n.
>
> Wouldn't be one alternative also be to do that in the UI?
thats what i meant in that sentence. (replacing in yew widget toolkit)
>
>>
>> No real preference from my side, but this patch fixes the task log file
>> without touching our central worker task code, so it seemed sensible.
>>
>> src/PVE/Storage/ISCSIPlugin.pm | 6 +++++-
>> src/PVE/Storage/LVMPlugin.pm | 6 +++++-
>> src/PVE/Storage/Plugin.pm | 10 ++++++++--
>> 3 files changed, 18 insertions(+), 4 deletions(-)
>>
>> diff --git a/src/PVE/Storage/ISCSIPlugin.pm b/src/PVE/Storage/ISCSIPlugin.pm
>> index eb70453..33604cd 100644
>> --- a/src/PVE/Storage/ISCSIPlugin.pm
>> +++ b/src/PVE/Storage/ISCSIPlugin.pm
>> @@ -631,7 +631,11 @@ sub volume_export {
>> $size = int($1);
>> });
>> PVE::Storage::Plugin::write_common_header($fh, $size);
>> - run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh));
>> + run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh), errfunc => sub {
>> + # convert dd's \r to \n
>
> I'd move the comment into the line re-printing the output, shorter
> and also avoids having something before extracting the parameters,
> which should always be first in perl for now; once we widely switch
> to using signatures that wouldn't be a problem anymore.
>
> Maybe also add some reasoning to the comment, like: "convert \r to \n to avoid issues in browsers"
sure, makes sense
>
>> + my ($line) = @_;
>> + warn "$line\n";
>> + });
>
> Why not use `print STDERR "$line\n";`?
>
> Because warn could be caught by a $SIG{__WARN__} handler from the call chain and
> interpreted as problem. For relaying stderr messages to stderr again printing
> directly to STDERR feels a bit more expressive and safer to me.
>
OK
>> return;
>> }
>>
>> diff --git a/src/PVE/Storage/LVMPlugin.pm b/src/PVE/Storage/LVMPlugin.pm
>> index 38f7fa1..d41647b 100644
>> --- a/src/PVE/Storage/LVMPlugin.pm
>> +++ b/src/PVE/Storage/LVMPlugin.pm
>> @@ -647,7 +647,11 @@ sub volume_export {
>> $size = int($1);
>> });
>> PVE::Storage::Plugin::write_common_header($fh, $size);
>> - run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh));
>> + run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh), errfunc => sub {
>> + # convert dd's \r to \n
>> + my ($line) = @_;
>> + warn "$line\n";
>
> same as above
>
>> + });
>> }
>>
>> sub volume_import_formats {
>> diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
>> index 65cf43f..c42a675 100644
>> --- a/src/PVE/Storage/Plugin.pm
>> +++ b/src/PVE/Storage/Plugin.pm
>> @@ -1703,11 +1703,17 @@ sub volume_export {
>> my $file_format = ($class->parse_volname($volname))[6];
>> my $size = file_size_info($file, undef, $file_format);
>>
>> + # convert dd's \r to \n
>> + my $errfunc = sub {
>> + my ($line) = @_;
>> + warn "$line\n";
>
> same here
>
>> + };
>> +
>> if ($format eq 'raw+size') {
>> die $err_msg if $with_snapshots || $file_format eq 'subvol';
>> write_common_header($fh, $size);
>> if ($file_format eq 'raw') {
>> - run_command(['dd', "if=$file", "bs=4k", "status=progress"], output => '>&'.fileno($fh));
>> + run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh), errfunc => $errfunc);
>> } else {
>> run_command(['qemu-img', 'convert', '-f', $file_format, '-O', 'raw', $file, '/dev/stdout'],
>> output => '>&'.fileno($fh));
>> @@ -1717,7 +1723,7 @@ sub volume_export {
>> my $data_format = $1;
>> die $err_msg if !$with_snapshots || $file_format ne $data_format;
>> write_common_header($fh, $size);
>> - run_command(['dd', "if=$file", "bs=4k", "status=progress"], output => '>&'.fileno($fh));
>> + run_command(['dd', "if=$file", "bs=64k", "status=progress"], output => '>&'.fileno($fh), errfunc => $errfunc);
>> return;
>> } elsif ($format eq 'tar+size') {
>> die $err_msg if $file_format ne 'subvol';
>
More information about the pve-devel
mailing list