vm: implement tag manager to fire events on change

While at it, adjust implementation to specification: tags don't have
value, only one bit of information (present/not present).

Fixes QubesOS/qubes-issues#2686
This commit is contained in:
Marek Marczykowski-Górecki 2017-05-13 16:27:34 +02:00
父節點 68a426f0ba
當前提交 ba86d6da79
沒有發現已知的金鑰在資料庫的簽署中
GPG Key ID: 063938BA42CFA724
共有 3 個文件被更改,包括 97 次插入5 次删除

查看文件

@ -67,7 +67,7 @@ class TC_10_BaseVM(qubes.tests.QubesTestCase):
</properties>
<tags>
<tag name="testtag">tagvalue</tag>
<tag name="testtag"/>
</tags>
<features>
@ -101,7 +101,7 @@ class TC_10_BaseVM(qubes.tests.QubesTestCase):
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.tags, {'testtag'})
self.assertEqual(vm.features, {
'testfeature_empty': '',
'testfeature_aqq': 'aqq',

查看文件

@ -28,6 +28,7 @@
import datetime
import os
import re
import string
import subprocess
import sys
import xml.parsers.expat
@ -159,6 +160,82 @@ class Features(dict):
return default
class Tags(set):
'''Manager of the tags.
Tags are simple: tag either can be present on qube or not. Tag is a
simple string consisting of ASCII alphanumeric characters, plus `_` and
`-`.
This class inherits from set, but has most of the methods that manipulate
the item disarmed (they raise NotImplementedError). The ones that are left
fire appropriate events on the qube that owns an instance of this class.
'''
#
# Those are the methods that affect contents. Either disarm them or make
# them report appropriate events. Good approach is to rewrite them carefully
# using official documentation, but use only our (overloaded) methods.
#
def __init__(self, vm, seq=()):
super(Tags, self).__init__()
self.vm = vm
self.update(seq)
def clear(self):
'''Remove all tags'''
for item in tuple(self):
self.remove(item)
def symmetric_difference_update(self, *args, **kwargs):
'''Not implemented
:raises: NotImplementedError
'''
raise NotImplementedError()
def intersection_update(self, *args, **kwargs):
'''Not implemented
:raises: NotImplementedError
'''
raise NotImplementedError()
def pop(self):
'''Not implemented
:raises: NotImplementedError
'''
raise NotImplementedError()
def discard(self, elem):
'''Remove a tag if present'''
if elem in self:
self.remove(elem)
def update(self, *others):
'''Add tags from iterable(s)'''
for other in others:
for elem in other:
self.add(elem)
def add(self, elem):
'''Add a tag'''
allowed_chars = string.ascii_letters + string.digits + '_-'
if any(i not in allowed_chars for i in elem):
raise ValueError('Invalid character in tag')
if elem in self:
return
self.vm.fire_event('domain-tag-add', tag=elem)
super(Tags, self).add(elem)
def remove(self, elem):
'''Remove a tag'''
super(Tags, self).remove(elem)
self.vm.fire_event('domain-tag-delete', tag=elem)
#
# end of overriding
#
class BaseVM(qubes.PropertyHolder):
'''Base class for all VMs
@ -192,7 +269,7 @@ class BaseVM(qubes.PropertyHolder):
self.devices = devices or qubes.devices.DeviceManager(self)
#: user-specified tags
self.tags = tags or {}
self.tags = Tags(self, tags or ())
#: logger instance for logging messages related to this VM
self.log = None
@ -223,7 +300,7 @@ class BaseVM(qubes.PropertyHolder):
# tags
for node in self.xml.xpath('./tags/tag'):
self.tags[node.get('name')] = node.text
self.tags.add(node.get('name'))
# SEE:1815 firewall, policy.
@ -262,7 +339,6 @@ class BaseVM(qubes.PropertyHolder):
tags = lxml.etree.Element('tags')
for tag in self.tags:
node = lxml.etree.Element('tag', name=tag)
node.text = self.tags[tag]
tags.append(node)
element.append(tags)

查看文件

@ -304,6 +304,22 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
:param event: Event name (``'domain-feature-set'``)
:param key: feature name
.. event:: domain-tag-add (subject, event, tag)
A tag was added.
:param subject: Event emitter (the qube object)
:param event: Event name (``'domain-tag-add'``)
:param tag: tag name
.. event:: domain-tag-delete (subject, event, tag)
A feature was removed.
:param subject: Event emitter (the qube object)
:param event: Event name (``'domain-tag-delete'``)
:param tag: tag name
.. event:: feature-request (subject, event, *, untrusted_features)
The domain is performing a feature request.