api/admin: add 'wait' parameter to admin.vm.Shutdown

Add support for blocking shutdown call. This adds a symmetry to
admin.vm.Start call which is blocking.
Since the admin.vm.Shutdown has established semantic already, add a
'wait' parameter. It can be combined with 'force' as 'force+wait' (or
the other way around).
This commit is contained in:
Marek Marczykowski-Górecki 2021-01-12 23:40:36 +01:00
parent d3d6b9de2b
commit 6d11388807
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 55 additions and 5 deletions

View File

@ -899,9 +899,15 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
scope='local', execute=True)
@asyncio.coroutine
def vm_shutdown(self):
force = (self.arg == 'force')
self.fire_event_for_permission(force=force)
yield from self.dest.shutdown(force=force)
if self.arg:
args = self.arg.split('+')
else:
args = []
self.enforce(all(arg in ('force', 'wait') for arg in args))
force = ('force' in args)
wait = ('wait' in args)
self.fire_event_for_permission(force=force, wait=wait)
yield from self.dest.shutdown(force=force, wait=wait)
@qubes.api.method('admin.vm.Pause', no_payload=True,
scope='local', execute=True)

View File

@ -1030,7 +1030,7 @@ netvm default=True type=vm \n'''
self.vm.shutdown = coroutine_mock
value = self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1')
self.assertIsNone(value)
func_mock.assert_called_once_with(force=False)
func_mock.assert_called_once_with(force=False, wait=False)
def test_231_shutdown_force(self):
func_mock = unittest.mock.Mock()
@ -1041,7 +1041,51 @@ netvm default=True type=vm \n'''
self.vm.shutdown = coroutine_mock
value = self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1', b'force')
self.assertIsNone(value)
func_mock.assert_called_once_with(force=True)
func_mock.assert_called_once_with(force=True, wait=False)
def test_232_shutdown_wait(self):
func_mock = unittest.mock.Mock()
@asyncio.coroutine
def coroutine_mock(*args, **kwargs):
return func_mock(*args, **kwargs)
self.vm.shutdown = coroutine_mock
value = self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1', b'wait')
self.assertIsNone(value)
func_mock.assert_called_once_with(force=False, wait=True)
def test_233_shutdown_wait_force(self):
func_mock = unittest.mock.Mock()
@asyncio.coroutine
def coroutine_mock(*args, **kwargs):
return func_mock(*args, **kwargs)
self.vm.shutdown = coroutine_mock
value = self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1', b'wait+force')
self.assertIsNone(value)
func_mock.assert_called_once_with(force=True, wait=True)
def test_234_shutdown_force_wait(self):
func_mock = unittest.mock.Mock()
@asyncio.coroutine
def coroutine_mock(*args, **kwargs):
return func_mock(*args, **kwargs)
self.vm.shutdown = coroutine_mock
value = self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1', b'force+wait')
self.assertIsNone(value)
func_mock.assert_called_once_with(force=True, wait=True)
def test_234_shutdown_force_wait_invalid(self):
func_mock = unittest.mock.Mock()
@asyncio.coroutine
def coroutine_mock(*args, **kwargs):
return func_mock(*args, **kwargs)
self.vm.shutdown = coroutine_mock
with self.assertRaises(qubes.api.PermissionDenied):
self.call_mgmt_func(b'admin.vm.Shutdown', b'test-vm1', b'forcewait')
func_mock.assert_not_called()
def test_240_pause(self):
func_mock = unittest.mock.Mock()