Skip to content

Commit

Permalink
tools/qvm-run: wait for user session unless qvm-run --no-gui is used
Browse files Browse the repository at this point in the history
Avoid race condition with X server startup, especially important for
qvm-run --autostart.
  • Loading branch information
marmarek committed May 17, 2017
1 parent 210876b commit 2d7ca9f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
51 changes: 44 additions & 7 deletions qubesadmin/tests/tools/qvm_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ def test_000_run_single(self):
# 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', {
Expand All @@ -63,7 +65,8 @@ def test_001_run_multiple(self):
# 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, [
Expand Down Expand Up @@ -96,7 +99,7 @@ def test_002_passio(self):
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)
Expand Down Expand Up @@ -124,7 +127,7 @@ def test_002_color_output(self):
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)
Expand Down Expand Up @@ -154,7 +157,8 @@ def test_003_no_color_output(self):
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)
Expand Down Expand Up @@ -184,7 +188,8 @@ def test_004_no_filter_esc(self):
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)
Expand All @@ -210,7 +215,7 @@ def test_005_localcmd(self):
# ('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)
Expand All @@ -225,3 +230,35 @@ def test_005_localcmd(self):
('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()
4 changes: 4 additions & 0 deletions qubesadmin/tools/qvm_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 2d7ca9f

Please sign in to comment.