Browse Source

storage: add Volume.export_end() function

This is a counterpart to Volume.export(). Up until now, no driver needed
any cleanup after exporting data, but it doesn't mean there won't be
any. This is especially relevant because Volume.export() is supposed to
return a path of a snapshot from before VM start - which may be a
different one than currently active one.

QubesOS/qubes-issues#5935
Marek Marczykowski-Górecki 4 years ago
parent
commit
d96480719f
3 changed files with 31 additions and 1 deletions
  1. 4 0
      doc/qubes-storage.rst
  2. 2 1
      qubes/backup.py
  3. 25 0
      qubes/storage/__init__.py

+ 4 - 0
doc/qubes-storage.rst

@@ -99,6 +99,10 @@ Methods and properties required to be implemented by the volume class:
  - :py:meth:`~qubes.storage.Volume.export` - return a path to be read to extract
    volume data; for complex formats, this can be a pipe (connected to some
    data-extracting process)
+ - :py:meth:`~qubes.storage.Volume.export_end` - cleanup after exporting the
+   data; this function is called when the path returned by
+   :py:meth:`~qubes.storage.Volume.export` is not used anymore. This method
+   optional - some storage drivers may not implement it if not needed.
  - :py:meth:`~qubes.storage.Volume.import_data` - return a path the data should
    be written to, to import volume data; for complex formats, this can be pipe
    (connected to some data-importing process)

+ 2 - 1
qubes/backup.py

@@ -394,7 +394,8 @@ class Backup:
                     volume.export,
                     subdir,
                     name + '.img',
-                    volume.usage))
+                    volume.usage,
+                    cleanup_func=volume.export_end))
 
             vm_files.extend(self.FileToBackup(i, subdir)
                 for i in vm.fire_event('backup-get-files'))

+ 25 - 0
qubes/storage/__init__.py

@@ -206,6 +206,18 @@ class Volume:
         '''
         raise self._not_implemented("export")
 
+    def export_end(self, path):
+        """ Cleanup after exporting data.
+
+            This method is called after exporting the volume data (using
+            :py:meth:`export`), when the *path* is not needed anymore.
+
+            This can be implemented as a coroutine.
+
+            :param path: path to cleanup, returned by :py:meth:`export`
+        """
+        # do nothing by default (optional method)
+
     def import_data(self, size):
         ''' Returns a path to overwrite volume data.
 
@@ -643,6 +655,19 @@ class Storage:
 
         return self.vm.volumes[volume].export()
 
+    @asyncio.coroutine
+    def export_end(self, volume, export_path):
+        """ Cleanup after exporting data from the volume
+
+        :param volume: volume that was exported
+        :param export_path: path returned by the export() call
+        """
+        assert isinstance(volume, (Volume, str)), \
+            "You need to pass a Volume or pool name as str"
+        if not isinstance(volume, Volume):
+            volume = self.vm.volumes[volume]
+        yield from qubes.utils.coro_maybe(volume.export_end(export_path))
+
     @asyncio.coroutine
     def import_data(self, volume, size):
         '''