diff --git a/.rootkeys b/.rootkeys index 9547abccdd..12babc83d8 100644 --- a/.rootkeys +++ b/.rootkeys @@ -260,8 +260,9 @@ 40ee75a967sxgcRY4Q7zXoVUaJ4flA tools/examples/vif-bridge 40e15b7edWEtBf_oe3eBwGKuh1dyzQ tools/examples/vifctl 40ee75a93cqxHp6MiYXxxwR5j2_8QQ tools/examples/xend-config.sxp -40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults -40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd +41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmdefaults +40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample +40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd-example 3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile 3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec 3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h @@ -427,6 +428,7 @@ 40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py 40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py 40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py +4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py 40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py 40c9c4692hckPol_EK0EGB16ZyDsyQ tools/python/xen/xend/server/blkif.py 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py diff --git a/tools/examples/xmdefaults b/tools/examples/xmdefaults index ebb894d53e..0b7c5b2230 100644 --- a/tools/examples/xmdefaults +++ b/tools/examples/xmdefaults @@ -1,28 +1,14 @@ # -*- mode: python; -*- #============================================================================ # Python defaults setup for 'xm create'. -# Edit this file to reflect the configuration of your system. +# This script sets the parameters used when a domain is created using 'xm create'. +# You use a separate script for each domain you want to create, or +# you can set the parameters for the domain on the xm command line. #============================================================================ -# Define script variables here. -# xm_vars is defined automatically, use xm_vars.var() to define a variable. - -def vmid_check(var, val): - val = int(val) - if val <= 0: - raise ValueError - return val - -xm_vars.var('vmid', - use="Virtual machine id. Integer greater than 0.", - check=vmid_check) - -# This checks the script variables. -xm_vars.check() - #---------------------------------------------------------------------------- # Kernel image file. -kernel = "../../../install/boot/vmlinuz-2.4.26-xenU" +kernel = "/boot/vmlinuz-2.4.26-xenU" # Optional ramdisk. #ramdisk = "/boot/initrd.gz" @@ -34,12 +20,11 @@ kernel = "../../../install/boot/vmlinuz-2.4.26-xenU" # Initial memory allocation (in megabytes) for the new domain. memory = 64 -# A handy name for your new domain. -name = "This is VM %d" % vmid +# A name for your domain. All domains must have different names. +name = "ExampleDomain" # Which CPU to start domain on? #cpu = -1 # leave to Xen to pick -cpu = vmid # set based on vmid (mod number of CPUs) #---------------------------------------------------------------------------- # Define network interfaces. @@ -54,12 +39,11 @@ cpu = vmid # set based on vmid (mod number of CPUs) #---------------------------------------------------------------------------- # Define the disk devices you want the domain to have access to, and # what you want them accessible as. -# Each disk entry is of the form phy:DEV,VDEV,MODE -# where DEV is the device, VDEV is the device name the domain will see, +# Each disk entry is of the form phy:UNAME,DEV,MODE +# where UNAME is the device, DEV is the device name the domain will see, # and MODE is r for read-only, w for read-write. -disk = [ 'phy:sda%d,sda1,w' % (7+vmid), - 'phy:sda6,sda6,r' ] +disk = [ 'phy:hda1,xda1,r' ] #---------------------------------------------------------------------------- # Set the kernel command line for the new domain. @@ -78,7 +62,7 @@ disk = [ 'phy:sda%d,sda1,w' % (7+vmid), #hostname= "vm%d" % vmid # Set root device. -root = "/dev/sda1 ro" +root = "/dev/xda1 ro" # Root device for nfs. #root = "/dev/nfs" @@ -87,8 +71,8 @@ root = "/dev/sda1 ro" # Root directory on the nfs server. #nfs_root = '/full/path/to/root/directory' -# Sets runlevel 4 and the device for /usr. -extra = "4 VMID=%d usr=/dev/sda6" % vmid +# Sets runlevel 4. +extra = "4" #---------------------------------------------------------------------------- # Set according to whether you want the domain restarted when it exits. diff --git a/tools/examples/xmexample b/tools/examples/xmexample new file mode 100644 index 0000000000..d6df731c45 --- /dev/null +++ b/tools/examples/xmexample @@ -0,0 +1,120 @@ +# -*- mode: python; -*- +#============================================================================ +# Example Python setup script for 'xm create'. +# This script sets the parameters used when a domain is created using 'xm create'. +# +# This is a relatively advanced script that uses a parameter, vmid, to control +# the settings. So this script can be used to start a set of domains by +# setting the vmid parameter on the 'xm create' command line. For example: +# +# xm create vmid=1 +# xm create vmid=2 +# xm create vmid=3 +# +# The vmid is purely a script variable, and has no effect on the the domain +# id assigned to the new domain. +#============================================================================ + +# Define script variables here. +# xm_vars is defined automatically, use xm_vars.var() to define a variable. + +# This function checks that 'vmid' has been given a valid value. +# It is called automatically by 'xm create'. +def vmid_check(var, val): + val = int(val) + if val <= 0: + raise ValueError + return val + +# Define the 'vmid' variable so that 'xm create' knows about it. +xm_vars.var('vmid', + use="Virtual machine id. Integer greater than 0.", + check=vmid_check) + +# Check the defined variables have valid values.. +xm_vars.check() + +#---------------------------------------------------------------------------- +# Kernel image file. +kernel = "/boot/vmlinuz-2.4.26-xenU" + +# Optional ramdisk. +#ramdisk = "/boot/initrd.gz" + +# The domain build function. Default is 'linux'. +#builder='linux' +#builder='netbsd' + +# Initial memory allocation (in megabytes) for the new domain. +memory = 64 + +# A name for the new domain. All domains have to have different names, +# so we use the vmid to create a name. +name = "VM%d" % vmid + +# Which CPU to start domain on? +#cpu = -1 # leave to Xen to pick +cpu = vmid # set based on vmid (mod number of CPUs) + +#---------------------------------------------------------------------------- +# Define network interfaces. + +# Number of network interfaces. Default is 1. +#nics=1 + +# Optionally define mac and/or bridge for the network interfaces. +# Random MACs are assigned if not given. +#vif = [ 'mac=aa:00:00:00:00:11, bridge=xen-br0' ] + +#---------------------------------------------------------------------------- +# Define the disk devices you want the domain to have access to, and +# what you want them accessible as. +# Each disk entry is of the form phy:UNAME,DEV,MODE +# where UNAME is the device, DEV is the device name the domain will see, +# and MODE is r for read-only, w for read-write. + +# This makes the disk device depend on the vmid - assuming +# that devices sda7, sda8 etc. exist. The device is exported +# to all domains as sda1. +# All domains get sda6 read-only (to use for /usr, see below). +disk = [ 'phy:sda%d,sda1,w' % (7+vmid), + 'phy:sda6,sda6,r' ] + +#---------------------------------------------------------------------------- +# Set the kernel command line for the new domain. +# You only need to define the IP parameters and hostname if the domain's +# IP config doesn't, e.g. in ifcfg-eth0 or via DHCP. +# You can use 'extra' to set the runlevel and custom environment +# variables used by custom rc scripts (e.g. VMID=, usr= ). + +# Set if you want dhcp to allocate the IP address. +#dhcp="dhcp" +# Set netmask. +#netmask= +# Set default gateway. +#gateway= +# Set the hostname. +#hostname= "vm%d" % vmid + +# Set root device. +root = "/dev/sda1 ro" + +# Root device for nfs. +#root = "/dev/nfs" +# The nfs server. +#nfs_server = '169.254.1.0' +# Root directory on the nfs server. +#nfs_root = '/full/path/to/root/directory' + +# Sets runlevel 4 and the device for /usr. +extra = "4 VMID=%d usr=/dev/sda6" % vmid + +#---------------------------------------------------------------------------- +# Set according to whether you want the domain restarted when it exits. +# The default is 'onreboot', which restarts the domain when it shuts down +# with exit code reboot. +# Other values are 'always', and 'never'. + +#restart = 'onreboot' + +#============================================================================ diff --git a/tools/examples/xmnetbsd b/tools/examples/xmnetbsd-example similarity index 69% rename from tools/examples/xmnetbsd rename to tools/examples/xmnetbsd-example index f2a525d2e9..8d1662483a 100644 --- a/tools/examples/xmnetbsd +++ b/tools/examples/xmnetbsd-example @@ -1,23 +1,37 @@ # -*- mode: python; -*- #============================================================================ -# Python defaults setup for 'xm create'. -# Edit this file to reflect the configuration of your system. +# Example Python setup script for 'xm create'. +# This script sets the parameters used when a domain is created using 'xm create'. +# +# This is a relatively advanced script that uses a parameter, vmid, to control +# the settings. So this script can be used to start a set of domains by +# setting the vmid parameter on the 'xm create' command line. For example: +# +# xm create vmid=1 +# xm create vmid=2 +# xm create vmid=3 +# +# The vmid is purely a script variable, and has no effect on the the domain +# id assigned to the new domain. #============================================================================ # Define script variables here. # xm_vars is defined automatically, use xm_vars.var() to define a variable. +# This function checks that 'vmid' has been given a valid value. +# It is called automatically by 'xm create'. def vmid_check(var, val): val = int(val) if val <= 0: raise ValueError return val - + +# Define the 'vmid' variable so that 'xm create' knows about it. xm_vars.var('vmid', use="Virtual machine id. Integer greater than 0.", check=vmid_check) -# This checks the script variables. +# Check the defined variables have valid values.. xm_vars.check() #---------------------------------------------------------------------------- @@ -30,8 +44,9 @@ builder='netbsd' # Initial memory allocation (in megabytes) for the new domain. memory = 16 -# A handy name for your new domain. -name = "NetBSD VM %d" % vmid +# A name for the new domain. All domains have to have different names, +# so we use the vmid to create a name. +name = "NETBSD%d" % vmid #---------------------------------------------------------------------------- # Define network interfaces. @@ -55,12 +70,16 @@ name = "NetBSD VM %d" % vmid #---------------------------------------------------------------------------- # Define the disk devices you want the domain to have access to, and # what you want them accessible as. -# Each disk entry is of the form phy:DEV,VDEV,MODE -# where DEV is the device, VDEV is the device name the domain will see, +# Each disk entry is of the form phy:UNAME,DEV,MODE +# where UNAME is the device, DEV is the device name the domain will see, # and MODE is r for read-only, w for read-write. -#disk = [ 'phy:sda%d,sda1,w' % (7+vmid), -# 'phy:sda6,sda6,r' ] +# This makes the disk device depend on the vmid - assuming +# that devices sda7, sda8 etc. exist. The device is exported +# to all domains as sda1. +# All domains get sda6 read-only (to use for /usr, see below). +disk = [ 'phy:sda%d,sda1,w' % (7+vmid), + 'phy:sda6,sda6,r' ] #---------------------------------------------------------------------------- # Set the kernel command line for the new domain. @@ -100,4 +119,5 @@ extra = "4 VMID=%d bootdev=xennet0" % vmid # Other values are 'always', and 'never'. # #restart = 'onreboot' + #============================================================================ diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 3846fbce76..cc5b06fd10 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -9,6 +9,7 @@ The 'data-plane' is done separately. For example, consoles are accessed via sockets on xend, but the list of consoles is accessible via this API. """ +import os import sys import httplib import types @@ -130,7 +131,6 @@ class XendRequest: class XendClientProtocol: """Abstract class for xend clients. """ - def xendRequest(self, url, method, args=None): """Make a request to xend. Implement in a subclass. @@ -176,6 +176,9 @@ class XendClientProtocol: """Handle the data returned in response to the request. """ if data is None: return None + type = self.getHeader('Content-Type') + if type != sxp.mime_type: + return data try: pin = sxp.Parser() pin.input(data); @@ -194,11 +197,22 @@ class XendClientProtocol: """ raise err + def getHeader(self, key): + """Get a header from the response. + Case is ignored in the key. + + @param key: header key + @return: header + """ + raise NotImplementedError() + class SynchXendClientProtocol(XendClientProtocol): """A synchronous xend client. This will make a request, wait for the reply and return the result. """ + resp = None + def xendRequest(self, url, method, args=None): """Make a request to xend. @@ -211,6 +225,7 @@ class SynchXendClientProtocol(XendClientProtocol): if DEBUG: conn.set_debuglevel(1) conn.request(method, url.fullpath(), self.request.data, self.request.headers) resp = conn.getresponse() + self.resp = resp val = self.handleStatus(resp.version, resp.status, resp.reason) if val is None: data = None @@ -220,6 +235,10 @@ class SynchXendClientProtocol(XendClientProtocol): val = self.handleResponse(data) return val + def getHeader(self, key): + return self.resp.getheader(key) + + class AsynchXendClient(http.HTTPClient): """A subclass of twisted's HTTPClient to deal with a connection to xend. Makes the request when connected, and delegates handling responses etc. @@ -245,6 +264,9 @@ class AsynchXendClient(http.HTTPClient): def handleStatus(self, version, status, message): return self.protocol.handleStatus(version, status, message) + def handleHeader(self, key, val): + return self.protocol.handleHeader(key, val) + def handleResponse(self, data): return self.protocol.handleResponse(data) @@ -257,47 +279,7 @@ class AsynchXendClientProtocol(XendClientProtocol): """ def __init__(self): self.err = None - - def xendRequest(self, url, method, args=None): - """Make a request to xend. The returned deferred is called when - the result is available. - - @param url: xend request url - @param method: http method: POST or GET - @param args: request arguments (dict) - @return: deferred - """ - request = XendRequest(url, method, args) - self.deferred = Deferred() - clientCreator = ClientCreator(reactor, AsynchXendClient, self, request) - clientCreator.connectTCP(url.host, url.port) - return self.deferred - - def callErrback(self, err): - if not self.deferred.called: - self.err = err - self.deferred.errback(err) - return err - - def callCallback(self, val): - if not self.deferred.called: - self.deferred.callback(val) - return val - - def handleException(self, err): - return self.callErrback(err) - - def handleResponse(self, data): - if self.err: return self.err - val = XendClientProtocol.handleResponse(self, data) - if isinstance(val, Exception): - self.callErrback(val) - else: - self.callCallback(val) - return val - - def __init__(self): - self.err = None + self.headers = {} def xendRequest(self, url, method, args=None): """Make a request to xend. The returned deferred is called when @@ -328,6 +310,12 @@ class AsynchXendClientProtocol(XendClientProtocol): def handleException(self, err): return self.callErrback(err) + def handleHeader(self, key, val): + self.headers[key.lower()] = val + + def getHeader(self, key): + return self.headers.get(key.lower()) + def handleResponse(self, data): if self.err: return self.err val = XendClientProtocol.handleResponse(self, data) @@ -344,9 +332,15 @@ class Xend: """Default location of the xend server.""" SRV_DEFAULT = "localhost:8000" + """Environment variable to set the location of xend.""" + SRV_VAR = "XEND" + """Default path to the xend root on the server.""" ROOT_DEFAULT = "/xend/" + """Environment variable to set the xend root path.""" + ROOT_VAR = "XEND_ROOT" + def __init__(self, client=None, srv=None, root=None): """Create a xend client interface. If the client protocol is not specified, the default @@ -361,14 +355,24 @@ class Xend: self.client = client self.bind(srv, root) + def default_server(self): + """Get the default location of the xend server. + """ + return os.getenv(self.SRV_VAR, self.SRV_DEFAULT) + + def default_root(self): + """Get the default root path on the xend server. + """ + return os.getenv(self.ROOT_VAR, self.ROOT_DEFAULT) + def bind(self, srv=None, root=None): """Bind to a given server. @param srv: server location (host:port) @param root: xend root path on the server """ - if srv is None: srv = self.SRV_DEFAULT - if root is None: root = self.ROOT_DEFAULT + if srv is None: srv = self.default_server() + if root is None: root = self.default_root() if not root.endswith('/'): root += '/' (host, port) = srv.split(':', 1) self.url = URL(host=host, port=port, path=root) @@ -397,9 +401,6 @@ class Xend: def eventurl(self, id=''): return self.url.relative('event/' + str(id)) - def dmesgurl(self, id=''): - return self.url.relative('node/dmesg/' + str(id)) - def xend(self): return self.xendGet(self.url) @@ -408,14 +409,17 @@ class Xend: def xend_node_shutdown(self): return self.xendPost(self.nodeurl(), - {'op' : 'shutdown'}) + {'op' : 'shutdown'}) def xend_node_restart(self): return self.xendPost(self.nodeurl(), - {'op' : 'reboot'}) + {'op' : 'reboot'}) def xend_node_dmesg(self): - return self.xendGet(self.dmesgurl()) + return self.xendGet(self.nodeurl('dmesg')) + + def xend_node_log(self): + return self.xendGet(self.nodeurl('log')) def xend_node_cpu_rrobin_slice_set(self, slice): return self.xendPost(self.nodeurl(), diff --git a/tools/python/xen/xend/XendDmesg.py b/tools/python/xen/xend/XendDmesg.py index b4a5ca9cad..8d070ba45a 100644 --- a/tools/python/xen/xend/XendDmesg.py +++ b/tools/python/xen/xend/XendDmesg.py @@ -1,4 +1,4 @@ -# Copyright (C) 2004 Mike Wray + # Copyright (C) 2004 Mike Wray """Get dmesg output for this node. """ @@ -11,7 +11,7 @@ class XendDmesg: self.xc = xen.lowlevel.xc.new() def info(self): - return [ self.xc.readconsolering() ] + return self.xc.readconsolering() def instance(): diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 1e6a91a244..ce00717eb7 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -39,15 +39,23 @@ class XendDomain: dbpath = "domain" """Table of domain info indexed by domain id.""" - domain = {} + domain_by_id = {} + domain_by_name = {} """Table of domains to restart, indexed by domain id.""" - restarts = {} + restarts_by_id = {} + restarts_by_name = {} """Table of delayed calls.""" schedule = {} def __init__(self): + # Hack alert. Python does not support mutual imports, but XendDomainInfo + # needs access to the XendDomain instance to look up domains. Attempting + # to import XendDomain from XendDomainInfo causes unbounded recursion. + # So we stuff the XendDomain instance (self) into XendDomainInfo's + # namespace as 'xd'. + XendDomainInfo.xd = self # Table of domain info indexed by domain id. self.db = XendDB.XendDB(self.dbpath) self.domain_db = self.db.fetchall("") @@ -173,7 +181,8 @@ class XendDomain: @return: deferred """ def cbok(dominfo): - self.domain[dominfo.id] = dominfo + self.domain_by_id[dominfo.id] = dominfo + self.domain_by_name[dominfo.name] = dominfo if dominfo.restart_pending(): self.domain_restart_add(dominfo) @@ -181,17 +190,17 @@ class XendDomain: deferred.addCallback(cbok) return deferred - def _add_domain(self, id, info, notify=1): + def _add_domain(self, info, notify=1): """Add a domain entry to the tables. - @param id: domain id @param info: domain info object @param notify: send a domain created event if true """ - self.domain[id] = info - self.domain_db[id] = info.sxpr() - self.sync_domain(id) - if notify: eserver.inject('xend.domain.created', id) + self.domain_by_id[info.id] = info + self.domain_db[info.id] = info.sxpr() + self.domain_by_name[info.name] = info + self.sync_domain(info.id) + if notify: eserver.inject('xend.domain.created', info.name) def _delete_domain(self, id, notify=1): """Remove a domain from the tables. @@ -199,9 +208,12 @@ class XendDomain: @param id: domain id @param notify: send a domain died event if true """ - if id in self.domain: - if notify: eserver.inject('xend.domain.died', id) - del self.domain[id] + if id in self.domain_by_id: + info = self.domain_by_id[id] + if notify: eserver.inject('xend.domain.died', info.name) + if info.name in self.domain_by_name: + del self.domain_by_name[info.name] + del self.domain_by_id[id] if id in self.domain_db: del self.domain_db[id] self.db.delete(id) @@ -229,7 +241,7 @@ class XendDomain: if reason in ['poweroff', 'reboot']: self.domain_restart_schedule(id, reason) self.final_domain_destroy(id) - if len(self.restarts): + if self.domain_restarts_exist(): self.domain_restarts_schedule() def refresh(self): @@ -243,14 +255,14 @@ class XendDomain: for d in domlist: id = str(d['dom']) doms[id] = d - if id not in self.domain: + if id not in self.domain_by_id: savedinfo = None deferred = XendDomainInfo.vm_recreate(savedinfo, d) def cbok(dominfo): - self._add_domain(dominfo.id, dominfo) + self._add_domain(dominfo) deferred.addCallback(cbok) # Remove entries for domains that no longer exist. - for d in self.domain.values(): + for d in self.domain_by_id.values(): info = doms.get(d.id) if info: d.update(info) @@ -263,7 +275,7 @@ class XendDomain: @param id: domain id """ - dominfo = self.domain.get(id) + dominfo = self.domain_by_id.get(id) if dominfo: self.domain_db[id] = dominfo.sxpr() self.sync_domain(id) @@ -283,17 +295,25 @@ class XendDomain: raise pass else: - d = self.domain.get(id) + d = self.domain_by_id.get(id) if d: d.update(dominfo[0]) def domain_ls(self): - """Get list of domain ids. + """Get list of domain names. - @return: domain ids + @return: domain names """ self.refresh() - return self.domain.keys() + return self.domain_by_name.keys() + + def domain_ls_ids(self): + """Get list of domain ids. + + @return: domain names + """ + self.refresh() + return self.domain_by_id.keys() def domains(self): """Get list of domain objects. @@ -301,7 +321,7 @@ class XendDomain: @return: domain objects """ self.refresh() - return self.domain.values() + return self.domain_by_id.values() def domain_create(self, config): """Create a domain from a configuration. @@ -310,7 +330,7 @@ class XendDomain: @return: deferred """ def cbok(dominfo): - self._add_domain(dominfo.id, dominfo) + self._add_domain(dominfo) return dominfo deferred = XendDomainInfo.vm_create(config) deferred.addCallback(cbok) @@ -323,7 +343,7 @@ class XendDomain: @return: deferred """ def cbok(dominfo): - self._add_domain(dominfo.id, dominfo) + self._add_domain(dominfo) return dominfo log.info("Restarting domain: id=%s name=%s", dominfo.id, dominfo.name) deferred = dominfo.restart() @@ -338,15 +358,14 @@ class XendDomain: @param config: configuration @return: deferred """ - log.debug('domain_configure> id=%s config=%s', id, str(config)) - dom = int(id) - dominfo = self.domain_get(dom) + dominfo = self.domain_get(id) if not dominfo: raise XendError("Invalid domain: " + str(id)) + log.debug('domain_configure> id=%s config=%s', id, str(config)) if dominfo.config: - raise XendError("Domain already configured: " + str(id)) + raise XendError("Domain already configured: " + dominfo.name) def cbok(dominfo): - self._add_domain(dominfo.id, dominfo) + self._add_domain(dominfo) return dominfo deferred = dominfo.construct(config) deferred.addCallback(cbok) @@ -361,7 +380,7 @@ class XendDomain: """ def cbok(dominfo): - self._add_domain(dominfo.id, dominfo) + self._add_domain(dominfo) return dominfo deferred = XendDomainInfo.vm_restore(src, progress=progress) deferred.addCallback(cbok) @@ -375,25 +394,45 @@ class XendDomain: """ id = str(id) self.refresh_domain(id) - return self.domain.get(id) - + return self.domain_by_id.get(id) + + def domain_lookup(self, name): + name = str(name) + dominfo = self.domain_by_name.get(name) or self.domain_by_id.get(name) + if dominfo: + return dominfo + raise XendError('invalid domain:' + name) + + def domain_exists(self, name): + name = str(name) + if self.domain_by_name.get(name) or self.domain_by_id.get(name): + return 1 + else: + return 0 + def domain_unpause(self, id): """Unpause domain execution. @param id: domain id """ - dom = int(id) - eserver.inject('xend.domain.unpause', id) - return xc.domain_unpause(dom=dom) + dominfo = self.domain_lookup(id) + eserver.inject('xend.domain.unpause', dominfo.name) + try: + return xc.domain_unpause(dom=dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) def domain_pause(self, id): """Pause domain execution. @param id: domain id """ - dom = int(id) - eserver.inject('xend.domain.pause', id) - return xc.domain_pause(dom=dom) + dominfo = self.domain_lookup(id) + eserver.inject('xend.domain.pause', dominfo.name) + try: + return xc.domain_pause(dom=dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) def domain_shutdown(self, id, reason='poweroff'): """Shutdown domain (nicely). @@ -406,18 +445,15 @@ class XendDomain: @param id: domain id @param reason: shutdown type: poweroff, reboot, suspend, halt """ - dom = int(id) - id = str(id) - if dom <= 0: - return 0 + dominfo = self.domain_lookup(id) if reason == 'halt': - self.domain_restart_cancel(id) + self.domain_restart_cancel(dominfo.id) else: - self.domain_restart_schedule(id, reason, force=1) - eserver.inject('xend.domain.shutdown', [id, reason]) + self.domain_restart_schedule(dominfo.id, reason, force=1) + eserver.inject('xend.domain.shutdown', [dominfo.name, reason]) if reason == 'halt': reason = 'poweroff' - val = xend.domain_shutdown(dom, reason) + val = xend.domain_shutdown(dominfo.id, reason) self.refresh_schedule() return val @@ -428,10 +464,10 @@ class XendDomain: @param reason: shutdown reason """ log.debug('domain_restart_schedule> %s %s %d', id, reason, force) - dominfo = self.domain.get(id) + dominfo = self.domain_lookup(id) if not dominfo: return - if id in self.restarts: + if dominfo.id in self.restarts_by_id: return restart = (force and reason == 'reboot') or dominfo.restart_needed(reason) if restart: @@ -439,8 +475,9 @@ class XendDomain: self.domain_restart_add(dominfo) def domain_restart_add(self, dominfo): - self.restarts[dominfo.id] = dominfo - log.info('Scheduling restart for domain: id=%s name=%s', dominfo.id, dominfo.name) + self.restarts_by_name[dominfo.name] = dominfo + self.restarts_by_id[dominfo.id] = dominfo + log.info('Scheduling restart for domain: name=%s id=%s', dominfo.name, dominfo.id) self.domain_restarts_schedule() def domain_restart_cancel(self, id): @@ -448,53 +485,57 @@ class XendDomain: @param id: domain id """ - dominfo = self.restarts.get(id) + dominfo = self.restarts_by_id.get(id) or self.restarts_by_name.get(id) if dominfo: - log.info('Cancelling restart for domain: id=%s name=%s', dominfo.id, dominfo.name) + log.info('Cancelling restart for domain: name=%s id=%s', dominfo.name, dominfo.id) dominfo.restart_cancel() - del self.restarts[id] + del self.restarts_by_id[dominfo.id] + del self.restarts_by_name[dominfo.name] def domain_restarts(self): """Execute any scheduled domain restarts for domains that have gone. """ self.domain_restarts_cancel() - for id in self.restarts.keys(): - if id in self.domain: + for dominfo in self.restarts_by_id.values(): + if dominfo.id in self.domain_by_id: # Don't execute restart for domains still running. continue - dominfo = self.restarts[id] # Remove it from the restarts. - del self.restarts[id] + del self.restarts_by_id[dominfo.id] + del self.restarts_by_name[dominfo.name] try: def cbok(dominfo): - log.info('Restarted domain id=%s as %s', id, dominfo.id) + log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id) self.domain_unpause(dominfo.id) def cberr(err): - log.exception("Delayed exception restarting domain: id=%s", id) + log.exception("Delayed exception restarting domain: name=%s id=%s", + dominfo.name, dominfo.id) deferred = self.domain_restart(dominfo) deferred.addCallback(cbok) deferred.addErrback(cberr) except: - log.exception("Exception restarting domain: id=%s", id) - if len(self.restarts): + log.exception("Exception restarting domain: name=%s id=%s", + dominfo.name, dominfo.id) + if self.domain_restarts_exist(): # Run again later if any restarts remain. self.refresh_schedule(delay=5) + + def domain_restarts_exist(self): + return len(self.restarts_by_id) def final_domain_destroy(self, id): """Final destruction of a domain.. @param id: domain id """ - dom = int(id) - if dom <= 0: - return 0 - log.info('Destroying domain: id=%s', str(id)) - eserver.inject('xend.domain.destroy', id) - dominfo = self.domain.get(id) + dominfo = self.domain_lookup(id) + log.info('Destroying domain: name=%s', dominfo.name) + eserver.inject('xend.domain.destroy', dominfo.name) if dominfo: val = dominfo.destroy() else: - val = xc.domain_destroy(dom=dom) + #todo + val = xc.domain_destroy(dom=dominfo.dom) return val def domain_destroy(self, id, reason='halt'): @@ -504,7 +545,6 @@ class XendDomain: @param id: domain id """ - id = str(id) if reason == 'halt': self.domain_restart_cancel(id) elif reason == 'reboot': @@ -522,9 +562,9 @@ class XendDomain: # Need a cancel too? # Don't forget to cancel restart for it. print 'domain_migrate>', id, dst - dom = int(id) + dominfo = self.domain_lookup(id) xmigrate = XendMigrate.instance() - val = xmigrate.migrate_begin(dom, dst) + val = xmigrate.migrate_begin(dominfo.id, dst) print 'domain_migrate<', val return val @@ -536,9 +576,9 @@ class XendDomain: @param progress: output progress if true @return: deferred """ - dom = int(id) + dominfo = self.domain_lookup(id) xmigrate = XendMigrate.instance() - return xmigrate.save_begin(dom, dst) + return xmigrate.save_begin(dominfo.id, dst) def domain_pincpu(self, dom, cpu): """Pin a domain to a cpu. @@ -546,156 +586,176 @@ class XendDomain: @param dom: domain @param cpu: cpu number """ - dom = int(dom) - return xc.domain_pincpu(dom, cpu) + dominfo = self.domain_lookup(id) + try: + return xc.domain_pincpu(itn(dominfo.id), cpu) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu): + def domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): """Set BVT (Borrowed Virtual Time) scheduler parameters for a domain. """ - dom = int(dom) - return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv, - warp=warp, warpl=warpl, warpu=warpu) + dominfo = self.domain_lookup(id) + try: + return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv, + warp=warp, warpl=warpl, warpu=warpu) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_bvt_get(self, dom): + def domain_cpu_bvt_get(self, id): """Get BVT (Borrowed Virtual Time) scheduler parameters for a domain. """ - dom = int(dom) - return xc.bvtsched_domain_get(dom) + dominfo = self.domain_lookup(id) + try: + return xc.bvtsched_domain_get(dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_fbvt_set(self, dom, mcuadv, warp, warpl, warpu): + def domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu): """Set FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain. """ - dom = int(dom) - return xc.fbvtsched_domain_set(dom=dom, mcuadv=mcuadv, - warp=warp, warpl=warpl, warpu=warpu) + dominfo = self.domain_lookup(id) + try: + return xc.fbvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv, + warp=warp, warpl=warpl, warpu=warpu) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_fbvt_get(self, dom): + def domain_cpu_fbvt_get(self, id): """Get FBVT (Fair Borrowed Virtual Time) scheduler parameters for a domain. """ - dom = int(dom) - return xc.fbvtsched_domain_get(dom) + dominfo = self.domain_lookup(id) + try: + return xc.fbvtsched_domain_get(dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime): + def domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): """Set Atropos scheduler parameters for a domain. """ - dom = int(dom) - return xc.atropos_domain_set(dom, period, slice, latency, xtratime) + dominfo = self.domain_lookup(id) + try: + return xc.atropos_domain_set(dominfo.dom, period, slice, latency, xtratime) + except Exception, ex: + raise XendError(str(ex)) - def domain_cpu_atropos_get(self, dom): + def domain_cpu_atropos_get(self, id): """Get Atropos scheduler parameters for a domain. """ - dom = int(dom) - return xc.atropos_domain_get(dom) + dominfo = self.domain_lookup(id) + try: + return xc.atropos_domain_get(dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) - def domain_device_create(self, dom, devconfig): + def domain_device_create(self, id, devconfig): """Create a new device for a domain. - @param dom: domain id + @param id: domain id @param devconfig: device configuration @return: deferred """ - dom = int(dom) - dominfo = self.domain_get(dom) - if not dominfo: - raise XendError("invalid domain:" + str(dom)) + dominfo = self.domain_lookup(id) self.refresh_schedule() val = dominfo.device_create(devconfig) self.update_domain(dominfo.id) return val - def domain_device_destroy(self, dom, type, idx): + def domain_device_destroy(self, id, type, idx): """Destroy a device. - @param dom: domain id + @param id: domain id @param type: device type @param idx: device index """ - dom = int(dom) - dominfo = self.domain_get(dom) - if not dominfo: - raise XendError("invalid domain:" + str(dom)) + dominfo = self.domain_lookup(id) self.refresh_schedule() val = dominfo.device_destroy(type, idx) self.update_domain(dominfo.id) return val - def domain_devtype_ls(self, dom, type): + def domain_devtype_ls(self, id, type): """Get list of device indexes for a domain. - @param dom: domain + @param id: domain @param type: device type @return: device indexes """ - dominfo = self.domain_get(dom) - if not dominfo: return None + dominfo = self.domain_lookup(id) devs = dominfo.get_devices(type) - return range(0, len(devs)) + #return range(0, len(devs)) + return devs - def domain_devtype_get(self, dom, type, idx): + def domain_devtype_get(self, id, type, idx): """Get a device from a domain. - @param dom: domain + @param id: domain @param type: device type @param idx: device index @return: device object (or None) """ - dominfo = self.domain_get(dom) - if not dominfo: return None + dominfo = self.domain_lookup(id) return dominfo.get_device_by_index(type, idx) - def domain_vif_ls(self, dom): + def domain_vif_ls(self, id): """Get list of virtual network interface (vif) indexes for a domain. - @param dom: domain + @param id: domain @return: vif indexes """ - return self.domain_devtype_ls(dom, 'vif') + return self.domain_devtype_ls(id, 'vif') - def domain_vif_get(self, dom, vif): + def domain_vif_get(self, id, vif): """Get a virtual network interface (vif) from a domain. - @param dom: domain + @param id: domain @param vif: vif index @return: vif device object (or None) """ - return self.domain_devtype_get(dom, 'vif', vif) + return self.domain_devtype_get(id, 'vif', vif) - def domain_vbd_ls(self, dom): + def domain_vbd_ls(self, id): """Get list of virtual block device (vbd) indexes for a domain. - @param dom: domain + @param id: domain @return: vbd indexes """ - return self.domain_devtype_ls(dom, 'vbd') + return self.domain_devtype_ls(id, 'vbd') - def domain_vbd_get(self, dom, vbd): + def domain_vbd_get(self, id, vbd): """Get a virtual block device (vbd) from a domain. - @param dom: domain + @param id: domain @param vbd: vbd index @return: vbd device (or None) """ - return self.domain_devtype_get(dom, 'vbd', vbd) + return self.domain_devtype_get(id, 'vbd', vbd) - def domain_shadow_control(self, dom, op): + def domain_shadow_control(self, id, op): """Shadow page control. - @param dom: domain + @param id: domain @param op: operation """ - dom = int(dom) - return xc.shadow_control(dom, op) + dominfo = self.domain_lookup(id) + try: + return xc.shadow_control(dominfo.dom, op) + except Exception, ex: + raise XendError(str(ex)) - def domain_maxmem_set(self, dom, mem): + def domain_maxmem_set(self, id, mem): """Set the memory limit for a domain. @param dom: domain @param mem: memory limit (in MB) @return: 0 on success, -1 on error """ - dom = int(dom) + dominfo = self.domain_lookup(id) maxmem = int(mem) * 1024 - return xc.domain_setmaxmem(dom, maxmem_kb = maxmem) + try: + return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem) + except Exception, ex: + raise XendError(str(ex)) def instance(): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 9d7dfe325c..e7128c06c0 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -193,8 +193,8 @@ config_handlers = {} def add_config_handler(name, h): """Add a handler for a config field. - name field name - h handler: fn(vm, config, field, index) + @param name: field name + @param h: handler: fn(vm, config, field, index) """ config_handlers[name] = h @@ -212,16 +212,15 @@ image_handlers = {} def add_image_handler(name, h): """Add a handler for an image type - name image type - h handler: fn(config, name, memory, image) + @param name: image type + @param h: handler: fn(config, name, memory, image) """ image_handlers[name] = h def get_image_handler(name): """Get the handler for an image type. - name image type - - returns handler or None + @param name: image type + @return: handler or None """ return image_handlers.get(name) @@ -233,17 +232,16 @@ device_handlers = {} def add_device_handler(name, h): """Add a handler for a device type. - name device type - h handler: fn(vm, dev) + @param name: device type + @param h: handler: fn(vm, dev) """ device_handlers[name] = h def get_device_handler(name): """Get the handler for a device type. - name device type - - returns handler or None + @param name : device type + @return; handler or None """ return device_handlers.get(name) @@ -252,10 +250,9 @@ def vm_create(config): If a vm has been partially created and there is an error it is destroyed. - config configuration - - returns Deferred - raises VmError for invalid configuration + @param config configuration + @return: Deferred + @raise: VmError for invalid configuration """ vm = XendDomainInfo() return vm.construct(config) @@ -314,21 +311,27 @@ def vm_restore(src, progress=0): return deferred def dom_get(dom): + """Get info from xen for an existing domain. + + @param dom: domain id + @return: info or None + """ domlist = xc.domain_getinfo(dom=dom) if domlist and dom == domlist[0]['dom']: return domlist[0] return None - def append_deferred(dlist, v): + """Append a value to a deferred list if it is a deferred. + + @param dlist: list of deferreds + @param v: value to add + """ if isinstance(v, defer.Deferred): dlist.append(v) def _vm_configure1(val, vm): d = vm.create_devices() - def cbok(x): - return x - d.addCallback(cbok) d.addCallback(_vm_configure2, vm) return d @@ -348,7 +351,7 @@ class XendDomainInfo: """Minimum time between domain restarts in seconds. """ - MINIMUM_RESTART_TIME = 10 + MINIMUM_RESTART_TIME = 20 def __init__(self): self.recreate = 0 @@ -363,6 +366,7 @@ class XendDomainInfo: self.cmdline = None self.console = None self.devices = {} + self.device_index = {} self.configs = [] self.info = None self.ipaddrs = [] @@ -378,9 +382,13 @@ class XendDomainInfo: self.console_port = None def setdom(self, dom): + """Set the domain id. + + @param dom: domain id + """ self.dom = int(dom) self.id = str(dom) - + def update(self, info): """Update with info from xc.domain_getinfo(). """ @@ -437,13 +445,39 @@ class XendDomainInfo: sxpr.append(['config', self.config]) return sxpr + def check_name(self, name): + """Check if a vm name is valid. Valid names start with a non-digit + and contain alphabetic characters, digits, or characters in '_-.'. + The same name cannot be used for more than one vm at the same time. + + @param name: name + @raise: VMerror if invalid + """ + if name is None or name == '': + raise VmError('missing vm name') + if name[0] in string.digits: + raise VmError('invalid vm name') + for c in name: + if c in string.digits: continue + if c in '_-.': continue + if c in string.ascii_letters: continue + raise VmError('invalid vm name') + # See comment in XendDomain constructor about 'xd'. + if xd.domain_exists(name): + raise VmError('vm name clash: ' + name) + def construct(self, config): + """Construct the vm instance from its configuration. + + @param config: configuration + @return: deferred + @raise: VmError on error + """ # todo - add support for scheduling params? self.config = config try: self.name = sxp.child_value(config, 'name') - if self.name is None: - raise VmError('missing domain name') + self.check_name(self.name) self.memory = int(sxp.child_value(config, 'memory')) if self.memory is None: raise VmError('missing memory size') @@ -462,12 +496,9 @@ class XendDomainInfo: raise VmError('unknown image type: ' + image_name) image_handler(self, image) deferred = self.configure() - def cbok(x): - return x def cberr(err): self.destroy() return err - deferred.addCallback(cbok) deferred.addErrback(cberr) except StandardError, ex: # Catch errors, cleanup and re-raise. @@ -478,8 +509,10 @@ class XendDomainInfo: def config_devices(self, name): """Get a list of the 'device' nodes of a given type from the config. - name device type - return list of device configs + @param name: device type + @type name: string + @return: device configs + @rtype: list """ devices = [] for d in sxp.children(self.config, 'device'): @@ -490,31 +523,57 @@ class XendDomainInfo: return devices def config_device(self, type, idx): + """Get a device config from the device nodes of a given type + from the config. + + @param type: device type + @type type: string + @param idx: index + @type idx: int + @return config or None + """ devs = self.config_devices(type) if 0 <= idx < len(devs): return devs[idx] else: return None + def next_device_index(self, type): + """Get the next index for a given device type. + + @param type: device type + @type type: string + @return device index + @rtype: int + """ + idx = self.device_index.get(type, 0) + self.device_index[type] = idx + 1 + return idx + def add_device(self, type, dev): """Add a device to a virtual machine. - dev device to add + @param type: device type + @param dev: device to add """ dl = self.devices.get(type, []) dl.append(dev) self.devices[type] = dl def get_devices(self, type): + """Get a list of the devices of a given type. + + @param type: device type + @return: devices + """ val = self.devices.get(type, []) return val def get_device_by_id(self, type, id): """Get the device with the given id. - id device id - - returns device or None + @param id: device id + @return: device or None """ dl = self.get_devices(type) for d in dl: @@ -525,20 +584,20 @@ class XendDomainInfo: def get_device_by_index(self, type, idx): """Get the device with the given index. - idx device index - - returns device or None + @param idx: device index + @return: device or None """ + idx = str(idx) dl = self.get_devices(type) - if 0 <= idx < len(dl): - return dl[idx] - else: - return None + for d in dl: + if d.getidx() == idx: + return d + return None def add_config(self, val): """Add configuration data to a virtual machine. - val data to add + @param val: data to add """ self.configs.append(val) @@ -563,7 +622,10 @@ class XendDomainInfo: if chan: log.debug("Closing channel to domain %d", self.dom) chan.close() - return xc.domain_destroy(dom=self.dom) + try: + return xc.domain_destroy(dom=self.dom) + except Exception, err: + log.exception("Domain destroy failed: ", self.name) def cleanup(self): """Cleanup vm resources: release devices. @@ -661,11 +723,11 @@ class XendDomainInfo: def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n): """Create a domain. Builds the image but does not configure it. - ostype OS type - kernel kernel image - ramdisk kernel ramdisk - cmdline kernel commandline - vifs_n number of network interfaces + @param ostype: OS type + @param kernel: kernel image + @param ramdisk: kernel ramdisk + @param cmdline: kernel commandline + @param vifs_n: number of network interfaces """ if not self.recreate: if not os.path.isfile(kernel): @@ -685,8 +747,8 @@ class XendDomainInfo: def create_devices(self): """Create the devices for a vm. - returns Deferred - raises VmError for invalid devices + @return: Deferred + @raise: VmError for invalid devices """ dlist = [] devices = sxp.children(self.config, 'device') @@ -730,16 +792,17 @@ class XendDomainInfo: """ dev = self.get_device_by_index(type, idx) if not dev: - raise VmError('invalid device: %s %d' % (type, idx)) + raise VmError('invalid device: %s %s' % (type, idx)) devs = self.devices.get(type) - if 0 <= idx < len(devs): - del devs[idx] - dev_config = self.config_device(type, idx) + index = devs.index(dev) + dev_config = self.config_device(type, index) if dev_config: self.config.remove(['device', dev_config]) dev.destroy() def configure_console(self): + """Configure the vm console port. + """ x = sxp.child_value(self.config, 'console') if x: try: @@ -749,12 +812,20 @@ class XendDomainInfo: self.console_port = port 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. + + @param reason: shutdown reason + @return 1 if needs restaert, 0 otherwise + """ if self.restart_mode == RESTART_NEVER: return 0 if self.restart_mode == RESTART_ALWAYS: @@ -764,12 +835,18 @@ class XendDomainInfo: return 0 def restart_cancel(self): + """Cancel a vm restart. + """ self.restart_state = None def restarting(self): + """Put the vm into restart mode. + """ self.restart_state = STATE_RESTART_PENDING def restart_pending(self): + """Test if the vm has a pending restart. + """ return self.restart_state == STATE_RESTART_PENDING def restart_check(self): @@ -781,7 +858,8 @@ class XendDomainInfo: if self.restart_time is not None: tdelta = tnow - self.restart_time if tdelta < self.MINIMUM_RESTART_TIME: - msg = 'VM %d restarting too fast' % self.dom + self.restart_cancel() + msg = 'VM %s restarting too fast' % self.name log.error(msg) raise VmError(msg) self.restart_time = tnow @@ -830,17 +908,17 @@ class XendDomainInfo: """ if self.blkif_backend: d = defer.Deferred() - d.callback(1) + d.callback(self) else: d = xend.blkif_create(self.dom, recreate=self.recreate) d.addCallback(_vm_configure1, self) return d def dom_configure(self, dom): - """Configure a domain. + """Configure a vm for an existing domain. - dom domain id - returns deferred + @param dom: domain id + @return: deferred """ d = dom_get(dom) if not d: @@ -860,6 +938,8 @@ class XendDomainInfo: return deferred def configure_fields(self): + """Process the vm configuration fields using the registered handlers. + """ dlist = [] index = {} for field in sxp.children(self.config): @@ -880,11 +960,10 @@ class XendDomainInfo: def vm_image_linux(vm, image): """Create a VM for a linux image. - name vm name - memory vm memory - image image config - - returns vm + @param name: vm name + @param memory: vm memory + @param image: image config + @return: vm """ kernel = sxp.child_value(image, "kernel") cmdline = "" @@ -905,11 +984,10 @@ def vm_image_linux(vm, image): def vm_image_netbsd(vm, image): """Create a VM for a bsd image. - name vm name - memory vm memory - image image config - - returns vm + @param name: vm name + @param memory: vm memory + @param image: image config + @return: vm """ #todo: Same as for linux. Is that right? If so can unify them. kernel = sxp.child_value(image, "kernel") @@ -932,13 +1010,14 @@ def vm_image_netbsd(vm, image): def vm_dev_vif(vm, val, index): """Create a virtual network interface (vif). - vm virtual machine - val vif config - index vif index + @param vm: virtual machine + @param val: vif config + @param index: vif index + @return: deferred """ if vm.netif_backend: raise VmError('vif: vif in netif backend domain') - vif = index #todo + vif = vm.next_device_index('vif') vmac = sxp.child_value(val, "mac") xend.netif_create(vm.dom, recreate=vm.recreate) log.debug("Creating vif dom=%d vif=%d mac=%s", vm.dom, vif, str(vmac)) @@ -954,13 +1033,13 @@ def vm_dev_vif(vm, val, index): def vm_dev_vbd(vm, val, index): """Create a virtual block device (vbd). - vm virtual machine - val vbd config - index vbd index + @param vm: virtual machine + @param val: vbd config + @param index: vbd index + @return: deferred """ if vm.blkif_backend: raise VmError('vbd: vbd in blkif backend domain') - vdev = index uname = sxp.child_value(val, 'uname') if not uname: raise VmError('vbd: Missing uname') @@ -971,13 +1050,16 @@ def vm_dev_vbd(vm, val, index): log.debug("Creating vbd dom=%d uname=%s dev=%s", vm.dom, uname, dev) defer = make_disk(vm.dom, uname, dev, mode, vm.recreate) def fn(vbd): - dev = xend.blkif_dev(vm.dom, vdev) - vm.add_device('vbd', dev) + vbd.dev = dev + vbd.uname = uname + vm.add_device('vbd', vbd) return vbd defer.addCallback(fn) return defer def parse_pci(val): + """Parse a pci field. + """ if isinstance(val, types.StringType): radix = 10 if val.startswith('0x') or val.startswith('0X'): @@ -988,6 +1070,13 @@ def parse_pci(val): return v def vm_dev_pci(vm, val, index): + """Add a pci device. + + @param vm: virtual machine + @param val: device configuration + @param index: device index + @return: 0 on success + """ bus = sxp.child_value(val, 'bus') if not bus: raise VmError('pci: Missing bus') @@ -1013,78 +1102,21 @@ def vm_dev_pci(vm, val, index): return rc -def vm_field_vfr(vm, config, val, index): - """Handle a vfr field in a config. - - vm virtual machine - config vm config - val vfr field - """ - # Get the rules and add them. - # (vfr (vif (id foo) (ip x.x.x.x)) ... ) - list = sxp.children(val, 'vif') - ipaddrs = [] - for v in list: - id = sxp.child_value(v, 'id') - if id is None: - raise VmError('vfr: missing vif id') - id = int(id) - dev = vm.get_device_by_index('vif', id) - if not dev: - raise VmError('vfr: invalid vif id %d' % id) - vif = sxp.child_value(dev, 'vif') - ip = sxp.child_value(v, 'ip') - if not ip: - raise VmError('vfr: missing ip address') - ipaddrs.append(ip); - # todo: Configure the ipaddrs. - vm.ipaddrs = ipaddrs - -def vnet_bridge(vnet, vmac, dom, idx): - """Add the device for the vif to the bridge for its vnet. - """ - vif = "vif%d.%d" % (dom, idx) - try: - cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac) - log.debug("vnet_bridge> %s", cmd) - out = file("/proc/vnet/policy", "wb") - out.write(cmd) - err = out.close() - log.debug("vnet_bridge> err=%d", err) - except IOError, ex: - log.exception("vnet_bridge>") - -def vm_field_vnet(vm, config, val, index): - """Handle a vnet field in a config. - - vm virtual machine - config vm config - val vnet field - index index - """ - # Get the vif children. For each vif look up the vif device - # with the given id and configure its vnet. - # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... ) - vif_vnets = sxp.children(val, 'vif') - for v in vif_vnets: - id = sxp.child_value(v, 'id') - if id is None: - raise VmError('vnet: missing vif id') - dev = vm.get_device_by_id('vif', id) - #vnet = sxp.child_value(v, 'vnet', 1) - #mac = sxp.child_value(dev, 'mac') - #vif = sxp.child_value(dev, 'vif') - #vnet_bridge(vnet, mac, vm.dom, 0) - #vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]]) - def vm_field_ignore(vm, config, val, index): + """Dummy config field handler used for fields with built-in handling. + + @param vm: virtual machine + @param config: vm config + @param val: vfr field + @param index: field index + """ pass -# Register image handlers for linux and bsd. +# Register image handlers. add_image_handler('linux', vm_image_linux) add_image_handler('netbsd', vm_image_netbsd) -# Register device handlers for vifs and vbds. +# Register device handlers. add_device_handler('vif', vm_dev_vif) add_device_handler('vbd', vm_dev_vbd) add_device_handler('pci', vm_dev_pci) @@ -1098,6 +1130,4 @@ add_config_handler('image', vm_field_ignore) add_config_handler('device', vm_field_ignore) add_config_handler('backend', vm_field_ignore) -# Register config handlers for vfr and vnet. -add_config_handler('vfr', vm_field_vfr) -add_config_handler('vnet', vm_field_vnet) +# Register other config handlers. diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py index 106345e36a..9be84b834c 100644 --- a/tools/python/xen/xend/XendLogging.py +++ b/tools/python/xen/xend/XendLogging.py @@ -44,6 +44,7 @@ class XendLogging: mode='a', maxBytes=self.maxBytes, backupCount=self.backupCount) + self.logfilename = filename self.logfile.setFormatter(Formatter(self.logFileFormat, self.dateFormat)) log = self.getLogger() log.addHandler(self.logfile) @@ -51,6 +52,9 @@ class XendLogging: def getLogFile(self): return self.logfile + def getLogFilename(self): + return self.logfilename + def initLogStderr(self): self.logstderr = StreamHandler() self.logstderr.setFormatter(Formatter(self.logStderrFormat, self.dateFormat)) diff --git a/tools/python/xen/xend/server/SrvDmesg.py b/tools/python/xen/xend/server/SrvDmesg.py index 7580ecded7..2e7b538c55 100644 --- a/tools/python/xen/xend/server/SrvDmesg.py +++ b/tools/python/xen/xend/server/SrvDmesg.py @@ -1,10 +1,12 @@ # Copyright (C) 2004 Mike Wray import os -from SrvDir import SrvDir + from xen.xend import sxp from xen.xend import XendDmesg +from SrvDir import SrvDir + class SrvDmesg(SrvDir): """Xen Dmesg output. """ @@ -16,13 +18,13 @@ class SrvDmesg(SrvDir): def render_GET(self, req): try: if self.use_sxp(req): - req.setHeader("Content-Type", sxp.mime_type) - sxp.show(['dmesg'] + self.info(), out=req) + req.setHeader("Content-Type", "text/plain") + req.write(self.info()) else: req.write('') - req.write('
')
                 self.print_path(req)
-                req.write(self.info()[0])
+                req.write('
')
+                req.write(self.info())
                 req.write('
') return '' except Exception, ex: diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 886021ee75..7b398a3606 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -22,9 +22,9 @@ class SrvDomain(SrvDir): def op_configure(self, op, req): fn = FormFn(self.xd.domain_configure, - [['dom', 'int'], + [['dom', 'str'], ['config', 'sxpr']]) - deferred = fn(req.args, {'dom': self.dom.id}) + deferred = fn(req.args, {'dom': self.dom.name}) deferred.addErrback(self._op_configure_err, req) return deferred @@ -33,35 +33,35 @@ class SrvDomain(SrvDir): return str(err) def op_unpause(self, op, req): - val = self.xd.domain_unpause(self.dom.id) + val = self.xd.domain_unpause(self.dom.name) return val def op_pause(self, op, req): - val = self.xd.domain_pause(self.dom.id) + val = self.xd.domain_pause(self.dom.name) return val def op_shutdown(self, op, req): fn = FormFn(self.xd.domain_shutdown, - [['dom', 'int'], + [['dom', 'str'], ['reason', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) req.setResponseCode(http.ACCEPTED) req.setHeader("Location", "%s/.." % req.prePathURL()) return val def op_destroy(self, op, req): fn = FormFn(self.xd.domain_destroy, - [['dom', 'int'], + [['dom', 'str'], ['reason', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) req.setHeader("Location", "%s/.." % req.prePathURL()) return val def op_save(self, op, req): fn = FormFn(self.xd.domain_save, - [['dom', 'int'], + [['dom', 'str'], ['file', 'str']]) - deferred = fn(req.args, {'dom': self.dom.id}) + deferred = fn(req.args, {'dom': self.dom.name}) deferred.addCallback(self._op_save_cb, req) deferred.addErrback(self._op_save_err, req) return deferred @@ -75,9 +75,9 @@ class SrvDomain(SrvDir): def op_migrate(self, op, req): fn = FormFn(self.xd.domain_migrate, - [['dom', 'int'], + [['dom', 'str'], ['destination', 'str']]) - deferred = fn(req.args, {'dom': self.dom.id}) + deferred = fn(req.args, {'dom': self.dom.name}) print 'op_migrate>', deferred deferred.addCallback(self._op_migrate_cb, req) deferred.addErrback(self._op_migrate_err, req) @@ -99,99 +99,85 @@ class SrvDomain(SrvDir): req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err)) return str(err) - def op_device_create(self, op, req): - fn = FormFn(self.xd.domain_device_create, - [['dom', 'int'], - ['config', 'sxpr']]) - d = fn(req.args, {'dom': self.dom.id}) - return d - - def op_device_destroy(self, op, req): - fn = FormFn(self.xd.domain_device_destroy, - [['dom', 'int'], - ['type', 'str'], - ['index', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - def op_pincpu(self, op, req): fn = FormFn(self.xd.domain_pincpu, - [['dom', 'int'], + [['dom', 'str'], ['cpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) return val def op_cpu_bvt_set(self, op, req): fn = FormFn(self.xd.domain_cpu_bvt_set, - [['dom', 'int'], + [['dom', 'str'], ['mcuadv', 'int'], ['warp', 'int'], ['warpl', 'int'], ['warpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) return val def op_cpu_fbvt_set(self, op, req): fn = FormFn(self.xd.domain_cpu_fbvt_set, - [['dom', 'int'], + [['dom', 'str'], ['mcuadv', 'int'], ['warp', 'int'], ['warpl', 'int'], ['warpu', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) return val def op_cpu_atropos_set(self, op, req): fn = FormFn(self.xd.domain_cpu_atropos_set, - [['dom', 'int'], + [['dom', 'str'], ['period', 'int'], ['slice', 'int'], ['latency', 'int'], ['xtratime', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) return val def op_maxmem_set(self, op, req): fn = FormFn(self.xd.domain_maxmem_set, - [['dom', 'int'], + [['dom', 'str'], ['memory', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + val = fn(req.args, {'dom': self.dom.name}) return val + def op_device_create(self, op, req): + fn = FormFn(self.xd.domain_device_create, + [['dom', 'str'], + ['config', 'sxpr']]) + d = fn(req.args, {'dom': self.dom.name}) + return d + + def op_device_destroy(self, op, req): + fn = FormFn(self.xd.domain_device_destroy, + [['dom', 'str'], + ['type', 'str'], + ['idx', 'str']]) + val = fn(req.args, {'dom': self.dom.name}) + return val + def op_vifs(self, op, req): - return self.xd.domain_vif_ls(self.dom.id) + devs = self.xd.domain_vif_ls(self.dom.name) + return [ dev.sxpr() for dev in devs ] def op_vif(self, op, req): fn = FormFn(self.xd.domain_vif_get, - [['dom', 'int'], - ['vif', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) + [['dom', 'str'], + ['vif', 'str']]) + val = fn(req.args, {'dom': self.dom.name}) return val def op_vbds(self, op, req): - return self.xd.domain_vbd_ls(self.dom.id) + devs = self.xd.domain_vbd_ls(self.dom.name) + return [ dev.sxpr() for dev in devs ] def op_vbd(self, op, req): fn = FormFn(self.xd.domain_vbd_get, - [['dom', 'int'], - ['vbd', 'int']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbd_add(self, op, req): - fn = FormFn(self.xd.domain_vbd_add, - [['dom', 'int'], - ['uname', 'str'], - ['dev', 'str'], - ['mode', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) - return val - - def op_vbd_remove(self, op, req): - fn = FormFn(self.xd.domain_vbd_remove, - [['dom', 'int'], - ['dev', 'str']]) - val = fn(req.args, {'dom': self.dom.id}) + [['dom', 'str'], + ['vbd', 'str']]) + val = fn(req.args, {'dom': self.dom.name}) return val def render_POST(self, req): diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index 130072c871..cc41c78c61 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -24,7 +24,7 @@ class SrvDomainDir(SrvDir): def domain(self, x): val = None - dom = self.xd.domain_get(x) + dom = self.xd.domain_lookup(x) if not dom: raise XendError('No such domain ' + str(x)) val = SrvDomain(dom) @@ -74,7 +74,7 @@ class SrvDomainDir(SrvDir): def _op_create_cb(self, dominfo, configstring, req): """Callback to handle deferred domain creation. """ - dom = dominfo.id + dom = dominfo.name domurl = "%s/%s" % (req.prePathURL(), dom) req.setResponseCode(http.CREATED, "created") req.setHeader("Location", domurl) @@ -112,7 +112,7 @@ class SrvDomainDir(SrvDir): return deferred def _op_restore_cb(self, dominfo, req): - dom = dominfo.id + dom = dominfo.name domurl = "%s/%s" % (req.prePathURL(), dom) req.setResponseCode(http.CREATED) req.setHeader("Location", domurl) @@ -159,12 +159,12 @@ class SrvDomainDir(SrvDir): sxp.show(domains, out=req) else: domains = self.xd.domains() - domains.sort(lambda x, y: cmp(x.id, y.id)) + domains.sort(lambda x, y: cmp(x.name, y.name)) req.write('
    ') for d in domains: req.write('
  • Domain %s' - % (url, d.id, d.id)) - req.write('name=%s' % d.name) + % (url, d.name, d.name)) + req.write('id=%s' % d.id) req.write('memory=%d'% d.memory) req.write('
  • ') req.write('
') diff --git a/tools/python/xen/xend/server/SrvNode.py b/tools/python/xen/xend/server/SrvNode.py index e99526fabf..b68b33ea84 100644 --- a/tools/python/xen/xend/server/SrvNode.py +++ b/tools/python/xen/xend/server/SrvNode.py @@ -1,6 +1,7 @@ # Copyright (C) 2004 Mike Wray import os + from SrvDir import SrvDir from xen.xend import sxp from xen.xend import XendNode @@ -14,6 +15,7 @@ class SrvNode(SrvDir): SrvDir.__init__(self) self.xn = XendNode.instance() self.add('dmesg', 'SrvDmesg') + self.add('log', 'SrvXendLog') def op_shutdown(self, op, req): val = self.xn.shutdown() @@ -58,7 +60,8 @@ class SrvNode(SrvDir): req.write('