def waitForDevice(self, devid): log.debug("Waiting for %s.", devid) status = self.waitForBackend(devid) if status == Timeout: self.destroyDevice(devid) raise VmError("Device %s (%s) could not be connected. " "Hotplug scripts not working." % (devid, self.deviceClass)) elif status == Error: self.destroyDevice(devid) raise VmError("Device %s (%s) could not be connected. " "Backend device not found." % (devid, self.deviceClass)) elif status == Missing: # Don't try to destroy the device; it's already gone away. raise VmError("Device %s (%s) could not be connected. " "Device not found." % (devid, self.deviceClass)) elif status == Busy: err = None frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE) if not err: err = "Busy." self.destroyDevice(devid) raise VmError("Device %s (%s) could not be connected.\n%s" % (devid, self.deviceClass, err))
def waitForBackend(self, devid): frontpath = self.frontendPath(devid) # lookup a phantom phantomPath = xstransact.Read(frontpath, 'phantom_vbd') if phantomPath is not None: log.debug("Waiting for %s's phantom %s.", devid, phantomPath) statusPath = phantomPath + '/' + HOTPLUG_STATUS_NODE ev = Event() result = {'status': Timeout} xswatch(statusPath, hotplugStatusCallback, ev, result) ev.wait(DEVICE_CREATE_TIMEOUT) err = xstransact.Read(statusPath, HOTPLUG_ERROR_NODE) if result['status'] != Connected: return (result['status'], err) backpath = self.readVm(devid, "backend") if backpath: statusPath = backpath + '/' + HOTPLUG_STATUS_NODE ev = Event() result = {'status': Timeout} xswatch(statusPath, hotplugStatusCallback, ev, result) ev.wait(DEVICE_CREATE_TIMEOUT) err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE) return (result['status'], err) else: return (Missing, None)
def readBackend(self, devid, *args): frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: return xstransact.Read(backpath, *args) else: raise VmError("Device %s not connected" % devid)
def recreate_active_pools(cls): """ Read active pool config from hypervisor and create pool instances. - Query pool ids and assigned CPUs from hypervisor. - Query additional information for any pool from xenstore. If an entry for a pool id is missing in xenstore, it will be recreated with a new uuid and generic name (this is an error case) - Create an XendCPUPool instance for any pool id Function have to be called after recreation of managed pools. """ log.debug('recreate_active_pools') for pool_rec in xc.cpupool_getinfo(): pool = pool_rec['cpupool'] # read pool data from xenstore path = XS_POOLROOT + "%s/" % pool uuid = xstransact.Read(path, 'uuid') if not uuid: # xenstore entry missing / invaild; create entry with new uuid uuid = genuuid.createString() name = "Pool-%s" % pool try: inst = XendCPUPool({'name_label': name}, uuid, False) inst.update_XS(pool) except PoolError, ex: # log error and skip domain log.error('cannot recreate pool %s; skipping (reason: %s)' \ % (name, ex)) else: (name, descr) = xstransact.Read(path, 'name', 'description') other_config = {} for key in xstransact.List(path + 'other_config'): other_config[key] = xstransact.Read(path + 'other_config/%s' % key) # check existance of pool instance inst = XendAPIStore.get(uuid, cls.getClass()) if inst: # update attributes of existing instance inst.name_label = name inst.name_description = descr inst.other_config = other_config else: # recreate instance try: inst = XendCPUPool( { 'name_label': name, 'name_description': descr, 'other_config': other_config, 'proposed_CPUs': pool_rec['cpulist'], 'ncpu': len(pool_rec['cpulist']), }, uuid, False) except PoolError, ex: # log error and skip domain log.error( 'cannot recreate pool %s; skipping (reason: %s)' \ % (name, ex))
def diagnose_console(): port = xstransact.Read(dompath + '/console/port') ringref = xstransact.Read(dompath + '/console/ring-ref') tty = xstransact.Read(dompath + '/console/tty') if not port: print "Console port is missing; Xend has failed." if not ringref: print "Console ring-ref is missing; Xend has failed." if not tty: print "Console tty is missing; Xenconsoled has failed."
def get_assigned_pci_devices(domid): dev_str_list = [] path = '/local/domain/0/backend/pci/%u/0/' % domid num_devs = xstransact.Read(path + 'num_devs') if num_devs is None or num_devs == "": return dev_str_list num_devs = int(num_devs) for i in range(num_devs): dev_str = xstransact.Read(path + 'dev-%i' % i) dev_str_list = dev_str_list + [dev_str] return dev_str_list
def get_all_assigned_pci_devices(domid=0): dom_list = xstransact.List('/local/domain') pci_str_list = [] ti = 0 ts = xstransact.Read('/local/domain/' + str(domid) + '/target') if ts is not None: ti = int(ts) for d in dom_list: target = xstransact.Read('/local/domain/' + d + '/target') if int(d) is not ti and target is None: pci_str_list = pci_str_list + get_assigned_pci_devices(int(d)) return pci_str_list
def signalDeviceModel(self, cmd, ret, par=None): if self.device_model is None: return # Signal the device model to for action if cmd is '' or ret is '': raise VmError( 'need valid command and result when signal device model') count = 0 while True: orig_state = xstransact.Read( "/local/domain/0/device-model/%i/state" % self.vm.getDomid()) # This can occur right after start-up if orig_state != None: break log.debug('signalDeviceModel: orig_state is None, retrying') time.sleep(0.1) count += 1 if count < 100: continue raise VmError('Device model isn\'t ready for commands') if par is not None: xstransact.Store( "/local/domain/0/device-model/%i" % self.vm.getDomid(), ('parameter', par)) xstransact.Store( "/local/domain/0/device-model/%i" % self.vm.getDomid(), ('command', cmd)) # Wait for confirmation. Could do this with a watch but we'd # still end up spinning here waiting for the watch to fire. state = '' count = 0 while state != ret: state = xstransact.Read("/local/domain/0/device-model/%i/state" % self.vm.getDomid()) time.sleep(0.1) count += 1 if count > 100: raise VmError('Timed out waiting for device model action') #resotre orig state xstransact.Store( "/local/domain/0/device-model/%i" % self.vm.getDomid(), ('state', orig_state)) log.info("signalDeviceModel:restore dm state to %s", orig_state)
def destroyDevice(self, devid, force): """Destroy the specified device. @param devid The device ID, or something device-specific from which the device ID can be determined (such as a guest-side device name). The implementation here simply deletes the appropriate paths from the store. This may be overridden by subclasses who need to perform other tasks on destruction. The implementation here accepts integer device IDs or paths containg integer deviceIDs, e.g. vfb/0. Subclasses may accept other values and convert them to integers before passing them here. """ dev = self.convertToDeviceNumber(devid) # Modify online status /before/ updating state (latter is watched by # drivers, so this ordering avoids a race). self.writeBackend(dev, 'online', "0") self.writeBackend(dev, 'state', str(xenbusState['Closing'])) if force: frontpath = self.frontendPath(dev) backpath = xstransact.Read(frontpath, "backend") if backpath: xstransact.Remove(backpath) xstransact.Remove(frontpath) self.vm._removeVm("device/%s/%d" % (self.deviceClass, dev))
def cleanupDevice(self, devid): devs = self.readBackendList(devid, "vscsi-devs") vscsipath = "vscsi-devs/" new_num_devs = 0 for dev in devs: new_num_devs = new_num_devs + 1 devpath = vscsipath + dev devstate = self.readBackend(devid, devpath + '/state') if str(xenbusState['Closed']) == devstate: self.removeBackend(devid, devpath) frontpath = self.frontendPath(devid) xstransact.Remove(frontpath + '/' + devpath) new_num_devs = new_num_devs - 1 frontpath = self.frontendPath(devid) front_devstate = xstransact.Read(frontpath + '/' + devpath) if front_devstate is not None: if str(xenbusState['Closed']) == front_devstate: self.removeBackend(devid, devpath) xstransact.Remove(frontpath + '/' + devpath) new_num_devs = new_num_devs - 1 return new_num_devs
def _handleAerStateWatch(self, _): log.debug('XendDomainInfo.handleAerStateWatch') if self.getDomid() == 0: raise XendError('Domain 0 cannot be shutdown') readPath = '/local/domain/0/backend/pci/%u/0/aerState' % (self.getDomid()) action = xstransact.Read(readPath) if action and action=='aerfail': log.debug('shutdown domain because of aer handle error') self.vm.shutdown('poweroff') return True
def configuration(self, devid): """@return an s-expression giving the current configuration of the specified device. This would be suitable for giving to {@link #createDevice} in order to recreate that device.""" 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 diagnose_devices(): global deviceClass global device global frontendPath global backendPath device_path = dompath + '/device' device_classes = xstransact.List(device_path) print "Found %d device classes in use." % len(device_classes) for dc in device_classes: deviceClass = dc device_class_path = device_path + '/' + deviceClass devices = xstransact.List(device_class_path) print "Found %d %s devices." % (len(devices), deviceClass) for d in devices: device = d print "Found device %s, %s." % (deviceClass, device) frontendPath = device_class_path + '/' + device backendPath = xstransact.Read(frontendPath, 'backend') if not backendPath: print("Cannot find backend path for device %s, %s." % (deviceClass, device)) else: frontend_state = xstransact.Read(frontendPath, 'state') backend_state = xstransact.Read(backendPath, 'state') print "Backend is in state %s." % stateString(backend_state) print "Frontend is in state %s." % stateString(frontend_state) check_for_error(True) check_for_error(False) diagnose_hotplugging()
def diagnose_hotplugging(): if deviceClass == 'vbd': phy = xstransact.Read(backendPath, 'physical-device') if phy: print( 'Device %s, %s hotplugging has completed successfully, ' 'and is connected to physical device %s.' % (deviceClass, device, phy)) else: print('Device %s, %s hotplugging failed.' % (deviceClass, device)) elif deviceClass == 'vif': handle = xstransact.Read(backendPath, 'handle') if handle: print( 'Device %s, %s hotplugging has completed successfully, ' 'and is using handle %s.' % (deviceClass, device, handle)) else: print('Device %s, %s hotplugging failed.' % (deviceClass, device))
def check_for_error(backend): if backend: path = backendPath.replace('backend/', 'error/backend/') else: path = frontendPath.replace('device/', 'error/device/') err = xstransact.Read(path, 'error') if err: print("%s for device %s, %s shows error %s." % (backend and 'Backend' or 'Frontend', deviceClass, device, err))
def query_pool_ref(cls, pool_id): """ Get pool ref by pool id. Take the ref from xenstore. @param pool_id: @type pool_id: int @return: ref @rtype: str """ uuid = xstransact.Read(XS_POOLROOT + "%s/" % pool_id, 'uuid') if uuid: return [uuid] else: return []
def xenbusStatusCallback(statusPath, ev, result): log.debug("xenbusStatusCallback %s.", statusPath) status = xstransact.Read(statusPath) if status == str(xenbusState['Connected']): result['status'] = Connected else: return 1 log.debug("xenbusStatusCallback %d.", result['status']) ev.set() return 0
def deviceDestroyCallback(statusPath, ev, result): log.debug("deviceDestroyCallback %s.", statusPath) status = xstransact.Read(statusPath) if status is None: result['status'] = Disconnected else: return 1 log.debug("deviceDestroyCallback %d.", result['status']) ev.set() return 0
def frontendStatusCallback(statusPath, ev, result): status = xstransact.Read(statusPath) log.debug("frontendStatusCallback %s = %s" % (statusPath, status)) try: status = int(status) if status == xenbusState['Connected']: result['status'] = Connected elif status == xenbusState['Closed']: result['status'] = Error else: raise except: return 1 ev.set() return 0
def getDeviceConfiguration(self, devid, transaction=None): """Returns the configuration of a device. @note: Similar to L{configuration} except it returns a dict. @return: dict """ if transaction is None: backdomid = xstransact.Read(self.frontendPath(devid), "backend-id") else: backdomid = transaction.read( self.frontendPath(devid) + "/backend-id") if backdomid is None: raise VmError("Device %s not connected" % devid) return {'backend': int(backdomid)}
def waitForBackend_reconfigure(self, devid): frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: statusPath = backpath + '/' + "state" ev = Event() result = {'status': Timeout} xswatch(statusPath, xenbusStatusCallback, ev, result) ev.wait(DEVICE_CREATE_TIMEOUT) return (result['status'], None) else: return (Missing, None)
def query_pool_id(self): """ Get corresponding pool-id of pool instance from XenStore. @return: pool id or None @rytpe: int """ self.pool_lock.acquire() try: for pool_id in xstransact.List(XS_POOLROOT): uuid = xstransact.Read(XS_POOLROOT + "%s/" % pool_id, 'uuid') if uuid == self.get_uuid(): return int(pool_id) finally: self.pool_lock.release() return None
def waitForBackend_destroy(self, backpath): statusPath = backpath + '/' + HOTPLUG_STATUS_NODE ev = Event() result = {'status': Timeout} xswatch(statusPath, deviceDestroyCallback, ev, result) for i in range(1, 50): ev.wait(DEVICE_DESTROY_TIMEOUT / 50) status = xstransact.Read(statusPath) if status is None: result['status'] = Disconnected break return result['status']
def change_xenstore(self, action, device, major, minor): for type in DEVICE_TYPES: path = self.dbpath + '/' + type domains = xstransact.List(path) log.debug('domains: %s', domains) for domain in domains: # for each domain devices = xstransact.List(path + '/' + domain) log.debug('devices: %s', devices) for device in devices: # for each vbd device str = device.split('/') vbd_type = None vbd_physical_device = None vbd_media = None vbd_device_path = path + '/' + domain + '/' + device listing = xstransact.List(vbd_device_path) for entry in listing: # for each entry item = path + '/' + entry value = xstransact.Read(vbd_device_path + '/' + entry) log.debug('%s=%s', item, value) if item.find('media-present') != -1: vbd_media = item vbd_media_path = item if item.find('physical-device') != -1: vbd_physical_device = value if item.find('type') != -1: vbd_type = value if vbd_type is not None and vbd_physical_device is not None and vbd_media is not None: inode = vbd_physical_device.split(':') imajor = parse_hex(inode[0]) iminor = parse_hex(inode[1]) log.debug( "action:%s major:%s- minor:%s- imajor:%s- iminor:%s- inode: %s", action, major, minor, imajor, iminor, inode) if int(imajor) == int(major) and int(iminor) == int( minor): if action == "add": xs_dict = {'media': "1"} xstransact.Write(vbd_device_path, 'media-present', "1") log.debug( "wrote xenstore media-present 1 path:%s", vbd_media_path) else: xstransact.Write(vbd_device_path, 'media-present', "0") log.debug("wrote xenstore media 0 path:%s", vbd_media_path)
def saveDeviceModel(self): if self.device_model is None: return # Signal the device model to pause itself and save its state xstransact.Store( "/local/domain/0/device-model/%i" % self.vm.getDomid(), ('command', 'save')) # Wait for confirmation. Could do this with a watch but we'd # still end up spinning here waiting for the watch to fire. state = '' count = 0 while state != 'paused': state = xstransact.Read("/local/domain/0/device-model/%i/state" % self.vm.getDomid()) time.sleep(0.1) count += 1 if count > 100: raise VmError('Timed out waiting for device model to save')
def hotplugStatusCallback(statusPath, ev, result): log.debug("hotplugStatusCallback %s.", statusPath) status = xstransact.Read(statusPath) if status is not None: if status == HOTPLUG_STATUS_ERROR: result['status'] = Error elif status == HOTPLUG_STATUS_BUSY: result['status'] = Busy else: result['status'] = Connected else: return 1 log.debug("hotplugStatusCallback %d.", result['status']) ev.set() return 0
def waitForBackend(self, devid): # FIXME!!! We haven't udev daemon... #result = { 'status': Connected } #return result['status'] frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: statusPath = backpath + '/' + HOTPLUG_STATUS_NODE ev = Event() result = { 'status': Timeout } xswatch(statusPath, hotplugStatusCallback, ev, result) ev.wait(DEVICE_CREATE_TIMEOUT) return result['status'] else: return Missing
def destroyDevice(self, devid): """Destroy the specified device. @param devid The device ID, or something device-specific from which the device ID can be determined (such as a guest-side device name). The implementation here simply deletes the appropriate paths from the store. This may be overridden by subclasses who need to perform other tasks on destruction. Further, the implementation here can only accept integer device IDs, or values that can be converted to integers. Subclasses may accept other values and convert them to integers before passing them here. """ devid = int(devid) frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: xstransact.Write(backpath, 'state', str(xenbusState['Closing'])) else: raise VmError("Device %s not connected" % devid)
def readFrontend(self, devid, *args): return xstransact.Read(self.frontendPath(devid), *args)
def readBackend(self, devid, *args): backpath = self.readVm(devid, "backend") if backpath: return xstransact.Read(backpath, *args) else: raise VmError("Device %s not connected" % devid)