The previous file-read implementation in the Proxmox API always
attempted to read a fixed 16 MiB. On busy or resource-constrainted
hosts, that often caused request timeouts, with no option to
reduce the number of read bytes to at least read something.

The new parameter count now allows specifying the exact number of
bytes that should be read from the given file. To be backwards
compatible with the previous behavior, it defaults to 16 MiB.
These 16 MiB are further also the maximum allowed value.

Signed-off-by: Markus Ebner <[email protected]>
---
 src/PVE/API2/Qemu/Agent.pm | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/PVE/API2/Qemu/Agent.pm b/src/PVE/API2/Qemu/Agent.pm
index de36ce1e..f32e1dc2 100644
--- a/src/PVE/API2/Qemu/Agent.pm
+++ b/src/PVE/API2/Qemu/Agent.pm
@@ -464,6 +464,14 @@ __PACKAGE__->register_method({
                 'pve-vmid',
                 { completion => \&PVE::QemuServer::complete_vmid_running },
             ),
+            count => {
+                type => 'integer',
+                optional => 1,
+                minimum => 0,
+                maximum => $MAX_READ_SIZE,
+                default => $MAX_READ_SIZE,
+                description => "Number of bytes to read.",
+            },
             file => {
                 type => 'string',
                 description => 'The path to the file',
@@ -487,6 +495,7 @@ __PACKAGE__->register_method({
     },
     code => sub {
         my ($param) = @_;
+        my $count = int($param->{count} // $MAX_READ_SIZE);
 
         my $vmid = $param->{vmid};
         my $conf = PVE::QemuConfig->load_config($vmid);
@@ -494,18 +503,20 @@ __PACKAGE__->register_method({
         my $qgafh =
             agent_cmd($vmid, $conf, "file-open", { path => $param->{file} }, 
"can't open file");
 
-        my $bytes_left = $MAX_READ_SIZE;
+        my $bytes_read = 0;
         my $eof = 0;
         my $read_size = 1024 * 1024;
         my $content = "";
 
-        while ($bytes_left > 0 && !$eof) {
+        while ($bytes_read < $count && !$eof) {
+            my $bytes_left = $count - $bytes_read;
+            my $chunk_size = $bytes_left < $read_size ? $bytes_left : 
$read_size;
             my $read =
-                mon_cmd($vmid, "guest-file-read", handle => $qgafh, count => 
int($read_size));
+                mon_cmd($vmid, "guest-file-read", handle => $qgafh, count => 
int($chunk_size));
             check_agent_error($read, "can't read from file");
 
             $content .= decode_base64($read->{'buf-b64'});
-            $bytes_left -= $read->{count};
+            $bytes_read += $read->{count};
             $eof = $read->{eof} // 0;
         }
 
@@ -514,12 +525,14 @@ __PACKAGE__->register_method({
 
         my $result = {
             content => $content,
-            'bytes-read' => ($MAX_READ_SIZE - $bytes_left),
+            'bytes-read' => $bytes_read,
         };
 
         if (!$eof) {
-            warn
-                "agent file-read: reached maximum read size: $MAX_READ_SIZE 
bytes. output might be truncated.\n";
+            if (!defined $param->{count}) {
+                warn "agent file-read: reached maximum read size: 
$MAX_READ_SIZE bytes."
+                    . " output might be truncated.\n";
+            }
             $result->{truncated} = 1;
         }
 
-- 
2.53.0



Reply via email to