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 collections | ||||||
| import functools | import functools | ||||||
| import sys | import sys | ||||||
| @ -115,6 +116,16 @@ class VMPlugin(qubes.plugins.Plugin): | |||||||
|         cls.__hooks__ = collections.defaultdict(list) |         cls.__hooks__ = collections.defaultdict(list) | ||||||
| 
 | 
 | ||||||
| class BaseVM(object): | 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 |     __metaclass__ = VMPlugin | ||||||
| 
 | 
 | ||||||
|     def get_props_list(self): |     def get_props_list(self): | ||||||
| @ -125,10 +136,45 @@ class BaseVM(object): | |||||||
|                 if isinstance(prop, property)) |                 if isinstance(prop, property)) | ||||||
|         return sorted(props, key=lambda prop: (prop.order, prop.__name__)) |         return sorted(props, key=lambda prop: (prop.order, prop.__name__)) | ||||||
| 
 | 
 | ||||||
|     def __init__(self, D): |     def __init__(self, xml): | ||||||
|         for prop in self.get_props_list(): |         self._xml = xml | ||||||
|             if prop.__name__ in D: | 
 | ||||||
|                 setattr(self, prop.__name__, D[prop.__name__]) |         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): |     def __repr__(self): | ||||||
|         return '<{} object at {:#x} {}>'.format( |         return '<{} object at {:#x} {}>'.format( | ||||||
| @ -150,7 +196,7 @@ class BaseVM(object): | |||||||
|         cls.__hooks__[event].append(f) |         cls.__hooks__[event].append(f) | ||||||
| 
 | 
 | ||||||
|     def fire_hooks(self, event, *args, **kwargs): |     def fire_hooks(self, event, *args, **kwargs): | ||||||
|         '''Fire hooks associated with an event. |         '''Fire hooks associated with an event | ||||||
| 
 | 
 | ||||||
|         :param str event: event type |         :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
	 Wojtek Porczyk
						Wojtek Porczyk