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
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}
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)
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 ''} )
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")
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})
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')
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)