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>
This commit is contained in:
cl349@firebug.cl.cam.ac.uk committed 2005-06-09 09:01:57 +00:00
1 parent 57c8cb2125
commit 42d8ee3480
12 files changed
+420 -190

No files matched your search

+48 -35
View File
@@ -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):
+113 -99
View File
@@ -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()
# 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 cleanup: %s", ex)
pass
try:
self.destroy_domain()
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
-10
View File
@@ -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.
+11 -11
View File
@@ -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():
+20 -20
View File
@@ -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
+18 -5
View File
@@ -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)
+76 -3
View File
@@ -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.
"""
+7
View File
@@ -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()
+65 -6
View File
@@ -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()
+52
View File
@@ -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)
+6
View File
@@ -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)
+4 -1
View File
@@ -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):
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.