tools/qvm-run: wait for user session unless qvm-run --no-gui is used

Avoid race condition with X server startup, especially important for
qvm-run --autostart.
This commit is contained in:
Marek Marczykowski-Górecki 2017-05-17 11:07:48 +02:00
parent 210876bd8f
commit 2d7ca9f95e
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 48 additions and 7 deletions

View File

@ -41,7 +41,9 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
# self.app.expected_calls[
# ('test-vm', 'admin.vm.List', None, None)] = \
# b'0\x00test-vm class=AppVM state=Running\n'
ret = qubesadmin.tools.qvm_run.main(['test-vm', 'command'], app=self.app)
ret = qubesadmin.tools.qvm_run.main(
['--no-gui', 'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
self.assertEqual(self.app.service_calls, [
('test-vm', 'qubes.VMShell', {
@ -63,7 +65,8 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
# self.app.expected_calls[
# ('test-vm', 'admin.vm.List', None, None)] = \
# b'0\x00test-vm class=AppVM state=Running\n'
ret = qubesadmin.tools.qvm_run.main(['test-vm', 'test-vm2', 'command'],
ret = qubesadmin.tools.qvm_run.main(
['--no-gui', 'test-vm', 'test-vm2', 'command'],
app=self.app)
self.assertEqual(ret, 0)
self.assertEqual(self.app.service_calls, [
@ -96,7 +99,7 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
echo = subprocess.Popen(['echo', 'some-data'], stdout=subprocess.PIPE)
with unittest.mock.patch('sys.stdin', echo.stdout):
ret = qubesadmin.tools.qvm_run.main(
['--pass-io', 'test-vm', 'command'],
['--no-gui', '--pass-io', 'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
@ -124,7 +127,7 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
with unittest.mock.patch('sys.stdin', echo.stdout):
with unittest.mock.patch('sys.stdout', stdout):
ret = qubesadmin.tools.qvm_run.main(
['--pass-io', 'test-vm', 'command'],
['--no-gui', '--pass-io', 'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
@ -154,7 +157,8 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
with unittest.mock.patch('sys.stdin', echo.stdout):
with unittest.mock.patch('sys.stdout', stdout):
ret = qubesadmin.tools.qvm_run.main(
['--pass-io', '--no-color-output', 'test-vm', 'command'],
['--no-gui', '--pass-io', '--no-color-output',
'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
@ -184,7 +188,8 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
with unittest.mock.patch('sys.stdin', echo.stdout):
with unittest.mock.patch('sys.stdout', stdout):
ret = qubesadmin.tools.qvm_run.main(
['--pass-io', '--no-filter-esc', 'test-vm', 'command'],
['--no-gui', '--pass-io', '--no-filter-esc',
'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
@ -210,7 +215,7 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
# ('test-vm', 'admin.vm.List', None, None)] = \
# b'0\x00test-vm class=AppVM state=Running\n'
ret = qubesadmin.tools.qvm_run.main(
['--pass-io', '--localcmd', 'local-command',
['--no-gui', '--pass-io', '--localcmd', 'local-command',
'test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
@ -225,3 +230,35 @@ class TC_00_qvm_run(qubesadmin.tests.QubesTestCase):
('test-vm', 'qubes.VMShell', b'command\n')
])
self.assertAllCalled()
def test_006_run_single_with_gui(self):
self.app.expected_calls[
('dom0', 'admin.vm.List', None, None)] = \
b'0\x00test-vm class=AppVM state=Running\n'
self.app.expected_calls[
('test-vm', 'admin.vm.property.Get', 'default_user', None)] = \
b'0\x00default=yes type=str user'
# self.app.expected_calls[
# ('test-vm', 'admin.vm.List', None, None)] = \
# b'0\x00test-vm class=AppVM state=Running\n'
ret = qubesadmin.tools.qvm_run.main(
['test-vm', 'command'],
app=self.app)
self.assertEqual(ret, 0)
# make sure we have the same instance below
self.assertEqual(self.app.service_calls, [
('test-vm', 'qubes.WaitForSession', {
'stdout': subprocess.DEVNULL,
'stderr': subprocess.DEVNULL,
}),
('test-vm', 'qubes.WaitForSession', b'user'),
('test-vm', 'qubes.VMShell', {
'filter_esc': True,
'localcmd': None,
'stdout': subprocess.DEVNULL,
'stderr': subprocess.DEVNULL,
'user': None,
}),
('test-vm', 'qubes.VMShell', b'command\n')
])
self.assertAllCalled()

View File

@ -153,6 +153,10 @@ def main(args=None, app=None):
if args.passio and not args.localcmd:
loop = asyncio.new_event_loop()
loop.add_signal_handler(signal.SIGCHLD, loop.stop)
if args.gui:
wait_session = vm.run_service('qubes.WaitForSession',
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
wait_session.communicate(vm.default_user.encode())
proc = vm.run_service('qubes.VMShell',
user=args.user,
localcmd=args.localcmd,