mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
Use DevController.allocateDeviceID rather than using a local variable.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
This commit is contained in:
1 parent
03454aa712
commit
0c0fe2fcc7
4 files changed
+345
-279
No files matched your search
@@ -275,8 +275,7 @@ class XendDomain:
|
||||
@param config: configuration
|
||||
@return: domain
|
||||
"""
|
||||
dominfo = XendDomainInfo.create(self.dbmap, config)
|
||||
return dominfo
|
||||
return XendDomainInfo.create(self.dbmap.getPath(), config)
|
||||
|
||||
def domain_restart(self, dominfo):
|
||||
"""Restart a domain.
|
||||
@@ -309,8 +308,7 @@ class XendDomain:
|
||||
@param vmconfig: vm configuration
|
||||
"""
|
||||
config = sxp.child_value(vmconfig, 'config')
|
||||
dominfo = XendDomainInfo.restore(self.dbmap, config)
|
||||
return dominfo
|
||||
return XendDomainInfo.restore(self.dbmap.getPath(), config)
|
||||
|
||||
def domain_restore(self, src, progress=False):
|
||||
"""Restore a domain from file.
|
||||
@@ -352,13 +350,12 @@ class XendDomain:
|
||||
dompath = self.domroot
|
||||
log.info("Creating entry for unknown xend domain: id=%d uuid=%s",
|
||||
dom0, uuid)
|
||||
db = self.dbmap.addChild("%s/xend" % uuid)
|
||||
try:
|
||||
dominfo = XendDomainInfo.recreate(uuid, dompath, dom0,
|
||||
db, info)
|
||||
except:
|
||||
raise XendError("Error recreating xend domain info: id=%d" %
|
||||
dom0)
|
||||
dominfo = XendDomainInfo.recreate(uuid, dompath, info)
|
||||
except Exception, exn:
|
||||
log.exception(exn)
|
||||
raise XendError("Error recreating xend domain info: id=%d: %s" %
|
||||
(dom0, str(exn)))
|
||||
self._add_domain(dominfo)
|
||||
return dominfo
|
||||
|
||||
|
||||
@@ -136,123 +136,179 @@ class XendDomainInfo:
|
||||
"""
|
||||
MINIMUM_RESTART_TIME = 20
|
||||
|
||||
def create(cls, parentdb, config):
|
||||
|
||||
def create(cls, parentdbpath, config):
|
||||
"""Create a VM from a configuration.
|
||||
|
||||
@param parentdb: parent db
|
||||
@param parentdbpath: parent db path
|
||||
@param config configuration
|
||||
@raise: VmError for invalid configuration
|
||||
"""
|
||||
uuid = getUuid()
|
||||
db = parentdb.addChild("%s/xend" % uuid)
|
||||
path = parentdb.getPath()
|
||||
vm = cls(uuid, path, db)
|
||||
vm.construct(config)
|
||||
vm.saveToDB(sync=True)
|
||||
|
||||
log.debug("XendDomainInfo.create(%s, ...)", parentdbpath)
|
||||
|
||||
vm = cls(getUuid(), parentdbpath, cls.parseConfig(config))
|
||||
vm.construct()
|
||||
return vm
|
||||
|
||||
create = classmethod(create)
|
||||
|
||||
def recreate(cls, uuid, path, domid, db, info):
|
||||
|
||||
def recreate(cls, uuid, dompath, info):
|
||||
"""Create the VM object for an existing domain.
|
||||
|
||||
@param db: domain db
|
||||
@param dompath: The path to all domain information
|
||||
@param info: domain info from xc
|
||||
"""
|
||||
vm = cls(uuid, path, db)
|
||||
vm.setDomid(domid)
|
||||
vm.name, vm.start_time = vm.gatherVm(("name", str),
|
||||
("start-time", float))
|
||||
try:
|
||||
db.readDB()
|
||||
except: pass
|
||||
vm.importFromDB()
|
||||
config = vm.config
|
||||
log.debug('info=' + str(info))
|
||||
log.debug('config=' + prettyprintstring(config))
|
||||
|
||||
vm.memory = info['mem_kb'] / 1024
|
||||
vm.target = info['mem_kb'] * 1024
|
||||
log.debug("XendDomainInfo.recreate(%s, %s, ...)", uuid, dompath)
|
||||
|
||||
# ??? vm.setDomid(domid)
|
||||
# vm.name, vm.start_time = vm.gatherVm(("name", str),
|
||||
# ("start-time", float))
|
||||
# config = vm.config
|
||||
# log.debug('info=' + str(info))
|
||||
# log.debug('config=' + prettyprintstring(config))
|
||||
|
||||
# vm.memory = info['mem_kb'] / 1024
|
||||
# vm.target = info['mem_kb'] * 1024
|
||||
|
||||
|
||||
# Parse the configuration in the store, but allow the info we've
|
||||
# been given (from xc) to override it.
|
||||
path = "%s/%s" % (dompath, uuid)
|
||||
|
||||
config = xstransact.Read(path, 'config')
|
||||
if config:
|
||||
try:
|
||||
vm.recreate = True
|
||||
vm.construct(config)
|
||||
finally:
|
||||
vm.recreate = False
|
||||
else:
|
||||
vm.setName("Domain-%d" % domid)
|
||||
|
||||
vm.exportToDB(save=True)
|
||||
return vm
|
||||
temp_info = cls.parseConfig(config)
|
||||
temp_info.update(info)
|
||||
info = temp_info
|
||||
|
||||
return cls(uuid, dompath, info)
|
||||
|
||||
recreate = classmethod(recreate)
|
||||
|
||||
def restore(cls, parentdb, config, uuid=None):
|
||||
|
||||
def restore(cls, parentdbpath, config, uuid = None):
|
||||
"""Create a domain and a VM object to do a restore.
|
||||
|
||||
@param parentdb: parent db
|
||||
@param parentdbpath: parent db
|
||||
@param config: domain configuration
|
||||
@param uuid: uuid to use
|
||||
"""
|
||||
|
||||
log.debug("XendDomainInfo.restore(%s, ..., %s)", parentdbpath, uuid)
|
||||
|
||||
if not uuid:
|
||||
uuid = getUuid()
|
||||
db = parentdb.addChild("%s/xend" % uuid)
|
||||
path = parentdb.getPath()
|
||||
vm = cls(uuid, path, db)
|
||||
ssidref = int(sxp.child_value(config, 'ssidref'))
|
||||
log.debug('restoring with ssidref='+str(ssidref))
|
||||
id = xc.domain_create(ssidref = ssidref)
|
||||
vm.setDomid(id)
|
||||
vm.clear_shutdown()
|
||||
|
||||
try:
|
||||
vm.restore = True
|
||||
vm.construct(config)
|
||||
finally:
|
||||
vm.restore = False
|
||||
vm.exportToDB(save=True, sync=True)
|
||||
ssidref = int(sxp.child_value(config, 'ssidref'))
|
||||
except TypeError, exn:
|
||||
raise VmError('Invalid ssidref in config: %s' % exn)
|
||||
|
||||
log.debug('restoring with ssidref = %d' % ssidref)
|
||||
|
||||
vm = cls(uuid, parentdbpath, cls.parseConfig(config),
|
||||
xc.domain_create(ssidref = ssidref))
|
||||
vm.clear_shutdown()
|
||||
return vm
|
||||
|
||||
restore = classmethod(restore)
|
||||
|
||||
__exports__ = [
|
||||
DBVar('config', ty='sxpr'),
|
||||
DBVar('state', ty='str'),
|
||||
DBVar('restart_mode', ty='str'),
|
||||
DBVar('restart_state', ty='str'),
|
||||
DBVar('restart_time', ty='float'),
|
||||
DBVar('restart_count', ty='int'),
|
||||
]
|
||||
|
||||
def parseConfig(cls, config):
|
||||
def get_cfg(name, default = None):
|
||||
return sxp.child_value(config, name, default)
|
||||
|
||||
def int_get_cfg(name):
|
||||
val = get_cfg(name)
|
||||
if val:
|
||||
return int(val)
|
||||
else:
|
||||
return None
|
||||
|
||||
def flo_get_cfg(name):
|
||||
val = get_cfg(name)
|
||||
if val:
|
||||
return float(val)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
log.debug("parseConfig: config is %s" % str(config))
|
||||
|
||||
|
||||
result = {}
|
||||
imagecfg = "()"
|
||||
try:
|
||||
result['name'] = get_cfg('name')
|
||||
result['ssidref'] = int_get_cfg('ssidref')
|
||||
result['memory'] = int_get_cfg('memory')
|
||||
result['maxmem'] = int_get_cfg('maxmem')
|
||||
result['cpu'] = int_get_cfg('cpu')
|
||||
result['cpu_weight'] = flo_get_cfg('cpu_weight')
|
||||
result['bootloader'] = get_cfg('bootloader')
|
||||
result['restart_mode'] = get_cfg('restart')
|
||||
|
||||
imagecfg = get_cfg('image')
|
||||
|
||||
if imagecfg:
|
||||
result['image'] = imagecfg
|
||||
result['vcpus'] = int(sxp.child_value(imagecfg, 'vcpus', 1))
|
||||
else:
|
||||
result['vcpus'] = 1
|
||||
|
||||
result['backend'] = []
|
||||
for c in sxp.children(config, 'backend'):
|
||||
result['backend'].append(sxp.name(sxp.child0(c)))
|
||||
|
||||
result['device'] = []
|
||||
for d in sxp.children(config, 'device'):
|
||||
c = sxp.child0(d)
|
||||
result['device'].append((sxp.name(c), c))
|
||||
|
||||
|
||||
log.debug("parseConfig: result is %s" % str(result))
|
||||
return result
|
||||
|
||||
except TypeError, exn:
|
||||
raise VmError(
|
||||
'Invalid ssidref / memory / cpu / cpu_weight / vcpus value: %s %s %s %s %s: %s' %
|
||||
(get_cfg('ssidref'),
|
||||
get_cfg('memory'),
|
||||
get_cfg('cpu'),
|
||||
get_cfg('cpu_weight'),
|
||||
sxp.child_value(imagecfg, 'vcpus', 1),
|
||||
str(exn)))
|
||||
|
||||
parseConfig = classmethod(parseConfig)
|
||||
|
||||
|
||||
def __init__(self, uuid, path, db):
|
||||
def __init__(self, uuid, parentpath, info, domid = None):
|
||||
|
||||
self.uuid = uuid
|
||||
self.path = path + "/" + uuid
|
||||
self.info = info
|
||||
|
||||
self.db = db
|
||||
self.path = parentpath + "/" + uuid
|
||||
|
||||
if domid:
|
||||
self.domid = domid
|
||||
elif 'dom' in info:
|
||||
self.domid = int(info['dom'])
|
||||
else:
|
||||
self.domid = None
|
||||
|
||||
self.validateInfo()
|
||||
|
||||
self.recreate = 0
|
||||
self.restore = 0
|
||||
|
||||
self.config = None
|
||||
self.domid = None
|
||||
self.cpu_weight = 1
|
||||
self.start_time = None
|
||||
self.name = None
|
||||
self.memory = None
|
||||
self.ssidref = None
|
||||
self.image = None
|
||||
|
||||
self.target = None
|
||||
|
||||
self.store_channel = None
|
||||
self.store_mfn = None
|
||||
self.console_channel = None
|
||||
self.console_mfn = None
|
||||
|
||||
self.info = None
|
||||
self.backend_flags = 0
|
||||
|
||||
#todo: state: running, suspended
|
||||
self.state = STATE_VM_OK
|
||||
self.state_updated = threading.Condition()
|
||||
@@ -261,17 +317,69 @@ class XendDomainInfo:
|
||||
#todo: set to migrate info if migrating
|
||||
self.migrate = None
|
||||
|
||||
self.restart_mode = RESTART_ONREBOOT
|
||||
self.restart_state = None
|
||||
self.restart_time = None
|
||||
self.restart_count = 0
|
||||
|
||||
self.vcpus = 1
|
||||
self.bootloader = None
|
||||
self.device_model_pid = 0
|
||||
|
||||
self.writeVm("uuid", self.uuid)
|
||||
self.storeDom("vm", self.path)
|
||||
|
||||
|
||||
def validateInfo(self):
|
||||
"""Validate and normalise the info block. This has either been parsed
|
||||
by parseConfig, or received from xc through recreate.
|
||||
"""
|
||||
def defaultInfo(name, val):
|
||||
if name not in self.info or self.info[name] is None:
|
||||
self.info[name] = val()
|
||||
|
||||
|
||||
try:
|
||||
defaultInfo('name', lambda: "Domain-%d" % self.domid)
|
||||
defaultInfo('memory', lambda: self.info['mem_kb'] / 1024)
|
||||
defaultInfo('maxmem', lambda: self.info['memory'])
|
||||
defaultInfo('restart_mode', lambda: RESTART_ONREBOOT)
|
||||
defaultInfo('cpu_weight', lambda: 1.0)
|
||||
defaultInfo('bootloader', lambda: None)
|
||||
defaultInfo('backend', lambda: [])
|
||||
defaultInfo('device', lambda: [])
|
||||
|
||||
# vm.target = info['mem_kb'] * 1024
|
||||
|
||||
# !!! Consistency checks have the possibility of going wrong if
|
||||
# xen updates us with a setting which should stay consistent with
|
||||
# another. We should be storing only one value instead.
|
||||
|
||||
# Validate the given backend names.
|
||||
for s in self.info['backend']:
|
||||
if s not in backendFlags:
|
||||
raise VmError('Invalid backend type: %s' % s)
|
||||
|
||||
for (n, c) in self.info['device']:
|
||||
if not n or not c or n not in controllerClasses:
|
||||
raise VmError('invalid device (%s, %s)' %
|
||||
(str(n), str(c)))
|
||||
|
||||
if self.info['restart_mode'] not in restart_modes:
|
||||
raise VmError('invalid restart mode: ' +
|
||||
str(self.info['restart_mode']))
|
||||
|
||||
if self.info['memory'] <= 0:
|
||||
# !!! memory / mem_kb consistency check
|
||||
raise VmError('Invalid memory size: %d', self.info['memory'])
|
||||
|
||||
if 'cpumap' not in self.info:
|
||||
if [self.info['vcpus'] == 1]:
|
||||
self.info['cpumap'] = [1];
|
||||
else:
|
||||
raise VmError('Cannot create CPU map')
|
||||
|
||||
except KeyError, exn:
|
||||
raise VmError('Unspecified domain detail: %s' % str(exn))
|
||||
|
||||
|
||||
def readVm(self, *args):
|
||||
return xstransact.Read(self.path, *args)
|
||||
|
||||
@@ -302,18 +410,27 @@ class XendDomainInfo:
|
||||
def storeDom(self, *args):
|
||||
return xstransact.Store(self.path, *args)
|
||||
|
||||
def setDB(self, db):
|
||||
self.db = db
|
||||
|
||||
def saveToDB(self, save=False, sync=False):
|
||||
self.db.saveDB(save=save, sync=sync)
|
||||
def exportToDB(self, save=False):
|
||||
to_store = {
|
||||
'id': str(self.domid),
|
||||
'uuid': self.uuid,
|
||||
'config': sxp.to_string(self.sxpr()),
|
||||
|
||||
def exportToDB(self, save=False, sync=False):
|
||||
self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync)
|
||||
'start_time': str(self.start_time),
|
||||
'state': self.state,
|
||||
'restart_time': str(self.restart_time),
|
||||
'restart_count': str(self.restart_count),
|
||||
'device_model_pid': str(self.device_model_pid)
|
||||
}
|
||||
|
||||
for (k, v) in self.info.items():
|
||||
to_store[k] = str(v)
|
||||
|
||||
log.debug("Storing %s" % str(to_store))
|
||||
|
||||
self.writeVm(to_store)
|
||||
|
||||
def importFromDB(self):
|
||||
self.db.importFromDB(self, fields=self.__exports__)
|
||||
self.store_channel = self.eventChannel("store/port")
|
||||
|
||||
def setDomid(self, domid):
|
||||
"""Set the domain id.
|
||||
@@ -327,11 +444,11 @@ class XendDomainInfo:
|
||||
return self.domid
|
||||
|
||||
def setName(self, name):
|
||||
self.name = name
|
||||
self.info['name'] = name
|
||||
self.storeVm("name", name)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
return self.info['name']
|
||||
|
||||
def getPath(self):
|
||||
return self.path
|
||||
@@ -340,14 +457,14 @@ class XendDomainInfo:
|
||||
return self.uuid
|
||||
|
||||
def getVCpuCount(self):
|
||||
return self.vcpus
|
||||
return self.info['vcpus']
|
||||
|
||||
def getSsidref(self):
|
||||
return self.ssidref
|
||||
return self.info['ssidref']
|
||||
|
||||
def getMemoryTarget(self):
|
||||
"""Get this domain's target memory size, in MiB."""
|
||||
return self.memory
|
||||
return self.info['memory']
|
||||
|
||||
def setStoreRef(self, ref):
|
||||
self.store_mfn = ref
|
||||
@@ -355,7 +472,8 @@ class XendDomainInfo:
|
||||
|
||||
|
||||
def getBackendFlags(self):
|
||||
return self.backend_flags
|
||||
return reduce(lambda x, y: x | backendFlags[y],
|
||||
self.info['backend'], 0)
|
||||
|
||||
|
||||
def closeStoreChannel(self):
|
||||
@@ -379,18 +497,19 @@ class XendDomainInfo:
|
||||
def setMemoryTarget(self, target):
|
||||
self.storeDom("memory/target", target)
|
||||
|
||||
def update(self, info=None):
|
||||
"""Update with info from xc.domain_getinfo().
|
||||
|
||||
def update(self, info = None):
|
||||
"""Update with info from xc.domain_getinfo().
|
||||
"""
|
||||
if info:
|
||||
self.info = info
|
||||
else:
|
||||
di = dom_get(self.domid)
|
||||
if not di:
|
||||
|
||||
if not info:
|
||||
info = dom_get(self.domid)
|
||||
if not info:
|
||||
return
|
||||
self.info = di
|
||||
self.memory = self.info['mem_kb'] / 1024
|
||||
self.ssidref = self.info['ssidref']
|
||||
|
||||
self.info.update(info)
|
||||
self.validateInfo()
|
||||
|
||||
|
||||
def state_set(self, state):
|
||||
self.state_updated.acquire()
|
||||
@@ -398,7 +517,7 @@ class XendDomainInfo:
|
||||
self.state = state
|
||||
self.state_updated.notifyAll()
|
||||
self.state_updated.release()
|
||||
self.saveToDB()
|
||||
self.exportToDB()
|
||||
|
||||
def state_wait(self, state):
|
||||
self.state_updated.acquire()
|
||||
@@ -409,9 +528,9 @@ class XendDomainInfo:
|
||||
def __str__(self):
|
||||
s = "<domain"
|
||||
s += " id=" + str(self.domid)
|
||||
s += " name=" + self.name
|
||||
s += " memory=" + str(self.memory)
|
||||
s += " ssidref=" + str(self.ssidref)
|
||||
s += " name=" + self.info['name']
|
||||
s += " memory=" + str(self.info['memory'])
|
||||
s += " ssidref=" + str(self.info['ssidref'])
|
||||
s += ">"
|
||||
return s
|
||||
|
||||
@@ -441,32 +560,43 @@ class XendDomainInfo:
|
||||
def sxpr(self):
|
||||
sxpr = ['domain',
|
||||
['domid', self.domid],
|
||||
['name', self.name],
|
||||
['memory', self.memory],
|
||||
['ssidref', self.ssidref],
|
||||
['target', self.target] ]
|
||||
['name', self.info['name']],
|
||||
['memory', self.info['memory']],
|
||||
['ssidref', self.info['ssidref']]]
|
||||
# , ['target', self.target] ]
|
||||
if self.uuid:
|
||||
sxpr.append(['uuid', self.uuid])
|
||||
if self.info:
|
||||
sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ])
|
||||
run = (self.info['running'] and 'r') or '-'
|
||||
block = (self.info['blocked'] and 'b') or '-'
|
||||
pause = (self.info['paused'] and 'p') or '-'
|
||||
shut = (self.info['shutdown'] and 's') or '-'
|
||||
crash = (self.info['crashed'] and 'c') or '-'
|
||||
state = run + block + pause + shut + crash
|
||||
sxpr.append(['maxmem', self.info['maxmem']])
|
||||
|
||||
def stateChar(name):
|
||||
if name in self.info:
|
||||
if self.info[name]:
|
||||
return name[0]
|
||||
else:
|
||||
return '-'
|
||||
else:
|
||||
return '?'
|
||||
|
||||
state = reduce(
|
||||
lambda x, y: x + y,
|
||||
map(stateChar,
|
||||
['running', 'blocked', 'paused', 'shutdown', 'crashed']))
|
||||
|
||||
sxpr.append(['state', state])
|
||||
if self.info['shutdown']:
|
||||
if 'shutdown' in self.info and self.info['shutdown']:
|
||||
reason = shutdown_reason(self.info['shutdown_reason'])
|
||||
sxpr.append(['shutdown_reason', reason])
|
||||
sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
|
||||
sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
|
||||
if 'cpu_time' in self.info:
|
||||
sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
|
||||
sxpr.append(['vcpus', self.info['vcpus']])
|
||||
sxpr.append(['cpumap', self.info['cpumap']])
|
||||
# build a string, using '|' to seperate items, show only up
|
||||
# to number of vcpus in domain, and trim the trailing '|'
|
||||
sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x)+'|',
|
||||
self.info['vcpu_to_cpu'][0:self.info['vcpus']]))[:-1]])
|
||||
if 'vcpu_to_cpu' in self.info:
|
||||
sxpr.append(['cpu', self.info['vcpu_to_cpu'][0]])
|
||||
# build a string, using '|' to separate items, show only up
|
||||
# to number of vcpus in domain, and trim the trailing '|'
|
||||
sxpr.append(['vcpu_to_cpu', ''.join(map(lambda x: str(x)+'|',
|
||||
self.info['vcpu_to_cpu'][0:self.info['vcpus']]))[:-1]])
|
||||
|
||||
if self.start_time:
|
||||
up_time = time.time() - self.start_time
|
||||
@@ -492,8 +622,8 @@ class XendDomainInfo:
|
||||
sxpr.append(['restart_state', self.restart_state])
|
||||
if self.restart_time:
|
||||
sxpr.append(['restart_time', str(self.restart_time)])
|
||||
if self.config:
|
||||
sxpr.append(['config', self.config])
|
||||
# if self.config:
|
||||
# sxpr.append(['config', self.config])
|
||||
return sxpr
|
||||
|
||||
def check_name(self, name):
|
||||
@@ -504,7 +634,6 @@ class XendDomainInfo:
|
||||
@param name: name
|
||||
@raise: VMerror if invalid
|
||||
"""
|
||||
if self.recreate: return
|
||||
if name is None or name == '':
|
||||
raise VmError('missing vm name')
|
||||
for c in name:
|
||||
@@ -523,26 +652,49 @@ class XendDomainInfo:
|
||||
if not self.domid or (dominfo.domid != self.domid):
|
||||
raise VmError('vm name clash: ' + name)
|
||||
|
||||
def construct(self, config):
|
||||
def construct(self):
|
||||
"""Construct the vm instance from its configuration.
|
||||
|
||||
@param config: configuration
|
||||
@raise: VmError on error
|
||||
"""
|
||||
# todo - add support for scheduling params?
|
||||
self.config = config
|
||||
try:
|
||||
# Initial domain create.
|
||||
self.setName(sxp.child_value(config, 'name'))
|
||||
self.check_name(self.name)
|
||||
self.init_image()
|
||||
self.configure_cpus(config)
|
||||
self.init_domain()
|
||||
self.check_name(self.info['name'])
|
||||
self.setName(self.info['name'])
|
||||
|
||||
if 'image' not in self.info:
|
||||
raise VmError('Missing image in configuration')
|
||||
|
||||
self.image = ImageHandler.create(self, self.info['image'])
|
||||
|
||||
self.setMemoryTarget(self.info['memory'] * (1 << 20))
|
||||
|
||||
log.error('%s %s %s %s %s',
|
||||
str(self.domid),
|
||||
str(self.info['memory']),
|
||||
str(self.info['ssidref']),
|
||||
str(self.info['cpu']),
|
||||
str(self.info['cpu_weight']))
|
||||
|
||||
self.setDomid(self.image.initDomain(self.domid,
|
||||
self.info['memory'],
|
||||
self.info['ssidref'],
|
||||
self.info['cpu'],
|
||||
self.info['cpu_weight'],
|
||||
self.info['bootloader']))
|
||||
|
||||
if self.start_time is None:
|
||||
self.start_time = time.time()
|
||||
self.storeVm(("start-time", self.start_time))
|
||||
|
||||
log.debug('init_domain> Created domain=%d name=%s memory=%d',
|
||||
self.domid, self.info['name'], self.info['memory'])
|
||||
|
||||
self.register_domain()
|
||||
|
||||
# Create domain devices.
|
||||
self.configure_backends()
|
||||
self.configure_restart()
|
||||
self.construct_image()
|
||||
self.configure()
|
||||
self.exportToDB(save=True)
|
||||
@@ -559,41 +711,12 @@ class XendDomainInfo:
|
||||
xd._add_domain(self)
|
||||
self.exportToDB(save=True)
|
||||
|
||||
def configure_cpus(self, config):
|
||||
try:
|
||||
self.cpu_weight = float(sxp.child_value(config, 'cpu_weight', '1'))
|
||||
except:
|
||||
raise VmError('invalid cpu weight')
|
||||
self.memory = int(sxp.child_value(config, 'memory'))
|
||||
if self.memory is None:
|
||||
raise VmError('missing memory size')
|
||||
self.setMemoryTarget(self.memory * (1 << 20))
|
||||
self.ssidref = int(sxp.child_value(config, 'ssidref'))
|
||||
cpu = sxp.child_value(config, 'cpu')
|
||||
if self.recreate and self.domid and cpu is not None and int(cpu) >= 0:
|
||||
xc.domain_pincpu(self.domid, 0, 1<<int(cpu))
|
||||
try:
|
||||
image = sxp.child_value(self.config, 'image')
|
||||
vcpus = sxp.child_value(image, 'vcpus')
|
||||
if vcpus:
|
||||
self.vcpus = int(vcpus)
|
||||
except:
|
||||
raise VmError('invalid vcpus value')
|
||||
|
||||
def configure_vcpus(self, vcpus):
|
||||
d = {}
|
||||
for v in range(0, vcpus):
|
||||
d["cpu/%d/availability" % v] = "online"
|
||||
self.writeVm(d)
|
||||
|
||||
def init_image(self):
|
||||
"""Create boot image handler for the domain.
|
||||
"""
|
||||
image = sxp.child_value(self.config, 'image')
|
||||
if image is None:
|
||||
raise VmError('missing image')
|
||||
self.image = ImageHandler.create(self, image)
|
||||
|
||||
def construct_image(self):
|
||||
"""Construct the boot image for the domain.
|
||||
"""
|
||||
@@ -604,21 +727,17 @@ class XendDomainInfo:
|
||||
IntroduceDomain(self.domid, self.store_mfn,
|
||||
self.store_channel.port1, self.path)
|
||||
# get the configured value of vcpus and update store
|
||||
self.configure_vcpus(self.vcpus)
|
||||
self.configure_vcpus(self.info['vcpus'])
|
||||
|
||||
|
||||
def delete(self):
|
||||
"""Delete the vm's db.
|
||||
"""
|
||||
self.domid = None
|
||||
self.saveToDB(sync=True)
|
||||
try:
|
||||
# Todo: eventually will have to wait for devices to signal
|
||||
# destruction before can delete the db.
|
||||
if self.db:
|
||||
self.db.delete()
|
||||
xstransact.Remove(self.path, 'id')
|
||||
except Exception, ex:
|
||||
log.warning("error in domain db delete: %s", ex)
|
||||
pass
|
||||
|
||||
|
||||
def destroy_domain(self):
|
||||
"""Destroy the vm's domain.
|
||||
@@ -630,7 +749,7 @@ class XendDomainInfo:
|
||||
try:
|
||||
xc.domain_destroy(dom=self.domid)
|
||||
except Exception, err:
|
||||
log.exception("Domain destroy failed: %s", self.name)
|
||||
log.exception("Domain destroy failed: %s", self.info['name'])
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup vm resources: release devices.
|
||||
@@ -653,11 +772,14 @@ class XendDomainInfo:
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
"""Clenup vm and destroy domain.
|
||||
"""Cleanup vm and destroy domain.
|
||||
"""
|
||||
|
||||
log.debug("XendDomainInfo.destroy")
|
||||
|
||||
self.destroy_domain()
|
||||
self.cleanup()
|
||||
self.saveToDB()
|
||||
self.exportToDB()
|
||||
return 0
|
||||
|
||||
def is_terminated(self):
|
||||
@@ -670,6 +792,7 @@ class XendDomainInfo:
|
||||
"""
|
||||
|
||||
t = xstransact("%s/device" % self.path)
|
||||
|
||||
for n in controllerClasses.keys():
|
||||
for d in t.list(n):
|
||||
try:
|
||||
@@ -686,28 +809,11 @@ class XendDomainInfo:
|
||||
def show(self):
|
||||
"""Print virtual machine info.
|
||||
"""
|
||||
print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.domid, self.name, self.memory, self.ssidref)
|
||||
print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.domid, self.info['name'], self.info['memory'], self.info['ssidref'])
|
||||
print "image:"
|
||||
sxp.show(self.image)
|
||||
print "]"
|
||||
|
||||
def init_domain(self):
|
||||
"""Initialize the domain memory.
|
||||
"""
|
||||
if self.recreate:
|
||||
return
|
||||
if self.start_time is None:
|
||||
self.start_time = time.time()
|
||||
self.storeVm(("start-time", self.start_time))
|
||||
try:
|
||||
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
|
||||
except:
|
||||
raise VmError('invalid cpu')
|
||||
id = self.image.initDomain(self.domid, self.memory, self.ssidref, cpu, self.cpu_weight)
|
||||
log.debug('init_domain> Created domain=%d name=%s memory=%d',
|
||||
id, self.name, self.memory)
|
||||
self.setDomid(id)
|
||||
|
||||
def eventChannel(self, path=None):
|
||||
"""Create an event channel to the domain.
|
||||
|
||||
@@ -731,14 +837,8 @@ class XendDomainInfo:
|
||||
self.console_channel = self.eventChannel("console/port")
|
||||
|
||||
def create_configured_devices(self):
|
||||
devices = sxp.children(self.config, 'device')
|
||||
for d in devices:
|
||||
dev_config = sxp.child0(d)
|
||||
if dev_config is None:
|
||||
raise VmError('invalid device')
|
||||
dev_type = sxp.name(dev_config)
|
||||
|
||||
self.createDevice(dev_type, dev_config)
|
||||
for (n, c) in self.info['device']:
|
||||
self.createDevice(n, c)
|
||||
|
||||
|
||||
def create_devices(self):
|
||||
@@ -770,14 +870,6 @@ class XendDomainInfo:
|
||||
self.configureDevice(deviceClass, devid, dev_config)
|
||||
|
||||
|
||||
def configure_restart(self):
|
||||
"""Configure the vm restart mode.
|
||||
"""
|
||||
r = sxp.child_value(self.config, 'restart', RESTART_ONREBOOT)
|
||||
if r not in restart_modes:
|
||||
raise VmError('invalid restart mode: ' + str(r))
|
||||
self.restart_mode = r;
|
||||
|
||||
def restart_needed(self, reason):
|
||||
"""Determine if the vm needs to be restarted when shutdown
|
||||
for the given reason.
|
||||
@@ -785,11 +877,11 @@ class XendDomainInfo:
|
||||
@param reason: shutdown reason
|
||||
@return True if needs restart, False otherwise
|
||||
"""
|
||||
if self.restart_mode == RESTART_NEVER:
|
||||
if self.info['restart_mode'] == RESTART_NEVER:
|
||||
return False
|
||||
if self.restart_mode == RESTART_ALWAYS:
|
||||
if self.info['restart_mode'] == RESTART_ALWAYS:
|
||||
return True
|
||||
if self.restart_mode == RESTART_ONREBOOT:
|
||||
if self.info['restart_mode'] == RESTART_ONREBOOT:
|
||||
return reason == 'reboot'
|
||||
return False
|
||||
|
||||
@@ -821,7 +913,7 @@ class XendDomainInfo:
|
||||
tdelta = tnow - self.restart_time
|
||||
if tdelta < self.MINIMUM_RESTART_TIME:
|
||||
self.restart_cancel()
|
||||
msg = 'VM %s restarting too fast' % self.name
|
||||
msg = 'VM %s restarting too fast' % self.info['name']
|
||||
log.error(msg)
|
||||
raise VmError(msg)
|
||||
self.restart_time = tnow
|
||||
@@ -840,14 +932,13 @@ class XendDomainInfo:
|
||||
self.exportToDB()
|
||||
self.restart_state = STATE_RESTART_BOOTING
|
||||
self.configure_bootloader()
|
||||
self.construct(self.config)
|
||||
self.saveToDB()
|
||||
self.construct()
|
||||
self.exportToDB()
|
||||
finally:
|
||||
self.restart_state = None
|
||||
|
||||
def configure_bootloader(self):
|
||||
self.bootloader = sxp.child_value(self.config, "bootloader")
|
||||
if not self.bootloader:
|
||||
if not self.info['bootloader']:
|
||||
return
|
||||
# if we're restarting with a bootloader, we need to run it
|
||||
# FIXME: this assumes the disk is the first device and
|
||||
@@ -858,30 +949,13 @@ class XendDomainInfo:
|
||||
if dev:
|
||||
disk = sxp.child_value(dev, "uname")
|
||||
fn = blkdev_uname_to_file(disk)
|
||||
blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
|
||||
blcfg = bootloader(self.info['bootloader'], fn, 1, self.info['vcpus'])
|
||||
if blcfg is None:
|
||||
msg = "Had a bootloader specified, but can't find disk"
|
||||
log.error(msg)
|
||||
raise VmError(msg)
|
||||
self.config = sxp.merge(['vm', ['image', blcfg]], self.config)
|
||||
|
||||
def configure_backends(self):
|
||||
"""Set configuration flags if the vm is a backend for netif or blkif.
|
||||
Configure the backends to use for vbd and vif if specified.
|
||||
"""
|
||||
for c in sxp.children(self.config, 'backend'):
|
||||
v = sxp.child0(c)
|
||||
name = sxp.name(v)
|
||||
if name == 'blkif':
|
||||
self.backend_flags |= SIF_BLK_BE_DOMAIN
|
||||
elif name == 'netif':
|
||||
self.backend_flags |= SIF_NET_BE_DOMAIN
|
||||
elif name == 'usbif':
|
||||
pass
|
||||
elif name == 'tpmif':
|
||||
self.backend_flags |= SIF_TPM_BE_DOMAIN
|
||||
else:
|
||||
raise VmError('invalid backend type:' + str(name))
|
||||
|
||||
def configure(self):
|
||||
"""Configure a vm.
|
||||
@@ -899,19 +973,16 @@ class XendDomainInfo:
|
||||
"""
|
||||
return
|
||||
|
||||
|
||||
def configure_maxmem(self):
|
||||
try:
|
||||
maxmem = int(sxp.child_value(self.config, 'maxmem', self.memory))
|
||||
xc.domain_setmaxmem(self.domid, maxmem_kb = maxmem * 1024)
|
||||
except:
|
||||
raise VmError("invalid maxmem: " +
|
||||
sxp.child_value(self.config, 'maxmem'))
|
||||
xc.domain_setmaxmem(self.domid,
|
||||
maxmem_kb = self.info['maxmem'] * 1024)
|
||||
|
||||
|
||||
def vcpu_hotplug(self, vcpu, state):
|
||||
"""Disable or enable VCPU in domain.
|
||||
"""
|
||||
if vcpu > self.vcpus:
|
||||
if vcpu > self.info['vcpus']:
|
||||
log.error("Invalid VCPU %d" % vcpu)
|
||||
return
|
||||
if int(state) == 0:
|
||||
@@ -1000,16 +1071,24 @@ implements the device control specific to that device-class."""
|
||||
controllerClasses = {}
|
||||
|
||||
|
||||
def addControllerClass(device_class, cls):
|
||||
"""A map of backend names and the corresponding flag."""
|
||||
backendFlags = {}
|
||||
|
||||
|
||||
def addControllerClass(device_class, backend_name, backend_flag, cls):
|
||||
"""Register a subclass of DevController to handle the named device-class.
|
||||
|
||||
@param backend_flag One of the SIF_XYZ_BE_DOMAIN constants, or None if
|
||||
no flag is to be set.
|
||||
"""
|
||||
cls.deviceClass = device_class
|
||||
backendFlags[backend_name] = backend_flag
|
||||
controllerClasses[device_class] = cls
|
||||
|
||||
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, usbif
|
||||
addControllerClass('vbd', blkif.BlkifController)
|
||||
addControllerClass('vif', netif.NetifController)
|
||||
addControllerClass('vtpm', tpmif.TPMifController)
|
||||
addControllerClass('pci', pciif.PciController)
|
||||
addControllerClass('usb', usbif.UsbifController)
|
||||
addControllerClass('vbd', 'blkif', SIF_BLK_BE_DOMAIN, blkif.BlkifController)
|
||||
addControllerClass('vif', 'netif', SIF_NET_BE_DOMAIN, netif.NetifController)
|
||||
addControllerClass('vtpm', 'tpmif', SIF_TPM_BE_DOMAIN, tpmif.TPMifController)
|
||||
addControllerClass('pci', 'pciif', None, pciif.PciController)
|
||||
addControllerClass('usb', 'usbif', None, usbif.UsbifController)
|
||||
@@ -145,22 +145,21 @@ class ImageHandler:
|
||||
except OSError, ex:
|
||||
log.warning("error removing bootloader file '%s': %s", f, ex)
|
||||
|
||||
def initDomain(self, dom, memory, ssidref, cpu, cpu_weight):
|
||||
def initDomain(self, dom, memory, ssidref, cpu, cpu_weight, bootloading):
|
||||
"""Initial domain create.
|
||||
|
||||
@return domain id
|
||||
"""
|
||||
|
||||
mem_kb = self.getDomainMemory(memory)
|
||||
if not self.vm.restore:
|
||||
dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
|
||||
# if bootloader, unlink here. But should go after buildDomain() ?
|
||||
if self.vm.bootloader:
|
||||
self.unlink(self.kernel)
|
||||
self.unlink(self.ramdisk)
|
||||
if dom <= 0:
|
||||
raise VmError('Creating domain failed: name=%s' %
|
||||
self.vm.getName())
|
||||
dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
|
||||
# if bootloader, unlink here. But should go after buildDomain() ?
|
||||
if bootloading:
|
||||
self.unlink(self.kernel)
|
||||
self.unlink(self.ramdisk)
|
||||
if dom <= 0:
|
||||
raise VmError('Creating domain failed: name=%s' %
|
||||
self.vm.getName())
|
||||
log.debug("initDomain: cpu=%d mem_kb=%d ssidref=%d dom=%d", cpu, mem_kb, ssidref, dom)
|
||||
xc.domain_setcpuweight(dom, cpu_weight)
|
||||
xc.domain_setmaxmem(dom, mem_kb)
|
||||
@@ -184,9 +183,6 @@ class ImageHandler:
|
||||
def createDomain(self):
|
||||
"""Build the domain boot image.
|
||||
"""
|
||||
if self.vm.recreate or self.vm.restore:
|
||||
return
|
||||
|
||||
# Set params and call buildDomain().
|
||||
self.flags = self.vm.getBackendFlags()
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ from xen.xend import sxp
|
||||
from xen.xend.server.DevController import DevController
|
||||
|
||||
|
||||
next_devid = 1
|
||||
|
||||
|
||||
class NetifController(DevController):
|
||||
"""Network interface controller. Handles all network devices for a domain.
|
||||
"""
|
||||
@@ -41,8 +38,6 @@ class NetifController(DevController):
|
||||
def getDeviceDetails(self, config):
|
||||
"""@see DevController.getDeviceDetails"""
|
||||
|
||||
global next_devid
|
||||
|
||||
from xen.xend import XendRoot
|
||||
xroot = XendRoot.instance()
|
||||
|
||||
@@ -52,9 +47,6 @@ class NetifController(DevController):
|
||||
val.append(sxp.child0(ipaddr))
|
||||
return val
|
||||
|
||||
devid = next_devid
|
||||
next_devid += 1
|
||||
|
||||
script = os.path.join(xroot.network_script_dir,
|
||||
sxp.child_value(config, 'script',
|
||||
xroot.get_vif_script()))
|
||||
@@ -63,6 +55,8 @@ class NetifController(DevController):
|
||||
mac = sxp.child_value(config, 'mac')
|
||||
ipaddr = _get_config_ipaddr(config)
|
||||
|
||||
devid = self.allocateDeviceID()
|
||||
|
||||
back = { 'script' : script,
|
||||
'mac' : mac,
|
||||
'bridge' : bridge,
|
||||
|
||||