Ejemplo n.º 1
0
 def delete(self, name):
     try:
         utils._remove_lv(name)
     except OperationFailed as e:
         raise OperationFailed("GINLV00006E", {'err': e.message})
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    def get_list(self):
        if self.host_swupdate is None:
            raise OperationFailed('GGBPKGUPD0004E')

        return self.host_swupdate.getUpdates()
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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']
Ejemplo n.º 6
0
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})
Ejemplo n.º 7
0
            })

        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':
Ejemplo n.º 8
0
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})
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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})
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
    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:
Ejemplo n.º 15
0
 def _event_loop_run(self):
     while True:
         if libvirt.virEventRunDefaultImpl() < 0:
             raise OperationFailed('KCHEVENT0003E')
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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})
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
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})
Ejemplo n.º 20
0
 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})
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
 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)
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
 def create(cls, poolArgs):
     for klass in cls.__subclasses__():
         if poolArgs['type'] == klass.poolType:
             return klass(poolArgs)
     raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']})
Ejemplo n.º 25
0
 def _get_repos(self):
     try:
         repos = self._sourceslist()
     except Exception, e:
         raise OperationFailed('GGBREPOS0025E', {'err': e.message})
Ejemplo n.º 26
0
 def lookup(self, name):
     if ARCH.startswith('s390x'):
         return self.get_smt_status_s390x()
     else:
         raise OperationFailed("GINSMT0013E", {'name': ARCH})
Ejemplo n.º 27
0
    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
Ejemplo n.º 28
0
    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)
Ejemplo n.º 29
0
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")
Ejemplo n.º 30
0
    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)