Browse Source

Merge remote-tracking branch 'origin/pr/359'

* origin/pr/359:
  Add tests for vm.volume.Clear.
  Use self.dest.storage.import* wrappers instead.
  Add admin.vm.volume.Clear call (QubesOS/qubes-issues#5946)
Marek Marczykowski-Górecki 3 years ago
parent
commit
784878f1f7
2 changed files with 66 additions and 0 deletions
  1. 27 0
      qubes/api/admin.py
  2. 39 0
      qubes/tests/api_admin.py

+ 27 - 0
qubes/api/admin.py

@@ -27,6 +27,7 @@ import itertools
 import os
 import string
 import subprocess
+import pathlib
 
 import libvirt
 import lxml.etree
@@ -486,6 +487,32 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
         finally:  # even if calling qubes.ResizeDisk inside the VM failed
             self.app.save()
 
+    @qubes.api.method('admin.vm.volume.Clear', no_payload=True,
+        scope='local', write=True)
+    @asyncio.coroutine
+    def vm_volume_clear(self):
+        self.enforce(self.arg in self.dest.volumes.keys())
+
+        self.fire_event_for_permission()
+
+        volume = self.dest.volumes[self.arg]
+        size = volume.size
+
+        # Clear the volume by importing empty data into it
+        path = yield from self.dest.storage.import_data(self.arg, size)
+        self.dest.fire_event('domain-volume-import-begin',
+            volume=self.arg, size=size)
+        pathlib.Path(path).touch()
+        try:
+            yield from self.dest.storage.import_data_end(self.arg, True)
+        except:
+            self.dest.fire_event('domain-volume-import-end',
+                volume=self.arg, success=False)
+            raise
+        self.dest.fire_event('domain-volume-import-end',
+            volume=self.arg, success=True)
+        self.app.save()
+
     @qubes.api.method('admin.vm.volume.Set.revisions_to_keep',
         scope='local', write=True)
     @asyncio.coroutine

+ 39 - 0
qubes/tests/api_admin.py

@@ -2756,6 +2756,44 @@ netvm default=True type=vm \n'''
         }
         value = self.call_mgmt_func(b'admin.pool.volume.List', b'dom0', b'pool1')
         self.assertEqual(value, 'vol1\nvol2\n')
+    
+    def test_710_vm_volume_clear(self):
+        with tempfile.TemporaryDirectory() as tmpdir:
+            tmpfile = os.path.join(tmpdir, 'testfile')
+
+            @asyncio.coroutine
+            def coroutine_mock(*args, **kwargs):
+                return tmpfile
+
+            self.vm.volumes = unittest.mock.MagicMock()
+            volumes_conf = {
+                'keys.return_value': ['root', 'private', 'volatile', 'kernel'],
+                '__getitem__.return_value.size': 0xdeadbeef
+            }
+            self.vm.volumes.configure_mock(**volumes_conf)
+            self.vm.storage = unittest.mock.Mock()
+            storage_conf = {
+                'import_data.side_effect': coroutine_mock,
+                'import_data_end.side_effect': self.dummy_coro
+            }
+            self.vm.storage.configure_mock(**storage_conf)
+            self.app.domains['test-vm1'].fire_event = self.emitter.fire_event
+            value = self.call_mgmt_func(b'admin.vm.volume.Clear',
+                b'test-vm1', b'private')
+            self.assertIsNone(value)
+            self.assertTrue(os.path.exists(tmpfile))
+            self.assertEqual(self.vm.volumes.mock_calls, [
+                unittest.mock.call.keys(),
+                unittest.mock.call.__getattr__('__getitem__')('private')])
+            self.assertEqual(self.vm.storage.mock_calls, [
+                unittest.mock.call.import_data('private', 0xdeadbeef),
+                unittest.mock.call.import_data_end('private', True)])
+            self.assertEventFired(
+                self.emitter, 'admin-permission:admin.vm.volume.Clear')
+            self.assertEventFired(
+                self.emitter, 'domain-volume-import-begin')
+            self.assertEventFired(
+                self.emitter, 'domain-volume-import-end')
 
     def test_800_current_state_default(self):
         value = self.call_mgmt_func(b'admin.vm.CurrentState', b'test-vm1')
@@ -3057,6 +3095,7 @@ netvm default=True type=vm \n'''
             b'admin.vm.volume.Info',
             b'admin.vm.volume.Revert',
             b'admin.vm.volume.Resize',
+            b'admin.vm.volume.Clear',
             b'admin.vm.Start',
             b'admin.vm.Shutdown',
             b'admin.vm.Pause',