__init__.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/python2 -O
  2. '''Qubes Virtual Machines
  3. Main public classes
  4. -------------------
  5. .. autoclass:: BaseVM
  6. :members:
  7. :show-inheritance:
  8. .. autoclass:: property
  9. :members:
  10. :show-inheritance:
  11. Helper classes and functions
  12. ----------------------------
  13. .. autoclass:: VMPlugin
  14. :members:
  15. :show-inheritance:
  16. Particular VM classes
  17. ---------------------
  18. Main types:
  19. .. toctree::
  20. :maxdepth: 1
  21. qubesvm
  22. appvm
  23. templatevm
  24. Special VM types:
  25. .. toctree::
  26. :maxdepth: 1
  27. netvm
  28. proxyvm
  29. dispvm
  30. adminvm
  31. HVMs:
  32. .. toctree::
  33. :maxdepth: 1
  34. hvm
  35. templatehvm
  36. '''
  37. import collections
  38. import functools
  39. import sys
  40. import dateutil.parser
  41. import qubes.plugins
  42. class property(object):
  43. '''Qubes VM property.
  44. This class holds one property that can be saved and loaded from qubes.xml
  45. :param str name: name of the property
  46. :param object default: default value
  47. :param type type: if not :py:obj:`None`, this is used to initialise value
  48. :param int order: order of evaluation (bigger order values are later)
  49. :param str doc: docstring
  50. '''
  51. def __init__(self, name, default=None, type=None, order=0, doc=None):
  52. self.__name__ = name
  53. self._default = default
  54. self._type = type
  55. self.order = order
  56. self.__doc__ = doc
  57. self._attr_name = '_qubesprop_' + self.__name__
  58. def __get__(self, instance, owner):
  59. if instance is None:
  60. return self
  61. try:
  62. return getattr(instance, self._attr_name)
  63. except AttributeError:
  64. if self._default is None:
  65. raise AttributeError('property not set')
  66. else:
  67. return self._default
  68. def __set__(self, instance, value):
  69. setattr(instance, self._attr_name,
  70. (self._type(value) if self._type is not None else value))
  71. def __repr__(self):
  72. return '<{} object at {:#x} name={!r} default={!r}>'.format(
  73. self.__class__.__name__, id(self), self.__name__, self._default)
  74. def __hash__(self):
  75. return hash(self.__name__)
  76. def __eq__(self, other):
  77. return self.__name__ == other.__name__
  78. class VMPlugin(qubes.plugins.Plugin):
  79. '''Metaclass for :py:class:`.BaseVM`'''
  80. def __init__(cls, name, bases, dict_):
  81. super(VMPlugin, cls).__init__(name, bases, dict_)
  82. cls.__hooks__ = collections.defaultdict(list)
  83. class BaseVM(object):
  84. __metaclass__ = VMPlugin
  85. def get_props_list(self):
  86. '''List all properties attached to this VM'''
  87. props = set()
  88. for class_ in self.__class__.__mro__:
  89. props.update(prop for prop in class_.__dict__.values()
  90. if isinstance(prop, property))
  91. return sorted(props, key=lambda prop: (prop.order, prop.__name__))
  92. def __init__(self, D):
  93. for prop in self.get_props_list():
  94. if prop.__name__ in D:
  95. setattr(self, prop.__name__, D[prop.__name__])
  96. def __repr__(self):
  97. return '<{} object at {:#x} {}>'.format(
  98. self.__class__.__name__, id(self),
  99. ' '.join('{}={}'.format(prop.__name__, getattr(self, prop.__name__))
  100. for prop in self.get_props_list()))
  101. @classmethod
  102. def add_hook(cls, event, f):
  103. '''Add hook to entire VM class and all subclasses
  104. :param str event: event type
  105. :param callable f: function to fire on event
  106. Prototype of the function depends on the exact type of event. Classes
  107. which inherit from this class will also inherit the hook.
  108. '''
  109. cls.__hooks__[event].append(f)
  110. def fire_hooks(self, event, *args, **kwargs):
  111. '''Fire hooks associated with an event.
  112. :param str event: event type
  113. *args* and *kwargs* are passed to each function
  114. '''
  115. for cls in self.__class__.__mro__:
  116. if not hasattr(cls, '__hooks__'): continue
  117. for hook in cls.__hooks__[event]:
  118. hook(self, *args, **kwargs)
  119. def load(class_, D):
  120. cls = BaseVM[class_]
  121. return cls(D)
  122. __all__ = qubes.plugins.load(__file__)