tools: move event loop creation/closing to main function
Do not close event loop in utility function - handle it only in main(). For this reason, change appropriate functions to coroutines. Fixes QubesOS/qubes-issues#2865
This commit is contained in:
parent
0012eb3ac6
commit
5430e04e1c
@ -42,19 +42,20 @@ def interrupt_on_vm_shutdown(vm, subject, event):
|
||||
raise Interrupt
|
||||
|
||||
|
||||
def wait_for_domain_shutdown(vm, timeout):
|
||||
@asyncio.coroutine
|
||||
def wait_for_domain_shutdown(vm, timeout, loop=None):
|
||||
''' Helper function to wait for domain shutdown.
|
||||
|
||||
This function wait for domain shutdown, but do not initiate the shutdown
|
||||
itself.
|
||||
|
||||
Note: you need to close event loop after calling this function.
|
||||
|
||||
:param vm: QubesVM object to wait for shutdown on
|
||||
:param timeout: Timeout in seconds, use 0 for no timeout
|
||||
:param loop: asyncio event loop
|
||||
'''
|
||||
if loop is None:
|
||||
loop = asyncio.get_event_loop()
|
||||
events = qubesadmin.events.EventsDispatcher(vm.app)
|
||||
loop = asyncio.get_event_loop()
|
||||
events.add_handler('domain-shutdown',
|
||||
functools.partial(interrupt_on_vm_shutdown, vm))
|
||||
events.add_handler('connection-established',
|
||||
@ -65,7 +66,7 @@ def wait_for_domain_shutdown(vm, timeout):
|
||||
# pylint: disable=no-member
|
||||
loop.call_later(timeout, events_task.cancel)
|
||||
try:
|
||||
loop.run_until_complete(events_task)
|
||||
yield from events_task
|
||||
except asyncio.CancelledError:
|
||||
raise qubesadmin.exc.QubesVMShutdownTimeout(
|
||||
'VM %s shutdown timeout expired', vm.name)
|
||||
|
@ -255,6 +255,7 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
('test-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\0test-vm class=TemplateVM state=Halted\n'
|
||||
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
ret = qubesadmin.tools.qvm_template_postprocess.main([
|
||||
'--really', 'post-install', 'test-vm', self.source_dir.name],
|
||||
app=self.app)
|
||||
@ -274,6 +275,10 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
])
|
||||
self.assertAllCalled()
|
||||
|
||||
@asyncio.coroutine
|
||||
def wait_for_shutdown(self, vm, timeout):
|
||||
pass
|
||||
|
||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_appmenus')
|
||||
@mock.patch('qubesadmin.tools.qvm_template_postprocess.import_root_img')
|
||||
def test_021_post_install_reinstall(self, mock_import_root_img,
|
||||
@ -298,11 +303,13 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
'qubesadmin.events.utils.wait_for_domain_shutdown')
|
||||
self.addCleanup(patch_domain_shutdown.stop)
|
||||
mock_domain_shutdown = patch_domain_shutdown.start()
|
||||
mock_domain_shutdown.side_effect = self.wait_for_shutdown
|
||||
else:
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\0test-vm class=TemplateVM state=Halted\n'
|
||||
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
ret = qubesadmin.tools.qvm_template_postprocess.main([
|
||||
'--really', 'post-install', 'test-vm', self.source_dir.name],
|
||||
app=self.app)
|
||||
@ -334,7 +341,9 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
'qubesadmin.events.utils.wait_for_domain_shutdown')
|
||||
self.addCleanup(patch_domain_shutdown.stop)
|
||||
mock_domain_shutdown = patch_domain_shutdown.start()
|
||||
mock_domain_shutdown.side_effect = self.wait_for_shutdown
|
||||
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
ret = qubesadmin.tools.qvm_template_postprocess.main([
|
||||
'--really', '--skip-start', 'post-install', 'test-vm',
|
||||
self.source_dir.name],
|
||||
|
@ -143,6 +143,7 @@ def import_appmenus(vm, source_dir):
|
||||
vm.log.warning('Failed to set default application list: %s', e)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def post_install(args):
|
||||
'''Handle post-installation tasks'''
|
||||
|
||||
@ -192,17 +193,16 @@ def post_install(args):
|
||||
if have_events:
|
||||
try:
|
||||
# pylint: disable=no-member
|
||||
qubesadmin.events.utils.wait_for_domain_shutdown(vm,
|
||||
qubesadmin.config.defaults['shutdown_timeout'])
|
||||
yield from qubesadmin.events.utils.wait_for_domain_shutdown(
|
||||
vm, qubesadmin.config.defaults['shutdown_timeout'])
|
||||
except qubesadmin.exc.QubesVMShutdownTimeout:
|
||||
vm.kill()
|
||||
asyncio.get_event_loop().close()
|
||||
else:
|
||||
timeout = qubesadmin.config.defaults['shutdown_timeout']
|
||||
while timeout >= 0:
|
||||
if vm.is_halted():
|
||||
break
|
||||
time.sleep(1)
|
||||
yield from asyncio.sleep(1)
|
||||
timeout -= 1
|
||||
if not vm.is_halted():
|
||||
vm.kill()
|
||||
@ -252,7 +252,13 @@ def main(args=None, app=None):
|
||||
if not args.really:
|
||||
parser.error('Do not call this tool directly.')
|
||||
if args.action == 'post-install':
|
||||
return post_install(args)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
loop.run_until_complete(post_install(args))
|
||||
loop.stop()
|
||||
loop.run_forever()
|
||||
finally:
|
||||
loop.close()
|
||||
elif args.action == 'pre-remove':
|
||||
pre_remove(args)
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user