Skip to content
Snippets Groups Projects
Commit de56364c authored by Anael Beutot's avatar Anael Beutot
Browse files

Basic hypervisor working with listing VMs.

parent 85073695
No related branches found
No related tags found
No related merge requests found
......@@ -4,7 +4,7 @@ from subprocess import Popen, PIPE, STDOUT
from sjrpc.utils import pure
from ccnode.node import DefaultHandler
from ccnode.tags import Tag, DynamicTags, tag_inspector
from ccnode.tags import tag_inspector
from ccnode.host import tags
......@@ -16,7 +16,7 @@ class Handler(DefaultHandler):
def __init__(self, *args, **kwargs):
DefaultHandler.__init__(self, *args, **kwargs)
for t in tag_inspector(tags, 'ccnode.host.tags'):
for t in tag_inspector(tags):
self.tags[t.name] = t
@pure
......
import logging
import libvirt
from sjrpc.utils import pure
from ccnode.host import Handler as HostHandler
from ccnode.tags import tag_inspector, get_tags
from ccnode.hypervisor import tags
from ccnode.hypervisor import lib as _libvirt
from ccnode.hypervisor.domains import VirtualMachine
logger = logging.getLogger(__name__)
class Handler(HostHandler):
def __init__(self, *args, **kwargs):
"""
:param proxy: sjRpc proxy
"""
HostHandler.__init__(self, *args, **kwargs)
for t in tag_inspector(tags):
self.tags[t.name] = t
# set tag hv
# self.tags['hv'] = Tag('hv', )
# initialize hypervisor instance
global hypervisor
if hypervisor is None:
hypervisor = Hypervisor()
# register domains
proxy = kwargs.pop('proxy')
for dom in hypervisor.domains:
name = dom.name
logger.debug(u'Registered domain %s' % name)
proxy.register(name, 'vm')
@pure
def sub_tags(self, sub_id, tags=None, noresolve_tags=None):
"""Get subtags."""
global hypervisor
domain = hypervisor.get_domain_by_name(sub_id)
if domain is None:
logger.debug(u'Failed to find domain with name %s.' % sub_id)
return
return get_tags(domain, tags, noresolve_tags)
@pure
def vm_define(self, name):
pass
@pure
def vm_undefine(self, name):
pass
@pure
def vm_export(self, name, format='xml'):
pass
@pure
def vm_stop(self, vm_names=None, force=False):
pass
@pure
def vm_start(self, vm_names=None):
pass
@pure
def vm_suspend(self, vm_names=None):
pass
@pure
def vm_resume(self, vm_names=None):
pass
class Hypervisor(object):
"""Container for all hypervisor related state."""
def __init__(self):
# initialize connection to libvirt
logger.debug(u'Connecting to libvirt.')
_libvirt.connection = libvirt.open('qemu:///system') # currently only support KVM
#: domains: vms, containers...
self.domains = [
VirtualMachine(
_libvirt.connection.lookupByID(id),
) for id in _libvirt.connection.listDomainsID()
]
logger.debug(u'Domains: %s' % unicode(self.domains))
def get_domain_by_name(self, name):
"""Get a domain by name."""
for d in self.domains:
if d.name == name:
return d
return None
def _count_domain(self, filter=lambda d: True):
count = 0
for dom in self.domains:
if filter(dom):
count += 1
return count
@property
def vm_started(self):
"""Number of VMs started."""
return self._count_domain(lambda d: d.status == 'started')
@property
def vm_stopped(self):
"""Number of VMs stopped."""
return self._count_domain(lambda d: d.status == 'stopped')
@property
def vm_paused(self):
"""Number of VMs paused."""
return self._count_domain(lambda d: d.status == 'paused')
@property
def vm_total(self):
"""Total number of VMs on the hypervisor."""
return self._count_domain()
hypervisor = None
from ccnode.tags import Tag
from ccnode.hypervisor import lib as _libvirt
from ccnode.hypervisor.lib import DOMAIN_STATES as STATE
class VirtualMachine(object):
"""Represent a VM instance."""
def __init__(self, dom):
"""
:param dom: libvirt domain instance
"""
#: UUID string of domain
self.uuid = dom.UUIDString()
#: state of VM: started, stoped, paused
self.state = STATE[dom.info()[0]]
#: tags for this VM
self.tags = dict(
test=Tag('test', 'plop'),
)
@property
def name(self):
return _libvirt.connection.lookupByUUIDString(self.uuid).name()
def start():
pass
def stop():
pass
def pause():
pass
def define():
pass
def undefined():
pass
"""Helpers for libvirt."""
#: connection to the libvirt
connection = None # TODO create a watcher thread for this
#: 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
'running', # 2 blocked
'paused', # 3 paused
'running', # 4 shutdown
'stopped', # 5 shuttoff
'stopped', # 6 crashed
'unknown', # 7 ??
)
from ccnode.utils import and_
# hypervisor related tags
def htype():
"""Hypervisor type."""
# FIXME for other support
return u'kvm'
def hv():
"""Hypervisor name."""
# What is the point of this tag ? if the information not already in a and id
# ?
def hvm():
"""Hardware virtualization enable."""
# see
# http://www.linux-kvm.org/page/FAQ#How_can_I_tell_if_I_have_Intel_VT_or_AMD-V.3F
# or
# http://www.cyberciti.biz/faq/linux-xen-vmware-kvm-intel-vt-amd-v-support/
# if we are in a xen hypervisor we won't see vt in /proc/cpuinfo
result = {True: u'yes', False: u'no'}
if htype() == u'kvm':
# findout in /proc/cpuinfo if all CPUs have virtualisation enabled
return result[and_(
set(
'vmx', # Intel VT
'svm', # AMD
) & set(
l.split(': ')[-1].split()
) for l in open('/proc/cpuinfo').readline() if l.startswith('Tags')
)]
return None
def hvver():
"""Hypervisor version."""
def libvirtver():
"""Version of running libvirt."""
# jobs
def rjobs():
"""Number of currently running jobs."""
# storage pools
def sto():
"""Storage pool names."""
# dynamic sto
# Vm related tags
def nvm():
"""Number of VMS in the current hypervisor."""
def vmpaused():
"""Count of VMs paused."""
def vmstarted():
"""Count of VMs started."""
def vmstopped():
"""Count of VMs Stopped."""
......@@ -6,7 +6,7 @@ from sjrpc.client import SimpleRpcClient
from sjrpc.utils import ConnectionProxy, RpcHandler, pure
from ccnode import __version__
from ccnode.tags import Tag
from ccnode.tags import Tag, get_tags
logger = logging.getLogger(__name__)
......@@ -23,7 +23,7 @@ class DefaultHandler(RpcHandler):
"""
def __init__(self, *args, **kwargs):
RpcHandler.__init__(self, *args, **kwargs)
RpcHandler.__init__(self)
self.tags = dict((t.name, t) for t in DEFAULT_TAGS)
......@@ -34,33 +34,7 @@ class DefaultHandler(RpcHandler):
:param iterable tags: list of tags to return
:param iterable noresolve_tags: list of tags to not return
"""
logger.debug('Tags request: %s, %s' % (
unicode(tags),
unicode(noresolve_tags),
))
tags = set(tags) - set(noresolve_tags) if tags is not None else None
if tags is None:
tags = self.tags.iterkeys()
else:
tags = tags & set(self.tags.iterkeys())
profile = time.time()
try:
result = dict((
t, # tag name
dict(
value=self.tags[t].value,
ttl=self.tags[t].ttl,
),
) for t in tags)
except Exception:
logger.exception(u'SHould not happend, result.')
logger.debug(u'Profiling: %f seconds.' % (time.time() - profile))
logger.debug(u'Returning: %s' % unicode(result))
return result
return get_tags(self, tags, noresolve_tags)
class Node(Thread):
......@@ -127,6 +101,10 @@ class Node(Thread):
self.role = u'host'
elif role == u'hv':
logger.debug(u'Role hypervisor affected.')
from ccnode.hypervisor import Handler as HypervisorHandler
# FIXME bad API
self.manager._connection.set_handler(HypervisorHandler(
proxy=self.proxy))
self.role = u'hv'
else:
logger.debug(u'Wrong role returned: %s' % role)
......@@ -167,6 +145,8 @@ class Node(Thread):
auth_thread.daemon = True
auth_thread.start()
auth_thread.join()
# FIXME for debug
time.sleep(4)
# wait for rpc thread to terminates (it means error)
rpc_thread.join()
......
import inspect
import logging
import time
logger = logging.getLogger(__name__)
......@@ -7,11 +8,15 @@ logger = logging.getLogger(__name__)
class Tag(object):
"""``class`` that abstract tags and act as a simple container."""
def __init__(self, name, valuable, ttl):
def __init__(self, name, valuable, ttl=-1):
"""
:param string name: tag name
:param valuable: something that gives tag value, string or function
:param None,int ttl: Time to live for caching the tags
:param None,int ttl: Time to live for caching the tags, possible values
are:
* None (means no ttl)
* -1 (means infinite ttl)
* positive integer in seconds
"""
self.name = name
self._value = valuable
......@@ -75,11 +80,10 @@ class DynamicTags(object):
yield t
def tag_inspector(mod, match):
def tag_inspector(mod):
"""Inspect module to find tags.
:param module mod: module to inspect
:param string match: module name to match for tags
Currently there are three ways to define a tag inside a module:
......@@ -96,7 +100,7 @@ def tag_inspector(mod, match):
tags = []
for n, m in inspect.getmembers(mod): # (name, member)
# only keep strings or functions as tags
if getattr(m, '__module__', None) != match or (
if getattr(m, '__module__', None) != mod.__name__ or (
n.startswith('_')):
continue
elif isinstance(m, (str, unicode)):
......@@ -106,7 +110,6 @@ def tag_inspector(mod, match):
# if function take function ttl argument or set -1 by default
ttl = getattr(m, 'ttl', -1)
elif isinstance(m, DynamicTags):
logger.debug('plop')
for t in m.iter_tags():
tags.append(t)
logger.debug('Introspected %s with ttl %s.' % (t.name,
......@@ -122,3 +125,40 @@ def tag_inspector(mod, match):
tags.append(Tag(n, m, ttl))
return tags
def get_tags(obj, tags, noresolve_tags):
"""Helper to get tags.
:param obj: object with a dict ``tags`` attribute
:param tags: List of tags to get (None mean all tags)
:param noresolve_tags: List of tags to exclude from result
"""
# TODO clean this fucntion
logger.debug('Tags request: %s, %s' % (
unicode(tags),
unicode(noresolve_tags),
))
tags = set(tags) - set(noresolve_tags) if tags is not None else None
if tags is None:
tags = obj.tags.iterkeys()
else:
tags = tags & set(obj.tags)
profile = time.time()
try:
result = dict((
t, # tag name
dict(
value=obj.tags[t].value,
ttl=obj.tags[t].ttl,
),
) for t in tags)
except Exception:
logger.exception(u'SHould not happend, result.')
logger.debug(u'Profiling: %f seconds.' % (time.time() - profile))
logger.debug(u'Returning: %s' % unicode(result))
return result
......@@ -9,3 +9,15 @@ def signal_(signum):
return func
return decorator
def and_(iter):
"""Do an and logic condition over the iterable element.
:param iterable iter: meat for condition
"""
for i in iter:
if not i:
return False
return True
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment