Ver código fonte

backup: fix handling target write error (like no disk space)

When writing process returns an error, prefer reporting that one,
instead of other process (which in most cases will be canceled, so
the error will be meaningless CancelledError).
Then, include sanitized stderr from VM process in the error message.
Marek Marczykowski-Górecki 6 anos atrás
pai
commit
5e6ba4ff5c
1 arquivos alterados com 18 adições e 5 exclusões
  1. 18 5
      qubes/backup.py

+ 18 - 5
qubes/backup.py

@@ -23,6 +23,7 @@ from __future__ import unicode_literals
 import itertools
 import logging
 import functools
+import string
 import termios
 
 import asyncio
@@ -665,6 +666,13 @@ class Backup(object):
             raise
 
         if proc.returncode:
+            if proc.stderr is not None:
+                proc_stderr = (yield from proc.stderr.read())
+                proc_stderr = proc_stderr.decode('ascii', errors='ignore')
+                proc_stderr = ''.join(
+                    c for c in proc_stderr if c in string.printable and
+                                              c not in '\r\n%{}')
+                error_message += ': ' + proc_stderr
             raise qubes.exc.QubesException(error_message)
 
     @staticmethod
@@ -717,7 +725,9 @@ class Backup(object):
             # If APPVM, STDOUT is a PIPE
             read_fd, write_fd = os.pipe()
             vmproc = yield from self.target_vm.run_service('qubes.Backup',
-                stdin=read_fd, stderr=subprocess.PIPE)
+                stdin=read_fd,
+                stderr=subprocess.PIPE,
+                stdout=subprocess.DEVNULL)
             os.close(read_fd)
             os.write(write_fd, (self.target_dir.
                 replace("\r", "").replace("\n", "") + "\n").encode())
@@ -755,11 +765,12 @@ class Backup(object):
 
         vmproc_task = None
         if vmproc is not None:
-            vmproc_task = asyncio.ensure_future(self._cancel_on_error(
+            vmproc_task = asyncio.ensure_future(
                 self._monitor_process(vmproc,
                     'Writing backup to VM {} failed'.format(
-                        self.target_vm.name)),
-                    send_task))
+                        self.target_vm.name)))
+            asyncio.ensure_future(self._cancel_on_error(
+                vmproc_task, send_task))
 
         for file_name in header_files:
             yield from to_send.put(file_name)
@@ -783,10 +794,12 @@ class Backup(object):
             except:
                 yield from to_send.put(QUEUE_ERROR)
                 # in fact we may be handling CancelledError, induced by
-                # exception in send_task (and propagated by
+                # exception in send_task or vmproc_task (and propagated by
                 # self._cancel_on_error call above); in such a case this
                 # yield from will raise exception, covering CancelledError -
                 # this is intended behaviour
+                if vmproc_task:
+                    yield from vmproc_task
                 yield from send_task
                 raise