qubes/vm: New XML format loading
This commit is contained in:
parent
f3673dd34c
commit
87ae0112eb
@ -51,6 +51,7 @@ HVMs:
|
||||
|
||||
'''
|
||||
|
||||
import ast
|
||||
import collections
|
||||
import functools
|
||||
import sys
|
||||
@ -115,6 +116,16 @@ class VMPlugin(qubes.plugins.Plugin):
|
||||
cls.__hooks__ = collections.defaultdict(list)
|
||||
|
||||
class BaseVM(object):
|
||||
'''Base class for all VMs
|
||||
|
||||
:param xml: xml node from which to deserialise
|
||||
:type xml: :py:class:`lxml.etree._Element` or :py:obj:`None`
|
||||
|
||||
This class is responsible for serialising and deserialising machines and
|
||||
provides basic framework. It contains no management logic. For that, see
|
||||
:py:class:`qubes.vm.qubesvm.QubesVM`.
|
||||
'''
|
||||
|
||||
__metaclass__ = VMPlugin
|
||||
|
||||
def get_props_list(self):
|
||||
@ -125,10 +136,45 @@ class BaseVM(object):
|
||||
if isinstance(prop, property))
|
||||
return sorted(props, key=lambda prop: (prop.order, prop.__name__))
|
||||
|
||||
def __init__(self, D):
|
||||
for prop in self.get_props_list():
|
||||
if prop.__name__ in D:
|
||||
setattr(self, prop.__name__, D[prop.__name__])
|
||||
def __init__(self, xml):
|
||||
self._xml = xml
|
||||
|
||||
self.services = {}
|
||||
self.devices = collections.defaultdict(list)
|
||||
self.tags = {}
|
||||
|
||||
if self._xml is None:
|
||||
return
|
||||
|
||||
# properties
|
||||
all_names = set(prop.__name__ for prop in self.get_props_list())
|
||||
for node in self._xml.xpath('.//property'):
|
||||
name = node.get('name')
|
||||
value = node.get('ref') or node.text
|
||||
|
||||
if not name in all_names:
|
||||
raise AttributeError(
|
||||
'No property {!r} found in {!r}'.format(
|
||||
name, self.__class__))
|
||||
|
||||
setattr(self, name, value)
|
||||
|
||||
# tags
|
||||
for node in self._xml.xpath('.//tag'):
|
||||
self.tags[node.get('name')] = node.text
|
||||
|
||||
# services
|
||||
for node in self._xml.xpath('.//service'):
|
||||
self.services[node.text] = bool(ast.literal_eval(node.get('enabled', 'True')))
|
||||
|
||||
# devices (pci, usb, ...)
|
||||
for parent in self._xml.xpath('.//devices'):
|
||||
devclass = parent.get('class')
|
||||
for node in parent.xpath('./device'):
|
||||
self.devices[devclass].append(node.text)
|
||||
|
||||
# firewall
|
||||
#TODO
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} object at {:#x} {}>'.format(
|
||||
@ -150,7 +196,7 @@ class BaseVM(object):
|
||||
cls.__hooks__[event].append(f)
|
||||
|
||||
def fire_hooks(self, event, *args, **kwargs):
|
||||
'''Fire hooks associated with an event.
|
||||
'''Fire hooks associated with an event
|
||||
|
||||
:param str event: event type
|
||||
|
||||
|
88
tests/vm.py
Normal file
88
tests/vm.py
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/python2 -O
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import lxml.etree
|
||||
|
||||
sys.path.insert(0, '../')
|
||||
import qubes.vm
|
||||
|
||||
class TestVM(qubes.vm.BaseVM):
|
||||
testprop = qubes.vm.property('testprop')
|
||||
testlabel = qubes.vm.property('testlabel')
|
||||
defaultprop = qubes.vm.property('defaultprop', default='defaultvalue')
|
||||
|
||||
class TC_BaseVM(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.xml = lxml.etree.XML('''
|
||||
<qubes version="3"> <!-- xmlns="https://qubes-os.org/QubesXML/1" -->
|
||||
<labels>
|
||||
<label id="label-1" color="#cc0000">red</label>
|
||||
</labels>
|
||||
|
||||
<domains>
|
||||
<domain id="domain-1" class="TestVM">
|
||||
<properties>
|
||||
<property name="testprop">testvalue</property>
|
||||
<property name="testlabel" ref="label-1" />
|
||||
</properties>
|
||||
|
||||
<tags>
|
||||
<tag name="testtag">tagvalue</tag>
|
||||
</tags>
|
||||
|
||||
<services>
|
||||
<service>testservice</service>
|
||||
<service enabled="True">enabledservice</service>
|
||||
<service enabled="False">disabledservice</service>
|
||||
</services>
|
||||
|
||||
<devices class="pci">
|
||||
<device>00:11.22</device>
|
||||
</devices>
|
||||
|
||||
<devices class="usb" />
|
||||
<devices class="audio-in" />
|
||||
<devices class="firewire" />
|
||||
<devices class="i2c" />
|
||||
<devices class="isa" />
|
||||
</domain>
|
||||
</domains>
|
||||
</qubes>
|
||||
''')
|
||||
|
||||
def test_000_BaseVM_load(self):
|
||||
node = self.xml.xpath('//domain')[0]
|
||||
vm = TestVM(node)
|
||||
|
||||
self.assertEqual(vm.testprop, 'testvalue')
|
||||
self.assertEqual(vm.testlabel, 'label-1')
|
||||
self.assertEqual(vm.defaultprop, 'defaultvalue')
|
||||
self.assertEqual(vm.tags, {'testtag': 'tagvalue'})
|
||||
self.assertEqual(vm.devices, {'pci': ['00:11.22']})
|
||||
self.assertEqual(vm.services, {
|
||||
'testservice': True,
|
||||
'enabledservice': True,
|
||||
'disabledservice': False,
|
||||
})
|
||||
|
||||
def test_001_BaseVM_nxproperty(self):
|
||||
xml = lxml.etree.XML('''
|
||||
<qubes version="3">
|
||||
<domains>
|
||||
<domain id="domain-1" class="TestVM">
|
||||
<properties>
|
||||
<property name="nxproperty">nxvalue</property>
|
||||
</properties>
|
||||
</domain>
|
||||
</domains>
|
||||
</qubes>
|
||||
''')
|
||||
|
||||
node = xml.xpath('//domain')[0]
|
||||
|
||||
def f():
|
||||
vm = TestVM(node)
|
||||
|
||||
self.assertRaises(AttributeError, f)
|
Loading…
Reference in New Issue
Block a user