Merge branch 'devel-6'
* devel-6: qvm-ls: fix total VM size reporting doc: update manpage of qvm-service tools: qvm-service tool tests: too much copy&paste features: serialize True as '1' tools/qvm-start-gui: add --force-stubdomain options tools/qvm-shutdown: fix help message tools/qvm-shutdown: drop --force option, it isn't supported anymore
This commit is contained in:
commit
f48321dd98
@ -8,6 +8,7 @@ Synopsis
|
||||
========
|
||||
| :command:`qvm-service` [-l] <*vmname*>
|
||||
| :command:`qvm-service` [-e|-d|-D] <*vmname*> <*service*>
|
||||
| :command:`qvm-service` <*vmname*> <*service*> [on|off]
|
||||
|
||||
Options
|
||||
=======
|
||||
@ -27,11 +28,19 @@ Options
|
||||
|
||||
Disable service
|
||||
|
||||
.. option:: --default, -D
|
||||
.. option:: --default, -D, --delete, --unset
|
||||
|
||||
Reset service to its default state (remove from the list). Default state
|
||||
means "lets VM choose" and can depend on VM type (NetVM, AppVM etc).
|
||||
|
||||
.. option:: --verbose, -v
|
||||
|
||||
increase verbosity
|
||||
|
||||
.. option:: --quiet, -q
|
||||
|
||||
decrease verbosity
|
||||
|
||||
Supported services
|
||||
==================
|
||||
|
||||
@ -50,11 +59,6 @@ meminfo-writer
|
||||
remove it (reset to default state), will be recreated with the rule: enabled
|
||||
if VM have no PCI devices assigned, otherwise disabled.
|
||||
|
||||
qubes-dvm
|
||||
Default: disabled
|
||||
|
||||
Used internally when creating DispVM savefile.
|
||||
|
||||
qubes-firewall
|
||||
Default: enabled only in ProxyVM
|
||||
|
||||
@ -72,14 +76,6 @@ qubes-network
|
||||
Expose network for other VMs. This includes enabling network forwarding,
|
||||
MASQUERADE, DNS redirection and basic firewall.
|
||||
|
||||
qubes-netwatcher
|
||||
Default: enabled only in ProxyVM
|
||||
|
||||
Monitor IP change notification from NetVM. When received, reload
|
||||
qubes-firewall service (to force DNS resolution).
|
||||
|
||||
This service makes sense only with qubes-firewall enabled.
|
||||
|
||||
qubes-update-check
|
||||
Default: enabled
|
||||
|
||||
@ -103,12 +99,12 @@ network-manager
|
||||
Enable NetworkManager. Only VM with direct access to network device needs
|
||||
this service, but can be useful in ProxyVM to ease VPN setup.
|
||||
|
||||
ntpd
|
||||
clocksync
|
||||
Default: disabled
|
||||
|
||||
Enable NTPD service. By default Qubes calls ntpdate every 6 minutes in
|
||||
selected VM (aka ClockVM), then propagate the result using qrexec calls.
|
||||
Enabling ntpd *do not* disable this behaviour.
|
||||
Enable NTPD (or equivalent) service. If disabled, VM will sync clock with
|
||||
selected VM (aka ClockVM) instead. ClockVM for particular VM can be set in
|
||||
policy of qubes.GetDate service, using target= parameter.
|
||||
|
||||
qubes-yum-proxy
|
||||
Deprecated name for qubes-updates-proxy.
|
||||
@ -130,9 +126,8 @@ updates-proxy-setup
|
||||
|
||||
.. note::
|
||||
|
||||
this service is automatically enabled when you allow VM to access yum
|
||||
proxy (in firewall settings) and disabled when you deny access to yum
|
||||
proxy.
|
||||
this service is automatically enabled when you allow VM to access updates
|
||||
proxy and disabled when you deny access to updates proxy.
|
||||
|
||||
disable-default-route
|
||||
Default: disabled
|
||||
|
@ -15,7 +15,7 @@
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
:command:`qvm-shutdown` [-h] [--verbose] [--quiet] [--all] [--exclude *EXCLUDE*] [--force] [--wait] [--timeout *TIMEOUT*] [*VMNAME*]
|
||||
:command:`qvm-shutdown` [-h] [--verbose] [--quiet] [--all] [--exclude *EXCLUDE*] [--wait] [--timeout *TIMEOUT*] [*VMNAME*]
|
||||
|
||||
Options
|
||||
-------
|
||||
@ -40,11 +40,6 @@ Options
|
||||
|
||||
exclude the qube from :option:`--all`
|
||||
|
||||
.. option:: --force
|
||||
|
||||
force operation, even if may damage other VMs (eg. shutdown of network
|
||||
provider)
|
||||
|
||||
.. option:: --wait
|
||||
|
||||
wait for the VMs to shut down
|
||||
|
@ -15,7 +15,7 @@
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
:command:`qvm-start-gui` [-h] [--verbose] [--quiet] [--all] [--exclude *EXCLUDE*] [--watch] [--pidfile *PIDFILE*] [--notify-monitory-layout] [*VMNAME* [*VMNAME* ...]]
|
||||
:command:`qvm-start-gui` [-h] [--verbose] [--quiet] [--all] [--exclude *EXCLUDE*] [--watch] [--force-stubdomain] [--pidfile *PIDFILE*] [--notify-monitory-layout] [*VMNAME* [*VMNAME* ...]]
|
||||
|
||||
Options
|
||||
-------
|
||||
@ -44,6 +44,10 @@ Options
|
||||
|
||||
Keep watching for further domains startups, must be used with --all
|
||||
|
||||
.. option:: --force-stubdomain
|
||||
|
||||
Start GUI to stubdomain-emulated VGA, even if gui-agent is running in the VM
|
||||
|
||||
.. option:: --pidfile
|
||||
|
||||
Pidfile path to create in --watch mode
|
||||
|
@ -42,9 +42,10 @@ class Features(object):
|
||||
self.vm.qubesd_call(self.vm.name, 'admin.vm.feature.Remove', key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if value is False:
|
||||
if isinstance(value, bool):
|
||||
# False value needs to be serialized as empty string
|
||||
self.vm.qubesd_call(self.vm.name, 'admin.vm.feature.Set', key, b'')
|
||||
self.vm.qubesd_call(self.vm.name, 'admin.vm.feature.Set', key,
|
||||
b'1' if value else b'')
|
||||
else:
|
||||
self.vm.qubesd_call(self.vm.name, 'admin.vm.feature.Set', key,
|
||||
str(value).encode())
|
||||
|
@ -1350,6 +1350,8 @@ class TC_10_BackupCompatibility(qubesadmin.tests.backup.BackupTestCase):
|
||||
for feature, value in vm['features'].items():
|
||||
if value is False:
|
||||
value = ''
|
||||
elif value is True:
|
||||
value = '1'
|
||||
self.app.expected_calls[
|
||||
(name, 'admin.vm.feature.Set', feature,
|
||||
str(value).encode())] = b'0\0'
|
||||
|
@ -78,7 +78,7 @@ class TC_00_Features(qubesadmin.tests.QubesTestCase):
|
||||
|
||||
def test_021_set_bool(self):
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.feature.Set', 'feature1', b'True')] = \
|
||||
('test-vm', 'admin.vm.feature.Set', 'feature1', b'1')] = \
|
||||
b'0\0'
|
||||
self.vm.features['feature1'] = True
|
||||
self.assertAllCalled()
|
||||
|
@ -91,162 +91,3 @@ class TC_00_qvm_features(qubesadmin.tests.QubesTestCase):
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_004_running_verbose(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Running\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--running',
|
||||
'some-vm'], app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VM some-vm is running\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_005_running_multi_verbose(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Running\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm2', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm2 class=AppVM state=Running\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--running',
|
||||
'some-vm', 'some-vm2'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VMs some-vm, some-vm2 are running\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_006_running_multi_verbose2(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Running\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm2', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm2 class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm3', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm3 class=AppVM state=Halted\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--running',
|
||||
'--all'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VMs some-vm, some-vm2 are running\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_007_not_running_verbose(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Running\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm3', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm3 class=AppVM state=Halted\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--running',
|
||||
'some-vm3'],
|
||||
app=self.app),
|
||||
1)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'None of given VM is running\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_008_paused(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Paused\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm2', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm2 class=AppVM state=Paused\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--paused',
|
||||
'some-vm2'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VM some-vm2 is paused\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_009_paused_multi(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Paused\n' \
|
||||
b'some-vm3 class=AppVM state=Halted\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm2', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm2 class=AppVM state=Paused\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--paused',
|
||||
'some-vm2', 'some-vm'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VM some-vm2 is paused\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
|
||||
def test_010_template(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Paused\n' \
|
||||
b'some-vm3 class=TemplateVM state=Halted\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--template',
|
||||
'some-vm3'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VM some-vm3 is a template\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_011_template_multi(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n' \
|
||||
b'some-vm2 class=AppVM state=Paused\n' \
|
||||
b'some-vm3 class=TemplateVM state=Halted\n'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_check.main(['--template',
|
||||
'some-vm2', 'some-vm3'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'VM some-vm3 is a template\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
|
203
qubesadmin/tests/tools/qvm_service.py
Normal file
203
qubesadmin/tests/tools/qvm_service.py
Normal file
@ -0,0 +1,203 @@
|
||||
# -*- encoding: utf8 -*-
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2017 Marek Marczykowski-Górecki
|
||||
# <marmarek@invisiblethingslab.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License along
|
||||
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
import unittest
|
||||
|
||||
import qubesadmin.tests
|
||||
import qubesadmin.tools.qvm_service
|
||||
|
||||
|
||||
class TC_00_qvm_service(qubesadmin.tests.QubesTestCase):
|
||||
def test_000_list(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.List', None, None)] = \
|
||||
b'0\x00feature1\nservice.service1\nservice.service2\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Get', 'service.service1', None)] = \
|
||||
b'0\x00value1'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Get', 'service.service2', None)] = \
|
||||
b'0\x00'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(['some-vm'], app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'service1 on\n'
|
||||
'service2 off\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_001_list_l(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.List', None, None)] = \
|
||||
b'0\x00feature1\nservice.service1\nservice.service2\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Get', 'service.service1', None)] = \
|
||||
b'0\x00value1'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Get', 'service.service2', None)] = \
|
||||
b'0\x00'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(['-l', 'some-vm'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'service1 on\n'
|
||||
'service2 off\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_002_enable(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Set',
|
||||
'service.service1', b'1')] = b'0\x00'
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(['some-vm', 'service1',
|
||||
'on'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_003_enable_opt(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Set',
|
||||
'service.service1', b'1')] = b'0\x00'
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(['--enable', 'some-vm',
|
||||
'service1'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertAllCalled()
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_004_enable_opt_mixed(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Set',
|
||||
'service.service1', b'1')] = b'0\x00'
|
||||
with self.assertNotRaises(SystemExit):
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['some-vm', '--enable', 'service1'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_005_disable(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Set',
|
||||
'service.service1', b'')] = b'0\x00'
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['some-vm', 'service1', 'off'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_006_disable_opt(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Set',
|
||||
'service.service1', b'')] = b'0\x00'
|
||||
with self.assertNotRaises(SystemExit):
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['--disable', 'some-vm', 'service1'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_007_get(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Get', 'service.service3', None)] = \
|
||||
b'0\x00value2 with spaces'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(['some-vm', 'service3'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'on\n')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_008_del(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Remove', 'service.srv4', None)] = \
|
||||
b'0\x00'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['--unset', 'some-vm', 'srv4'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_009_del_legacy(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
self.app.expected_calls[
|
||||
('some-vm', 'admin.vm.feature.Remove', 'service.srv4', None)] = \
|
||||
b'0\x00'
|
||||
with qubesadmin.tests.tools.StdoutBuffer() as stdout:
|
||||
self.assertEqual(
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['--default', 'some-vm', 'srv4'],
|
||||
app=self.app),
|
||||
0)
|
||||
self.assertEqual(stdout.getvalue(),
|
||||
'')
|
||||
self.assertAllCalled()
|
||||
|
||||
def test_010_set_invalid(self):
|
||||
self.app.expected_calls[
|
||||
('dom0', 'admin.vm.List', None, None)] = \
|
||||
b'0\x00some-vm class=AppVM state=Running\n'
|
||||
with self.assertRaises(SystemExit):
|
||||
qubesadmin.tools.qvm_service.main(
|
||||
['some-vm', 'service1', 'invalid-value'],
|
||||
app=self.app),
|
||||
self.assertAllCalled()
|
@ -243,7 +243,7 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.property.Reset', 'netvm', None)] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.feature.Set', 'qrexec', b'True')] = b'0\0'
|
||||
('test-vm', 'admin.vm.feature.Set', 'qrexec', b'1')] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.Start', None, None)] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
@ -293,7 +293,7 @@ class TC_00_qvm_template_postprocess(qubesadmin.tests.QubesTestCase):
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.property.Reset', 'netvm', None)] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.feature.Set', 'qrexec', b'True')] = b'0\0'
|
||||
('test-vm', 'admin.vm.feature.Set', 'qrexec', b'1')] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
('test-vm', 'admin.vm.Start', None, None)] = b'0\0'
|
||||
self.app.expected_calls[
|
||||
|
@ -351,7 +351,7 @@ Column('MEMORY',
|
||||
doc='Memory currently used by VM')
|
||||
|
||||
Column('DISK',
|
||||
attr=(lambda vm: vm.storage.get_disk_utilization() / 1024 / 1024),
|
||||
attr=(lambda vm: vm.get_disk_utilization() // 1024 // 1024),
|
||||
doc='Total disk utilisation.')
|
||||
|
||||
|
||||
|
136
qubesadmin/tools/qvm_service.py
Normal file
136
qubesadmin/tools/qvm_service.py
Normal file
@ -0,0 +1,136 @@
|
||||
# coding=utf-8
|
||||
#
|
||||
# The Qubes OS Project, https://www.qubes-os.org/
|
||||
#
|
||||
# Copyright (C) 2010-2016 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
||||
# Copyright (C) 2016 Wojtek Porczyk <woju@invisiblethingslab.com>
|
||||
# Copyright (C) 2017 Marek Marczykowski-Górecki
|
||||
# <marmarek@invisiblethingslab.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
'''qvm-service - Manage domain's services'''
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
import qubesadmin
|
||||
import qubesadmin.exc
|
||||
import qubesadmin.tools
|
||||
|
||||
parser = qubesadmin.tools.QubesArgumentParser(
|
||||
vmname_nargs=1,
|
||||
argument_default=argparse.SUPPRESS,
|
||||
description='manage domain\'s services')
|
||||
|
||||
parser.add_argument('service', metavar='FEATURE',
|
||||
action='store', nargs='?',
|
||||
help='name of the feature')
|
||||
|
||||
parser.add_argument('value', metavar='VALUE',
|
||||
action='store', nargs='?',
|
||||
help='new value of the service')
|
||||
|
||||
parser.add_argument('--unset', '--default', '--delete', '-D',
|
||||
dest='delete', default=False,
|
||||
action='store_true',
|
||||
help='unset service (default to VM preference)')
|
||||
|
||||
parser.add_argument('--list', '-l',
|
||||
dest='list',
|
||||
action='store_true',
|
||||
help='list services (default action)')
|
||||
|
||||
parser.add_argument('--enable', '-e',
|
||||
dest='value',
|
||||
action='store_const', const='1',
|
||||
help='enable service')
|
||||
|
||||
parser.add_argument('--disable', '-d',
|
||||
dest='value',
|
||||
action='store_const', const='0',
|
||||
help='disable service')
|
||||
|
||||
def parse_bool(value):
|
||||
'''Convert string value to bool according to well known representations
|
||||
|
||||
It accepts (case-insensitive) ``'0'``, ``'no'`` and ``false`` as
|
||||
:py:obj:`False` and ``'1'``, ``'yes'`` and ``'true'`` as
|
||||
:py:obj:`True`.
|
||||
'''
|
||||
if isinstance(value, str):
|
||||
lcvalue = value.lower()
|
||||
if lcvalue in ('0', 'no', 'false', 'off'):
|
||||
return False
|
||||
if lcvalue in ('1', 'yes', 'true', 'on'):
|
||||
return True
|
||||
raise qubesadmin.exc.QubesValueError(
|
||||
'Invalid literal for boolean value: {!r}'.format(value))
|
||||
|
||||
return bool(value)
|
||||
|
||||
|
||||
def main(args=None, app=None):
|
||||
'''Main routine of :program:`qvm-features`.
|
||||
|
||||
:param list args: Optional arguments to override those delivered from \
|
||||
command line.
|
||||
'''
|
||||
|
||||
args = parser.parse_args(args, app=app)
|
||||
vm = args.domains[0]
|
||||
|
||||
if not hasattr(args, 'service'):
|
||||
if args.delete:
|
||||
parser.error('--unset requires a feature')
|
||||
|
||||
services = [(feat[len('service.'):],
|
||||
'on' if vm.features[feat] else 'off') for feat in
|
||||
vm.features if feat.startswith('service.')]
|
||||
qubesadmin.tools.print_table(services)
|
||||
|
||||
elif args.delete:
|
||||
if hasattr(args, 'value'):
|
||||
parser.error('cannot both set and unset a value')
|
||||
try:
|
||||
del vm.features['service.' + args.service]
|
||||
except KeyError:
|
||||
pass
|
||||
except qubesadmin.exc.QubesException as err:
|
||||
parser.error_runtime(str(err))
|
||||
|
||||
elif hasattr(args, 'value'):
|
||||
try:
|
||||
vm.features['service.' + args.service] = parse_bool(args.value)
|
||||
except qubesadmin.exc.QubesException as err:
|
||||
parser.error_runtime(str(err))
|
||||
|
||||
else:
|
||||
try:
|
||||
print('on' if vm.features['service.' + args.service] else 'off')
|
||||
return 0
|
||||
except KeyError:
|
||||
return 1
|
||||
except qubesadmin.exc.QubesException as err:
|
||||
parser.error_runtime(str(err))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -40,11 +40,6 @@ import qubesadmin.exc
|
||||
parser = qubesadmin.tools.QubesArgumentParser(
|
||||
description=__doc__, vmname_nargs='+')
|
||||
|
||||
parser.add_argument('--force',
|
||||
action='store_true', default=False,
|
||||
help='force operation, even if may damage other VMs (eg. shutdown of'
|
||||
' network provider)')
|
||||
|
||||
parser.add_argument('--wait',
|
||||
action='store_true', default=False,
|
||||
help='wait for the VMs to shut down')
|
||||
@ -53,7 +48,7 @@ parser.add_argument('--timeout',
|
||||
action='store', type=float,
|
||||
default=60,
|
||||
help='timeout after which domains are killed when using --wait'
|
||||
' (default: %d)')
|
||||
' (default: %(default)d)')
|
||||
|
||||
|
||||
def main(args=None, app=None): # pylint: disable=missing-docstring
|
||||
|
@ -347,6 +347,9 @@ parser = qubesadmin.tools.QubesArgumentParser(
|
||||
description='start GUI for qube(s)', vmname_nargs='*')
|
||||
parser.add_argument('--watch', action='store_true',
|
||||
help='Keep watching for further domains startups, must be used with --all')
|
||||
parser.add_argument('--force-stubdomain', action='store_true',
|
||||
help='Start GUI to stubdomain-emulated VGA, even if gui-agent is running '
|
||||
'in the VM')
|
||||
parser.add_argument('--pidfile', action='store', default=pidfile_path,
|
||||
help='Pidfile path to create in --watch mode')
|
||||
parser.add_argument('--notify-monitor-layout', action='store_true',
|
||||
@ -400,7 +403,8 @@ def main(args=None):
|
||||
tasks = []
|
||||
for vm in args.domains:
|
||||
if vm.is_running():
|
||||
tasks.append(asyncio.ensure_future(launcher.start_gui(vm)))
|
||||
tasks.append(asyncio.ensure_future(launcher.start_gui(
|
||||
vm, force_stubdom=args.force_stubdomain)))
|
||||
if tasks:
|
||||
loop.run_until_complete(asyncio.wait(tasks))
|
||||
loop.stop()
|
||||
|
@ -257,6 +257,10 @@ class QubesVM(qubesadmin.base.PropertyHolder):
|
||||
vm=self.name, vm_name=volname)
|
||||
return self._volumes
|
||||
|
||||
def get_disk_utilization(self):
|
||||
'''Get total disk usage of the VM'''
|
||||
return sum(vol.usage for vol in self.volumes.values())
|
||||
|
||||
def run_service(self, service, **kwargs):
|
||||
'''Run service on this VM
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user