aboutsummaryrefslogtreecommitdiffstats
path: root/tools/python/xen/xend/XendDomain.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/python/xen/xend/XendDomain.py')
-rw-r--r--tools/python/xen/xend/XendDomain.py369
1 files changed, 369 insertions, 0 deletions
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
new file mode 100644
index 0000000000..3aaf080c36
--- /dev/null
+++ b/tools/python/xen/xend/XendDomain.py
@@ -0,0 +1,369 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Handler for domain operations.
+ Nothing here is persistent (across reboots).
+ Needs to be persistent for one uptime.
+"""
+import sys
+
+from twisted.internet import defer
+
+import xen.ext.xc; xc = xen.ext.xc.new()
+
+import sxp
+import XendRoot
+xroot = XendRoot.instance()
+import XendDB
+import XendDomainInfo
+import XendConsole
+import EventServer
+
+from xen.xend.server import SrvDaemon
+xend = SrvDaemon.instance()
+
+eserver = EventServer.instance()
+
+__all__ = [ "XendDomain" ]
+
+class XendDomain:
+ """Index of all domains. Singleton.
+ """
+
+ dbpath = "domain"
+ domain = {}
+
+ def __init__(self):
+ self.xconsole = XendConsole.instance()
+ # Table of domain info indexed by domain id.
+ self.db = XendDB.XendDB(self.dbpath)
+ #self.domain = {}
+ self.domain_db = self.db.fetchall("")
+ if xroot.get_rebooted():
+ print 'XendDomain> rebooted: removing all domain info'
+ self.rm_all()
+ eserver.subscribe('xend.virq', self.onVirq)
+ self.initial_refresh()
+
+ def onVirq(self, event, val):
+ print 'XendDomain> virq', val
+ self.reap()
+
+ def rm_all(self):
+ """Remove all domain info. Used after reboot.
+ """
+ for (k, v) in self.domain_db.items():
+ self._delete_domain(k, notify=0)
+
+ def initial_refresh(self):
+ """Refresh initial domain info from domain_db.
+ """
+ print "initial_refresh>"
+ for d in self.domain_db.values(): print 'db dom=', d
+ domlist = xc.domain_getinfo()
+ for d in domlist: print 'xc dom=', d
+ doms = {}
+ for d in domlist:
+ domid = str(d['dom'])
+ doms[domid] = d
+ dlist = []
+ for config in self.domain_db.values():
+ domid = str(sxp.child_value(config, 'id'))
+ print "dom=", domid, "config=", config
+ if domid in doms:
+ print "dom=", domid, "new"
+ deferred = self._new_domain(config, doms[domid])
+ dlist.append(deferred)
+ else:
+ print "dom=", domid, "del"
+ self._delete_domain(domid)
+ deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
+ def cbok(val):
+ #print "doms:"
+ #for d in self.domain.values(): print 'dom', d
+ self.refresh()
+ print "XendDomain>initial_refresh> doms:"
+ for d in self.domain.values(): print 'dom', d
+ deferred.addCallback(cbok)
+
+ def sync(self):
+ """Sync domain db to disk.
+ """
+ self.db.saveall("", self.domain_db)
+
+ def sync_domain(self, dom):
+ """Sync info for a domain to disk.
+
+ dom domain id (string)
+ """
+ self.db.save(dom, self.domain_db[dom])
+
+ def close(self):
+ pass
+
+ def _new_domain(self, savedinfo, info):
+ """Create a domain entry from saved info.
+ """
+## console = None
+## kernel = None
+## id = sxp.child_value(info, 'id')
+## dom = int(id)
+## name = sxp.child_value(info, 'name')
+## memory = int(sxp.child_value(info, 'memory'))
+## consoleinfo = sxp.child(info, 'console')
+## if consoleinfo:
+## consoleid = sxp.child_value(consoleinfo, 'id')
+## console = self.xconsole.console_get(consoleid)
+## if dom and console is None:
+## # Try to connect a console.
+## console = self.xconsole.console_create(dom)
+## config = sxp.child(info, 'config')
+## if config:
+## image = sxp.child(info, 'image')
+## if image:
+## image = sxp.child0(image)
+## kernel = sxp.child_value(image, 'kernel')
+## dominfo = XendDomainInfo.XendDomainInfo(
+## config, dom, name, memory, kernel, console)
+ config = sxp.child_value(savedinfo, 'config')
+ deferred = XendDomainInfo.vm_recreate(config, info)
+ def fn(dominfo):
+ self.domain[dominfo.id] = dominfo
+ deferred.addCallback(fn)
+ return deferred
+
+ def _add_domain(self, id, info, notify=1):
+ self.domain[id] = info
+ self.domain_db[id] = info.sxpr()
+ self.sync_domain(id)
+ if notify: eserver.inject('xend.domain.created', id)
+
+ def _delete_domain(self, id, notify=1):
+ if id in self.domain:
+ if notify: eserver.inject('xend.domain.died', id)
+ del self.domain[id]
+ if id in self.domain_db:
+ del self.domain_db[id]
+ self.db.delete(id)
+
+ def reap(self):
+ """Go through the domains looking for ones that have crashed or stopped.
+ Tidy them up.
+ """
+ print 'XendDomain>reap>'
+ domlist = xc.domain_getinfo()
+ casualties = []
+ for d in domlist:
+ #print 'dom', d
+ dead = 0
+ dead = dead or (d['crashed'] or d['shutdown'])
+ dead = dead or (d['dying'] and
+ not(d['running'] or d['paused'] or d['blocked']))
+ if dead:
+ casualties.append(d)
+ for d in casualties:
+ id = str(d['dom'])
+ print 'XendDomain>reap> died id=', id, d
+ dominfo = self.domain.get(id)
+ if not dominfo: continue
+ dominfo.died()
+ self.domain_destroy(id, refresh=0)
+ print 'XendDomain>reap<'
+
+ def refresh(self):
+ """Refresh domain list from Xen.
+ """
+ domlist = xc.domain_getinfo()
+ # Index the domlist by id.
+ # Add entries for any domains we don't know about.
+ doms = {}
+ for d in domlist:
+ id = str(d['dom'])
+ doms[id] = d
+ if id not in self.domain:
+ config = None
+ #image = None
+ #newinfo = XendDomainInfo.XendDomainInfo(
+ # config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
+ deferred = XendDomainInfo.vm_recreate(config, d)
+ def fn(dominfo):
+ self._add_domain(dominfo.id, dominfo)
+ deferred.addCallback(fn)
+ # Remove entries for domains that no longer exist.
+ for d in self.domain.values():
+ dominfo = doms.get(d.id)
+ if dominfo:
+ d.update(dominfo)
+ else:
+ self._delete_domain(d.id)
+ self.reap()
+
+ def refresh_domain(self, id):
+ dom = int(id)
+ dominfo = xc.domain_getinfo(dom, 1)
+ if dominfo == [] or dominfo[0]['dom'] != dom:
+ try:
+ self._delete_domain(id)
+ except:
+ print 'refresh_domain: error'
+ raise
+ pass
+ else:
+ d = self.domain.get(id)
+ if d:
+ d.update(dominfo[0])
+
+ def domain_ls(self):
+ # List domains.
+ # Update info from kernel first.
+ self.refresh()
+ return self.domain.keys()
+
+ def domains(self):
+ self.refresh()
+ return self.domain.values()
+
+ def domain_create(self, config):
+ # Create domain, log it.
+ deferred = XendDomainInfo.vm_create(config)
+ def fn(dominfo):
+ self._add_domain(dominfo.id, dominfo)
+ return dominfo
+ deferred.addCallback(fn)
+ return deferred
+
+ def domain_get(self, id):
+ id = str(id)
+ self.refresh_domain(id)
+ return self.domain.get(id)
+
+ def domain_unpause(self, id):
+ """(Re)start domain running.
+ """
+ dom = int(id)
+ eserver.inject('xend.domain.unpause', id)
+ return xc.domain_unpause(dom=dom)
+
+ def domain_pause(self, id):
+ """Pause domain execution.
+ """
+ dom = int(id)
+ eserver.inject('xend.domain.pause', id)
+ return xc.domain_pause(dom=dom)
+
+ def domain_shutdown(self, id, reason='poweroff'):
+ """Shutdown domain (nicely).
+ """
+ dom = int(id)
+ if dom <= 0:
+ return 0
+ eserver.inject('xend.domain.shutdown', [id, reason])
+ val = xend.domain_shutdown(dom, reason)
+ self.refresh()
+ return val
+
+ def domain_destroy(self, id, refresh=1):
+ """Terminate domain immediately.
+ """
+ dom = int(id)
+ if dom <= 0:
+ return 0
+ eserver.inject('xend.domain.destroy', id)
+ val = xc.domain_destroy(dom=dom)
+ if refresh: self.refresh()
+ return val
+
+ def domain_migrate(self, id, dst):
+ """Start domain migration.
+ """
+ # Need a cancel too?
+ pass
+
+ def domain_save(self, id, dst, progress=0):
+ """Save domain state to file, destroy domain.
+ """
+ dom = int(id)
+ dominfo = self.domain_get(id)
+ if not dominfo:
+ return -1
+ vmconfig = sxp.to_string(dominfo.sxpr())
+ self.domain_pause(id)
+ eserver.inject('xend.domain.save', id)
+ rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
+ if rc == 0:
+ self.domain_destroy(id)
+ return rc
+
+ def domain_restore(self, src, progress=0):
+ """Restore domain from file.
+ """
+ dominfo = XendDomainInfo.vm_restore(src, progress=progress)
+ self._add_domain(dominfo.id, dominfo)
+ return dominfo
+
+ #============================================================================
+ # Backward compatibility stuff from here on.
+
+ def domain_pincpu(self, dom, cpu):
+ dom = int(dom)
+ return xc.domain_pincpu(dom, cpu)
+
+ def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
+ dom = int(dom)
+ return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
+ warp=warp, warpl=warpl, warpu=warpu)
+
+ def domain_cpu_bvt_get(self, dom):
+ dom = int(dom)
+ return xc.bvtsched_domain_get(dom)
+
+ def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
+ dom = int(dom)
+ return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
+
+ def domain_cpu_atropos_get(self, dom):
+ dom = int(dom)
+ return xc.atropos_domain_get(dom)
+
+ def domain_vif_ls(self, dom):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ devs = dominfo.get_devices('vif')
+ return range(0, len(devs))
+
+ def domain_vif_get(self, dom, vif):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ return dominfo.get_device_by_index(vif)
+
+## def domain_vif_ip_add(self, dom, vif, ip):
+## dom = int(dom)
+## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
+
+ def domain_vbd_ls(self, dom):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return []
+ devs = dominfo.get_devices('vbd')
+ return [ sxp.child_value(v, 'dev') for v in devs ]
+
+ def domain_vbd_get(self, dom, vbd):
+ dominfo = self.domain_get(dom)
+ if not dominfo: return None
+ devs = dominfo.get_devices('vbd')
+ for v in devs:
+ if sxp.child_value(v, 'dev') == vbd:
+ return v
+ return None
+
+ def domain_shadow_control(self, dom, op):
+ dom = int(dom)
+ return xc.shadow_control(dom, op)
+
+ #============================================================================
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = XendDomain()
+ return inst