Merge branch 'services'
* services: tests: check clockvm-related handlers doc: include list of extensions qubesvm: fix docstring ext/services: move exporting 'service.*' features to extensions app: update handling features/service os ClockVM
This commit is contained in:
commit
36f1a3abaf
@ -1,8 +1,22 @@
|
||||
:py:mod:`qubes.ext` -- Qubes extensions
|
||||
=======================================
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: qubes.ext
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Extensions defined here
|
||||
-----------------------
|
||||
|
||||
.. autoclass:: qubes.ext.admin.AdminExtension
|
||||
.. autoclass:: qubes.ext.block.BlockDeviceExtension
|
||||
.. autoclass:: qubes.ext.core_features.CoreFeatures
|
||||
.. autoclass:: qubes.ext.gui.GUI
|
||||
.. autoclass:: qubes.ext.pci.PCIDeviceExtension
|
||||
.. autoclass:: qubes.ext.r3compatibility.R3Compatibility
|
||||
.. autoclass:: qubes.ext.services.ServicesExtension
|
||||
|
||||
.. vim: ts=3 sw=3 et
|
||||
|
26
qubes/app.py
26
qubes/app.py
@ -680,7 +680,7 @@ class Qubes(qubes.PropertyHolder):
|
||||
doc='''Which VM to use as `yum` proxy for updating AdminVM and
|
||||
TemplateVMs''')
|
||||
clockvm = qubes.VMProperty('clockvm', load_stage=3,
|
||||
allow_none=True,
|
||||
default=None, allow_none=True,
|
||||
doc='Which VM to use as NTP proxy for updating AdminVM')
|
||||
default_kernel = qubes.property('default_kernel', load_stage=3,
|
||||
doc='Which kernel to use when not overriden in VM')
|
||||
@ -830,17 +830,6 @@ class Qubes(qubes.PropertyHolder):
|
||||
self.property_require('clockvm', allow_none=True)
|
||||
self.property_require('updatevm', allow_none=True)
|
||||
|
||||
# Disable ntpd in ClockVM - to not conflict with ntpdate (both are
|
||||
# using 123/udp port)
|
||||
if hasattr(self, 'clockvm') and self.clockvm is not None:
|
||||
if self.clockvm.features.get('service.ntpd', False):
|
||||
self.log.warning(
|
||||
'VM set as clockvm (%r) has enabled \'ntpd\' service! '
|
||||
'Expect failure when syncing time in dom0.',
|
||||
self.clockvm)
|
||||
else:
|
||||
self.clockvm.features['service.ntpd'] = ''
|
||||
|
||||
for vm in self.domains:
|
||||
vm.events_enabled = True
|
||||
vm.fire_event('domain-load')
|
||||
@ -1173,13 +1162,14 @@ class Qubes(qubes.PropertyHolder):
|
||||
# pylint: disable=unused-argument,no-self-use
|
||||
if newvalue is None:
|
||||
return
|
||||
if newvalue.features.get('service.ntpd', False):
|
||||
raise qubes.exc.QubesVMError(newvalue,
|
||||
'Cannot set {!r} as {!r} since it has ntpd enabled.'.format(
|
||||
newvalue.name, name))
|
||||
else:
|
||||
newvalue.features['service.ntpd'] = ''
|
||||
if 'service.clocksync' not in newvalue.features:
|
||||
newvalue.features['service.clocksync'] = True
|
||||
|
||||
@qubes.events.handler('property-set:clockvm')
|
||||
def on_property_set_clockvm(self, event, name, newvalue, oldvalue=None):
|
||||
# pylint: disable=unused-argument,no-self-use
|
||||
if oldvalue and oldvalue.features.get('service.clocksync', False):
|
||||
del oldvalue.features['service.clocksync']
|
||||
|
||||
@qubes.events.handler(
|
||||
'property-pre-set:default_netvm',
|
||||
|
62
qubes/ext/services.py
Normal file
62
qubes/ext/services.py
Normal file
@ -0,0 +1,62 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
#
|
||||
# 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 General Public License as published by
|
||||
# the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
'''Extension responsible for qvm-service framework'''
|
||||
|
||||
import qubes.ext
|
||||
|
||||
class ServicesExtension(qubes.ext.Extension):
|
||||
'''This extension export features with 'service.' prefix to QubesDB in
|
||||
/qubes-service/ tree.
|
||||
'''
|
||||
# pylint: disable=no-self-use
|
||||
@qubes.ext.handler('domain-qdb-create')
|
||||
def on_domain_qdb_create(self, vm):
|
||||
'''Actually export features'''
|
||||
for feature, value in vm.features.items():
|
||||
if not feature.startswith('service.'):
|
||||
continue
|
||||
service = feature[len('service.'):]
|
||||
# forcefully convert to '0' or '1'
|
||||
vm.untrusted_qdb.write('/qubes-service/{}'.format(service),
|
||||
str(int(bool(value))))
|
||||
|
||||
@qubes.ext.handler('domain-feature-set')
|
||||
def on_domain_feature_set(self, vm, feature, value, oldvalue=None):
|
||||
'''Update /qubes-service/ QubesDB tree in runtime'''
|
||||
# pylint: disable=unused-argument
|
||||
if not vm.is_running():
|
||||
return
|
||||
if not feature.startswith('service.'):
|
||||
return
|
||||
service = feature[len('service.'):]
|
||||
# forcefully convert to '0' or '1'
|
||||
vm.untrusted_qdb.write('/qubes-service/{}'.format(service),
|
||||
str(int(bool(value))))
|
||||
|
||||
@qubes.ext.handler('domain-feature-delete')
|
||||
def on_domain_feature_delete(self, vm, feature):
|
||||
'''Update /qubes-service/ QubesDB tree in runtime'''
|
||||
if not vm.is_running():
|
||||
return
|
||||
if not feature.startswith('service.'):
|
||||
return
|
||||
service = feature[len('service.'):]
|
||||
vm.untrusted_qdb.rm('/qubes-service/{}'.format(service))
|
@ -261,15 +261,41 @@ class TC_30_VMCollection(qubes.tests.QubesTestCase):
|
||||
|
||||
|
||||
class TC_90_Qubes(qubes.tests.QubesTestCase):
|
||||
def tearDown(self):
|
||||
try:
|
||||
os.unlink('/tmp/qubestest.xml')
|
||||
except:
|
||||
pass
|
||||
super(TC_90_Qubes, self).tearDown()
|
||||
|
||||
@qubes.tests.skipUnlessDom0
|
||||
def test_000_init_empty(self):
|
||||
# pylint: disable=no-self-use,unused-variable,bare-except
|
||||
try:
|
||||
os.unlink('/tmp/qubestest.xml')
|
||||
except:
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
qubes.Qubes.create_empty_store('/tmp/qubestest.xml')
|
||||
|
||||
def test_100_clockvm(self):
|
||||
app = qubes.Qubes('/tmp/qubestest.xml', load=False, offline_mode=True)
|
||||
app.load_initial_values()
|
||||
|
||||
template = app.add_new_vm('TemplateVM', name='test-template',
|
||||
label='green')
|
||||
appvm = app.add_new_vm('AppVM', name='test-vm', template=template,
|
||||
label='red')
|
||||
self.assertIsNone(app.clockvm)
|
||||
self.assertNotIn('service.clocksync', appvm.features)
|
||||
self.assertNotIn('service.clocksync', template.features)
|
||||
app.clockvm = appvm
|
||||
self.assertIn('service.clocksync', appvm.features)
|
||||
self.assertTrue(appvm.features['service.clocksync'])
|
||||
app.clockvm = template
|
||||
self.assertNotIn('service.clocksync', appvm.features)
|
||||
self.assertIn('service.clocksync', template.features)
|
||||
self.assertTrue(template.features['service.clocksync'])
|
||||
|
||||
@qubes.tests.skipUnlessGit
|
||||
def test_900_example_xml_in_doc(self):
|
||||
self.assertXMLIsValid(
|
||||
|
@ -289,7 +289,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
:param value: new value
|
||||
:param oldvalue: old value, if any
|
||||
|
||||
.. event:: domain-feature-delete (subject, event, key)
|
||||
.. event:: domain-feature-delete (subject, event, feature)
|
||||
|
||||
A feature was removed.
|
||||
|
||||
@ -1746,14 +1746,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
if tzname:
|
||||
self.untrusted_qdb.write('/qubes-timezone', tzname)
|
||||
|
||||
for feature, value in self.features.items():
|
||||
if not feature.startswith('service.'):
|
||||
continue
|
||||
service = feature[len('service.'):]
|
||||
# forcefully convert to '0' or '1'
|
||||
self.untrusted_qdb.write('/qubes-service/{}'.format(service),
|
||||
str(int(bool(value))))
|
||||
|
||||
self.untrusted_qdb.write('/qubes-block-devices', '')
|
||||
|
||||
self.untrusted_qdb.write('/qubes-usb-devices', '')
|
||||
|
@ -294,6 +294,7 @@ fi
|
||||
%{python3_sitelib}/qubes/ext/pci.py
|
||||
%{python3_sitelib}/qubes/ext/qubesmanager.py
|
||||
%{python3_sitelib}/qubes/ext/r3compatibility.py
|
||||
%{python3_sitelib}/qubes/ext/services.py
|
||||
|
||||
%dir %{python3_sitelib}/qubes/tests
|
||||
%dir %{python3_sitelib}/qubes/tests/__pycache__
|
||||
|
Loading…
Reference in New Issue
Block a user