aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-09 09:01:57 +0000
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-09 09:01:57 +0000
commit42d8ee3480d321fd2dfff4b8393152b94236bbfd (patch)
treef08d4c2a8c7e3ccde89dcb38194628200de7ce71 /tools
parent57c8cb2125af4c1db6381529b38cae3561b0436a (diff)
downloadxen-42d8ee3480d321fd2dfff4b8393152b94236bbfd.tar.gz
xen-42d8ee3480d321fd2dfff4b8393152b94236bbfd.tar.bz2
xen-42d8ee3480d321fd2dfff4b8393152b94236bbfd.zip
bitkeeper revision 1.1662.1.21 (42a80585xAt7ZrRcqmCRm3HvTrL7Mg)
Many files: Switch to xenstore for storing persistent information. Signed-off-by: Mike Wray <mike.wray@hp.com> Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
Diffstat (limited to 'tools')
-rw-r--r--tools/python/xen/xend/XendDomain.py83
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py212
-rw-r--r--tools/python/xen/xend/XendRoot.py10
-rw-r--r--tools/python/xen/xend/XendVnet.py22
-rw-r--r--tools/python/xen/xend/image.py40
-rwxr-xr-xtools/python/xen/xend/server/blkif.py23
-rwxr-xr-xtools/python/xen/xend/server/channel.py79
-rwxr-xr-xtools/python/xen/xend/server/console.py7
-rwxr-xr-xtools/python/xen/xend/server/controller.py71
-rwxr-xr-xtools/python/xen/xend/server/netif.py52
-rw-r--r--tools/python/xen/xend/server/usbif.py6
-rw-r--r--tools/python/xen/xend/xenstore/xsobj.py5
12 files changed, 420 insertions, 190 deletions
diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py
index 5819a9e4bf..11f434a46d 100644
--- a/tools/python/xen/xend/XendDomain.py
+++ b/tools/python/xen/xend/XendDomain.py
@@ -23,7 +23,8 @@ 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 import XendDB
+from xen.xend.uuid import getUuid
+from xen.xend.xenstore import XenNode, DBMap
__all__ = [ "XendDomain" ]
@@ -40,9 +41,6 @@ class XendDomain:
"""Index of all domains. Singleton.
"""
- """Path to domain database."""
- dbpath = "domain"
-
"""Dict of domain info indexed by domain id."""
domains = None
@@ -53,7 +51,7 @@ class XendDomain:
# So we stuff the XendDomain instance (self) into xroot's components.
xroot.add_component("xen.xend.XendDomain", self)
self.domains = XendDomainDict()
- self.db = XendDB.XendDB(self.dbpath)
+ self.dbmap = DBMap(db=XenNode("/domain"))
eserver.subscribe('xend.virq', self.onVirq)
self.initial_refresh()
@@ -96,11 +94,18 @@ class XendDomain:
"""Refresh initial domain info from db.
"""
doms = self.xen_domains()
- for config in self.db.fetchall("").values():
- domid = int(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._new_domain(domdb, doms[domid])
except Exception, ex:
log.exception("Error recreating domain info: id=%d", domid)
self._delete_domain(domid)
@@ -108,27 +113,20 @@ class XendDomain:
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(str(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 db: saved info from the db
@param info: domain info from xen
@return: domain
"""
- uuid = sxp.child_value(savedinfo, 'uuid')
- dominfo = XendDomainInfo.recreate(savedinfo, info, uuid)
+ log.error(db)
+ log.error(db.uuid)
+ dominfo = XendDomainInfo.recreate(db, info)
self.domains[dominfo.id] = dominfo
- self.sync_domain(dominfo)
return dominfo
def _add_domain(self, info, notify=True):
@@ -141,11 +139,11 @@ class XendDomain:
for i, d in self.domains.items():
if i != d.id:
del self.domains[i]
- self.db.delete(str(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])
@@ -155,12 +153,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]
- self.db.delete(str(id))
+ info.cleanup()
+ info.delete()
if notify:
eserver.inject('xend.domain.died', [info.name, info.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.
@@ -263,8 +275,7 @@ class XendDomain:
@param config: configuration
@return: domain
"""
- dominfo = XendDomainInfo.create(config)
- self._add_domain(dominfo)
+ dominfo = XendDomainInfo.create(self.dbmap, config)
return dominfo
def domain_restart(self, dominfo):
@@ -277,7 +288,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"])
@@ -297,8 +307,7 @@ class XendDomain:
"""
config = sxp.child_value(vmconfig, 'config')
uuid = sxp.child_value(vmconfig, 'uuid')
- dominfo = XendDomainInfo.restore(config, uuid=uuid)
- self._add_domain(dominfo)
+ dominfo = XendDomainInfo.restore(self.dbmap, config, uuid=uuid)
return dominfo
def domain_restore(self, src, progress=False):
@@ -330,8 +339,12 @@ class XendDomain:
try:
info = self.xen_domain(id)
if info:
- log.info("Creating entry for unknown domain: id=%d", id)
- dominfo = XendDomainInfo.recreate(None, 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)
@@ -593,7 +606,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_create(devconfig)
- self.sync_domain(dominfo)
+ dominfo.exportToDB()
return val
def domain_device_configure(self, id, devconfig, devid):
@@ -606,7 +619,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_configure(devconfig, devid)
- self.sync_domain(dominfo)
+ dominfo.exportToDB()
return val
def domain_device_refresh(self, id, type, devid):
@@ -618,7 +631,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_refresh(type, devid)
- self.sync_domain(dominfo)
+ dominfo.exportToDB()
return val
def domain_device_destroy(self, id, type, devid):
@@ -630,7 +643,7 @@ class XendDomain:
"""
dominfo = self.domain_lookup(id)
val = dominfo.device_destroy(type, devid)
- self.sync_domain(dominfo)
+ dominfo.exportToDB()
return val
def domain_devtype_ls(self, id, type):
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 97d6dbbf31..16415d78a7 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -30,6 +30,7 @@ from XendError import XendError, VmError
from xen.xend.XendRoot import get_component
from xen.xend.uuid import getUuid
+from xen.xend.xenstore import DBVar
"""Flag for a block device backend domain."""
SIF_BLK_BE_DOMAIN = (1<<4)
@@ -145,94 +146,92 @@ class XendDomainInfo:
"""
MINIMUM_RESTART_TIME = 20
- def _create(cls, uuid=None):
- """Create a vm object with a uuid.
-
- @param uuid uuid to use
- @return vm
- """
- if uuid is None:
- uuid = getUuid()
- vm = cls()
- vm.uuid = uuid
- return vm
-
- _create = classmethod(_create)
-
- def create(cls, config):
+ def create(cls, parentdb, config):
"""Create a VM from a configuration.
- If a vm has been partially created and there is an error it
- is destroyed.
+ @param parentdb: parent db
@param config configuration
@raise: VmError for invalid configuration
"""
- vm = cls._create()
+ uuid = getUuid()
+ db = parentdb.addChild(uuid)
+ vm = cls(db)
vm.construct(config)
+ vm.saveDB(sync=True)
return vm
create = classmethod(create)
- def recreate(cls, savedinfo, info, uuid=None):
+ def recreate(cls, db, info):
"""Create the VM object for an existing domain.
- @param savedinfo: saved info from the domain DB
+ @param db: domain db
@param info: domain info from xc
- @param uuid: uuid to use
- @type info: xc domain dict
"""
- vm = cls._create(uuid=uuid)
-
- log.debug('savedinfo=' + prettyprintstring(savedinfo))
+ dom = info['dom']
+ vm = cls(db)
+ db.readDB()
+ vm.importFromDB()
+ config = vm.config
log.debug('info=' + str(info))
+ log.debug('config=' + prettyprintstring(config))
- vm.recreate = True
- vm.savedinfo = savedinfo
- vm.setdom(info['dom'])
+ vm.setdom(dom)
vm.memory = info['mem_kb']/1024
- start_time = sxp.child_value(savedinfo, 'start_time')
- if start_time is not None:
- vm.start_time = float(start_time)
- vm.restart_state = sxp.child_value(savedinfo, 'restart_state')
- vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0))
- restart_time = sxp.child_value(savedinfo, 'restart_time')
- if restart_time is not None:
- vm.restart_time = float(restart_time)
- config = sxp.child_value(savedinfo, 'config')
-
if config:
- vm.construct(config)
+ try:
+ vm.recreate = True
+ vm.construct(config)
+ finally:
+ vm.recreate = False
else:
- vm.setName(sxp.child_value(savedinfo, 'name',
- "Domain-%d" % info['dom']))
- vm.recreate = False
- vm.savedinfo = None
+ vm.setName("Domain-%d" % dom)
+ vm.exportToDB(save=True)
return vm
recreate = classmethod(recreate)
- def restore(cls, config, uuid=None):
+ def restore(cls, parentdb, config, uuid=None):
"""Create a domain and a VM object to do a restore.
+ @param parentdb: parent db
@param config: domain configuration
@param uuid: uuid to use
"""
- vm = cls._create(uuid=uuid)
+ db = parentdb.addChild(uuid)
+ vm = cls(db)
dom = xc.domain_create()
vm.setdom(dom)
vm.dom_construct(vm.id, config)
+ vm.saveDB(sync=True)
return vm
restore = classmethod(restore)
- def __init__(self):
+ __exports__ = [
+ DBVar('id', ty='str'),
+ DBVar('name', ty='str'),
+ DBVar('uuid', ty='str'),
+ DBVar('config', ty='sxpr'),
+ DBVar('start_time', ty='float'),
+ DBVar('state', ty='str'),
+ DBVar('store_mfn', ty='long'),
+ DBVar('restart_mode', ty='str'),
+ DBVar('restart_state', ty='str'),
+ DBVar('restart_time', ty='float'),
+ DBVar('restart_count', ty='int'),
+ ]
+
+ def __init__(self, db):
+ self.db = db
+ self.uuid = db.getName()
+
self.recreate = 0
self.restore = 0
self.config = None
- self.uuid = None
self.id = None
self.cpu_weight = 1
self.start_time = None
@@ -262,23 +261,39 @@ class XendDomainInfo:
self.restart_count = 0
self.console_port = None
- self.savedinfo = None
self.vcpus = 1
self.bootloader = None
+ def setDB(self, db):
+ self.db = db
+
+ def saveDB(self, save=False, sync=False):
+ self.db.saveDB(save=save, sync=sync)
+
+ def exportToDB(self, save=False, sync=False):
+ if self.channel:
+ self.channel.saveToDB(self.db.addChild("channel"))
+ if self.store_channel:
+ self.store_channel.saveToDB(self.db.addChild("store_channel"))
+ self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
+
+ def importFromDB(self):
+ self.db.importFromDB(self, fields=self.__exports__)
+
def setdom(self, dom):
"""Set the domain id.
@param dom: domain id
"""
self.id = int(dom)
+ #self.db.id = self.id
def getDomain(self):
return self.id
def setName(self, name):
self.name = name
- #self.db.name = self.name
+ self.db.name = self.name
def getName(self):
return self.name
@@ -301,6 +316,7 @@ class XendDomainInfo:
self.state = state
self.state_updated.notifyAll()
self.state_updated.release()
+ self.saveDB()
def state_wait(self, state):
self.state_updated.acquire()
@@ -484,6 +500,7 @@ class XendDomainInfo:
self.configure_restart()
self.construct_image()
self.configure()
+ self.exportToDB()
except Exception, ex:
# Catch errors, cleanup and re-raise.
print 'Domain construction error:', ex
@@ -495,6 +512,7 @@ class XendDomainInfo:
def register_domain(self):
xd = get_component('xen.xend.XendDomain')
xd._add_domain(self)
+ self.exportToDB()
def configure_cpus(self, config):
try:
@@ -528,42 +546,26 @@ class XendDomainInfo:
"""
self.create_channel()
self.image.createImage()
- #self.image.exportToDB()
+ self.image.exportToDB()
#if self.store_channel:
# self.db.introduceDomain(self.id,
# self.store_mfn,
# self.store_channel)
- def get_device_savedinfo(self, type, id):
- val = None
- if self.savedinfo is None:
- return val
- devices = sxp.child(self.savedinfo, 'devices')
- if devices is None:
- return val
- for d in sxp.children(devices, type):
- did = sxp.child_value(d, 'id')
- if did is None: continue
- if int(did) == id:
- val = d
- break
- return val
-
- def get_device_recreate(self, type, id):
- return self.get_device_savedinfo(type, id) or self.recreate
-
- def destroy(self):
- """Completely destroy the vm.
+ def delete(self):
+ """Delete the vm's db.
"""
+ if self.dom_get(self.id):
+ return
+ self.id = None
+ self.saveDB(sync=True)
try:
- self.cleanup()
- except Exception, ex:
- log.warning("error in domain cleanup: %s", ex)
- pass
- try:
- self.destroy_domain()
+ # Todo: eventually will have to wait for devices to signal
+ # destruction before can delete the db.
+ if self.db:
+ self.db.delete()
except Exception, ex:
- log.warning("error in domain destroy: %s", ex)
+ log.warning("error in domain db delete: %s", ex)
pass
def destroy_domain(self):
@@ -571,6 +573,18 @@ class XendDomainInfo:
The domain will not finally go away unless all vm
devices have been released.
"""
+ if self.id is None:
+ return
+ try:
+ xc.domain_destroy(dom=self.id)
+ except Exception, err:
+ log.exception("Domain destroy failed: %s", self.name)
+
+ def cleanup(self):
+ """Cleanup vm resources: release devices.
+ """
+ self.state = STATE_VM_TERMINATED
+ self.release_devices()
if self.channel:
try:
self.channel.close()
@@ -583,23 +597,25 @@ class XendDomainInfo:
self.store_channel = None
except:
pass
+ #try:
+ # self.db.releaseDomain(self.id)
+ #except Exception, ex:
+ # log.warning("error in domain release on xenstore: %s", ex)
+ # pass
if self.image:
try:
self.image.destroy()
self.image = None
except:
pass
- if self.id is None: return 0
- try:
- xc.domain_destroy(dom=self.id)
- except Exception, err:
- log.exception("Domain destroy failed: %s", self.name)
- def cleanup(self):
- """Cleanup vm resources: release devices.
+ def destroy(self):
+ """Clenup vm and destroy domain.
"""
- self.state = STATE_VM_TERMINATED
- self.release_devices()
+ self.cleanup()
+ self.destroy_domain()
+ self.saveDB()
+ return 0
def is_terminated(self):
"""Check if a domain has been terminated.
@@ -639,27 +655,24 @@ class XendDomainInfo:
if not self.restore:
self.setdom(dom)
- def openChannel(self, name, local, remote):
+ def openChannel(self, key, local, remote):
"""Create a channel to the domain.
If saved info is available recreate the channel.
+ @param key db key for the saved data (if any)
@param local default local port
@param remote default remote port
"""
- local = 0
- remote = 1
- if self.savedinfo:
- info = sxp.child(self.savedinfo, name)
- if info:
- local = int(sxp.child_value(info, "local_port", 0))
- remote = int(sxp.child_value(info, "remote_port", 1))
- chan = channelFactory().openChannel(self.id, local_port=local,
- remote_port=remote)
+ db = self.db.addChild(key)
+ chan = channelFactory().restoreFromDB(db, self.id, local, remote)
+ #todo: save here?
+ #chan.saveToDB(db)
return chan
- def eventChannel(self, name):
- return EventChannel.interdomain(0, self.id)
-
+ def eventChannel(self, key):
+ db = self.db.addChild(key)
+ return EventChannel.restoreFromDB(db, 0, self.id)
+
def create_channel(self):
"""Create the channels to the domain.
"""
@@ -823,6 +836,7 @@ class XendDomainInfo:
if self.bootloader:
self.config = self.bootloader_config()
self.construct(self.config)
+ self.saveDB()
finally:
self.restart_state = None
diff --git a/tools/python/xen/xend/XendRoot.py b/tools/python/xen/xend/XendRoot.py
index 10e560fbcc..045a5a5fa4 100644
--- a/tools/python/xen/xend/XendRoot.py
+++ b/tools/python/xen/xend/XendRoot.py
@@ -25,9 +25,6 @@ import sxp
class XendRoot:
"""Root of the management classes."""
- """Default path to the root of the database."""
- dbroot_default = "/var/lib/xen/xend-db"
-
"""Default path to the config file."""
config_default = "/etc/xen/xend-config.sxp"
@@ -82,7 +79,6 @@ class XendRoot:
components = {}
def __init__(self):
- self.dbroot = None
self.config_path = None
self.config = None
self.logging = None
@@ -171,7 +167,6 @@ class XendRoot:
def configure(self):
self.set_config()
self.configure_logger()
- self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
def configure_logger(self):
logfile = self.get_config_value("logfile", self.logfile_default)
@@ -192,11 +187,6 @@ class XendRoot:
"""
return self.logging and self.logging.getLogger()
- def get_dbroot(self):
- """Get the path to the database root.
- """
- return self.dbroot
-
def set_config(self):
"""If the config file exists, read it. If not, ignore it.
diff --git a/tools/python/xen/xend/XendVnet.py b/tools/python/xen/xend/XendVnet.py
index d95fd204aa..3614127c49 100644
--- a/tools/python/xen/xend/XendVnet.py
+++ b/tools/python/xen/xend/XendVnet.py
@@ -4,11 +4,10 @@
"""
from xen.util import Brctl
-
-import sxp
-import XendDB
-from XendError import XendError
-from XendLogging import log
+from xen.xend import sxp
+from xen.xend.XendError import XendError
+from xen.xend.XendLogging import log
+from xen.xend.xenstore import XenNode, DBMap
def vnet_cmd(cmd):
out = None
@@ -63,14 +62,15 @@ class XendVnet:
"""Index of all vnets. Singleton.
"""
- dbpath = "vnet"
+ dbpath = "/vnet"
def __init__(self):
# Table of vnet info indexed by vnet id.
self.vnet = {}
- self.db = XendDB.XendDB(self.dbpath)
- vnets = self.db.fetchall("")
- for config in vnets.values():
+ self.dbmap = DBMap(db=XenNode(self.dbpath))
+ self.dbmap.readDB()
+ for vnetdb in self.dbmap.values():
+ config = vnetdb.config
info = XendVnetInfo(config)
self.vnet[info.id] = info
try:
@@ -115,7 +115,7 @@ class XendVnet:
"""
info = XendVnetInfo(config)
self.vnet[info.id] = info
- self.db.save(info.id, info.sxpr())
+ self.dbmap["%s/config" % info.id] = info.sxpr()
info.configure()
def vnet_delete(self, id):
@@ -126,7 +126,7 @@ class XendVnet:
info = self.vnet_get(id)
if info:
del self.vnet[id]
- self.db.delete(id)
+ self.dbmap.delete(id)
info.delete()
def instance():
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index d7f6965767..e0d70581bf 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -4,7 +4,7 @@ import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.xend import sxp
from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
-#from xen.xend.xenstore import DBVar
+from xen.xend.xenstore import DBVar
class ImageHandler:
"""Abstract base class for image handlers.
@@ -73,7 +73,7 @@ class ImageHandler:
#======================================================================
# Instance vars and methods.
- #db = None
+ db = None
ostype = None
config = None
@@ -82,25 +82,25 @@ class ImageHandler:
cmdline = None
flags = 0
- #__exports__ = [
- # DBVar('ostype', ty='str'),
- # DBVar('config', ty='sxpr'),
- # DBVar('kernel', ty='str'),
- # DBVar('ramdisk', ty='str'),
- # DBVar('cmdline', ty='str'),
- # DBVar('flags', ty='int'),
- # ]
+ __exports__ = [
+ DBVar('ostype', ty='str'),
+ DBVar('config', ty='sxpr'),
+ DBVar('kernel', ty='str'),
+ DBVar('ramdisk', ty='str'),
+ DBVar('cmdline', ty='str'),
+ DBVar('flags', ty='int'),
+ ]
def __init__(self, vm, config):
self.vm = vm
- #self.db = vm.db.addChild('/image')
+ self.db = vm.db.addChild('/image')
self.config = config
- #def exportToDB(self, save=False):
- # self.db.exportToDB(self, fields=self.__exports__, save=save)
+ def exportToDB(self, save=False):
+ self.db.exportToDB(self, fields=self.__exports__, save=save)
- #def importFromDB(self):
- # self.db.importFromDB(self, fields=self.__exports__)
+ def importFromDB(self):
+ self.db.importFromDB(self, fields=self.__exports__)
def unlink(self, f):
if not f: return
@@ -234,11 +234,11 @@ class Plan9ImageHandler(ImageHandler):
class VmxImageHandler(ImageHandler):
- #__exports__ = ImageHandler.__exports__ + [
- # DBVar('memmap', ty='str'),
- # DBVar('memmap_value', ty='sxpr'),
- # # device channel?
- # ]
+ __exports__ = ImageHandler.__exports__ + [
+ DBVar('memmap', ty='str'),
+ DBVar('memmap_value', ty='sxpr'),
+ # device channel?
+ ]
ostype = "vmx"
memmap = None
diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py
index 602979fed0..75a76e8bda 100755
--- a/tools/python/xen/xend/server/blkif.py
+++ b/tools/python/xen/xend/server/blkif.py
@@ -9,6 +9,7 @@ from xen.xend.XendRoot import get_component
from xen.xend.XendLogging import log
from xen.xend import sxp
from xen.xend import Blkctl
+from xen.xend.xenstore import DBVar
from xen.xend.server import channel
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
@@ -158,6 +159,18 @@ class BlkDev(Dev):
"""Info record for a block device.
"""
+ __exports__ = Dev.__exports__ + [
+ DBVar('dev', ty='str'),
+ DBVar('vdev', ty='int'),
+ DBVar('mode', ty='str'),
+ DBVar('viftype', ty='str'),
+ DBVar('params', ty='str'),
+ DBVar('node', ty='str'),
+ DBVar('device', ty='long'),
+ DBVar('start_sector', ty='long'),
+ DBVar('nr_sectors', ty='long'),
+ ]
+
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
self.dev = None
@@ -215,8 +228,7 @@ class BlkDev(Dev):
def attach(self, recreate=False, change=False):
if recreate:
- node = sxp.child_value(recreate, 'node')
- self.setNode(node)
+ pass
else:
node = Blkctl.block('bind', self.type, self.params)
self.setNode(node)
@@ -299,7 +311,8 @@ class BlkDev(Dev):
return self.controller.getBackend(self.backendDomain)
def refresh(self):
- log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, self.id)
+ log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain,
+ self.id)
self.interfaceChanged()
def destroy(self, change=False, reboot=False):
@@ -308,7 +321,8 @@ class BlkDev(Dev):
@param change: change flag
"""
self.destroyed = True
- log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, self.id)
+ log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain,
+ self.id)
self.send_be_vbd_destroy()
if change:
self.interfaceChanged()
@@ -445,5 +459,4 @@ class BlkifController(DevController):
log.error("Exception connecting backend: %s", ex)
else:
log.error('interface connect on unknown interface: id=%d', id)
-
diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py
index e5b82b5330..00f451a7b8 100755
--- a/tools/python/xen/xend/server/channel.py
+++ b/tools/python/xen/xend/server/channel.py
@@ -31,6 +31,33 @@ class EventChannel(dict):
interdomain = classmethod(interdomain)
+ def restoreFromDB(cls, db, dom1, dom2, port1=0, port2=0):
+ """Create an event channel using db info if available.
+ Inverse to saveToDB().
+
+ @param db db
+ @param dom1
+ @param dom2
+ @param port1
+ @param port2
+ """
+ try:
+ dom1 = int(db['dom1'])
+ except: pass
+ try:
+ dom2 = int(db['dom2'])
+ except: pass
+ try:
+ port1 = int(db['port1'])
+ except: pass
+ try:
+ port2 = int(db['port2'])
+ except: pass
+ evtchn = cls.interdomain(dom1, dom2, port1=port1, port2=port2)
+ return evtchn
+
+ restoreFromDB = classmethod(restoreFromDB)
+
def __init__(self, dom1, dom2, d):
d['dom1'] = dom1
d['dom2'] = dom2
@@ -54,6 +81,18 @@ class EventChannel(dict):
evtchn_close(self.dom1, self.port1)
evtchn_close(self.dom2, self.port2)
+ def saveToDB(self, db):
+ """Save the event channel to the db so it can be restored later,
+ using restoreFromDB() on the class.
+
+ @param db db
+ """
+ db['dom1'] = str(self.dom1)
+ db['dom2'] = str(self.dom2)
+ db['port1'] = str(self.port1)
+ db['port2'] = str(self.port2)
+ db.saveDB()
+
def sxpr(self):
return ['event-channel',
['dom1', self.dom1 ],
@@ -63,7 +102,7 @@ class EventChannel(dict):
]
def __repr__(self):
- return ("<EventChannel dom1:%s:%s dom2:%s:%s>"
+ return ("<EventChannel dom1:%d:%d dom2:%d:%d>"
% (self.dom1, self.port1, self.dom2, self.port2))
def eventChannel(dom1, dom2, port1=0, port2=0):
@@ -241,8 +280,31 @@ class ChannelFactory:
@type remote: int
@return: port object
"""
- return xu.port(dom, local_port=int(local_port),
- remote_port=int(remote_port))
+ return xu.port(dom, local_port=local_port, remote_port=remote_port)
+
+ def restoreFromDB(self, db, dom, local, remote):
+ """Create a channel using ports restored from the db (if available).
+ Otherwise use the given ports. This is the inverse operation to
+ saveToDB() on a channel.
+
+ @param db db
+ @param dom domain the channel connects to
+ @param local default local port
+ @param remote default remote port
+ """
+ try:
+ local_port = int(db['local_port'])
+ except:
+ local_port = local
+ try:
+ remote_port = int(db['remote_port'])
+ except:
+ remote_port = remote
+ try:
+ chan = self.openChannel(dom, local_port, remote_port)
+ except:
+ return None
+ return chan
def channelFactory():
"""Singleton constructor for the channel factory.
@@ -277,6 +339,17 @@ class Channel:
# Make sure the port will deliver all the messages.
self.port.register(TYPE_WILDCARD)
+ def saveToDB(self, db):
+ """Save the channel ports to the db so the channel can be restored later,
+ using restoreFromDB() on the factory.
+
+ @param db db
+ """
+ if self.closed: return
+ db['local_port'] = str(self.getLocalPort())
+ db['remote_port'] = str(self.getRemotePort())
+ db.saveDB()
+
def getKey(self):
"""Get the channel key.
"""
diff --git a/tools/python/xen/xend/server/console.py b/tools/python/xen/xend/server/console.py
index 1d0489de7f..743ace4aec 100755
--- a/tools/python/xen/xend/server/console.py
+++ b/tools/python/xen/xend/server/console.py
@@ -13,6 +13,7 @@ from xen.xend import EventServer; eserver = EventServer.instance()
from xen.xend.XendLogging import log
from xen.xend import XendRoot; xroot = XendRoot.instance()
from xen.xend import sxp
+from xen.xend.xenstore import DBVar
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
from xen.xend.server.messages import *
@@ -76,6 +77,12 @@ class ConsoleDev(Dev, protocol.ServerFactory):
STATUS_CONNECTED = 'connected'
STATUS_LISTENING = 'listening'
+ __exports__ = Dev.__exports__ + [
+ DBVar('status', ty='str'),
+ #DBVar('listening', ty='str'),
+ DBVar('console_port', ty='int'),
+ ]
+
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config)
self.lock = threading.RLock()
diff --git a/tools/python/xen/xend/server/controller.py b/tools/python/xen/xend/server/controller.py
index 5f99545fb9..d1e19efee1 100755
--- a/tools/python/xen/xend/server/controller.py
+++ b/tools/python/xen/xend/server/controller.py
@@ -4,6 +4,7 @@ for a domain.
"""
from xen.xend.XendError import XendError
+from xen.xend.xenstore import DBVar
from xen.xend.server.messages import msgTypeName, printMsg, getMessageType
DEBUG = 0
@@ -155,11 +156,16 @@ class DevController:
"""
+ # State:
+ # controller/<type> : for controller
+ # device/<type>/<id> : for each device
+
def createDevController(cls, vm, recreate=False):
"""Class method to create a dev controller.
"""
ctrl = cls(vm, recreate=recreate)
ctrl.initController(recreate=recreate)
+ ctrl.exportToDB()
return ctrl
createDevController = classmethod(createDevController)
@@ -169,16 +175,38 @@ class DevController:
getType = classmethod(getType)
+ __exports__ = [
+ DBVar('type', 'str'),
+ DBVar('destroyed', 'bool'),
+ ]
+
# Set when registered.
type = None
def __init__(self, vm, recreate=False):
self.destroyed = False
self.vm = vm
+ self.db = self.getDB()
self.deviceId = 0
self.devices = {}
self.device_order = []
+ def getDB(self):
+ """Get the db node to use for a controller.
+ """
+ return self.vm.db.addChild("/controller/%s" % self.getType())
+
+ def getDevDB(self, id):
+ """Get the db node to use for a device.
+ """
+ return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id))
+
+ def exportToDB(self, save=False):
+ self.db.exportToDB(self, fields=self.__exports__, save=save)
+
+ def importFromDB(self):
+ self.db.importFromDB(self, fields=self.__exports__)
+
def getDevControllerType(self):
return self.dctype
@@ -229,15 +257,15 @@ class DevController:
If change is true the device is a change to an existing domain,
i.e. it is being added at runtime rather than when the domain is created.
"""
- # skanky hack: we use the device ids to maybe find the savedinfo
- # of the device...
- id = self.nextDeviceId()
- if recreate:
- recreate = self.vm.get_device_savedinfo(self.getType(), id)
- dev = self.newDevice(id, config, recreate=recreate)
+ dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate)
+ if self.vm.recreate:
+ dev.importFromDB()
dev.init(recreate=recreate)
self.addDevice(dev)
+ if not recreate:
+ dev.exportToDB()
dev.attach(recreate=recreate, change=change)
+ dev.exportToDB()
def configureDevice(self, id, config, change=False):
"""Reconfigure an existing device.
@@ -344,11 +372,42 @@ class Dev:
@type controller: DevController
"""
+ # ./status : need 2: actual and requested?
+ # down-down: initial.
+ # up-up: fully up.
+ # down-up: down requested, still up. Watch front and back, when both
+ # down go to down-down. But what if one (or both) is not connected?
+ # Still have front/back trees with status? Watch front/status, back/status?
+ # up-down: up requested, still down.
+ # Back-end watches ./status, front/status
+ # Front-end watches ./status, back/status
+ # i.e. each watches the other 2.
+ # Each is status/request status/actual?
+ #
+ # backend?
+ # frontend?
+
+ __exports__ = [
+ DBVar('id', ty='int'),
+ DBVar('type', ty='str'),
+ DBVar('config', ty='sxpr'),
+ DBVar('destroyed', ty='bool'),
+ ]
+
def __init__(self, controller, id, config, recreate=False):
self.controller = controller
self.id = id
self.config = config
self.destroyed = False
+ self.type = self.getType()
+
+ self.db = controller.getDevDB(id)
+
+ def exportToDB(self, save=False):
+ self.db.exportToDB(self, fields=self.__exports__, save=save)
+
+ def importFromDB(self):
+ self.db.importFromDB(self, fields=self.__exports__)
def getDomain(self):
return self.controller.getDomain()
diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py
index 157490f5a2..0a49842522 100755
--- a/tools/python/xen/xend/server/netif.py
+++ b/tools/python/xen/xend/server/netif.py
@@ -12,6 +12,7 @@ from xen.xend.XendError import XendError, VmError
from xen.xend.XendLogging import log
from xen.xend import XendVnet
from xen.xend.XendRoot import get_component
+from xen.xend.xenstore import DBVar
from xen.xend.server import channel
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
@@ -21,6 +22,57 @@ class NetDev(Dev):
"""A network device.
"""
+ # State:
+ # inherited +
+ # ./config
+ # ./mac
+ # ./be_mac
+ # ./bridge
+ # ./script
+ # ./ipaddr ?
+ #
+ # ./credit
+ # ./period
+ #
+ # ./vifctl: up/down?
+ # ./vifname
+ #
+ #
+ # Poss should have no backend state here - except for ref to backend's own tree
+ # for the device? And a status - the one we want.
+ # ./back/dom
+ # ./back/devid - id for back-end (netif_handle) - same as front/devid
+ # ./back/id - backend id (if more than one b/e per domain)
+ # ./back/status
+ # ./back/tx_shmem_frame - actually these belong in back-end state
+ # ./back/rx_shmem_frame
+ #
+ # ./front/dom
+ # ./front/devid
+ # ./front/status - need 2: one for requested, one for actual? Or drive from dev status
+ # and this is front status only.
+ # ./front/tx_shmem_frame
+ # ./front/rx_shmem_frame
+ #
+ # ./evtchn/front - here or in front/back?
+ # ./evtchn/back
+ # ./evtchn/status ?
+ # At present created by dev: but should be created unbound by front/back
+ # separately and then bound (by back)?
+
+ __exports__ = Dev.__exports__ + [
+ DBVar('config', ty='sxpr'),
+ DBVar('mac', ty='mac'),
+ DBVar('be_mac', ty='mac'),
+ DBVar('bridge', ty='str'),
+ DBVar('script', ty='str'),
+ #DBVar('ipaddr'),
+ DBVar('credit', ty='int'),
+ DBVar('period', ty='int'),
+ DBVar('vifname', ty='str'),
+ DBVar('evtchn'), #todo: export fields (renamed)
+ ]
+
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
self.vif = int(self.id)
diff --git a/tools/python/xen/xend/server/usbif.py b/tools/python/xen/xend/server/usbif.py
index 657a98e671..d366985740 100644
--- a/tools/python/xen/xend/server/usbif.py
+++ b/tools/python/xen/xend/server/usbif.py
@@ -7,6 +7,7 @@
from xen.xend import sxp
from xen.xend.XendLogging import log
from xen.xend.XendError import XendError
+from xen.xend.xenstore import DBVar
from xen.xend.server import channel
from xen.xend.server.controller import Dev, DevController
@@ -141,6 +142,11 @@ class UsbBackend:
class UsbDev(Dev):
+
+ __exports__ = Dev.__exports__ + [
+ DBVar('port', ty='int'),
+ DBVar('path', ty='str'),
+ ]
def __init__(self, controller, id, config, recreate=False):
Dev.__init__(self, controller, id, config, recreate=recreate)
diff --git a/tools/python/xen/xend/xenstore/xsobj.py b/tools/python/xen/xend/xenstore/xsobj.py
index 62e18d07d9..b1c9a4f1d1 100644
--- a/tools/python/xen/xend/xenstore/xsobj.py
+++ b/tools/python/xen/xend/xenstore/xsobj.py
@@ -201,7 +201,10 @@ class DBVar:
setAttr(o, self.attr, val)
def getDB(self, db):
- data = getattr(db, self.path)
+ try:
+ data = getattr(db, self.path)
+ except AttributeError:
+ return None
return DBConverter.convertFromDB(data, ty=self.ty)
def setDB(self, db, val):