Merge branch 'windows-tools'
* windows-tools: doc: add info what properties are inherited from template Add 'gui-emulated' feature qvm-start-gui: fix handlign rpc-clipboard feature
This commit is contained in:
commit
87122e54c9
@ -59,13 +59,28 @@ List of known features
|
|||||||
gui
|
gui
|
||||||
^^^
|
^^^
|
||||||
|
|
||||||
Qube provide any kind of GUI. Setting this feature to :py:obj:`False` disable
|
Qube has gui-agent installed. Setting this feature to :py:obj:`True` enables GUI
|
||||||
GUI for given qubes - both gui-agent based and emulated VGA based one. Setting
|
based on a gui-agent installed inside the VM.
|
||||||
this feature to :py:obj:`True` enable gui-agent based GUI (i.e. with support of
|
See also `gui-emulated` feature.
|
||||||
tools installed inside of qube). Not setting this feature at all, enable showing
|
|
||||||
VGA emulated output.
|
|
||||||
|
|
||||||
Default: show emulated VGA output only
|
If neither `gui` nor `gui-emulated` is set, emulated VGA is used (if
|
||||||
|
applicable for given VM virtualization mode).
|
||||||
|
|
||||||
|
gui-emulated
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Qube provides GUI through emulated VGA. Setting this feature to
|
||||||
|
:py:obj:`True` enables emulated VGA output. Note that when gui-agent connects to
|
||||||
|
actual VM, emulated VGA output is closed (unless `debug` property is set to
|
||||||
|
:py:obj:`True`). It's possible to open emulated VGA output for a running qube,
|
||||||
|
regardless of this feature, using `qvm-start-gui --force-stubdomain QUBE_NAME`
|
||||||
|
command.
|
||||||
|
|
||||||
|
This feature is applicable only when qube's `virt_mode` is set to `hvm`.
|
||||||
|
See also `gui` feature.
|
||||||
|
|
||||||
|
If neither `gui` nor `gui-emulated` is set, emulated VGA is used (if
|
||||||
|
applicable for given VM virtualization mode).
|
||||||
|
|
||||||
qrexec
|
qrexec
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
@ -95,6 +95,8 @@ default_user
|
|||||||
Default user used by :manpage:`qvm-run(1)`. Note that it make sense only on
|
Default user used by :manpage:`qvm-run(1)`. Note that it make sense only on
|
||||||
non-standard template, as the standard one always have "user" account.
|
non-standard template, as the standard one always have "user" account.
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
dispvm_allowed
|
dispvm_allowed
|
||||||
Property type: bool
|
Property type: bool
|
||||||
|
|
||||||
@ -117,7 +119,9 @@ kernel
|
|||||||
Accepted values: kernel version, empty
|
Accepted values: kernel version, empty
|
||||||
|
|
||||||
Kernel version to use. Setting to empty value will use bootloader installed
|
Kernel version to use. Setting to empty value will use bootloader installed
|
||||||
in root volume (of VM's template) - available only for HVM
|
in root volume (of VM's template) - available only for HVM.
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
kernelopts
|
kernelopts
|
||||||
Accepted values: string
|
Accepted values: string
|
||||||
@ -128,6 +132,8 @@ kernelopts
|
|||||||
Some helpful options (for debugging purposes): ``earlyprintk=xen``,
|
Some helpful options (for debugging purposes): ``earlyprintk=xen``,
|
||||||
``init=/bin/bash``
|
``init=/bin/bash``
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
label
|
label
|
||||||
Accepted values: ``red``, ``orange``, ``yellow``, ``green``, ``gray``,
|
Accepted values: ``red``, ``orange``, ``yellow``, ``green``, ``gray``,
|
||||||
``blue``, ``purple``, ``black``
|
``blue``, ``purple``, ``black``
|
||||||
@ -151,6 +157,8 @@ maxmem
|
|||||||
qmemman disabled, this will be overridden by *memory* property (at VM
|
qmemman disabled, this will be overridden by *memory* property (at VM
|
||||||
startup).
|
startup).
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
memory
|
memory
|
||||||
Accepted values: memory size in MB
|
Accepted values: memory size in MB
|
||||||
|
|
||||||
@ -158,6 +166,8 @@ memory
|
|||||||
- before qmemman starts managing memory for this VM. For VM with qmemman
|
- before qmemman starts managing memory for this VM. For VM with qmemman
|
||||||
disabled, this is static memory size.
|
disabled, this is static memory size.
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
name
|
name
|
||||||
Accepted values: alphanumerical name
|
Accepted values: alphanumerical name
|
||||||
|
|
||||||
@ -184,6 +194,8 @@ qrexec_timeout
|
|||||||
Ignored if qrexec not installed at all (`qrexec` feature not set, see
|
Ignored if qrexec not installed at all (`qrexec` feature not set, see
|
||||||
:manpage:`qvm-features(1)`).
|
:manpage:`qvm-features(1)`).
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
stubdom_mem
|
stubdom_mem
|
||||||
Accepted values: memory in MB
|
Accepted values: memory in MB
|
||||||
|
|
||||||
@ -202,12 +214,16 @@ vcpus
|
|||||||
Number of CPU (cores) available to VM. Some VM types (eg DispVM) will not
|
Number of CPU (cores) available to VM. Some VM types (eg DispVM) will not
|
||||||
work properly with more than one CPU.
|
work properly with more than one CPU.
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
virt_mode
|
virt_mode
|
||||||
Accepted values: ``hvm``, ``pv``
|
Accepted values: ``hvm``, ``pv``
|
||||||
|
|
||||||
Virtualisation mode in VM should be started. ``hvm`` allow to install
|
Virtualisation mode in VM should be started. ``hvm`` allow to install
|
||||||
operating system without Xen-specific integration.
|
operating system without Xen-specific integration.
|
||||||
|
|
||||||
|
TemplateBasedVM use its template's value as a default.
|
||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -87,6 +87,10 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('dom0', 'admin.label.Index', 'red', None)] = \
|
('dom0', 'admin.label.Index', 'red', None)] = \
|
||||||
b'0\x001'
|
b'0\x001'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
||||||
|
'rpc-clipboard', None)] = \
|
||||||
|
b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00'
|
||||||
|
|
||||||
with unittest.mock.patch.object(self.launcher, 'kde_guid_args') as \
|
with unittest.mock.patch.object(self.launcher, 'kde_guid_args') as \
|
||||||
kde_mock:
|
kde_mock:
|
||||||
@ -117,6 +121,10 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('dom0', 'admin.label.Index', 'red', None)] = \
|
('dom0', 'admin.label.Index', 'red', None)] = \
|
||||||
b'0\x001'
|
b'0\x001'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
||||||
|
'rpc-clipboard', None)] = \
|
||||||
|
b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00'
|
||||||
|
|
||||||
with unittest.mock.patch.object(self.launcher, 'kde_guid_args') as \
|
with unittest.mock.patch.object(self.launcher, 'kde_guid_args') as \
|
||||||
kde_mock:
|
kde_mock:
|
||||||
@ -131,6 +139,40 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
def test_012_common_args_rpc_clipboard(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', 'label', None)] = \
|
||||||
|
b'0\x00default=False type=label red'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.property.Get', 'debug', None)] = \
|
||||||
|
b'0\x00default=False type=bool False'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('dom0', 'admin.label.Get', 'red', None)] = \
|
||||||
|
b'0\x000xff0000'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('dom0', 'admin.label.Index', 'red', None)] = \
|
||||||
|
b'0\x001'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
||||||
|
'rpc-clipboard', None)] = \
|
||||||
|
b'0\x001'
|
||||||
|
|
||||||
|
with unittest.mock.patch.object(self.launcher, 'kde_guid_args') as \
|
||||||
|
kde_mock:
|
||||||
|
kde_mock.return_value = []
|
||||||
|
|
||||||
|
args = self.launcher.common_guid_args(self.app.domains['test-vm'])
|
||||||
|
self.assertEqual(args, [
|
||||||
|
'/usr/bin/qubes-guid', '-N', 'test-vm',
|
||||||
|
'-c', '0xff0000',
|
||||||
|
'-i', '/usr/share/icons/hicolor/128x128/devices/appvm-red.png',
|
||||||
|
'-l', '1', '-q', '-Q'])
|
||||||
|
|
||||||
|
self.assertAllCalled()
|
||||||
|
|
||||||
@unittest.mock.patch('asyncio.create_subprocess_exec')
|
@unittest.mock.patch('asyncio.create_subprocess_exec')
|
||||||
def test_020_start_gui_for_vm(self, proc_mock):
|
def test_020_start_gui_for_vm(self, proc_mock):
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
@ -186,10 +228,6 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('test-vm', 'admin.vm.property.Get', 'debug', None)] = \
|
('test-vm', 'admin.vm.property.Get', 'debug', None)] = \
|
||||||
b'0\x00default=False type=bool False'
|
b'0\x00default=False type=bool False'
|
||||||
self.app.expected_calls[
|
|
||||||
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'rpc-clipboard',
|
|
||||||
None)] = \
|
|
||||||
b'0\x00True'
|
|
||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
||||||
'no-monitor-layout', None)] = \
|
'no-monitor-layout', None)] = \
|
||||||
@ -199,7 +237,7 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
loop.run_until_complete(self.launcher.start_gui_for_vm(
|
loop.run_until_complete(self.launcher.start_gui_for_vm(
|
||||||
self.app.domains['test-vm']))
|
self.app.domains['test-vm']))
|
||||||
# common arguments dropped for simplicity
|
# common arguments dropped for simplicity
|
||||||
proc_mock.assert_called_once_with('-d', '3000', '-n', '-Q')
|
proc_mock.assert_called_once_with('-d', '3000', '-n')
|
||||||
|
|
||||||
self.assertAllCalled()
|
self.assertAllCalled()
|
||||||
|
|
||||||
@ -226,10 +264,6 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('test-vm', 'admin.vm.property.Get', 'debug', None)] = \
|
('test-vm', 'admin.vm.property.Get', 'debug', None)] = \
|
||||||
b'0\x00default=False type=bool False'
|
b'0\x00default=False type=bool False'
|
||||||
self.app.expected_calls[
|
|
||||||
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'rpc-clipboard',
|
|
||||||
None)] = \
|
|
||||||
b'0\x00True'
|
|
||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
('test-vm', 'admin.vm.feature.CheckWithTemplate',
|
||||||
'no-monitor-layout', None)] = \
|
'no-monitor-layout', None)] = \
|
||||||
@ -252,7 +286,7 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.domains['test-vm']))
|
self.app.domains['test-vm']))
|
||||||
# common arguments dropped for simplicity
|
# common arguments dropped for simplicity
|
||||||
mock_proc.assert_called_once_with(
|
mock_proc.assert_called_once_with(
|
||||||
'-d', '3000', '-n', '-Q', '-K', '1234')
|
'-d', '3000', '-n', '-K', '1234')
|
||||||
finally:
|
finally:
|
||||||
unittest.mock.patch.stopall()
|
unittest.mock.patch.stopall()
|
||||||
|
|
||||||
@ -275,6 +309,43 @@ class TC_00_qvm_start_gui(qubesadmin.tests.QubesTestCase):
|
|||||||
self.app.expected_calls[
|
self.app.expected_calls[
|
||||||
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui', None)] = \
|
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui', None)] = \
|
||||||
b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00'
|
b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui-emulated',
|
||||||
|
None)] = \
|
||||||
|
b'2\x00QubesFeatureNotFoundError\x00\x00Feature not set\x00'
|
||||||
|
proc_mock = unittest.mock.Mock()
|
||||||
|
with unittest.mock.patch('asyncio.create_subprocess_exec',
|
||||||
|
lambda *args: self.mock_coroutine(proc_mock, *args)):
|
||||||
|
with unittest.mock.patch.object(self.launcher,
|
||||||
|
'common_guid_args', lambda vm: []):
|
||||||
|
loop.run_until_complete(self.launcher.start_gui_for_stubdomain(
|
||||||
|
self.app.domains['test-vm']))
|
||||||
|
# common arguments dropped for simplicity
|
||||||
|
proc_mock.assert_called_once_with('-d', '3001', '-t', '3000')
|
||||||
|
|
||||||
|
self.assertAllCalled()
|
||||||
|
|
||||||
|
def test_031_start_gui_for_stubdomain_forced(self):
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
self.addCleanup(loop.close)
|
||||||
|
|
||||||
|
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', 'xid', None)] = \
|
||||||
|
b'0\x00default=False type=int 3000'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.property.Get', 'stubdom_xid', None)] = \
|
||||||
|
b'0\x00default=False type=int 3001'
|
||||||
|
# self.app.expected_calls[
|
||||||
|
# ('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui', None)] = \
|
||||||
|
# b'0\x00'
|
||||||
|
self.app.expected_calls[
|
||||||
|
('test-vm', 'admin.vm.feature.CheckWithTemplate', 'gui-emulated',
|
||||||
|
None)] = \
|
||||||
|
b'0\x001'
|
||||||
proc_mock = unittest.mock.Mock()
|
proc_mock = unittest.mock.Mock()
|
||||||
with unittest.mock.patch('asyncio.create_subprocess_exec',
|
with unittest.mock.patch('asyncio.create_subprocess_exec',
|
||||||
lambda *args: self.mock_coroutine(proc_mock, *args)):
|
lambda *args: self.mock_coroutine(proc_mock, *args)):
|
||||||
|
@ -167,6 +167,9 @@ class GUILauncher(object):
|
|||||||
else:
|
else:
|
||||||
guid_cmd += ['-q']
|
guid_cmd += ['-q']
|
||||||
|
|
||||||
|
if vm.features.check_with_template('rpc-clipboard', False):
|
||||||
|
guid_cmd.extend(['-Q'])
|
||||||
|
|
||||||
guid_cmd += self.kde_guid_args(vm)
|
guid_cmd += self.kde_guid_args(vm)
|
||||||
return guid_cmd
|
return guid_cmd
|
||||||
|
|
||||||
@ -191,9 +194,6 @@ class GUILauncher(object):
|
|||||||
if vm.virt_mode == 'hvm':
|
if vm.virt_mode == 'hvm':
|
||||||
guid_cmd.extend(['-n'])
|
guid_cmd.extend(['-n'])
|
||||||
|
|
||||||
if vm.features.check_with_template('rpc-clipboard', False):
|
|
||||||
guid_cmd.extend(['-Q'])
|
|
||||||
|
|
||||||
stubdom_guid_pidfile = self.guid_pidfile(vm.stubdom_xid)
|
stubdom_guid_pidfile = self.guid_pidfile(vm.stubdom_xid)
|
||||||
if not vm.debug and os.path.exists(stubdom_guid_pidfile):
|
if not vm.debug and os.path.exists(stubdom_guid_pidfile):
|
||||||
# Terminate stubdom guid once "real" gui agent connects
|
# Terminate stubdom guid once "real" gui agent connects
|
||||||
@ -215,9 +215,13 @@ class GUILauncher(object):
|
|||||||
This function is a coroutine.
|
This function is a coroutine.
|
||||||
'''
|
'''
|
||||||
want_stubdom = force
|
want_stubdom = force
|
||||||
# if no 'gui' feature set at all, assume no gui agent installed
|
|
||||||
if not want_stubdom and \
|
if not want_stubdom and \
|
||||||
vm.features.check_with_template('gui', None) is None:
|
vm.features.check_with_template('gui-emulated', False):
|
||||||
|
want_stubdom = True
|
||||||
|
# if no 'gui' or 'gui-emulated' feature set at all, use emulated GUI
|
||||||
|
if not want_stubdom and \
|
||||||
|
vm.features.check_with_template('gui', None) is None and \
|
||||||
|
vm.features.check_with_template('gui-emulated', None) is None:
|
||||||
want_stubdom = True
|
want_stubdom = True
|
||||||
if not want_stubdom and vm.debug:
|
if not want_stubdom and vm.debug:
|
||||||
want_stubdom = True
|
want_stubdom = True
|
||||||
@ -241,13 +245,13 @@ class GUILauncher(object):
|
|||||||
:param force_stubdom: Force GUI daemon for stubdomain, even if the
|
:param force_stubdom: Force GUI daemon for stubdomain, even if the
|
||||||
one for target AppVM is running.
|
one for target AppVM is running.
|
||||||
'''
|
'''
|
||||||
if not vm.features.check_with_template('gui', True):
|
|
||||||
return
|
|
||||||
|
|
||||||
if vm.virt_mode == 'hvm':
|
if vm.virt_mode == 'hvm':
|
||||||
yield from self.start_gui_for_stubdomain(vm,
|
yield from self.start_gui_for_stubdomain(vm,
|
||||||
force=force_stubdom)
|
force=force_stubdom)
|
||||||
|
|
||||||
|
if not vm.features.check_with_template('gui', True):
|
||||||
|
return
|
||||||
|
|
||||||
if not os.path.exists(self.guid_pidfile(vm.xid)):
|
if not os.path.exists(self.guid_pidfile(vm.xid)):
|
||||||
yield from self.start_gui_for_vm(vm, monitor_layout=monitor_layout)
|
yield from self.start_gui_for_vm(vm, monitor_layout=monitor_layout)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user