Files
xen/tools/python/xen/xend/image.py
T
cl349@firebug.cl.cam.ac.uk 42d8ee3480 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>
2005-06-09 09:01:57 +00:00

340 lines
12 KiB
Python

import os
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
class ImageHandler:
"""Abstract base class for image handlers.
initDomain() is called to initialise the domain memory.
createImage() is called to configure and build the domain from its
kernel image and ramdisk etc.
The method buildDomain() is used to build the domain, and must be
defined in a subclass. Usually this is the only method that needs
defining in a subclass.
The method createDeviceModel() is called to create the domain device
model if it needs one. The default is to do nothing.
The method destroy() is called when the domain is destroyed.
The default is to do nothing.
"""
#======================================================================
# Class vars and methods.
"""Table of image handler classes for virtual machine images.
Indexed by image type.
"""
imageHandlerClasses = {}
def addImageHandlerClass(cls, h):
"""Add a handler class for an image type
@param h: handler: ImageHandler subclass
"""
cls.imageHandlerClasses[h.ostype] = h
addImageHandlerClass = classmethod(addImageHandlerClass)
def findImageHandlerClass(cls, image):
"""Find the image handler class for an image config.
@param image config
@return ImageHandler subclass or None
"""
ty = sxp.name(image)
if ty is None:
raise VmError('missing image type')
imageClass = cls.imageHandlerClasses.get(ty)
if imageClass is None:
raise VmError('unknown image type: ' + ty)
return imageClass
findImageHandlerClass = classmethod(findImageHandlerClass)
def create(cls, vm, image):
"""Create an image handler for a vm.
@param vm vm
@param image image config
@return ImageHandler instance
"""
imageClass = cls.findImageHandlerClass(image)
return imageClass(vm, image)
create = classmethod(create)
#======================================================================
# Instance vars and methods.
db = None
ostype = None
config = None
kernel = None
ramdisk = None
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'),
]
def __init__(self, vm, config):
self.vm = vm
self.db = vm.db.addChild('/image')
self.config = config
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 unlink(self, f):
if not f: return
try:
os.unlink(f)
except OSError, ex:
log.warning("error removing bootloader file '%s': %s", f, ex)
def initDomain(self, dom, memory, cpu, cpu_weight):
"""Initial domain create.
@return domain id
"""
mem_kb = self.getDomainMemory(memory)
if not self.vm.restore:
dom = xc.domain_create(dom = dom or 0)
# 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.name)
log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
# xc.domain_setuuid(dom, uuid)
xc.domain_setcpuweight(dom, cpu_weight)
xc.domain_setmaxmem(dom, mem_kb)
xc.domain_memory_increase_reservation(dom, mem_kb)
if cpu != -1:
xc.domain_pincpu(dom, 0, 1<<int(cpu))
return dom
def createImage(self):
"""Entry point to create domain memory image.
Override in subclass if needed.
"""
self.configure()
self.createDomain()
def configure(self):
"""Config actions common to all unix-like domains."""
self.kernel = sxp.child_value(self.config, "kernel")
self.cmdline = ""
ip = sxp.child_value(self.config, "ip", None)
if ip:
self.cmdline += " ip=" + ip
root = sxp.child_value(self.config, "root")
if root:
self.cmdline += " root=" + root
args = sxp.child_value(self.config, "args")
if args:
self.cmdline += " " + args
self.ramdisk = sxp.child_value(self.config, "ramdisk", '')
def createDomain(self):
"""Build the domain boot image.
"""
# Set params and call buildDomain().
self.flags = 0
if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN
if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN
if self.vm.recreate or self.vm.restore:
return
if not os.path.isfile(self.kernel):
raise VmError('Kernel image does not exist: %s' % self.kernel)
if self.ramdisk and not os.path.isfile(self.ramdisk):
raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk)
if len(self.cmdline) >= 256:
log.warning('kernel cmdline too long, domain %d', self.vm.getDomain())
log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype,
self.vm.getDomain(), self.vm.vcpus)
err = self.buildDomain()
if err != 0:
raise VmError('Building domain failed: ostype=%s dom=%d err=%d'
% (self.ostype, self.vm.getDomain(), err))
def getDomainMemory(self, mem_mb):
"""Memory (in KB) the domain will need for mem_mb (in MB)."""
return mem_mb * 1024
def buildDomain(self):
"""Build the domain. Define in subclass."""
raise NotImplementedError()
def createDeviceModel(self):
"""Create device model for the domain (define in subclass if needed)."""
pass
def destroy(self):
"""Extra cleanup on domain destroy (define in subclass if needed)."""
pass
addImageHandlerClass = ImageHandler.addImageHandlerClass
class LinuxImageHandler(ImageHandler):
ostype = "linux"
def buildDomain(self):
if self.vm.store_channel:
store_evtchn = self.vm.store_channel.port2
else:
store_evtchn = 0
ret = xc.linux_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = self.vm.channel.getRemotePort(),
store_evtchn = store_evtchn,
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags,
vcpus = self.vm.vcpus)
if isinstance(ret, dict):
self.vm.store_mfn = ret.get('store_mfn')
return 0
return ret
class Plan9ImageHandler(ImageHandler):
ostype = "plan9"
def buildDomain(self):
return xc.plan9_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = self.vm.channel.getRemotePort(),
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags,
vcpus = self.vm.vcpus)
class VmxImageHandler(ImageHandler):
__exports__ = ImageHandler.__exports__ + [
DBVar('memmap', ty='str'),
DBVar('memmap_value', ty='sxpr'),
# device channel?
]
ostype = "vmx"
memmap = None
memmap_value = None
device_channel = None
def createImage(self):
"""Create a VM for the VMX environment.
"""
self.configure()
self.parseMemmap()
self.createDomain()
def buildDomain(self):
return xc.vmx_build(dom = self.vm.getDomain(),
image = self.kernel,
control_evtchn = 0,
memsize = self.vm.memory,
memmap = self.memmap_value,
cmdline = self.cmdline,
ramdisk = self.ramdisk,
flags = self.flags)
def parseMemmap(self):
self.memmap = sxp.child_value(self.vm.config, "memmap")
if self.memmap is None:
raise VmError("missing memmap")
memmap = sxp.parse(open(self.memmap))[0]
from xen.util.memmap import memmap_parse
self.memmap_value = memmap_parse(memmap)
def createDeviceModel_old(self):
device_model = sxp.child_value(self.vm.config, 'device_model')
if not device_model:
raise VmError("vmx: missing device model")
device_config = sxp.child_value(self.vm.config, 'device_config')
if not device_config:
raise VmError("vmx: missing device config")
# Create an event channel.
self.device_channel = channel.eventChannel(0, self.vm.getDomain())
# Execute device model.
#todo: Error handling
os.system(device_model
+ " -f %s" % device_config
+ " -d %d" % self.vm.getDomain()
+ " -p %d" % self.device_channel['port1']
+ " -m %s" % self.vm.memory)
def createDeviceModel(self):
device_model = sxp.child_value(self.vm.config, 'device_model')
if not device_model:
raise VmError("vmx: missing device model")
device_config = sxp.child_value(self.vm.config, 'device_config')
if not device_config:
raise VmError("vmx: missing device config")
# Create an event channel
self.device_channel = channel.eventChannel(0, self.vm.getDomain())
# Execute device model.
#todo: Error handling
# XXX RN: note that the order of args matter!
os.system(device_model
+ " -f %s" % device_config
+ self.vncParams()
+ " -d %d" % self.vm.getDomain()
+ " -p %d" % self.device_channel['port1']
+ " -m %s" % self.vm.memory)
def vncParams(self):
# see if a vncviewer was specified
# XXX RN: bit of a hack. should unify this, maybe stick in config space
vncconnect=""
image = self.config
args = sxp.child_value(image, "args")
if args:
arg_list = string.split(args)
for arg in arg_list:
al = string.split(arg, '=')
if al[0] == "VNC_VIEWER":
vncconnect=" -v %s" % al[1]
break
return vncconnect
def destroy(self):
channel.eventChannelClose(self.device_channel)
def getDomainMemory(self, mem_mb):
return (mem_mb * 1024) + self.getPageTableSize(mem_mb)
def getPageTableSize(self, mem_mb):
"""Return the size of memory needed for 1:1 page tables for physical
mode.
@param mem_mb: size in MB
@return size in KB
"""
# Logic x86-32 specific.
# 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
return (1 + ((mem_mb + 3) >> 2)) * 4