def delete(self, name): try: utils._remove_lv(name) except OperationFailed as e: raise OperationFailed("GINLV00006E", {'err': e.message})
def to_vm_xml(self, vm_name, vm_uuid, **kwargs): params = dict(self.info) params['name'] = vm_name params['uuid'] = vm_uuid params['networks'] = self._get_networks_xml() params['interfaces'] = self._get_interfaces_xml() params['input_output'] = self._get_input_output_xml() params['qemu-namespace'] = '' params['cdroms'] = '' params['qemu-stream-cmdline'] = '' params['disks'] = self._get_disks_xml(vm_uuid) params['serial'] = get_serial_xml(params) params['title'] = kwargs.get('title', '') params['description'] = kwargs.get('description', '') graphics = dict(self.info['graphics']) graphics.update(kwargs.get('graphics', {})) # Graphics is not supported on s390x, this check will # not add graphics tag in domain xml. if params.get('arch') != 's390x': params['graphics'] = get_graphics_xml(graphics) libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', []) cdrom_xml = self._get_cdrom_xml(libvirt_stream_protocols) # Add information of CD-ROM device only if template have info about it. if cdrom_xml is not None: if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ libvirt_stream_protocols and \ params.get('iso_stream', False): params['qemu-stream-cmdline'] = cdrom_xml else: params['cdroms'] = cdrom_xml # Set the boot order of VM # TODO: need modify this when boot order edition feature came upstream. if cdrom_xml and params.get('arch') == 's390x': params['boot_order'] = get_bootorder_xml( ['cdrom', 'hd', 'network']) else: params['boot_order'] = get_bootorder_xml() # Setting maximum number of memory slots slots = str(self.info['mem_dev_slots']) # Rearrange memory parameters memory = self.info['memory'].get('current') maxmemory = self.info['memory'].get('maxmemory') if maxmemory < memory: raise OperationFailed("KCHVM0041E", {'maxmem': str(maxmemory)}) params['memory'] = self.info['memory'].get('current') params['max_memory'] = "" # if there is not support to memory hotplug in Libvirt or qemu, we # cannot add the tag maxMemory if memory != maxmemory and kwargs.get('mem_hotplug_support', True): maxmem_xml = "<maxMemory slots='%s' unit='MiB'>%s</maxMemory>" params['max_memory'] = maxmem_xml % (slots, maxmemory) # set a hard limit using max_memory + 1GiB params['hard_limit'] = maxmemory + 1024 # vcpu element cpus = params['cpu_info']['vcpus'] maxvcpus = params['cpu_info']['maxvcpus'] params['vcpus_xml'] = "<vcpu current='%d'>%d</vcpu>" % (cpus, maxvcpus) # cpu_info element params['cpu_info_xml'] = self._get_cpu_xml() # usb controller params['usb_controller'] = self._get_usb_controller() xml = """ <domain type='%(domain)s'> %(qemu-stream-cmdline)s <name>%(name)s</name> <title>%(title)s</title> <description>%(description)s</description> <uuid>%(uuid)s</uuid> <memtune> <hard_limit unit='MiB'>%(hard_limit)s</hard_limit> </memtune> %(max_memory)s <memory unit='MiB'>%(memory)s</memory> %(vcpus_xml)s %(cpu_info_xml)s <os> <type arch='%(arch)s'>hvm</type> %(boot_order)s </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> %(disks)s %(cdroms)s %(networks)s %(interfaces)s %(graphics)s %(input_output)s %(usb_controller)s %(serial)s <memballoon model='virtio' /> </devices> </domain> """ % params return xml
def get_list(self): if self.host_swupdate is None: raise OperationFailed('GGBPKGUPD0004E') return self.host_swupdate.getUpdates()
def create(self, vm_name, params): vol_model = None # Path will never be blank due to API.json verification. # There is no need to cover this case here. if not ('vol' in params) ^ ('path' in params): raise InvalidParameter("KCHVMSTOR0017E") dom = VMModel.get_vm(vm_name, self.conn) params['bus'] = _get_device_bus(params['type'], dom) params['format'] = 'raw' dev_list = [ dev for dev, bus in get_vm_disks(dom).iteritems() if bus == params['bus'] ] dev_list.sort() if len(dev_list) == 0: params['index'] = 0 else: char = dev_list.pop()[2] params['index'] = string.ascii_lowercase.index(char) + 1 if (params['bus'] not in HOTPLUG_TYPE and DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): raise InvalidOperation('KCHVMSTOR0011E') if params.get('vol'): try: pool = params['pool'] vol_model = StorageVolumeModel(conn=self.conn, objstore=self.objstore) vol_info = vol_model.lookup(pool, params['vol']) except KeyError: raise InvalidParameter("KCHVMSTOR0012E") except Exception as e: raise InvalidParameter("KCHVMSTOR0015E", {'error': e}) if len(vol_info['used_by']) != 0: raise InvalidParameter("KCHVMSTOR0016E") valid_format = { "disk": ["raw", "bochs", "qcow", "qcow2", "qed", "vmdk"], "cdrom": "iso" } if vol_info['type'] == 'file': if (params['type'] == 'disk' and vol_info['format'] in valid_format[params['type']]): params['format'] = vol_info['format'] else: raise InvalidParameter("KCHVMSTOR0018E", { "format": vol_info['format'], "type": params['type'] }) if (params['format'] == 'raw' and not vol_info['isvalid']): message = 'This is not a valid RAW disk image.' raise OperationFailed('KCHVMSTOR0008E', {'error': message}) params['path'] = vol_info['path'] params['disk'] = vol_info['type'] params.update(self._get_available_bus_address(params['bus'], vm_name)) # Add device to VM dev, xml = get_disk_xml(params) try: dom = VMModel.get_vm(vm_name, self.conn) dom.attachDeviceFlags(xml, get_vm_config_flag(dom, 'all')) except Exception as e: raise OperationFailed("KCHVMSTOR0008E", {'error': e.message}) # Don't put a try-block here. Let the exception be raised. If we # allow disks used_by to be out of sync, data corruption could # occour if a disk is added to two guests unknowingly. if params.get('vol'): used_by = vol_info['used_by'] used_by.append(vm_name) set_disk_used_by(self.objstore, params['path'], used_by) return dev
def update(self, name, params): edit_template = self.lookup(name) # If new name is not same as existing name # and new name already exists: raise exception with self.objstore as session: if ('name' in params and name != params['name'] and params['name'] in session.get_list('template')): raise InvalidOperation('KCHTMPL0001E', {'name': params['name']}) # Valid interfaces interfaces = params.get('interfaces', []) validate_interfaces(interfaces) if os.uname()[4] not in ['s390x', 's390'] and 'console' in params: raise InvalidParameter('KCHTMPL0043E') # Merge graphics settings graph_args = params.get('graphics') if graph_args: graphics = dict(edit_template['graphics']) graphics.update(graph_args) params['graphics'] = graphics # Merge cpu_info settings new_cpu_info = params.get('cpu_info') if new_cpu_info: cpu_info = dict(edit_template['cpu_info']) cpu_info.update(new_cpu_info) params['cpu_info'] = cpu_info # Fix memory values, because method update does not work recursively new_mem = params.get('memory') if new_mem is not None: params['memory'] = copy.copy(edit_template.get('memory')) params['memory'].update(new_mem) validate_memory(params['memory']) edit_template.update(params) for net_name in params.get(u'networks', []): try: conn = self.conn.get() conn.networkLookupByName(net_name) except Exception: raise InvalidParameter('KCHTMPL0003E', { 'network': net_name, 'template': name }) try: # make sure the new template will be created t = LibvirtVMTemplate(edit_template, scan=True, conn=self.conn) t.cpuinfo_validate() t._validate_memory() # remove the current one self.delete(name) # save the template return self.templates.save_template(edit_template) except InvalidOperation: raise except Exception as e: raise OperationFailed('KCHTMPL0032E', {'err': str(e)}) return params['name']
def del_port_from_ovsbridge(ovsbridge, port): cmd = ['ovs-vsctl', 'del-port', ovsbridge, port] out, err, returncode = run_ovsvsctl_command(cmd) if returncode != 0: raise OperationFailed('GINOVS00002E', {'err': err})
}) if name in self.get_list(): raise InvalidOperation("KCHPOOL0001E", {'name': name}) try: if task_id: # Create transient pool for deep scan conn.storagePoolCreateXML(xml, 0) return name pool = conn.storagePoolDefineXML(xml, 0) except libvirt.libvirtError as e: wok_log.error("Problem creating Storage Pool: %s", e) raise OperationFailed("KCHPOOL0007E", { 'name': name, 'err': e.get_error_message() }) # Build and set autostart value to pool # Ignore error as the pool was already successfully created # The build process fails when the pool directory already exists try: if params['type'] in ['logical', 'dir', 'netfs', 'scsi']: pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) pool.setAutostart(1) else: pool.setAutostart(0) except: pass if params['type'] == 'netfs':
def remove_lun(adapter, port, lun_id): """ Remove a LUN from system :param adapter: HBA adapter id :param port: Remote port wwpn :param lun_id: Id of the given LUN """ luns = [] # get lun information using lszfcp -l out, err, rc = run_command(['lszfcp', '-l', lun_id]) if out: parsed_zfcp_out = parse_lszfcp_out(out) if parsed_zfcp_out and isinstance(parsed_zfcp_out, dict): for path, scsi_dev in parsed_zfcp_out.iteritems(): dm_long_name = None try: path = path.split('/') luns.append((path[0], path[1], path[2])) scsi_dev_dir = scsi_dir + scsi_dev block_dev = os.listdir(scsi_dev_dir + "/block/")[0] dm_dev = os.listdir(scsi_dev_dir + "/block/" + block_dev + "/holders/")[0] with open( scsi_dev_dir + "/block/" + block_dev + "/holders/" + dm_dev + "/dm/name", 'r') as txt_file: dm_long_name = txt_file.readline().rstrip() except: # It may happen that the given device may not have # a corresponding dm device. In that case just # move on without doing anything. pass if dm_long_name: clear_multipath(dm_long_name) remove_auto_lun(scsi_dev) else: # try checking sg entries in scci_generic # Let's look for the sg_device associated with this LUN sg_dev = get_sg_dev(adapter, port, lun_id) if sg_dev: luns.append((adapter, port, lun_id)) sg_device = sg_dev sg_dev_path = sg_dir + "/" + sg_device other_paths = find_other_paths(sg_device) for op in other_paths: hba_id = op[0] wwpn = op[1] fcp_lun = op[2] luns.append((hba_id, wwpn, fcp_lun)) dm_long_name = None try: block_dev = os.listdir(sg_dev_path + "/device/block/")[0] dm_dev = os.listdir(sg_dev_path + "/device/block/" + block_dev + "/holders/")[0] dm_long_name = open(sg_dev_path + "/device/block/" + block_dev + "/holders/" + dm_dev + "/dm/name").readline().rstrip() except: # It may happen that the given device may not have # a corresponding dm device. In that case just # move on without doing anything. pass if dm_long_name: clear_multipath(dm_long_name) for lun in luns: port_dir = '/sys/bus/ccw/drivers/zfcp/' + lun[0] + '/' + lun[1] + '/' lun_dir = port_dir + lun[2] wok_log.info("Removing LUN, %s", lun_dir) if not os.path.exists(lun_dir): continue # move on... some other thread removed this LUN already try: with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(lun[2]) fo = open("/etc/zfcp.conf", "r") lines = fo.readlines() output = [] fo.close() fo = open("/etc/zfcp.conf", "w") for line in lines: if [lun[0], lun[1], lun[2]] == line.split(): continue else: output.append(line) fo.writelines(output) fo.close() except Exception as e: wok_log.error("Unable to remove LUN, %s", lun_dir) raise OperationFailed("GS390XSTG00002", {'err': e.message})
def get_lun_info(adapter, port, lun_id): """ Get detailed information about a specific LUN :param adapter: HBA adapter id :param port: Remote port wwpn :param lun_id: Id of the given LUN :return: Dictionary containing detailed information about a specific LUN """ port_dir = '/sys/bus/ccw/drivers/zfcp/' + adapter + '/' + port + '/' lun_dir = port_dir + lun_id lun_info = {} out, err, rc = run_command(['lszfcp', '-l', lun_id]) parsed_lszfcp_out = parse_lszfcp_out(out) lszfcp_key = adapter + '/' + port + '/' + lun_id if lszfcp_key in parsed_lszfcp_out.keys() or os.path.exists(lun_dir) \ or is_lun_scan_enabled()['current']: lun_info['configured'] = True else: lun_info['configured'] = False try: with open(port_dir + 'unit_add', "w") as txt_file: txt_file.write(lun_id) for _ in range(4): run_command([udevadm, "settle", "--exit-if-exists=" + lun_dir]) if os.path.exists(lun_dir): break if not os.path.exists(lun_dir): with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(lun0) with open(port_dir + 'unit_add', "w") as txt_file: txt_file.write(wlun) for _ in range(4): run_command( [udevadm, "settle", "--exit-if-exists=" + lun_dir]) if os.path.exists(lun_dir): break if not os.path.exists(lun_dir): with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(wlun) except Exception as e: if 'Invalid argument' in e or 'No such file or directory' in e: raise InvalidParameter("GS390XSTG00022") wok_log.error("Unable to add LUN temporarily, %s", lun_dir) raise OperationFailed("GS390XSTG00003", {'err': e.message}) # Get the list of FC only sg devices. This includes the sg_devices # of temporary LUNs as well. sg_devices = get_sg_devices() for sg_dev in sg_devices: try: wwpn = open(sg_dir + "/" + sg_dev + "/device/wwpn").readline().rstrip() fcp_lun = open(sg_dir + "/" + sg_dev + "/device/fcp_lun").readline().rstrip() hba_id = open(sg_dir + "/" + sg_dev + "/device/hba_id").readline().rstrip() if hba_id == adapter and wwpn == port and fcp_lun == lun_id: lun_info['hbaId'] = hba_id lun_info['remoteWwpn'] = port lun_info['lunId'] = lun_id lun_info['sgDev'] = sg_dev out, err, rc = run_command(["sg_inq", "/dev/" + sg_dev]) if rc == 0: lun_info.update(_get_sg_inq_dict(out)) break except: # While looking for relavent sg_device in an multithreaded # environment it may happen that the directory we are looking # into might get deleted by another thread. In this was just # just skip this current directory and look for the sg_device # somewhere else. This is why we should just pass this # exception. pass # Get rid of the LUN if it's not configured if not lun_info['configured']: lun_info['configured'] = "false" try: wok_log.info("Removing sg_device , %s", lun_info['sgDev']) with open(sg_dir + lun_info['sgDev'] + '/device/delete', "w")\ as txt_file: txt_file.write("1") del lun_info['sgDev'] except Exception as e: wok_log.error("Unable to remove sg_device , %s", lun_info['sgDev']) raise OperationFailed("GS390XSTG00001", {'err': e.message}) try: wok_log.info("Removing LUN , %s", lun_dir) with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(fcp_lun) except: # If failed to remove the given LUN, at least remove the wlun wok_log.info("Removing LUN , %s", port_dir + ":" + wlun) try: with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(wlun) except: # Just logging is sufficient. No need to raise exception and # stop the code flow wok_log.error("Removing LUN failed , %s", port_dir + ":" + wlun) else: lun_info['configured'] = "true" return lun_info
def get_final_list(): """ Comprehensive list of storage devices found on the system :return:List of dictionaries containing the information about individual disk """ try: out = get_lsblk_keypair_out(True) except OperationFailed: out = get_lsblk_keypair_out(False) final_list = [] try: dasds = get_dasd_devs() if dasds: final_list = dasds blk_dict = parse_lsblk_out(out) out = get_disks_by_id_out() ll_dict, ll_id_dict = parse_ll_out(out) fc_blk_dict = get_fc_path_elements() for blk in blk_dict: final_dict = {} if blk in ll_dict: final_dict['id'] = ll_dict[blk] if final_dict['id'].startswith('ccw-'): continue block_dev_list = ll_id_dict[final_dict['id']] max_slaves = 1 for block_dev in block_dev_list: slaves = os.listdir('/sys/block/' + block_dev + '/slaves/') if max_slaves < len(slaves): max_slaves = len(slaves) final_dict['mpath_count'] = max_slaves final_dict['name'] = blk final_dict['size'] = blk_dict[blk]['size'] final_dict['type'] = blk_dict[blk]['transport'] if final_dict['type'] == 'fc': final_dict['hba_id'] = fc_blk_dict[blk].get('hba_id', '') final_dict['wwpn'] = fc_blk_dict[blk].get('wwpn', '') final_dict['fcp_lun'] = fc_blk_dict[blk].get('fcp_lun', '') final_dict['vport'] = fc_blk_dict[blk].get('vport', '') if 'id' in final_dict: if final_dict['id'] in ll_id_dict: final_dict['name'] = ll_id_dict[final_dict['id']][0] if 'hba_id' in final_dict.keys(): if final_dict['hba_id']: final_list.append(final_dict) else: final_list.append(final_dict) except Exception as e: raise OperationFailed("GINSD00005E", {'err': e.message}) return final_list
def __init__(self, args, scan=False): """ Construct a VM Template from a widely variable amount of information. The only required parameter is a name for the VMTemplate. If present, the os_distro and os_version fields are used to lookup recommended settings. Any parameters provided by the caller will override the defaults. If scan is True and a cdrom or a base img is present, the operating system will be detected by probing the installation media. """ self.info = {} self.fc_host_support = args.get('fc_host_support') # Fetch defaults based on the os distro and version try: distro, version = self._get_os_info(args, scan) except ImageFormatError as e: raise OperationFailed('KCHTMPL0020E', {'err': e.message}) os_distro = args.get('os_distro', distro) os_version = args.get('os_version', version) entry = osinfo.lookup(os_distro, os_version) self.info.update(entry) # Auto-generate a template name if no one is passed if 'name' not in args or args['name'] == '': args['name'] = self._gen_name(distro, version) self.name = args['name'] # Merge graphics settings graph_args = args.get('graphics') if graph_args: graphics = dict(self.info['graphics']) graphics.update(graph_args) args['graphics'] = graphics default_disk = self.info['disks'][0] # Override template values according to 'args' self.info.update(args) disks = self.info.get('disks') basic_disk = ['index', 'format', 'pool', 'size'] ro_disk = ['index', 'format', 'pool', 'volume'] base_disk = ['index', 'base', 'pool', 'size', 'format'] for index, disk in enumerate(disks): disk_info = dict(default_disk) pool_type = self._get_storage_type(disk['pool']['name']) if pool_type in ['iscsi', 'scsi']: disk_info = {'index': 0, 'format': 'raw', 'volume': None} disk_info.update(disk) pool_name = disk_info.get('pool', {}).get('name') if pool_name is None: raise MissingParameter('KCHTMPL0028E') keys = sorted(disk_info.keys()) if ((keys != sorted(basic_disk)) and (keys != sorted(ro_disk)) and (keys != sorted(base_disk))): raise MissingParameter('KCHTMPL0028E') if pool_type in ['logical', 'iscsi', 'scsi']: if disk_info['format'] != 'raw': raise InvalidParameter('KCHTMPL0029E') disk_info['pool']['type'] = pool_type disk_info['index'] = disk_info.get('index', index) self.info['disks'][index] = disk_info
def create(self, params): name = params.get('name', '').strip() iso = params.get('cdrom') # check search permission if iso and iso.startswith('/') and os.path.exists(iso): st_mode = os.stat(iso).st_mode if stat.S_ISREG(st_mode) or stat.S_ISBLK(st_mode): user = UserTests().probe_user() run_setfacl_set_attr(iso, user=user) ret, excp = probe_file_permission_as_user(iso, user) if ret is False: raise InvalidParameter('KCHISO0008E', { 'filename': iso, 'user': user, 'err': excp }) cpu_info = params.get('cpu_info') if cpu_info: topology = cpu_info.get('topology') # Check, even though currently only topology # is supported. if topology: sockets = topology['sockets'] cores = topology['cores'] threads = topology['threads'] if params.get('cpus') is None: params['cpus'] = sockets * cores * threads # check_topoology will raise the appropriate # exception if a topology is invalid. CPUInfoModel(conn=self.conn).\ check_topology(params['cpus'], topology) conn = self.conn.get() pool_uri = params.get(u'storagepool', '') if pool_uri: try: pool_name = pool_name_from_uri(pool_uri) pool = conn.storagePoolLookupByName(pool_name.encode("utf-8")) except Exception: raise InvalidParameter("KCHTMPL0004E", { 'pool': pool_uri, 'template': name }) tmp_volumes = [ disk['volume'] for disk in params.get('disks', []) if 'volume' in disk ] self.template_volume_validate(tmp_volumes, pool) for net_name in params.get(u'networks', []): try: conn.networkLookupByName(net_name.encode('utf-8')) except Exception: raise InvalidParameter("KCHTMPL0003E", { 'network': net_name, 'template': name }) # Creates the template class with necessary information # Checkings will be done while creating this class, so any exception # will be raised here t = LibvirtVMTemplate(params, scan=True, conn=self.conn) name = params['name'] try: with self.objstore as session: if name in session.get_list('template'): raise InvalidOperation("KCHTMPL0001E", {'name': name}) session.store('template', name, t.info) except InvalidOperation: raise except Exception, e: raise OperationFailed('KCHTMPL0020E', {'err': e.message})
class StorageVolumesModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.task = TaskModel(**kargs) def create(self, pool_name, params): vol_source = ['url', 'capacity'] name = params.get('name') index_list = list(i for i in range(len(vol_source)) if vol_source[i] in params) if len(index_list) != 1: raise InvalidParameter("KCHVOL0018E", {'param': ",".join(vol_source)}) create_param = vol_source[index_list[0]] # Verify if the URL is valid if create_param == 'url': url = params['url'] try: urllib2.urlopen(url).close() except: raise InvalidParameter('KCHVOL0022E', {'url': url}) all_vol_names = self.get_list(pool_name) if name is None: # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have # 'name' == None if create_param in REQUIRE_NAME_PARAMS: raise InvalidParameter('KCHVOL0016E') # if 'name' is omitted - except for the methods listed in # 'REQUIRE_NAME_PARAMS' - the default volume name will be the # file/URL basename. if create_param == 'url': name = os.path.basename(params['url']) else: name = 'upload-%s' % int(time.time()) name = get_unique_file_name(all_vol_names, name) params['name'] = name try: create_func = getattr(self, '_create_volume_with_%s' % create_param) except AttributeError: raise InvalidParameter("KCHVOL0019E", {'param': create_param}) pool_info = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(pool_name) if pool_info['type'] in READONLY_POOL_TYPE: raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']}) if pool_info['state'] == 'inactive': raise InvalidParameter('KCHVOL0003E', { 'pool': pool_name, 'volume': name }) if name in all_vol_names: raise InvalidParameter('KCHVOL0001E', {'name': name}) params['pool'] = pool_name targeturi = '/plugins/kimchi/storagepools/%s/storagevolumes/%s' \ % (pool_name, name) taskid = add_task(targeturi, create_func, self.objstore, params) return self.task.lookup(taskid) def _create_volume_with_capacity(self, cb, params): pool_name = params.pop('pool') vol_xml = """ <volume> <name>%(name)s</name> <allocation unit='bytes'>%(allocation)s</allocation> <capacity unit='bytes'>%(capacity)s</capacity> <source> </source> <target> <format type='%(format)s'/> </target> </volume> """ params.setdefault('allocation', 0) params.setdefault('format', 'qcow2') name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool_name, self.conn) xml = vol_xml % params except KeyError, item: raise MissingParameter("KCHVOL0004E", { 'item': str(item), 'volume': name }) try: pool.createXML(xml, 0) except libvirt.libvirtError as e: raise OperationFailed("KCHVOL0007E", { 'name': name, 'pool': pool, 'err': e.get_error_message() }) vol_info = StorageVolumeModel(conn=self.conn, objstore=self.objstore).lookup( pool_name, name) vol_path = vol_info['path'] set_disk_used_by(self.objstore, vol_info['path'], []) if params.get('upload', False): upload_volumes[vol_path] = { 'lock': threading.Lock(), 'offset': 0, 'cb': cb } cb('ready for upload') else: cb('OK', True)
def _create_volume_with_url(self, cb, params): pool_name = params['pool'] name = params['name'] url = params['url'] pool_model = StoragePoolModel(conn=self.conn, objstore=self.objstore) pool = pool_model.lookup(pool_name) if pool['type'] in ['dir', 'netfs']: file_path = os.path.join(pool['path'], name) else: file_path = tempfile.mkstemp(prefix=name)[1] with contextlib.closing(urllib2.urlopen(url)) as response: with open(file_path, 'w') as volume_file: remote_size = response.info().getheader('Content-Length', '-') downloaded_size = 0 try: while True: chunk_data = response.read(READ_CHUNK_SIZE) if not chunk_data: break volume_file.write(chunk_data) downloaded_size += len(chunk_data) cb('%s/%s' % (downloaded_size, remote_size)) except (IOError, libvirt.libvirtError) as e: if os.path.isfile(file_path): os.remove(file_path) raise OperationFailed('KCHVOL0007E', { 'name': name, 'pool': pool_name, 'err': e.message }) if pool['type'] in ['dir', 'netfs']: virt_pool = StoragePoolModel.get_storagepool(pool_name, self.conn) virt_pool.refresh(0) else: def _stream_handler(stream, nbytes, fd): return fd.read(nbytes) virt_stream = virt_vol = None try: task = self.create( pool_name, { 'name': name, 'format': 'raw', 'capacity': downloaded_size, 'allocation': downloaded_size }) self.task.wait(task['id']) virt_vol = StorageVolumeModel.get_storagevolume( pool_name, name, self.conn) virt_stream = self.conn.get().newStream(0) virt_vol.upload(virt_stream, 0, downloaded_size, 0) with open(file_path) as fd: virt_stream.sendAll(_stream_handler, fd) virt_stream.finish() except (IOError, libvirt.libvirtError) as e: try: if virt_stream: virt_stream.abort() if virt_vol: virt_vol.delete(0) except libvirt.libvirtError, virt_e: wok_log.error(virt_e.message) finally: raise OperationFailed('KCHVOL0007E', { 'name': name, 'pool': pool_name, 'err': e.message }) finally:
def _event_loop_run(self): while True: if libvirt.virEventRunDefaultImpl() < 0: raise OperationFailed('KCHEVENT0003E')
def get_luns(): """ Get the list of all the LUNs including unconfigured ones :return: List of all the LUN paths """ lun_info_list = [] if is_lun_scan_enabled()['current']: return lun_info_list out, err, rc = run_command(['lszfcp', '-D']) if rc: wok_log.error('Error in lszfcp -D command, %s', err) parsed_lszfcp_out = parse_lszfcp_out(out) host_fcp_dict = _get_host_fcp_dict() global lun_dict lun_dict = _get_lun_dict() # Loop over all HBA adapters for adapter in host_fcp_dict: # Loop over every remote port for the given HBA adapter for port in host_fcp_dict[adapter]: temp_luns = {} port_dir = adapter_dir + adapter + '/' + port + '/' # If port went offline or is not accessible, skip. if not os.path.exists(port_dir): continue access_denied = open(port_dir + 'access_denied').readline().rstrip() if access_denied == "1": continue failed = open(port_dir + 'failed').readline().rstrip() if failed == "1": continue in_recovery = open(port_dir + 'in_recovery').readline().rstrip() if in_recovery == "1": continue # If no LUNs are associated with this port, try adding LUN 0 # to initiate LUN discovery on this port later add_discovery_lun = False if adapter not in lun_dict or port not in lun_dict[adapter]: add_discovery_lun = True if adapter in lun_dict and port in lun_dict[adapter]: port_luns_keys = lun_dict[adapter][port] add_discovery_lun = True for lun_key in port_luns_keys: if lun_key == lun0 or lun_key == wlun: add_discovery_lun = False if add_discovery_lun: try: with open(port_dir + 'unit_add', "w") as txt_file: txt_file.write(lun0) run_command([ udevadm, "settle", "--exit-if-exists=" + port_dir + lun0 ]) update_luns = True temp_luns[lun0] = True if os.path.exists(port_dir + lun0): failed = open(port_dir + lun0 + '/failed').readline().rstrip() if failed == "1": update_luns = False if adapter in lun_dict and port in lun_dict[ adapter]: del lun_dict[adapter][port] if update_luns: lun_dict = update_lun_dict(lun_dict, adapter, port, lun0) except Exception as e: wok_log.error("Unable to add LUN 0 , %s", port_dir + lun0) if adapter not in lun_dict or port not in lun_dict[adapter]: try: with open(port_dir + 'unit_remove', "w") as txt_file: txt_file.write(lun0) temp_luns[lun0] = False except Exception as e: wok_log.error("Unable to remove LUN 0 , %s", port_dir + lun0) try: with open(port_dir + 'unit_add', "w") as txt_file: txt_file.write(wlun) run_command([ udevadm, "settle", "--exit-if-exists=" + port_dir + "/" + wlun ]) lun_dict = update_lun_dict(lun_dict, adapter, port, wlun) temp_luns[wlun] = True except Exception as e: wok_log.error("Unable to add wlun , %s", port_dir + wlun) if adapter not in lun_dict or port not in lun_dict[adapter]: try: with open(port_dir + 'unit_remove', "w")\ as txt_file: txt_file.write(wlun) temp_luns[wlun] = False continue except Exception as e: wok_log.error("Unable to remove wlun , %s", port_dir + wlun) disc_sg_dev = '' if lun0 in lun_dict[adapter][port]: disc_sg_dev = lun_dict[adapter][port][lun0] if wlun in lun_dict[adapter][port]: disc_sg_dev = lun_dict[adapter][port][wlun] try: if disc_sg_dev: out, err, rc = run_command( ["sg_inq", "/dev/" + disc_sg_dev]) if rc == 0: for lun in lun_dict[adapter][port]: if lun == wlun: continue port_dir = '/sys/bus/ccw/drivers/zfcp/' +\ adapter + '/' + port + '/' lun_dir = port_dir + lun lun_info_dict = {} lun_info_dict.update(_get_sg_inq_dict(out)) lun_info_dict['hbaId'] = adapter lun_info_dict['remoteWwpn'] = port lun_info_dict['lunId'] = lun lszfcp_key = adapter + '/' + port + '/' + lun if lszfcp_key in parsed_lszfcp_out.keys()\ or os.path.exists(lun_dir): if lun in temp_luns and temp_luns[lun] is True: lun_info_dict['configured'] = "false" else: lun_info_dict['configured'] = "true" else: lun_info_dict['configured'] = "false" lun_info_list.append(lun_info_dict) except Exception as e: wok_log.error("Unable to get sg dev for discovery lun, %s", lun_dir) raise OperationFailed("GS390XSTG00021", {'err': e.message}) if adapter in lun_dict and port in lun_dict[adapter]: for lun in lun_dict[adapter][port]: # Get rid of the LUN if added temporarily for discovery if lun in temp_luns and temp_luns[lun] is True: sg_dev = '' if port in lun_dict[adapter] and lun in lun_dict[ adapter][port]: sg_dev = lun_dict[adapter][port][lun] if sg_dev: try: wok_log.info("Removing LUN 0, %s", port_dir) with open(port_dir + 'unit_remove', "w")\ as txt_file: txt_file.write(lun0) except: wok_log.error("unable to remove LUN 0, %s", port_dir) wok_log.info("Removing wlun, %s", wlun) try: with open(port_dir + 'unit_remove', "w")\ as txt_file: txt_file.write(wlun) except: # Can be safely ingored, so not raising # exception wok_log.error("unable to remove wlun, %s", port_dir) temp_luns[lun] = False return lun_info_list
def delete_ovsbridge(ovsbridge): cmd = ['ovs-vsctl', 'del-br', ovsbridge] out, err, returncode = run_ovsvsctl_command(cmd) if returncode != 0: raise OperationFailed('GINOVS00002E', {'err': err})
def get_list(self): out, err, rc = run_command(["cat", "/proc/swaps"]) if rc != 0: raise OperationFailed("GINSP00007E", {'err': err}) return utils._get_swapdev_list_parser(out)
def check_sensor_types(sensor_types): for sensor_type in sensor_types: if sensor_type not in ALLOWED_SENSOR_TYPES: raise OperationFailed( 'GINSDR00003E', {'sensor_type': sensor_type})
def get_list(self): try: return utils.get_luns() except OperationFailed as e: wok_log.error("Fetching list of LUNs failed") raise OperationFailed("GS390XSTG00007", {'err': e})
def create(self, vm_name, params): # Path will never be blank due to API.json verification. # There is no need to cover this case here. if not ('vol' in params) ^ ('path' in params): if not is_s390x(): raise InvalidParameter('KCHVMSTOR0017E') if 'dir_path' not in params: raise InvalidParameter('KCHVMSTOR0019E') dom = VMModel.get_vm(vm_name, self.conn) params['bus'] = _get_device_bus(params['type'], dom) if is_s390x() and params['type'] == 'disk' and 'dir_path' in params: if 'format' not in params: raise InvalidParameter('KCHVMSTOR0020E') size = params['size'] name = params['name'] dir_path = params.get('dir_path') params['path'] = dir_path + '/' + name if os.path.exists(params['path']): raise InvalidParameter('KCHVMSTOR0021E', {'disk_path': params['path']}) create_disk_image(format_type=params['format'], path=params['path'], capacity=size) else: params['format'] = 'raw' dev_list = [ dev for dev, bus in get_vm_disks(dom).items() if bus == params['bus'] ] dev_list.sort() if len(dev_list) == 0: params['index'] = 0 else: char = dev_list.pop()[2] params['index'] = string.ascii_lowercase.index(char) + 1 if (params['bus'] not in HOTPLUG_TYPE and DOM_STATE_MAP[dom.info()[0]] != 'shutoff'): raise InvalidOperation('KCHVMSTOR0011E') if params.get('vol'): vol_info = self._get_vol_info(params) params['path'] = vol_info['path'] params['disk'] = vol_info['type'] params.update(self._get_available_bus_address(params['bus'], vm_name)) # Add device to VM dev, xml = get_disk_xml(params) try: dom = VMModel.get_vm(vm_name, self.conn) dom.attachDeviceFlags(xml, get_vm_config_flag(dom, 'all')) except Exception as e: raise OperationFailed('KCHVMSTOR0008E', {'error': str(e)}) # Don't put a try-block here. Let the exception be raised. If we # allow disks used_by to be out of sync, data corruption could # occur if a disk is added to two guests unknowingly. if params.get('vol'): used_by = vol_info['used_by'] used_by.append(vm_name) return dev
def prepare(self, conn): source = self.poolArgs['source'] if not TargetClient(**source).validate(): msg_args = {'host': source['host'], 'target': source['target']} raise OperationFailed("KCHISCSI0002E", msg_args) self._prepare_auth(conn)
def to_vm_xml(self, vm_name, vm_uuid, **kwargs): params = dict(self.info) params['name'] = vm_name params['uuid'] = vm_uuid params['networks'] = self._get_networks_xml() params['input_output'] = self._get_input_output_xml() params['qemu-namespace'] = '' params['cdroms'] = '' params['qemu-stream-cmdline'] = '' params['cpu_info'] = self._get_cpu_xml() params['disks'] = self._get_disks_xml(vm_uuid) params['serial'] = get_serial_xml(params) graphics = dict(self.info['graphics']) graphics.update(kwargs.get('graphics', {})) params['graphics'] = get_graphics_xml(graphics) libvirt_stream_protocols = kwargs.get('libvirt_stream_protocols', []) cdrom_xml = self._get_cdrom_xml(libvirt_stream_protocols) if not urlparse.urlparse(self.info.get('cdrom', "")).scheme in \ libvirt_stream_protocols and \ params.get('iso_stream', False): params['qemu-stream-cmdline'] = cdrom_xml else: params['cdroms'] = cdrom_xml # Setting maximum number of slots to avoid errors when hotplug memory # Number of slots are the numbers of chunks of 1GB that fit inside # the max_memory of the host minus memory assigned to the VM. It # cannot have more than 32 slots in Power. params['slots'] = ( (params['max_memory'] >> 10) - params['memory']) >> 10 if params['slots'] < 0: raise OperationFailed("KCHVM0041E") elif params['slots'] == 0: params['slots'] = 1 elif params['slots'] > 32: distro, _, _ = platform.linux_distribution() if distro == "IBM_PowerKVM": params['slots'] = 32 xml = """ <domain type='%(domain)s'> %(qemu-stream-cmdline)s <name>%(name)s</name> <uuid>%(uuid)s</uuid> <maxMemory slots='%(slots)s' unit='KiB'>%(max_memory)s</maxMemory> <memory unit='MiB'>%(memory)s</memory> <vcpu>%(cpus)s</vcpu> %(cpu_info)s <os> <type arch='%(arch)s'>hvm</type> <boot dev='hd'/> <boot dev='cdrom'/> </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> %(disks)s %(cdroms)s %(networks)s %(graphics)s %(input_output)s %(serial)s <memballoon model='virtio' /> </devices> </domain> """ % params return xml
def create(cls, poolArgs): for klass in cls.__subclasses__(): if poolArgs['type'] == klass.poolType: return klass(poolArgs) raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']})
def _get_repos(self): try: repos = self._sourceslist() except Exception, e: raise OperationFailed('GGBREPOS0025E', {'err': e.message})
def lookup(self, name): if ARCH.startswith('s390x'): return self.get_smt_status_s390x() else: raise OperationFailed("GINSMT0013E", {'name': ARCH})
def __init__(self, args, scan=False, netboot=False): """ Construct a VM Template from a widely variable amount of information. The only required parameter is a name for the VMTemplate. If present, the os_distro and os_version fields are used to lookup recommended settings. Any parameters provided by the caller will override the defaults. If scan is True and a cdrom or a base img is present, the operating system will be detected by probing the installation media. If netboot is True, no cdrom or base img will be used to boot the VM. """ self.info = {} self.fc_host_support = args.get('fc_host_support') # Fetch defaults based on the os distro and version if netboot: distro = version = 'unknown' else: try: distro, version = self._get_os_info(args, scan) except ImageFormatError as e: raise OperationFailed('KCHTMPL0020E', {'err': e.message}) os_distro = args.get('os_distro', distro) os_version = args.get('os_version', version) entry = osinfo.lookup(os_distro, os_version) self.info.update(entry) # Auto-generate a template name if no one is passed if 'name' not in args or args['name'] == '': args['name'] = self._gen_name(distro, version) self.name = args['name'] # Merge graphics settings graph_args = args.get('graphics') if graph_args: graphics = dict(self.info['graphics']) graphics.update(graph_args) args['graphics'] = graphics default_disk = self.info['disks'][0] # Complete memory args, because dict method update is not recursive if 'memory' in args: if 'current' not in args['memory']: args['memory']['current'] = self.info['memory']['current'] if 'maxmemory' not in args['memory']: args['memory']['maxmemory'] = self.info['memory']['maxmemory'] # Override template values according to 'args' self.info.update(args) disks = self.info.get('disks') basic_disk = ['index', 'format', 'pool', 'size'] basic_path_disk = ['index', 'format', 'path', 'size'] ro_disk = ['index', 'format', 'pool', 'volume'] base_disk = ['index', 'base', 'pool', 'size', 'format'] base_path_disk = ['index', 'base', 'path', 'size', 'format'] for index, disk in enumerate(disks): disk_info = dict(default_disk) if is_s390x(): # Default disk should have either pool or path. if 'pool' not in default_disk and 'path' not in default_disk: raise InvalidParameter('KCHTMPL0040E') # Each disk should have either pool or path. # if not then use "default_disk" configuration. pool = disk.get('pool') path = disk.get('path') if not path and not pool: # If default disk is path then set disk with default path if default_disk.get('path'): path = default_disk.get('path') # If default disk is pool then set disk with default pool elif default_disk.get('pool'): pool = default_disk.get('pool') else: pool = disk.get('pool', default_disk.get('pool')) if pool: pool_type = self._get_storage_type(pool['name']) if pool_type in ['iscsi', 'scsi']: disk_info = {'index': 0, 'format': 'raw', 'volume': None} # This check is required where 'pool' disk # has to be added and hence default path # has to be removed during template update. if 'path' in disk_info: del disk_info['path'] disk_info.update(disk) pool_name = disk_info.get('pool', {}).get('name') if pool_name is None: raise MissingParameter('KCHTMPL0028E') keys = sorted(disk_info.keys()) if ((keys != sorted(basic_disk)) and (keys != sorted(ro_disk)) and (keys != sorted(base_disk))): # Addition check required only on s390x if not is_s390x() or (keys != sorted(basic_path_disk)): raise MissingParameter('KCHTMPL0028E') if pool_type in ['logical', 'iscsi', 'scsi']: if disk_info['format'] != 'raw': raise InvalidParameter('KCHTMPL0029E') disk_info['pool']['type'] = pool_type disk_info['index'] = disk_info.get('index', index) self.info['disks'][index] = disk_info elif is_s390x(): # This check is required where 'path' disk # has to be added and hence default pool # has to be removed during template update. if 'pool' in disk_info: del disk_info['pool'] disk_info.update(disk) keys = sorted(disk_info.keys()) if ((keys != sorted(basic_path_disk)) and (keys != sorted(base_path_disk))): raise MissingParameter('KCHTMPL0042E') disk_info['path'] = path disk_info['index'] = disk_info.get('index', index) self.info['disks'][index] = disk_info
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) driver = 'vfio' if self.caps.kernel_vfio else 'kvm' # 'vfio' systems requires a usb controller in order to support pci # hotplug on Power. if driver == 'vfio' and platform.machine().startswith('ppc') and \ DOM_STATE_MAP[dom.info()[0]] != "shutoff" and \ not self.have_usb_controller(vmid): msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid}) cb(msg.get_text(), False) raise InvalidOperation("KCHVMHDEV0008E", {'vmid': vmid}) # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [ self.dev_model.lookup(dev_name) for dev_name in group_names ] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifuction: try to attach all functions together within one # xml file. It requires libvirt support. if is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: # If operation fails, we try the other way, where each # function is attached individually pass else: rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return # attach each function individually (multi or single function) for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
class HostModel(object): def __init__(self, **kargs): # self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.task = TaskModel(**kargs) self.host_info = self._get_host_info() def _get_ppc_cpu_info(self): res = {} with open('/proc/cpuinfo') as f: for line in f.xreadlines(): # Parse CPU, CPU's revision and CPU's clock information for key in ['cpu', 'revision', 'clock']: if key in line: info = line.split(':')[1].strip() if key == 'clock': value = float(info.split('MHz')[0].strip()) / 1000 else: value = info.split('(')[0].strip() res[key] = value # Power machines show, for each cpu/core, a block with # all cpu information. Here we control the scan of the # necessary information (1st block provides # everything), skipping the function when find all # information. if len(res.keys()) == 3: return "%(cpu)s (%(revision)s) @ %(clock)s GHz\ " % res return "" def _get_host_info(self): res = {} if platform.machine().startswith('ppc'): res['cpu_model'] = self._get_ppc_cpu_info() else: with open('/proc/cpuinfo') as f: for line in f.xreadlines(): if "model name" in line: res['cpu_model'] = line.split(':')[1].strip() break res['cpus'] = 0 res['memory'] = 0L # Include IBM PowerKVM name to supported distro names _sup_distros = platform._supported_dists + ('ibm_powerkvm', ) # 'fedora' '17' 'Beefy Miracle' distro, version, codename = platform.linux_distribution( supported_dists=_sup_distros) res['os_distro'] = distro res['os_version'] = version res['os_codename'] = unicode(codename, "utf-8") return res def lookup(self, *name): cpus = psutil.NUM_CPUS # psutil is unstable on how to get the number of # cpus, different versions call it differently if hasattr(psutil, 'cpu_count'): cpus = psutil.cpu_count() elif hasattr(psutil, 'NUM_CPUS'): cpus = psutil.NUM_CPUS elif hasattr(psutil, '_psplatform'): for method_name in ['_get_num_cpus', 'get_num_cpus']: method = getattr(psutil._psplatform, method_name, None) if method is not None: cpus = method() break self.host_info['cpus'] = cpus if hasattr(psutil, 'phymem_usage'): self.host_info['memory'] = psutil.phymem_usage().total elif hasattr(psutil, 'virtual_memory'): self.host_info['memory'] = psutil.virtual_memory().total return self.host_info def swupdate(self, *name): try: swupdate = SoftwareUpdate() except: raise OperationFailed('GGBPKGUPD0004E') pkgs = swupdate.getNumOfUpdates() if pkgs == 0: raise OperationFailed('GGBPKGUPD0001E') wok_log.debug('Host is going to be updated.') taskid = add_task('/plugins/gingerbase/host/swupdate', swupdate.doUpdate, self.objstore, None) return self.task.lookup(taskid) def shutdown(self, args=None): # Check for running vms before shutdown running_vms = self.get_vmlist_bystate('running') if len(running_vms) > 0: raise OperationFailed("GGBHOST0001E") wok_log.info('Host is going to shutdown.') os.system('shutdown -h now') def reboot(self, args=None): # Check for running vms before reboot running_vms = self.get_vmlist_bystate('running') if len(running_vms) > 0: raise OperationFailed("GGBHOST0002E") wok_log.info('Host is going to reboot.') os.system('reboot') def get_vmlist_bystate(self, state='running'): try: libvirt_mod = __import__('libvirt') except Exception, e: wok_log.info("Unable to import libvirt module. Details:", e.message) # Ignore any error and assume there is no vm running in the host return [] try: conn = libvirt_mod.open(None) return [ dom.name().decode('utf-8') for dom in conn.listAllDomains(0) if (DOM_STATE_MAP[dom.info()[0]] == state) ] except Exception, e: wok_log.info( "Unable to get virtual machines information. " "Details:", e.message) raise OperationFailed("GGBHOST0003E")
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) # Due to libvirt limitation, we don't support live assigne device # to vfio driver. driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and self.caps.kernel_vfio else 'kvm') # on powerkvm systems it must be vfio driver. distro, _, _ = platform.linux_distribution() if distro == 'IBM_PowerKVM': driver = 'vfio' # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [ self.dev_model.lookup(dev_name) for dev_name in group_names ] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifunction hotplug is a special case where all functions # must be attached together within one xml file, the same does # not happen to multifunction coldplug - where each function # is attached individually if DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and \ is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach mutifunction device VM %s: \n%s', vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)