def certificate_service_replace_certificate():
    if not flask.request.json:
        raise error.BadRequest("Empty or malformed certificate")

    try:
        cert_string = flask.request.json['CertificateString']
        cert_type = flask.request.json['CertificateType']
        cert_uri = flask.request.json['CertificateUri']
    except KeyError as exc:
        raise error.BadRequest(f"Missing required parameter {exc}")

    match = _VMEDIA_URI_PATTERN.search(cert_uri)
    if not match:
        raise error.NotFound(
            f"Certificates at URI {cert_uri} are not supported")

    if cert_type != 'PEM':
        raise error.BadRequest(
            f"Only PEM certificates are supported, got {cert_type}")

    manager_id, device, cert_id = match.groups()

    flask.current_app.managers.get_manager(manager_id)
    flask.current_app.vmedia.replace_certificate(
        manager_id, device, cert_id, cert_string, cert_type)

    return '', 204
Exemple #2
0
def virtual_media_add_certificate(identity, device):
    flask.current_app.managers.get_manager(identity)
    if not flask.request.json:
        raise error.BadRequest("Empty or malformed certificate")

    try:
        cert_string = flask.request.json['CertificateString']
        cert_type = flask.request.json['CertificateType']
    except KeyError as exc:
        raise error.BadRequest(f"Missing required parameter {exc}")

    if cert_type != 'PEM':
        raise error.BadRequest(
            f"Only PEM certificates are supported, got {cert_type}")

    api_utils.debug('Adding certificate for virtual media %s at '
                    'manager "%s"', device, identity)

    cert = flask.current_app.vmedia.add_certificate(
        identity, device, cert_string, cert_type)

    location = (
        f'/redfish/v1/Managers/{identity}/VirtualMedia/{device}'
        f'/Certificates/{cert.id}'
    )
    return '', 204, {'Location': location}
Exemple #3
0
    def _remove_boot_images(self, domain, domain_tree, device):

        identity = domain.UUIDString()

        try:
            lv_device = self.BOOT_DEVICE_MAP[device]

        except KeyError:
            raise error.BadRequest('Unknown device %s at %s' %
                                   (device, identity))

        device_element = domain_tree.find('devices')
        if device_element is None:
            msg = ('Missing "devices" tag in the libvirt domain '
                   '"%(identity)s" configuration' % {
                       'identity': identity
                   })
            raise error.FishyError(msg)

        # Remove all existing devices
        disk_elements = device_element.findall('disk')

        for disk_element in disk_elements:
            dev_type = disk_element.attrib.get('device')
            if dev_type == lv_device:
                device_element.remove(disk_element)
Exemple #4
0
    def set_boot_device(self, identity, boot_source):
        """Set computer system boot device name

        :param identity: OpenStack instance name or ID
        :param boot_source: string literal requesting boot device
            change on the system. Valid values are: *Pxe*, *Hdd*, *Cd*.

        :raises: `error.FishyError` if boot device can't be set
        """
        instance = self._get_instance(identity)

        try:
            target = self.BOOT_DEVICE_MAP[boot_source]

        except KeyError:
            msg = ('Unknown power state requested: '
                   '%(boot_source)s' % {'boot_source': boot_source})

            raise error.BadRequest(msg)

        # NOTE(etingof): the following probably only works with
        # libvirt-backed compute nodes
        self._cc.compute.set_server_metadata(
            instance.id, **{'libvirt:pxe-first': '1'
                            if target == 'network' else ''}
        )
Exemple #5
0
def virtual_media_patch(identity, device):
    flask.current_app.managers.get_manager(identity)
    if not flask.request.json:
        raise error.BadRequest("Empty or malformed patch")

    api_utils.debug('Updating virtual media %s at manager "%s"',
                    device, identity)

    verify = flask.request.json.get('VerifyCertificate')
    if verify is not None:
        if not isinstance(verify, bool):
            raise error.BadRequest("VerifyCertificate must be a boolean")

        flask.current_app.vmedia.update_device_info(
            identity, device, verify=verify)
        return '', 204
    else:
        raise error.BadRequest("Empty or malformed patch")
Exemple #6
0
    def set_power_state(self, identity, state):
        """Set computer system power state

        :param identity: OpenStack instance name or ID
        :param state: string literal requesting power state transition.
            Valid values  are: *On*, *ForceOn*, *ForceOff*, *GracefulShutdown*,
            *GracefulRestart*, *ForceRestart*, *Nmi*.

        :raises: `error.FishyError` if power state can't be set

        """
        instance = self._get_instance(identity)

        if state in ('On', 'ForceOn'):
            if instance.power_state != self.NOVA_POWER_STATE_ON:
                self._cc.compute.start_server(instance.id)

        elif state == 'ForceOff':
            if instance.power_state == self.NOVA_POWER_STATE_ON:
                self._cc.compute.stop_server(instance.id)

        elif state == 'GracefulShutdown':
            if instance.power_state == self.NOVA_POWER_STATE_ON:
                self._cc.compute.stop_server(instance.id)

        elif state == 'GracefulRestart':
            if instance.power_state == self.NOVA_POWER_STATE_ON:
                self._cc.compute.reboot_server(
                    instance.id, reboot_type='SOFT'
                )

        elif state == 'ForceRestart':
            if instance.power_state == self.NOVA_POWER_STATE_ON:
                self._cc.compute.reboot_server(
                    instance.id, reboot_type='HARD'
                )

        # NOTE(etingof) can't support `state == "Nmi"` as
        # openstacksdk does not seem to support that
        else:
            raise error.BadRequest(
                'Unknown ResetType "%(state)s"' % {'state': state})
Exemple #7
0
    def _add_boot_image(self, domain, domain_tree, device, boot_image,
                        write_protected):

        identity = domain.UUIDString()

        device_element = domain_tree.find('devices')
        if device_element is None:
            msg = ('Missing "devices" tag in the libvirt domain '
                   '"%(identity)s" configuration' % {
                       'identity': identity
                   })
            raise error.FishyError(msg)

        controller_type = self._default_controller(domain_tree)

        with libvirt_open(self._uri) as conn:

            image_path = self._upload_image(domain, conn, boot_image)

            try:
                lv_device = self.BOOT_DEVICE_MAP[device]

            except KeyError:
                raise error.BadRequest('Unknown device %s at %s' %
                                       (device, identity))

            disk_elements = device_element.findall('disk')
            for disk_element in disk_elements:
                target_element = disk_element.find('target')
                if target_element is None:
                    continue
                elif target_element.attrib.get('bus') == 'scsi':
                    controller_type = 'scsi'
                elif target_element.attrib.get('bus') == 'sata':
                    controller_type = 'sata'

            if controller_type == 'ide':
                tgt_dev, tgt_bus = self.DEVICE_TARGET_MAP[device]
            elif lv_device == 'floppy':
                tgt_dev, tgt_bus = ('fda', 'fdc')
            else:
                tgt_dev, tgt_bus = ('sdx', controller_type)

            # Enumerate existing disks to find a free unit on the bus

            free_units = {i for i in range(100)}

            disk_elements = device_element.findall('disk')

            for disk_element in disk_elements:
                target_element = disk_element.find('target')
                if target_element is None:
                    continue

                bus_type = target_element.attrib.get('bus')
                if bus_type != tgt_bus:
                    continue

                address_element = disk_element.find('address')
                if address_element is None:
                    continue

                unit_num = address_element.attrib.get('unit')
                if unit_num is None:
                    continue

                if int(unit_num) in free_units:
                    free_units.remove(int(unit_num))

            if not free_units:
                msg = ('No free %(bus)s bus unit found in the libvirt domain '
                       '"%(identity)s" configuration' % {
                           'identity': identity,
                           'bus': tgt_bus
                       })
                raise error.FishyError(msg)

            # Add disk element pointing to the boot image

            disk_element = ET.SubElement(device_element, 'disk')
            disk_element.set('type', 'file')
            disk_element.set('device', lv_device)

            target_element = ET.SubElement(disk_element, 'target')
            target_element.set('dev', tgt_dev)
            target_element.set('bus', tgt_bus)

            address_element = ET.SubElement(disk_element, 'address')
            address_element.set('type', 'drive')
            address_element.set('controller', '0')
            address_element.set('bus', '0')
            address_element.set('target', '0')
            address_element.set('unit', '%s' % min(free_units))

            driver_element = ET.SubElement(disk_element, 'driver')
            driver_element.set('name', 'qemu')
            driver_element.set('type', 'raw')

            source_element = ET.SubElement(disk_element, 'source')
            source_element.set('file', image_path)

            if write_protected:
                ET.SubElement(disk_element, 'readonly')
Exemple #8
0
    def set_boot_mode(self, identity, boot_mode):
        """Set computer system boot mode.

        :param identity: libvirt domain name or ID

        :param boot_mode: string literal requesting boot mode
            change on the system. Valid values are: *UEFI*, *Legacy*.

        :raises: `error.FishyError` if boot mode can't be set
        """
        domain = self._get_domain(identity, readonly=True)

        # XML schema: https://libvirt.org/formatdomain.html#elementsOSBIOS
        tree = ET.fromstring(domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))

        try:
            loader_type = self.BOOT_MODE_MAP[boot_mode]

        except KeyError:
            msg = ('Unknown boot mode requested: '
                   '%(boot_mode)s' % {
                       'boot_mode': boot_mode
                   })

            raise error.BadRequest(msg)

        os_elements = tree.findall('os')
        if len(os_elements) != 1:
            msg = ('Can\'t set boot mode because "os" element must be present '
                   'exactly once in domain "%(identity)s" '
                   'configuration' % {
                       'identity': identity
                   })
            raise error.FishyError(msg)

        os_element = os_elements[0]

        type_element = os_element.find('type')
        if type_element is None:
            os_arch = None

        else:
            os_arch = type_element.get('arch')

        try:
            loader_path = self.BOOT_LOADER_MAP[boot_mode][os_arch]

        except KeyError:
            self._logger.warning(
                'Boot loader binary is not configured for '
                'boot mode %s and OS architecture %s. '
                'Assuming default boot loader for the domain.', boot_mode,
                os_arch)
            loader_path = None

        loader_elements = os_element.findall('loader')
        if len(loader_elements) > 1:
            msg = ('Can\'t set boot mode because "loader" element must be '
                   'present exactly once in domain "%(identity)s" '
                   'configuration' % {
                       'identity': identity
                   })
            raise error.FishyError(msg)

        if loader_elements:
            loader_element = loader_elements[0]

            if loader_element.text not in self.KNOWN_BOOT_LOADERS:
                msg = ('Unknown boot loader path "%(path)s" in domain '
                       '"%(identity)s" configuration encountered while '
                       'setting boot mode "%(mode)s", system architecture '
                       '"%(arch)s". Consider adding this loader path to '
                       'emulator config.' % {
                           'identity': identity,
                           'mode': boot_mode,
                           'arch': os_arch,
                           'path': loader_element.text
                       })
                raise error.FishyError(msg)

            if loader_path:
                loader_element.set('type', loader_type)
                loader_element.set('readonly', 'yes')
                loader_element.text = loader_path

            else:
                # NOTE(etingof): path must be present or element must be absent
                os_element.remove(loader_element)

        elif loader_path:
            loader_element = ET.SubElement(os_element, 'loader')
            loader_element.set('type', loader_type)
            loader_element.set('readonly', 'yes')
            loader_element.text = loader_path

        with libvirt_open(self._uri) as conn:

            try:
                conn.defineXML(ET.tostring(tree).decode('utf-8'))

            except libvirt.libvirtError as e:
                msg = ('Error changing boot mode at libvirt URI '
                       '"%(uri)s": %(error)s' % {
                           'uri': self._uri,
                           'error': e
                       })

                raise error.FishyError(msg)