X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sliver_libvirt.py;h=8189b192c7f67ae6d96c6db6f77d0c1d364b3e4a;hb=e57432c1dfdfeaa52cc32799e2abbc34b7704ce9;hp=753b0c3a297dfb112d38801cec8948f6267750d6;hpb=34bbf772786e0e674d2b83ddfb079cb060830ff1;p=nodemanager.git diff --git a/sliver_libvirt.py b/sliver_libvirt.py index 753b0c3..8189b19 100644 --- a/sliver_libvirt.py +++ b/sliver_libvirt.py @@ -2,8 +2,10 @@ import sys import os, os.path +import re import subprocess import pprint +import random import libvirt @@ -22,6 +24,13 @@ STATES = { libvirt.VIR_DOMAIN_CRASHED: 'crashed', } +REASONS = { + libvirt.VIR_CONNECT_CLOSE_REASON_ERROR: 'Misc I/O error', + libvirt.VIR_CONNECT_CLOSE_REASON_EOF: 'End-of-file from server', + libvirt.VIR_CONNECT_CLOSE_REASON_KEEPALIVE: 'Keepalive timer triggered', + libvirt.VIR_CONNECT_CLOSE_REASON_CLIENT: 'Client requested it', +} + connections = dict() # Common Libvirt code @@ -38,12 +47,6 @@ class Sliver_Libvirt(Account): uri = vtype + '://' return connections.setdefault(uri, libvirt.open(uri)) - @staticmethod - def debuginfo(dom): - ''' Helper method to get a "nice" output of the info struct for debug''' - [state, maxmem, mem, ncpu, cputime] = dom.info() - return '%s is %s, maxmem = %s, mem = %s, ncpu = %s, cputime = %s' % (dom.name(), STATES.get(state, state), maxmem, mem, ncpu, cputime) - def __init__(self, rec): self.name = rec['name'] logger.verbose ('sliver_libvirt: %s init'%(self.name)) @@ -68,14 +71,68 @@ class Sliver_Libvirt(Account): dom = self.conn.lookupByName(self.name) self.dom = dom + @staticmethod + def dom_details (dom): + output="" + output += " id=%s - OSType=%s"%(dom.ID(),dom.OSType()) + # calling state() seems to be working fine + (state,reason)=dom.state() + output += " state=%s, reason=%s"%(STATES.get(state,state),REASONS.get(reason,reason)) + try: + # try to use info() - this however does not work for some reason on f20 + # info cannot get info operation failed: Cannot read cputime for domain + [state, maxmem, mem, ncpu, cputime] = dom.info() + output += " [info: maxmem = %s, mem = %s, ncpu = %s, cputime = %s]" % (STATES.get(state, state), maxmem, mem, ncpu, cputime) + except: + # too bad but libvirt.py prints out stuff on stdout when this fails, don't know how to get rid of that.. + output += " [info: not available]" + return output + + def __repr__(self): + ''' Helper method to get a "nice" output of the domain struct for debug purposes''' + output="Domain %s"%self.name + dom=self.dom + if dom is None: + output += " [no attached dom ?!?]" + else: + output += Sliver_Libvirt.dom_details (dom) + return output + + # Thierry : I am not quite sure if /etc/libvirt/lxc/<>.xml holds a reliably up-to-date + # copy of the sliver XML config; I feel like issuing a virsh dumpxml first might be safer + def repair_veth(self): + # See workaround email, 2-14-2014, "libvirt 1.2.1 rollout" + xml = open("/etc/libvirt/lxc/%s.xml" % self.name).read() + veths = re.findall("", xml) + veths = [x[13:-3] for x in veths] + for veth in veths: + command = ["ip", "link", "delete", veth] + logger.log_call(command) + + logger.log("trying to redefine the VM") + command = ["virsh", "define", "/etc/libvirt/lxc/%s.xml" % self.name] + logger.log_call(command) + def start(self, delay=0): - ''' Just start the sliver ''' + '''Just start the sliver''' logger.verbose('sliver_libvirt: %s start'%(self.name)) # Check if it's running to avoid throwing an exception if the - # domain was already running, create actually means start + # domain was already running if not self.is_running(): - self.dom.create() + try: + # create actually means start + self.dom.create() + except Exception, e: + # XXX smbaker: attempt to resolve slivers that are stuck in + # "failed to allocate free veth". + if "ailed to allocate free veth" in str(e): + logger.log("failed to allocate free veth on %s" % self.name) + self.repair_veth() + logger.log("trying dom.create again") + self.dom.create() + else: + raise else: logger.verbose('sliver_libvirt: sliver %s already started'%(self.name)) @@ -95,30 +152,14 @@ class Sliver_Libvirt(Account): try: self.dom.destroy() except: - logger.verbose('sliver_libvirt: Domain %s not running ' \ - 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1])) - print 'sliver_libvirt: Domain %s not running ' \ - 'UNEXPECTED: %s'%(self.name, sys.exc_info()[1]) + logger.log_exc("in sliver_libvirt.stop",name=self.name) def is_running(self): ''' Return True if the domain is running ''' - logger.verbose('sliver_libvirt: %s is_running'%self.name) - try: - [state, _, _, _, _] = self.dom.info() - if state == libvirt.VIR_DOMAIN_RUNNING: - logger.verbose('sliver_libvirt: %s is RUNNING'%self.name) - return True - else: - info = debuginfo(self.dom) - logger.verbose('sliver_libvirt: %s is ' \ - 'NOT RUNNING...\n%s'%(self.name, info)) - return False - except: - logger.verbose('sliver_libvirt: UNEXPECTED ERROR in ' \ - '%s: %s'%(self.name, sys.exc_info()[1])) - print 'sliver_libvirt: UNEXPECTED ERROR in ' \ - '%s: %s'%(self.name, sys.exc_info()[1]) - return False + (state,_) = self.dom.state() + result = (state == libvirt.VIR_DOMAIN_RUNNING) + logger.verbose('sliver_libvirt.is_running: %s => %s'%(self,result)) + return result def configure(self, rec): @@ -171,14 +212,19 @@ class Sliver_Libvirt(Account): # Call the upper configure method (ssh keys...) Account.configure(self, rec) + @staticmethod + def get_unique_vif(): + return 'veth%s' % random.getrandbits(32) + # A placeholder until we get true VirtualInterface objects @staticmethod def get_interfaces_xml(rec): xml = """ + -""" +""" % (Sliver_Libvirt.get_unique_vif()) try: tags = rec['rspec']['tags'] if 'interface' in tags: @@ -198,14 +244,17 @@ class Sliver_Libvirt(Account): %s + - """ % (interface['bridge'], vlanxml) + """ % (interface['bridge'], vlanxml, Sliver_Libvirt.get_unique_vif()) else: tag_xml = tag_xml + """ + - """ + """ % (Sliver_Libvirt.get_unique_vif()) + xml = tag_xml logger.log('sliver_libvirty.py: interface XML is: %s' % xml)