def waitForDevice(self, devid): log.debug("Waiting for %s.", devid) if not self.hotplug: return (status, err) = self.waitForBackend(devid) if status == Timeout: self.destroyDevice(devid, False) raise VmError("Device %s (%s) could not be connected. " "Hotplug scripts not working." % (devid, self.deviceClass)) elif status == Error: self.destroyDevice(devid, False) if err is None: raise VmError("Device %s (%s) could not be connected. " "Backend device not found." % (devid, self.deviceClass)) else: raise VmError("Device %s (%s) could not be connected. " "%s" % (devid, self.deviceClass, err)) 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: self.destroyDevice(devid, False) if err is None: err = "Busy." raise VmError("Device %s (%s) could not be connected.\n%s" % (devid, self.deviceClass, err))
def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: val = config.get(field) if not val: raise VmError('ioports: Missing %s config setting' % field) return parse_ioport(val) except: raise VmError('ioports: Invalid config setting %s: %s' % (field, val)) io_from = get_param('from') io_to = get_param('to') if io_to < io_from or io_to >= 65536: raise VmError('ioports: Invalid i/o range: %s - %s' % (io_from, io_to)) rc = xc.domain_ioport_permission(domid=self.getDomid(), first_port=io_from, nr_ports=io_to - io_from + 1, allow_access=True) if rc < 0: #todo non-fatal raise VmError( 'ioports: Failed to configure legacy i/o range: %s - %s' % (io_from, io_to)) return (None, {}, {})
def configure(self, imageConfig, deviceConfig): ImageHandler.configure(self, imageConfig, deviceConfig) info = xc.xeninfo() if not 'hvm' in info['xen_caps']: raise VmError("Not an HVM capable platform, we stop creating!") self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig) self.device_model = sxp.child_value(imageConfig, 'device_model') if not self.device_model: raise VmError("hvm: missing device model") self.display = sxp.child_value(imageConfig, 'display') self.xauthority = sxp.child_value(imageConfig, 'xauthority') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), ("image/display", self.display)) self.pid = 0 self.dmargs += self.configVNC(imageConfig) self.pae = int(sxp.child_value(imageConfig, 'pae', 0)) self.acpi = int(sxp.child_value(imageConfig, 'acpi', 0)) self.apic = int(sxp.child_value(imageConfig, 'apic', 0))
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 getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" uname = config.get('uname', '') dev = config.get('dev', '') if 'ioemu:' in dev: (_, dev) = string.split(dev, ':', 1) try: (dev, dev_type) = string.split(dev, ':', 1) except ValueError: dev_type = "disk" if not uname: if dev_type == 'cdrom': (typ, params) = ("", "") else: raise VmError( 'Block device must have physical details specified') else: try: (typ, params) = string.split(uname, ':', 1) if not self._isValidProtocol(typ): raise VmError('Block device type "%s" is invalid.' % typ) except ValueError: raise VmError( 'Block device must have physical details specified') mode = config.get('mode', 'r') if mode not in ('r', 'w', 'w!'): raise VmError('Invalid mode') back = { 'dev': dev, 'type': typ, 'params': params, 'mode': mode, } uuid = config.get('uuid') if uuid: back['uuid'] = uuid bootable = config.get('bootable', None) if bootable != None: back['bootable'] = str(bootable) if security.on() == xsconstants.XS_POLICY_USE: self.do_access_control(config, uname) (device_path, devid) = blkif.blkdev_name_to_number(dev) if devid is None: raise VmError('Unable to find number for device (%s)' % (dev)) front = {device_path: "%i" % devid, 'device-type': dev_type} protocol = config.get('protocol') if protocol: front['protocol'] = protocol return (devid, back, front)
def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) if isinstance(val, types.StringType): return int(val, 10) radix = 10 else: return val except: raise VmError('irq: Invalid config setting %s: %s' % (field, val)) pirq = get_param('irq') rc = xc.domain_irq_permission(domid=self.getDomid(), pirq=pirq, allow_access=True) if rc < 0: #todo non-fatal raise VmError('irq: Failed to configure irq: %d' % (pirq)) rc = xc.physdev_map_pirq(domid=self.getDomid(), index=pirq, pirq=pirq) if rc < 0: raise VmError('irq: Failed to map irq %x' % (pirq)) back = dict([(k, config[k]) for k in self.valid_cfg if k in config]) return (self.allocateDeviceID(), back, {})
def pool_start(cls, poolname): pool = cls.lookup_pool(poolname) if not pool: raise VmError('unknown pool %s' % poolname) try: pool.activate() except XendAPIError, ex: raise VmError(ex.get_api_error())
def pool_delete(cls, poolname): pool = cls.lookup_pool(poolname) if not pool: raise VmError('unknown pool %s' % poolname) try: pool.destroy() except XendAPIError, ex: raise VmError(ex.get_api_error())
def get_param(field): try: val = config.get(field) if not val: raise VmError('ioports: Missing %s config setting' % field) return parse_ioport(val) except: raise VmError('ioports: Invalid config setting %s: %s' % (field, val))
def pool_cpu_remove(cls, poolname, cpu): pool = cls.lookup_pool(poolname) if not pool: raise VmError('unknown pool %s' % poolname) try: cpu_ref = cls._cpu_number_to_ref(int(cpu)) if cpu_ref: pool.remove_host_CPU_live(cpu_ref) else: raise PoolError(XEND_ERROR_INVALID_CPU, 'CPU unknown') except XendAPIError, ex: raise VmError(ex.get_api_error())
def findImageHandlerClass(image): """Find the image handler class for an image config. @param image config @return ImageHandler subclass or None """ ty = sxp.name(image) if ty is None: raise VmError('missing image type') imageClass = imageHandlerClasses.get(ty) if imageClass is None: raise VmError('unknown image type: ' + ty) return imageClass
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 do_access_control(self, config, uname): (label, ssidref, policy) = \ security.get_res_security_details(uname) domain_label = self.vm.get_security_label() if domain_label: rc = security.res_security_check_xapi(label, ssidref, policy, domain_label) if rc == 0: raise VmError("VM's access to block device '%s' denied" % uname) else: from xen.util.acmpolicy import ACM_LABEL_UNLABELED if label != ACM_LABEL_UNLABELED: raise VmError("VM must have a security label to access " "block device '%s'" % uname)
def get_param(field): try: val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) if isinstance(val, types.StringType): return int(val,10) radix = 10 else: return val except: raise VmError('irq: Invalid config setting %s: %s' % (field, val))
def reconfigureDevice(self, devid, config): """Reconfigure the specified device. The implementation here just raises VmError. This may be overridden by those subclasses that can reconfigure their devices. """ raise VmError('%s devices may not be reconfigured' % self.deviceClass)
def readBackendTxn(self, transaction, devid, *args): backpath = self.readVm(devid, "backend") if backpath: paths = map(lambda x: backpath + "/" + x, args) return transaction.read(*paths) else: raise VmError("Device %s not connected" % devid)
def pool_migrate(cls, domname, poolname): dom = XendDomain.instance() pool = cls.lookup_pool(poolname) if not pool: raise VmError('unknown pool %s' % poolname) dominfo = dom.domain_lookup_nr(domname) if not dominfo: raise VmError('unknown domain %s' % domname) domid = dominfo.getDomid() if domid is not None: if domid == 0: raise VmError('could not move Domain-0') try: cls.move_domain(pool.get_uuid(), domid) except Exception, ex: raise VmError('could not move domain')
def CheckSiblingDevices(self, domid, dev): """ Check if all sibling devices of dev are owned by pciback or pci-stub """ if not self.vm.info.is_hvm(): return group_str = xc.get_device_group(domid, dev.domain, dev.bus, dev.slot, dev.func) if group_str == "": return #group string format xx:xx.x,xx:xx.x, for i in group_str.split(','): if i == '': continue pci_dev = parse_pci_name(i) pci_dev['domain'] = '%04x' % dev.domain try: sdev = PciDevice(pci_dev) except Exception, e: #no dom0 drivers bound to sdev continue if sdev.driver != 'pciback' and sdev.driver != 'pci-stub': raise VmError(("pci: PCI Backend and pci-stub don't "+ \ "own sibling device %s of device %s"\ )%(sdev.name, dev.name))
def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) if isinstance(val, types.StringType): return int(val,10) radix = 10 else: return val except: raise VmError('irq: Invalid config setting %s: %s' % (field, val)) pirq = get_param('irq') rc = xc.domain_irq_permission(domid = self.getDomid(), pirq = pirq, allow_access = True) if rc < 0: #todo non-fatal raise VmError( 'irq: Failed to configure irq: %d' % (pirq)) return (None, {}, {})
def CheckSiblingDevices(self, domid, dev): """ Check if all sibling devices of dev are owned by pciback """ if not self.vm.info.is_hvm(): return group_str = xc.get_device_group(domid, dev.domain, dev.bus, dev.slot, dev.func) if group_str == "": return #group string format xx:xx.x,xx:xx.x, devstr_len = group_str.find(',') for i in range(0, len(group_str), devstr_len + 1): (bus, slotfunc) = group_str[i:i + devstr_len].split(':') (slot, func) = slotfunc.split('.') b = parse_hex(bus) d = parse_hex(slot) f = parse_hex(func) try: sdev = PciDevice(dev.domain, b, d, f) except Exception, e: #no dom0 drivers bound to sdev continue if sdev.driver != 'pciback': raise VmError(("pci: PCI Backend does not own\n "+ \ "sibling device %s of device %s\n"+ \ "See the pciback.hide kernel "+ \ "command-line parameter or\n"+ \ "bind your slot/device to the PCI backend using sysfs" \ )%(sdev.name, dev.name))
def writeBackend(self, devid, *args): backpath = self.readVm(devid, "backend") if backpath: xstransact.Write(backpath, *args) else: raise VmError("Device %s not connected" % devid)
def destroyDevice(self, devid): try: DevController.destroyDevice(self, int(devid)) time.sleep(5) t = xstransact() frontpath = self.frontendPath(int(devid)) backpath = t.Read(frontpath, "backend") if backpath: t.Remove(backpath) log.debug('in try: removed %s' % backpath) t.Remove(frontpath) log.debug('in try: removed %s' % frontpath) except ValueError: devid_end = type(devid) is str and devid.split('/')[-1] or None for i in self.deviceIDs(): d = self.readBackend(i, 'dev') if d == devid or (devid_end and d == devid_end): DevController.destroyDevice(self, i) time.sleep(5) frontpath = self.frontendPath(int(devid)) backpath = t.Read(frontpath, "backend") if backpath: t.Remove(backpath) log.debug('in err: removed %s' % backpath) t.Remove(frontpath) log.debug('in err: removed %s' % frontpath) return raise VmError("Device %s not connected" % devid)
def removeBackend(self, devid, *args): frontpath = self.frontendPath(devid) backpath = xstransact.Read(frontpath, "backend") if backpath: return xstransact.Remove(backpath, *args) else: raise VmError("Device %s not connected" % devid)
def pool_list(cls, names): sxprs = [] try: node = XendNode.instance() xd = XendDomain.instance() pools = cls.get_all_records() for (pool_uuid, pool_vals) in pools.items(): if pool_vals['name_label'] in names or len(names) == 0: # conv host_cpu refs to cpu number cpus = [ node.get_host_cpu_field(cpu_ref, 'number') for cpu_ref in pool_vals['host_CPUs'] ] cpus.sort() pool_vals['host_CPU_numbers'] = cpus # query VMs names. Take in account, that a VM # returned by get_all_records could be destroy, now vm_names = [ vm.getName() for vm in map( xd.get_vm_by_uuid, pool_vals['started_VMs']) if vm ] pool_vals['started_VM_names'] = vm_names pool_vals['auto_power_on'] = int( pool_vals['auto_power_on']) sxprs += [[pool_uuid] + map2sxp(pool_vals)] except XendAPIError, ex: raise VmError(ex.get_api_error())
def reconfigureDevice(self, _, config): """@see DevController.reconfigureDevice""" (devid, back, front) = self.getDeviceDetails(config) devid = int(devid) vscsi_config = config['devs'][0] state = vscsi_config.get('state', xenbusState['Unknown']) driver_state = self.readBackend(devid, 'state') if str(xenbusState['Connected']) != driver_state: raise VmError("Driver status is not connected") uuid = self.readBackend(devid, 'uuid') if state == xenbusState['Initialising']: back['uuid'] = uuid self.writeBackend(devid, back) elif state == xenbusState['Closing']: found = False devs = self.readBackendList(devid, "vscsi-devs") hostmode = int(self.readBackend(devid, 'feature-host')) vscsipath = "vscsi-devs/" vdev = vscsi_config.get('v-dev', '') for dev in devs: devpath = vscsipath + dev old_vdev = self.readBackend(devid, devpath + '/v-dev') if hostmode == 1: #At hostmode, all v-dev that belongs to devid is deleted. found = True self.writeBackend(devid, devpath + '/state', \ str(xenbusState['Closing'])) elif vdev == old_vdev: found = True self.writeBackend(devid, devpath + '/state', \ str(xenbusState['Closing'])) break if not found: raise VmError("Device %s not connected" % vdev) else: raise XendError("Error configuring device invalid " "state '%s'" % xenbusState[state]) self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring'])) return self.readBackend(devid, 'uuid')
def createDevice(self, config): bridge = config.get('bridge') if bridge is not None: bridge_result = commands.getstatusoutput("/sbin/ifconfig %s" % bridge) if bridge_result[0] != 0: raise VmError('Network bridge does not exist: %s' % bridge) DevController.createDevice(self, config)
def waitForDevice_reconfigure(self, devid): log.debug("Waiting for %s - reconfigureDevice.", devid) (status, err) = self.waitForBackend_reconfigure(devid) if status == Timeout: raise VmError("Device %s (%s) could not be reconfigured. " % (devid, self.deviceClass))
def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" script = config.get('script', xoptions.get_vif_script()) typ = config.get('type') bridge = config.get('bridge') mac = config.get('mac') vifname = config.get('vifname') rate = config.get('rate') uuid = config.get('uuid') ipaddr = config.get('ip') model = config.get('model') accel = config.get('accel') sec_lab = config.get('security_label') if not mac: raise VmError("MAC address not specified or generated.") devid = self.allocateDeviceID() back = {'script': script, 'mac': mac} if typ: back['type'] = typ if ipaddr: back['ip'] = ipaddr if bridge: back['bridge'] = bridge if vifname: back['vifname'] = vifname if rate: back['rate'] = rate if uuid: back['uuid'] = uuid if model: back['model'] = model if accel: back['accel'] = accel if sec_lab: back['security_label'] = sec_lab config_path = "device/%s/%d/" % (self.deviceClass, devid) for x in back: self.vm._writeVm(config_path + x, back[x]) back['handle'] = "%i" % devid back['script'] = os.path.join(xoptions.network_script_dir, script) if rate: back['rate'] = parseRate(rate) front = {} if typ != 'ioemu': front = {'handle': "%i" % devid, 'mac': mac} if security.on(): self.do_access_control(config) return (devid, back, front)
def pool_new(cls, config): try: record = sxp2map(config) if record.has_key('proposed_CPUs') and \ not isinstance(record['proposed_CPUs'], types.ListType): record['proposed_CPUs'] = [record['proposed_CPUs']] new_uuid = cls.create(record) except XendAPIError, ex: raise VmError(ex.get_api_error())
def do_access_control(self, config): """ do access control checking. Throws a VMError if access is denied """ domain_label = self.vm.get_security_label() stes = XSPolicyAdminInstance().get_stes_of_vmlabel(domain_label) res_label = config.get('security_label') if len(stes) > 1 or res_label: if not res_label: raise VmError("'VIF' must be labeled") (label, ssidref, policy) = \ security.security_label_to_details(res_label) if domain_label: rc = security.res_security_check_xapi(label, ssidref, policy, domain_label) if rc == 0: raise VmError("VM's access to network device denied. " "Check labeling") else: raise VmError("VM must have a security label to access " "network device")