123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- #!/usr/bin/python2 -O
- '''Qubes Virtual Machines
- Main public classes
- -------------------
- .. autoclass:: BaseVM
- :members:
- :show-inheritance:
- .. autoclass:: property
- :members:
- :show-inheritance:
- Helper classes and functions
- ----------------------------
- .. autoclass:: VMPlugin
- :members:
- :show-inheritance:
- Particular VM classes
- ---------------------
- Main types:
- .. toctree::
- :maxdepth: 1
- qubesvm
- appvm
- templatevm
- Special VM types:
- .. toctree::
- :maxdepth: 1
- netvm
- proxyvm
- dispvm
- adminvm
- HVMs:
- .. toctree::
- :maxdepth: 1
- hvm
- templatehvm
- '''
- import collections
- import functools
- import sys
- import dateutil.parser
- import qubes.plugins
- class property(object):
- '''Qubes VM property.
- This class holds one property that can be saved and loaded from qubes.xml
- :param str name: name of the property
- :param object default: default value
- :param type type: if not :py:obj:`None`, this is used to initialise value
- :param int order: order of evaluation (bigger order values are later)
- :param str doc: docstring
- '''
- def __init__(self, name, default=None, type=None, order=0, doc=None):
- self.__name__ = name
- self._default = default
- self._type = type
- self.order = order
- self.__doc__ = doc
- self._attr_name = '_qubesprop_' + self.__name__
- def __get__(self, instance, owner):
- if instance is None:
- return self
- try:
- return getattr(instance, self._attr_name)
- except AttributeError:
- if self._default is None:
- raise AttributeError('property not set')
- else:
- return self._default
- def __set__(self, instance, value):
- setattr(instance, self._attr_name,
- (self._type(value) if self._type is not None else value))
- def __repr__(self):
- return '<{} object at {:#x} name={!r} default={!r}>'.format(
- self.__class__.__name__, id(self), self.__name__, self._default)
- def __hash__(self):
- return hash(self.__name__)
- def __eq__(self, other):
- return self.__name__ == other.__name__
- class VMPlugin(qubes.plugins.Plugin):
- '''Metaclass for :py:class:`.BaseVM`'''
- def __init__(cls, name, bases, dict_):
- super(VMPlugin, cls).__init__(name, bases, dict_)
- cls.__hooks__ = collections.defaultdict(list)
- class BaseVM(object):
- __metaclass__ = VMPlugin
- def get_props_list(self):
- '''List all properties attached to this VM'''
- props = set()
- for class_ in self.__class__.__mro__:
- props.update(prop for prop in class_.__dict__.values()
- 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 __repr__(self):
- return '<{} object at {:#x} {}>'.format(
- self.__class__.__name__, id(self),
- ' '.join('{}={}'.format(prop.__name__, getattr(self, prop.__name__))
- for prop in self.get_props_list()))
- @classmethod
- def add_hook(cls, event, f):
- '''Add hook to entire VM class and all subclasses
- :param str event: event type
- :param callable f: function to fire on event
- Prototype of the function depends on the exact type of event. Classes
- which inherit from this class will also inherit the hook.
- '''
- cls.__hooks__[event].append(f)
- def fire_hooks(self, event, *args, **kwargs):
- '''Fire hooks associated with an event.
- :param str event: event type
- *args* and *kwargs* are passed to each function
- '''
- for cls in self.__class__.__mro__:
- if not hasattr(cls, '__hooks__'): continue
- for hook in cls.__hooks__[event]:
- hook(self, *args, **kwargs)
- def load(class_, D):
- cls = BaseVM[class_]
- return cls(D)
- __all__ = qubes.plugins.load(__file__)
|