Newer
Older
from cloudcontrol.node.utils import Singleton
#: corresponding name for enum state of libvirt domains
# see http://libvirt.org/html/libvirt-libvirt.html#virDomainState
DOMAIN_STATES = (
'stopped', # 0 no state
'running', # 1 running
'paused', # 3 paused
'running', # 4 shutdown
'stopped', # 5 shuttoff
'crashed', # 6 crashed
'suspended', # 7 suspended
STORAGE_STATES = (
'inactive',
'building',
'running',
'degraded',
'inaccessible',
'???', # 5
)
EVENTS = (
'Added',
'Removed',
'Started',
'Suspended',
'Resumed',
'Stopped',
'Saved',
'Restored',
)
# following event loop implementation was inspired by libvirt python example
"""This class contains the data we need to track for a single file handle.
"""
def __init__(self, loop, handle, fd, events, cb, opaque):
self._events = self.virt_to_ev(events)
self.watcher = loop.io(self.fd, self._events, self.ev_cb,
None, pyev.EV_MAXPRI)
def ev_to_virt(self, events):
"""Convert libev events into libvirt one."""
result = 0
if events & pyev.EV_READ:
result |= libvirt.VIR_EVENT_HANDLE_READABLE
if events & pyev.EV_WRITE:
result |= libvirt.VIR_EVENT_HANDLE_WRITABLE
return result
def virt_to_ev(self, events):
"""Convert libvirt event to libev one."""
result = 0
if events & (libvirt.VIR_EVENT_HANDLE_READABLE |
libvirt.VIR_EVENT_HANDLE_ERROR |
libvirt.VIR_EVENT_HANDLE_HANGUP):
result |= pyev.EV_READ
if events & libvirt.VIR_EVENT_HANDLE_WRITABLE:
result |= pyev.EV_WRITE
return result
if self._events != 0:
self.watcher.set(self.fd, self._events)
self.watcher.start()
@property
def events(self):
return self._events
self._events = self.virt_to_ev(events)
def ev_cb(self, watcher, revents):
# convert events
events = self.ev_to_virt(revents)
self._cb(self.handle, self.watcher.fd, events, self.opaque[0],
self.opaque[1])
"""This class contains the data we need to track for a single periodic
timer.
"""
def __init__(self, loop, timer, interval, cb, opaque):
self._interval = float(interval)
self._cb = cb
self.watcher = None
self.loop = loop
self._set()
def _set(self):
self.stop()
if self._interval >= 0.: # libvirt sends us interval == -1
self.watcher = self.loop.timer(self._interval, self._interval,
self.ev_cb, None, pyev.EV_MAXPRI)
@property
def interval(self):
return self._interval
@interval.setter
def interval(self, value):
self._interval = float(value)
self._set()
def start(self):
if self.watcher is not None:
self.watcher.start()
def stop(self):
if self.watcher is not None:
self.watcher.stop()
def ev_cb(self, *args):
self._cb(self.timer, self.opaque[0], self.opaque[1])
"""This class is used as an interface between the libvirt event handling and
the main pyev loop.
def counter():
count = 0
while True:
yield count
count += 1
self.handle_id = counter()
self.timer_id = counter()
self.handles = dict()
self.timers = dict()
# This tells libvirt what event loop implementation it
# should use
libvirt.virEventRegisterImpl(
self.add_handle,
self.update_handle,
self.remove_handle,
self.add_timer,
self.update_timer,
self.remove_timer,
)
def add_handle(self, fd, events, cb, opaque):
"""Registers a new file handle 'fd', monitoring for 'events' (libvirt
event constants), firing the callback cb() when an event occurs.
Returns a unique integer identier for this handle, that should be
used to later update/remove it.
Note: unlike in the libvirt example, we don't use an interrupt trick as
we run everything in the same thread, furthermore, calling start watcher
method from a different thread could be dangerous.
h = LoopHandler(self.loop, handle_id, fd, events, cb, opaque)
h.start()
self.handles[handle_id] = h
# logger.debug('Add handle %d fd %d events %d', handle_id, fd, events)
def add_timer(self, interval, cb, opaque):
"""Registers a new timer with periodic expiry at 'interval' ms,
firing cb() each time the timer expires. If 'interval' is -1,
then the timer is registered, but not enabled.
Returns a unique integer identier for this handle, that should be
used to later update/remove it.
Note: same note as for :method:`add_handle` applies here
h = LoopTimer(self.loop, timer_id, interval, cb, opaque)
h.start()
self.timers[timer_id] = h
# logger.debug('Add timer %d interval %d', timer_id, interval)
"""Change the set of events to be monitored on the file handle.
"""
# logger.debug('Update handle %d fd %d events %d', handle_id, h.fd, events)
"""Change the periodic frequency of the timer.
"""
t = self.timers.get(timer_id)
if t:
t.interval = interval
"""Stop monitoring for events on the file handle.
"""
h = self.handles.pop(handle_id, None)
if h:
h.stop()
# logger.debug('Remove handle %d', handle_id)
def remove_timer(self, timer_id):
"""Stop firing the periodic timer.
t = self.timers.pop(timer_id, None)
if t:
t.stop()
# logger.debug('Remove timer %d', timer_id)
def stop(self):
for handl in chain(self.handles.itervalues(), self.timers.itervalues()):
handl.stop()
self.handles = dict()
self.timers = dict()