diff options
Diffstat (limited to 'tools/python/xen/xend/XendDomain.py')
-rw-r--r-- | tools/python/xen/xend/XendDomain.py | 284 |
1 files changed, 151 insertions, 133 deletions
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 3fb066327f..ff688f6df1 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -7,46 +7,42 @@ """ import errno import os -import scheduler -import string import sys -import traceback import time +import traceback import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() -from xen.xend.server import relocate -import sxp -import XendRoot; xroot = XendRoot.instance() -import XendCheckpoint -import XendDB -import XendDomainInfo -import EventServer; eserver = EventServer.instance() -from XendError import XendError -from XendLogging import log - +from xen.xend import sxp +from xen.xend import XendRoot; xroot = XendRoot.instance() +from xen.xend import XendCheckpoint +from xen.xend.XendDomainInfo import XendDomainInfo, shutdown_reason +from xen.xend import EventServer; eserver = EventServer.instance() +from xen.xend.XendError import XendError +from xen.xend.XendLogging import log +from xen.xend import scheduler from xen.xend.server import channel +from xen.xend.server import relocate +from xen.xend.uuid import getUuid +from xen.xend.xenstore import XenNode, DBMap __all__ = [ "XendDomain" ] SHUTDOWN_TIMEOUT = 30 +class XendDomainDict(dict): + def get_by_name(self, name): + try: + return filter(lambda d: d.name == name, self.values())[0] + except IndexError, err: + return None + class XendDomain: """Index of all domains. Singleton. """ - """Path to domain database.""" - dbpath = "domain" - - class XendDomainDict(dict): - def get_by_name(self, name): - try: - return filter(lambda d: d.name == name, self.values())[0] - except IndexError, err: - return None - """Dict of domain info indexed by domain id.""" - domains = XendDomainDict() + domains = None def __init__(self): # Hack alert. Python does not support mutual imports, but XendDomainInfo @@ -54,8 +50,8 @@ class XendDomain: # to import XendDomain from XendDomainInfo causes unbounded recursion. # So we stuff the XendDomain instance (self) into xroot's components. xroot.add_component("xen.xend.XendDomain", self) - # Table of domain info indexed by domain id. - self.db = XendDB.XendDB(self.dbpath) + self.domains = XendDomainDict() + self.dbmap = DBMap(db=XenNode("/domain")) eserver.subscribe('xend.virq', self.onVirq) self.initial_refresh() @@ -77,18 +73,16 @@ class XendDomain: domlist = xc.domain_getinfo() doms = {} for d in domlist: - domid = str(d['dom']) + domid = d['dom'] doms[domid] = d return doms def xen_domain(self, dom): """Get info about a single domain from xc. Returns None if not found. + + @param dom domain id (int) """ - try: - dom = int(dom) - except ValueError: - return None dominfo = xc.domain_getinfo(dom, 1) if dominfo == [] or dominfo[0]['dom'] != dom: dominfo = None @@ -100,37 +94,36 @@ class XendDomain: """Refresh initial domain info from db. """ doms = self.xen_domains() - for config in self.db.fetchall("").values(): - domid = str(sxp.child_value(config, 'id')) - if domid in doms: + self.dbmap.readDB() + for domdb in self.dbmap.values(): + try: + domid = int(domdb.id) + except: + domid = None + # XXX if domid in self.domains, then something went wrong + if (domid is None) or (domid in self.domains): + domdb.delete() + elif domid in doms: try: - self._new_domain(config, doms[domid]) - self.update_domain(domid) + self._new_domain(domdb, doms[domid]) except Exception, ex: - log.exception("Error recreating domain info: id=%s", domid) + log.exception("Error recreating domain info: id=%d", domid) self._delete_domain(domid) else: self._delete_domain(domid) self.refresh(cleanup=True) - def sync_domain(self, info): - """Sync info for a domain to disk. - - info domain info - """ - self.db.save(info.id, info.sxpr()) - def close(self): pass - def _new_domain(self, savedinfo, info): + def _new_domain(self, db, info): """Create a domain entry from saved info. - @param savedinfo: saved info from the db - @param info: domain info from xen + @param db: saved info from the db + @param info: domain info from xen @return: domain """ - dominfo = XendDomainInfo.vm_recreate(savedinfo, info) + dominfo = XendDomainInfo.recreate(db, info) self.domains[dominfo.id] = dominfo return dominfo @@ -144,11 +137,11 @@ class XendDomain: for i, d in self.domains.items(): if i != d.id: del self.domains[i] - self.db.delete(i) + self.dbmap.delete(d.uuid) if info.id in self.domains: notify = False self.domains[info.id] = info - self.sync_domain(info) + info.exportToDB(save=True) if notify: eserver.inject('xend.domain.create', [info.name, info.id]) @@ -158,12 +151,26 @@ class XendDomain: @param id: domain id @param notify: send a domain died event if true """ + try: + if self.xen_domain(id): + return + except: + pass info = self.domains.get(id) if info: del self.domains[id] + info.cleanup() + info.delete() if notify: eserver.inject('xend.domain.died', [info.name, info.id]) - self.db.delete(id) + # XXX this should not be needed + for domdb in self.dbmap.values(): + try: + domid = int(domdb.id) + except: + domid = None + if (domid is None) or (domid == id): + domdb.delete() def reap(self): """Look for domains that have crashed or stopped. @@ -178,22 +185,19 @@ class XendDomain: not(d['running'] or d['paused'] or d['blocked'])) if dead: casualties.append(d) - destroyed = 0 for d in casualties: - id = str(d['dom']) - #print 'reap>', id + id = d['dom'] dominfo = self.domains.get(id) name = (dominfo and dominfo.name) or '??' if dominfo and dominfo.is_terminated(): - #print 'reap> already terminated:', id continue - log.debug('XendDomain>reap> domain died name=%s id=%s', name, id) + log.debug('XendDomain>reap> domain died name=%s id=%d', name, id) if d['shutdown']: - reason = XendDomainInfo.shutdown_reason(d['shutdown_reason']) - log.debug('XendDomain>reap> shutdown name=%s id=%s reason=%s', name, id, reason) + reason = shutdown_reason(d['shutdown_reason']) + log.debug('XendDomain>reap> shutdown name=%s id=%d reason=%s', name, id, reason) if reason in ['suspend']: if dominfo and dominfo.is_terminated(): - log.debug('XendDomain>reap> Suspended domain died id=%s', id) + log.debug('XendDomain>reap> Suspended domain died id=%d', id) else: eserver.inject('xend.domain.suspended', [name, id]) if dominfo: @@ -203,10 +207,9 @@ class XendDomain: eserver.inject('xend.domain.exit', [name, id, reason]) self.domain_restart_schedule(id, reason) else: - if xroot.get_enable_dump() == 'true': - xc.domain_dumpcore(dom = int(id), corefile = "/var/xen/dump/%s.%s.core"%(name,id)) + if xroot.get_enable_dump(): + self.domain_dumpcore(id) eserver.inject('xend.domain.exit', [name, id, 'crash']) - destroyed += 1 self.final_domain_destroy(id) def refresh(self, cleanup=False): @@ -216,7 +219,7 @@ class XendDomain: self.reap() doms = self.xen_domains() # Add entries for any domains we don't know about. - for (id, d) in doms.items(): + for id in doms.keys(): if id not in self.domains: self.domain_lookup(id) # Remove entries for domains that no longer exist. @@ -234,16 +237,7 @@ class XendDomain: scheduler.now(self.domain_restarts) def update_domain(self, id): - """Update the saved info for a domain. - - @param id: domain id - """ - dominfo = self.domains.get(id) - if dominfo: - self.sync_domain(dominfo) - - def refresh_domain(self, id): - """Refresh information for a single domain. + """Update information for a single domain. @param id: domain id """ @@ -279,8 +273,7 @@ class XendDomain: @param config: configuration @return: domain """ - dominfo = XendDomainInfo.vm_create(config) - self._add_domain(dominfo) + dominfo = XendDomainInfo.create(self.dbmap, config) return dominfo def domain_restart(self, dominfo): @@ -293,7 +286,6 @@ class XendDomain: [dominfo.name, dominfo.id, "begin"]) try: dominfo.restart() - self._add_domain(dominfo) log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id) eserver.inject("xend.domain.restart", [dominfo.name, dominfo.id, "success"]) @@ -309,14 +301,13 @@ class XendDomain: """Configure an existing domain. This is intended for internal use by domain restore and migrate. - @param id: domain id @param vmconfig: vm configuration """ config = sxp.child_value(vmconfig, 'config') - dominfo = XendDomainInfo.vm_restore(config) - self._add_domain(dominfo) + uuid = sxp.child_value(vmconfig, 'uuid') + dominfo = XendDomainInfo.restore(self.dbmap, config, uuid=uuid) return dominfo - + def domain_restore(self, src, progress=False): """Restore a domain from file. @@ -326,9 +317,7 @@ class XendDomain: try: fd = os.open(src, os.O_RDONLY) - return XendCheckpoint.restore(self, fd) - except OSError, ex: raise XendError("can't read guest state file %s: %s" % (src, ex[1])) @@ -339,24 +328,35 @@ class XendDomain: @param id: domain id @return: domain object (or None) """ - id = str(id) - self.refresh_domain(id) + self.update_domain(id) return self.domains.get(id) - def domain_lookup(self, name): - name = str(name) - dominfo = self.domains.get_by_name(name) or self.domains.get(name) - if dominfo: - return dominfo - try: - d = self.xen_domain(name) - if d: - log.info("Creating entry for unknown domain: id=%s", name) - dominfo = XendDomainInfo.vm_recreate(None, d) - self._add_domain(dominfo) - return dominfo - except Exception, ex: - log.exception("Error creating domain info: id=%s", name) + def domain_lookup(self, id): + dominfo = self.domains.get(id) + if not dominfo: + try: + info = self.xen_domain(id) + if info: + uuid = getUuid() + log.info( + "Creating entry for unknown domain: id=%d uuid=%s", + id, uuid) + db = self.dbmap.addChild(uuid) + dominfo = XendDomainInfo.recreate(db, info) + self._add_domain(dominfo) + except Exception, ex: + log.exception("Error creating domain info: id=%d", id) + return dominfo + + def domain_lookup_by_name(self, name): + dominfo = self.domains.get_by_name(name) + if not dominfo: + try: + id = int(name) + dominfo = self.domain_lookup(id) + except ValueError: + pass + return dominfo def domain_unpause(self, id): """Unpause domain execution. @@ -366,7 +366,7 @@ class XendDomain: dominfo = self.domain_lookup(id) eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id]) try: - return xc.domain_unpause(dom=dominfo.dom) + return xc.domain_unpause(dom=dominfo.id) except Exception, ex: raise XendError(str(ex)) @@ -378,7 +378,7 @@ class XendDomain: dominfo = self.domain_lookup(id) eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id]) try: - return xc.domain_pause(dom=dominfo.dom) + return xc.domain_pause(dom=dominfo.id) except Exception, ex: raise XendError(str(ex)) @@ -436,7 +436,7 @@ class XendDomain: @param id: domain id @param reason: shutdown reason """ - log.debug('domain_restart_schedule> %s %s %d', id, reason, force) + log.debug('domain_restart_schedule> %d %s %d', id, reason, force) dominfo = self.domain_lookup(id) if not dominfo: return @@ -484,7 +484,7 @@ class XendDomain: except: #todo try: - val = xc.domain_destroy(dom=int(id)) + val = xc.domain_destroy(dom=id) except Exception, ex: raise XendError(str(ex)) return val @@ -553,7 +553,7 @@ class XendDomain: """ dominfo = self.domain_lookup(id) try: - return xc.domain_pincpu(int(dominfo.id), vcpu, cpumap) + return xc.domain_pincpu(dominfo.id, vcpu, cpumap) except Exception, ex: raise XendError(str(ex)) @@ -562,7 +562,7 @@ class XendDomain: """ dominfo = self.domain_lookup(id) try: - return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv, + return xc.bvtsched_domain_set(dom=dominfo.id, mcuadv=mcuadv, warpback=warpback, warpvalue=warpvalue, warpl=warpl, warpu=warpu) except Exception, ex: @@ -573,7 +573,7 @@ class XendDomain: """ dominfo = self.domain_lookup(id) try: - return xc.bvtsched_domain_get(dominfo.dom) + return xc.bvtsched_domain_get(dominfo.id) except Exception, ex: raise XendError(str(ex)) @@ -581,20 +581,21 @@ class XendDomain: def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): """Set Simple EDF scheduler parameters for a domain. """ - dominfo = self.domain_lookup(id) + dominfo = self.domain_lookup(id) try: - return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight) + return xc.sedf_domain_set(dominfo.id, period, slice, latency, extratime, weight) except Exception, ex: raise XendError(str(ex)) def domain_cpu_sedf_get(self, id): - """Get Atropos scheduler parameters for a domain. + """Get Simple EDF scheduler parameters for a domain. """ dominfo = self.domain_lookup(id) try: - return xc.sedf_domain_get(dominfo.dom) + return xc.sedf_domain_get(dominfo.id) except Exception, ex: raise XendError(str(ex)) + def domain_device_create(self, id, devconfig): """Create a new device for a domain. @@ -603,44 +604,44 @@ class XendDomain: """ dominfo = self.domain_lookup(id) val = dominfo.device_create(devconfig) - self.update_domain(dominfo.id) + dominfo.exportToDB() return val - def domain_device_configure(self, id, devconfig, idx): + def domain_device_configure(self, id, devconfig, devid): """Configure an existing device for a domain. @param id: domain id @param devconfig: device configuration - @param idx: device index + @param devid: device id @return: updated device configuration """ dominfo = self.domain_lookup(id) - val = dominfo.device_configure(devconfig, idx) - self.update_domain(dominfo.id) + val = dominfo.device_configure(devconfig, devid) + dominfo.exportToDB() return val - def domain_device_refresh(self, id, type, idx): + def domain_device_refresh(self, id, type, devid): """Refresh a device. @param id: domain id - @param idx: device index + @param devid: device id @param type: device type """ dominfo = self.domain_lookup(id) - val = dominfo.device_refresh(type, idx) - self.update_domain(dominfo.id) + val = dominfo.device_refresh(type, devid) + dominfo.exportToDB() return val - def domain_device_destroy(self, id, type, idx): + def domain_device_destroy(self, id, type, devid): """Destroy a device. @param id: domain id - @param idx: device index + @param devid: device id @param type: device type """ dominfo = self.domain_lookup(id) - val = dominfo.device_destroy(type, idx) - self.update_domain(dominfo.id) + val = dominfo.device_destroy(type, devid) + dominfo.exportToDB() return val def domain_devtype_ls(self, id, type): @@ -653,22 +654,22 @@ class XendDomain: dominfo = self.domain_lookup(id) return dominfo.getDeviceSxprs(type) - def domain_devtype_get(self, id, type, idx): + def domain_devtype_get(self, id, type, devid): """Get a device from a domain. - + @param id: domain @param type: device type - @param idx: device index + @param devid: device id @return: device object (or None) """ dominfo = self.domain_lookup(id) - return dominfo.getDeviceByIndex(type, idx) + return dominfo.getDevice(type, devid) def domain_vif_limit_set(self, id, vif, credit, period): """Limit the vif's transmission rate """ dominfo = self.domain_lookup(id) - dev = dominfo.getDeviceById('vif', vif) + dev = dominfo.getDevice('vif', vif) if not dev: raise XendError("invalid vif") return dev.setCreditLimit(credit, period) @@ -681,30 +682,47 @@ class XendDomain: """ dominfo = self.domain_lookup(id) try: - return xc.shadow_control(dominfo.dom, op) + return xc.shadow_control(dominfo.id, op) except Exception, ex: raise XendError(str(ex)) def domain_maxmem_set(self, id, mem): """Set the memory limit for a domain. - @param dom: domain + @param id: domain @param mem: memory limit (in MB) @return: 0 on success, -1 on error """ dominfo = self.domain_lookup(id) maxmem = int(mem) * 1024 try: - return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem) + return xc.domain_setmaxmem(dominfo.id, maxmem_kb = maxmem) except Exception, ex: raise XendError(str(ex)) - def domain_mem_target_set(self, id, target): + def domain_mem_target_set(self, id, mem): + """Set the memory target for a domain. + + @param id: domain + @param mem: memory target (in MB) + @return: 0 on success, -1 on error + """ dominfo = self.domain_lookup(id) - return dominfo.mem_target_set(target) - + return dominfo.mem_target_set(mem) + def domain_dumpcore(self, id): + """Save a core dump for a crashed domain. + @param id: domain + """ + dominfo = self.domain_lookup(id) + corefile = "/var/xen/dump/%s.%s.core"% (dominfo.name, dominfo.id) + try: + xc.domain_dumpcore(dom=dominfo.id, corefile=corefile) + except Exception, ex: + log.warning("Dumpcore failed, id=%s name=%s: %s", + dominfo.id, dominfo.name, ex) + def instance(): """Singleton constructor. Use this instead of the class constructor. """ |