From a5ba036bad53e5c021df823ea6e6fed7cf7b29c2 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Mon, 7 Nov 2005 21:22:02 +0100 Subject: [PATCH 1/5] Rename parameter to avoid shadowing builtin. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendCheckpoint.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index 8ea93a834a..a8a82f8470 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -209,9 +209,9 @@ def forkHelper(cmd, fd, inputHandler, closeToChild): raise XendError("%s failed" % string.join(cmd)) -def slurp(file): +def slurp(infile): while 1: - line = file.readline() + line = infile.readline() if line == "": break else: From 2fe2ab90a22c73e470ad3227f1b86b3bc490fcd5 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Tue, 8 Nov 2005 01:26:16 +0100 Subject: [PATCH 2/5] Remove unused XENSTORED_XYZ constants. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/params.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/python/xen/xend/server/params.py b/tools/python/xen/xend/server/params.py index b2d43fbf6e..32ac063d1f 100644 --- a/tools/python/xen/xend/server/params.py +++ b/tools/python/xen/xend/server/params.py @@ -44,8 +44,3 @@ XEND_DEBUG_LOG = '/var/log/xend-debug.log' XEND_USER = 'root' XEND_DEBUG = getenv("XEND_DEBUG", 0, conv=int) XEND_DAEMONIZE = getenv("XEND_DAEMONIZE", not XEND_DEBUG, conv=int) - -XENSTORED_PID_FILE = '/var/run/xenstored.pid' -XENSTORED_RUN_DIR = '/var/run/xenstored' -XENSTORED_LIB_DIR = '/var/lib/xenstored' -XENSTORED_DEBUG = getenv("XENSTORED_DEBUG", 0, conv=int) From 44ae505717d416aced841d48219a4d42b68b5599 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Tue, 8 Nov 2005 02:51:34 +0100 Subject: [PATCH 3/5] Mark plenty of variables as unused, and remove an unused import. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDomain.py | 41 +++++++++++------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 676c5f37ca..8232f28e7a 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -19,7 +19,6 @@ from xen.web import http from xen.xend import sxp from xen.xend import XendDomain -from xen.xend import PrettyPrint from xen.xend.Args import FormFn from xen.web.SrvDir import SrvDir @@ -33,7 +32,7 @@ class SrvDomain(SrvDir): self.dom = dom self.xd = XendDomain.instance() - def op_configure(self, op, req): + def op_configure(self, _, req): """Configure an existing domain. Configure is unusual in that it requires a domain id, not a domain name. @@ -43,11 +42,11 @@ class SrvDomain(SrvDir): ['config', 'sxpr']]) return fn(req.args, {'dom': self.dom.domid}) - def op_unpause(self, op, req): + def op_unpause(self, _1, _2): val = self.xd.domain_unpause(self.dom.domid) return val - def op_pause(self, op, req): + def op_pause(self, _1, _2): val = self.xd.domain_pause(self.dom.domid) return val @@ -55,15 +54,15 @@ class SrvDomain(SrvDir): req.setResponseCode(http.ACCEPTED) req.setHeader("Location", "%s/.." % req.prePathURL()) - def op_shutdown(self, op, req): + def op_shutdown(self, _, req): self.acceptCommand(req) return self.dom.shutdown(req.args['reason'][0]) - def op_sysrq(self, op, req): + def op_sysrq(self, _, req): self.acceptCommand(req) return self.dom.send_sysrq(int(req.args['key'][0])) - def op_destroy(self, op, req): + def op_destroy(self, _, req): self.acceptCommand(req) return self.xd.domain_destroy(self.dom.domid) @@ -71,13 +70,13 @@ class SrvDomain(SrvDir): self.acceptCommand(req) return req.threadRequest(self.do_save, op, req) - def do_save(self, op, req): + def do_save(self, _, req): return self.xd.domain_save(self.dom.domid, req.args['file'][0]) def op_migrate(self, op, req): return req.threadRequest(self.do_migrate, op, req) - def do_migrate(self, op, req): + def do_migrate(self, _, req): fn = FormFn(self.xd.domain_migrate, [['dom', 'int'], ['destination', 'str'], @@ -85,7 +84,7 @@ class SrvDomain(SrvDir): ['resource', 'int']]) return fn(req.args, {'dom': self.dom.domid}) - def op_pincpu(self, op, req): + def op_pincpu(self, _, req): fn = FormFn(self.xd.domain_pincpu, [['dom', 'int'], ['vcpu', 'int'], @@ -93,7 +92,7 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.domid}) return val - def op_cpu_bvt_set(self, op, req): + def op_cpu_bvt_set(self, _, req): fn = FormFn(self.xd.domain_cpu_bvt_set, [['dom', 'int'], ['mcuadv', 'int'], @@ -105,14 +104,14 @@ class SrvDomain(SrvDir): return val - def op_cpu_sedf_get(self, op, req): + def op_cpu_sedf_get(self, _, req): fn = FormFn(self.xd.domain_cpu_sedf_get, [['dom', 'int']]) val = fn(req.args, {'dom': self.dom.domid}) return val - def op_cpu_sedf_set(self, op, req): + def op_cpu_sedf_set(self, _, req): fn = FormFn(self.xd.domain_cpu_sedf_set, [['dom', 'int'], ['period', 'int'], @@ -123,7 +122,7 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.domid}) return val - def op_maxmem_set(self, op, req): + def op_maxmem_set(self, _, req): fn = FormFn(self.xd.domain_maxmem_set, [['dom', 'int'], ['memory', 'int']]) @@ -135,35 +134,35 @@ class SrvDomain(SrvDir): return FormFn(fn, args)(req.args) - def op_mem_target_set(self, op, req): + def op_mem_target_set(self, _, req): return self.call(self.dom.setMemoryTarget, [['target', 'int']], req) - def op_devices(self, op, req): + def op_devices(self, _, req): return self.call(self.dom.getDeviceSxprs, [['type', 'str']], req) - def op_device_create(self, op, req): + def op_device_create(self, _, req): return self.call(self.dom.device_create, [['config', 'sxpr']], req) - def op_device_destroy(self, op, req): + def op_device_destroy(self, _, req): return self.call(self.dom.destroyDevice, [['type', 'str'], ['dev', 'str']], req) - def op_device_configure(self, op, req): + def op_device_configure(self, _, req): return self.call(self.dom.device_configure, [['config', 'sxpr'], ['dev', 'str']], req) - def op_vif_limit_set(self, op, req): + def op_vif_limit_set(self, _, req): fn = FormFn(self.xd.domain_vif_limit_set, [['dom', 'int'], ['vif', 'int'], @@ -172,7 +171,7 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.domid}) return val - def op_set_vcpus(self, op, req): + def op_set_vcpus(self, _, req): return self.call(self.dom.setVCpuCount, [['vcpus', 'int']], req) From c311699be94ec51ce78dd532831a117e053aacf8 Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Tue, 8 Nov 2005 03:07:57 +0100 Subject: [PATCH 4/5] Rearrange restart logic so that a failure to restart a domain does not cause cascading secondary errors. Fixes bug #384. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 40 ++++++++++++++----------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 6735ccc0f2..e03e5a63c5 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -90,6 +90,8 @@ ZOMBIE_PREFIX = 'Zombie-' """Minimum time between domain restarts in seconds.""" MINIMUM_RESTART_TIME = 20 +RESTART_IN_PROGRESS = 'xend/restart_in_progress' + xc = xen.lowlevel.xc.new() xroot = XendRoot.instance() @@ -1269,14 +1271,14 @@ class XendDomainInfo: config = self.sxpr() - if self.readVm('xend/restart_in_progress'): + if self.readVm(RESTART_IN_PROGRESS): log.error('Xend failed during restart of domain %d. ' 'Refusing to restart to avoid loops.', self.domid) self.destroy() return - self.writeVm('xend/restart_in_progress', 'True') + self.writeVm(RESTART_IN_PROGRESS, 'True') now = time.time() rst = self.readVm('xend/previous_restart_time') @@ -1298,26 +1300,28 @@ class XendDomainInfo: self.preserveForRestart() else: self.destroyDomain() - + + # new_dom's VM will be the same as this domain's VM, except where + # the rename flag has instructed us to call preserveForRestart. + # In that case, it is important that we remove the + # RESTART_IN_PROGRESS node from the new domain, not the old one, + # once the new one is available. + + new_dom = None try: xd = get_component('xen.xend.XendDomain') new_dom = xd.domain_create(config) - try: - new_dom.unpause() - except: - new_dom.destroy() - raise + new_dom.unpause() + new_dom.removeVm(RESTART_IN_PROGRESS) except: - log.exception('Failed to restart domain %d.', self.domid) - finally: - # new_dom's VM will be the same as this domain's VM, except where - # the rename flag has instructed us to call preserveForRestart. - # In that case, it is important that we use new_dom.removeVm, not - # self.removeVm. - new_dom.removeVm('xend/restart_in_progress') - - # self.configure_bootloader() - # self.exportToDB() + if new_dom: + new_dom.removeVm(RESTART_IN_PROGRESS) + new_dom.destroy() + else: + self.removeVm(RESTART_IN_PROGRESS) + raise + except: + log.exception('Failed to restart domain %d.', self.domid) def preserveForRestart(self): From e10bc057a594481978ae9ea77fae93d2808bd49c Mon Sep 17 00:00:00 2001 From: "emellor@leeni.uk.xensource.com" Date: Tue, 8 Nov 2005 03:34:23 +0100 Subject: [PATCH 5/5] Push the process of waiting for devices to come up right out of DevController, and drive this process from xm create. Architecturally, this separates the process of domain creation from the process of waiting for devices, allowing tools to choose when to perform that wait (if at all). This places the waiting in the same category as the unpause after domain creation, architecturally. The main advantage to this approach is that it takes waiting for devices out of the scope of XendDomain's domains_lock. When restarting a domain, the watch would fire for @releaseDomain while we were waiting for new domains to come up. This would deadlock the watch thread, as no more new watches could be delivered. Closes bug #387. In the longer term, we expect to be able to wait for devices to come up completely, not simply to wait for the hotplug scripts to run, and so it is necessary then to move the waiting procedure right out of the server, so that it can be performed after the domain unpause. Without unpausing the domain, the frontends will not come up, and so we cannot detect successful device completion. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendClient.py | 4 ++ tools/python/xen/xend/XendDomainInfo.py | 18 +++++++ tools/python/xen/xend/server/DevController.py | 48 ++++++++++++++----- tools/python/xen/xend/server/SrvDomain.py | 5 ++ tools/python/xen/xm/create.py | 4 ++ 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 9cbef2401b..6af92beec7 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -220,6 +220,10 @@ class Xend: def xend_domain(self, id): return self.xendGet(self.domainurl(id)) + def xend_domain_wait_for_devices(self, id): + return self.xendPost(self.domainurl(id), + {'op' : 'wait_for_devices' }) + def xend_domain_unpause(self, id): return self.xendPost(self.domainurl(id), {'op' : 'unpause' }) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index e03e5a63c5..adf656b5e3 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -897,6 +897,14 @@ class XendDomainInfo: return self.getDeviceController(deviceClass).createDevice(devconfig) + def waitForDevices_(self, deviceClass): + return self.getDeviceController(deviceClass).waitForDevices() + + + def waitForDevice(self, deviceClass, devid): + return self.getDeviceController(deviceClass).waitForDevice(devid) + + def reconfigureDevice(self, deviceClass, devid, devconfig): return self.getDeviceController(deviceClass).reconfigureDevice( devid, devconfig) @@ -1232,6 +1240,15 @@ class XendDomainInfo: self.image.createDeviceModel() + def waitForDevices(self): + """Wait for this domain's configured devices to connect. + + @raise: VmError if any device fails to initialise. + """ + for c in controllerClasses: + self.waitForDevices_(c) + + def device_create(self, dev_config): """Create a new device. @@ -1239,6 +1256,7 @@ class XendDomainInfo: """ dev_type = sxp.name(dev_config) devid = self.createDevice(dev_type, dev_config) + self.waitForDevice(dev_type, devid) # self.config.append(['device', dev.getConfig()]) return self.getDeviceController(dev_type).sxpr(devid) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index eed63ebbf9..f648562c1a 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -62,6 +62,18 @@ class DevController: self.writeDetails(config, devid, back, front) + return devid + + + def waitForDevices(self): + log.debug("Waiting for devices %s.", self.deviceClass) + + return map(self.waitForDevice, self.deviceIDs()) + + + def waitForDevice(self, devid): + log.debug("Waiting for %s.", devid) + status, fn_ret = self.waitForBackend(devid) if status: self.destroyDevice(devid) @@ -74,7 +86,6 @@ class DevController: raise VmError( ("Device %s (%s) could not be connected. " "Backend device not found!") % (devid, self.deviceClass)) - return devid def reconfigureDevice(self, devid, config): @@ -122,10 +133,11 @@ class DevController: specified device. This would be suitable for giving to {@link #createDevice} in order to recreate that device.""" - backdomid = int(xstransact.Read(self.frontendPath(devid), - "backend-id")) - - return [self.deviceClass, ['backend', backdomid]] + backdomid = xstransact.Read(self.frontendPath(devid), "backend-id") + if backdomid is None: + raise VmError("Device %s not connected" % devid) + + return [self.deviceClass, ['backend', int(backdomid)]] def sxprs(self): @@ -200,7 +212,10 @@ class DevController: def readBackend(self, devid, *args): frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") - return xstransact.Read(backpath, *args) + if backpath: + return xstransact.Read(backpath, *args) + else: + raise VmError("Device %s not connected" % devid) def deviceIDs(self): @@ -242,6 +257,8 @@ class DevController: frontpath = self.frontendPath(devid) backpath = self.backendPath(backdom, devid) + xstransact.Remove(backpath, HOTPLUG_STATUS_NODE) + frontDetails.update({ 'backend' : backpath, 'backend-id' : "%i" % backdom.getDomid() @@ -266,7 +283,10 @@ class DevController: ev = Event() def hotplugStatus(): - status = self.readBackend(devid, HOTPLUG_STATUS_NODE) + try: + status = self.readBackend(devid, HOTPLUG_STATUS_NODE) + except VmError: + status = "died" if status is not None: watch.xs.unwatch(backpath, watch) hotplugStatus.value = status @@ -276,14 +296,16 @@ class DevController: frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") - watch = xswatch(backpath, hotplugStatus) + if backpath: + watch = xswatch(backpath, hotplugStatus) - ev.wait(DEVICE_CREATE_TIMEOUT) - if ev.isSet(): - return (0, hotplugStatus.value) + ev.wait(DEVICE_CREATE_TIMEOUT) + if ev.isSet(): + return (0, hotplugStatus.value) + else: + return (-1, hotplugStatus.value) else: - return (-1, hotplugStatus.value) - + return (-1, "missing") def backendPath(self, backdom, devid): diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 8232f28e7a..a3e1584132 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -13,6 +13,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray +# Copyright (C) 2005 Xensource Ltd #============================================================================ from xen.web import http @@ -62,6 +63,10 @@ class SrvDomain(SrvDir): self.acceptCommand(req) return self.dom.send_sysrq(int(req.args['key'][0])) + def op_wait_for_devices(self, _, req): + self.acceptCommand(req) + return self.dom.waitForDevices() + def op_destroy(self, _, req): self.acceptCommand(req) return self.xd.domain_destroy(self.dom.domid) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index a290b6347a..aca68da365 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -815,6 +815,10 @@ def make_domain(opts, config): dom = sxp.child_value(dominfo, 'name') + if server.xend_domain_wait_for_devices(dom) < 0: + server.xend_domain_destroy(dom) + err("Device creation failed for domain %s" % dom) + if not opts.vals.paused: if server.xend_domain_unpause(dom) < 0: server.xend_domain_destroy(dom)