diff options
author | Stephan Schwär | 2021-02-19 00:09:54 +0100 |
---|---|---|
committer | Stephan Schwär | 2021-02-19 00:09:54 +0100 |
commit | 62dce8c2b4e519f689e89038ff2afe4496f60628 (patch) | |
tree | 7c6802a436e2beb943065b5a377b61eb77d93170 /src/main/java/org/openslx/util/vm/QemuMetaData.java | |
parent | [docker] Check recieved content. (diff) | |
parent | Add automatic RelaxNG schema validation for Libvirt domain XML documents (diff) | |
download | master-sync-shared-62dce8c2b4e519f689e89038ff2afe4496f60628.tar.gz master-sync-shared-62dce8c2b4e519f689e89038ff2afe4496f60628.tar.xz master-sync-shared-62dce8c2b4e519f689e89038ff2afe4496f60628.zip |
Merge remote-tracking branch 'origin/feature/qemu-integration'
Diffstat (limited to 'src/main/java/org/openslx/util/vm/QemuMetaData.java')
-rw-r--r-- | src/main/java/org/openslx/util/vm/QemuMetaData.java | 797 |
1 files changed, 709 insertions, 88 deletions
diff --git a/src/main/java/org/openslx/util/vm/QemuMetaData.java b/src/main/java/org/openslx/util/vm/QemuMetaData.java index 201ffd8..d3b8451 100644 --- a/src/main/java/org/openslx/util/vm/QemuMetaData.java +++ b/src/main/java/org/openslx/util/vm/QemuMetaData.java @@ -1,233 +1,854 @@ package org.openslx.util.vm; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; -import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.OperatingSystem; import org.openslx.bwlp.thrift.iface.Virtualizer; +import org.openslx.libvirt.domain.Domain; +import org.openslx.libvirt.domain.device.ControllerUsb; +import org.openslx.libvirt.domain.device.Disk.BusType; +import org.openslx.libvirt.domain.device.Disk.StorageType; +import org.openslx.libvirt.domain.device.DiskCdrom; +import org.openslx.libvirt.domain.device.DiskFloppy; +import org.openslx.libvirt.domain.device.DiskStorage; +import org.openslx.libvirt.domain.device.Graphics; +import org.openslx.libvirt.domain.device.GraphicsSpice; +import org.openslx.libvirt.domain.device.Interface; +import org.openslx.libvirt.domain.device.Sound; +import org.openslx.libvirt.domain.device.Video; +import org.openslx.libvirt.xml.LibvirtXmlDocumentException; +import org.openslx.libvirt.xml.LibvirtXmlSerializationException; +import org.openslx.libvirt.xml.LibvirtXmlValidationException; import org.openslx.thrifthelper.TConst; import org.openslx.util.vm.DiskImage.ImageFormat; -import org.openslx.util.vm.DiskImage.UnknownImageFormatException; -public class QemuMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta, VBoxHWVersionMeta, VBoxEthernetDevTypeMeta, VBoxUsbSpeedMeta> +/** + * Metadata to describe the hardware type of a QEMU sound card. + * + * @author Manuel Bentele + * @version 1.0 + */ +class QemuSoundCardMeta { + /** + * Stores the hardware model of the QEMU sound card. + */ + private final Sound.Model model; + + /** + * Creates metadata to describe the hardware model of a QEMU sound card. + * + * @param model hardware model of the QEMU sound card. + */ + public QemuSoundCardMeta( Sound.Model model ) + { + this.model = model; + } - private final Map<String, String> arguments = new HashMap<String, String>(); - // the above map's elements will take the place of <args> in the config string - private String config; - private static final Logger LOGGER = Logger.getLogger( QemuMetaData.class ); + /** + * Returns hardware model of the QEMU sound card. + * + * @return hardware model of the QEMU sound card. + */ + public Sound.Model getModel() + { + return this.model; + } +} - private static final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_QEMU, "QEMU-KVM" ); +/** + * Metadata to describe the hardware acceleration state of QEMU virtual graphics. + * + * @author Manuel Bentele + * @version 1.0 + */ +class QemuDDAccelMeta +{ + /** + * Stores state of the hardware acceleration for QEMU virtual graphics. + */ + private final boolean enabled; + + /** + * Creates metadata to describe the hardware acceleration state of QEMU virtual graphics. + * + * @param enabled state of the hardware acceleration for QEMU virtual graphics. + */ + public QemuDDAccelMeta( boolean enabled ) + { + this.enabled = enabled; + } - public QemuMetaData( List<OperatingSystem> osList, File file ) throws FileNotFoundException, IOException, UnsupportedVirtualizerFormatException + /** + * Returns state of the hardware acceleration of QEMU virtual graphics. + * + * @return state of the hardware acceleration for QEMU virtual graphics. + */ + public boolean isEnabled() + { + return this.enabled; + } +} + +/** + * Metadata to describe the version of a QEMU virtual machine configuration. + * + * @author Manuel Bentele + * @version 1.0 + */ +class QemuHWVersionMeta +{ + /** + * Stores the version of a QEMU virtual machine configuration. + */ + private final int version; + + /** + * Creates metadata to describe the version of a QEMU virtual machine configuration. + * + * @param version version of the QEMU virtual machine configuration. + */ + public QemuHWVersionMeta( int version ) + { + this.version = version; + } + + /** + * Returns version of the QEMU virtual machine configuration. + * + * @return version of the QEMU virtual machine configuration. + */ + public int getVersion() + { + return this.version; + } +} + +/** + * Metadata to describe the hardware type of a QEMU ethernet device. + * + * @author Manuel Bentele + * @version 1.0 + */ +class QemuEthernetDevTypeMeta +{ + /** + * Stores the hardware model of the QEMU ethernet device. + */ + private final Interface.Model model; + + /** + * Creates metadata to describe the hardware type of a QEMU ethernet device. + * + * @param model hardware type of the QEMU ethernet device. + */ + public QemuEthernetDevTypeMeta( Interface.Model model ) + { + this.model = model; + } + + /** + * Returns the hardware type of a QEMU ethernet device. + * + * @return hardware type of the QEMU ethernet device. + */ + public Interface.Model getModel() + { + return this.model; + } +} + +/** + * Metadata to describe a QEMU USB controller. + * + * @author Manuel Bentele + * @version 1.0 + */ +class QemuUsbSpeedMeta +{ + /** + * Stores the USB speed of the QEMU USB controller. + */ + private final int speed; + + /** + * Stores the QEMU hardware model of the USB controller. + */ + private final ControllerUsb.Model model; + + /** + * Creates metadata to describe a QEMU USB controller. + * + * @param speed USB speed of the QEMU USB controller. + * @param model QEMU hardware model of the USB controller. + */ + public QemuUsbSpeedMeta( int speed, ControllerUsb.Model model ) + { + this.speed = speed; + this.model = model; + } + + /** + * Returns the speed of the QEMU USB controller. + * + * @return speed of the QEMU USB controller. + */ + public int getSpeed() + { + return this.speed; + } + + /** + * Returns QEMU hardware model of the USB controller. + * + * @return hardware model of the QEMU USB controller. + */ + public ControllerUsb.Model getModel() + { + return this.model; + } +} + +/** + * Virtual machine configuration (managed by Libvirt) for the QEMU hypervisor. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class QemuMetaData extends + VmMetaData<QemuSoundCardMeta, QemuDDAccelMeta, QemuHWVersionMeta, QemuEthernetDevTypeMeta, QemuUsbSpeedMeta> +{ + /** + * Default bridge name of the network bridge connected to the LAN. + */ + public static final String NETWORK_DEFAULT_BRIDGE = "brBwLehrpool"; + + /** + * Default network name of the isolated host network (host only). + */ + public static final String NETWORK_DEFAULT_HOST_ONLY = "host"; + + /** + * Default network name of the NAT network. + */ + public static final String NETWORK_DEFAULT_NAT = "nat"; + + /** + * Default physical CDROM drive of the hypervisor host. + */ + public static final String CDROM_DEFAULT_PHYSICAL_DRIVE = "/dev/sr0"; + + /** + * List of supported image formats by the QEMU hypervisor. + */ + private static final List<DiskImage.ImageFormat> SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableList( + Arrays.asList( ImageFormat.QCOW2, ImageFormat.VMDK, ImageFormat.VDI ) ); + + /** + * Representation of a QEMU hypervisor (managed by Libvirt). + */ + private static final Virtualizer VIRTUALIZER = new Virtualizer( TConst.VIRT_QEMU, "QEMU" ); + + /** + * Libvirt XML configuration file to modify configuration of virtual machine for QEMU. + */ + private Domain vmConfig = null; + + /** + * Stores current index of added HDD device to the Libvirt XML configuration file. + */ + private int vmDeviceIndexHddAdd = 0; + + /** + * Stores current index of added CDROM device to the Libvirt XML configuration file. + */ + private int vmDeviceIndexCdromAdd = 0; + + /** + * Stores current index of added ethernet device to the Libvirt XML configuration file. + */ + private int vmDeviceIndexEthernetAdd = 0; + + /** + * Creates new virtual machine configuration (managed by Libvirt) for the QEMU hypervisor. + * + * @param osList list of operating systems. + * @param file image file for the QEMU hypervisor. + * @throws UnsupportedVirtualizerFormatException Libvirt XML configuration cannot be processed. + */ + public QemuMetaData( List<OperatingSystem> osList, File file ) throws UnsupportedVirtualizerFormatException { super( osList ); - DiskImage di; + try { - di = new DiskImage( file ); - } catch ( UnknownImageFormatException e ) { - di = null; + // read and parse Libvirt domain XML configuration document + this.vmConfig = new Domain( file ); + } catch ( LibvirtXmlDocumentException e ) { + throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() ); + } catch ( LibvirtXmlSerializationException e ) { + throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() ); + } catch ( LibvirtXmlValidationException e ) { + throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() ); } - if ( di == null || di.format != ImageFormat.QCOW2 ) { - throw new UnsupportedVirtualizerFormatException( "This is not a qcow2 disk image" ); + + // register virtual hardware models for graphical editing of virtual devices (GPU, sound, USB, ...) + this.registerVirtualHW(); + + // set display name of VM + this.displayName = vmConfig.getName(); + + // this property cannot be checked with the Libvirt domain XML configuration + // to check if machine is in a paused/suspended state, look in the QEMU qcow2 image for snapshots and machine states + this.isMachineSnapshot = false; + + // add HDDs, SSDs to QEMU metadata + for ( DiskStorage storageDiskDevice : this.vmConfig.getDiskStorageDevices() ) { + this.addHddMetaData( storageDiskDevice ); } - config = "qemu-system-i386 <args> <image> -enable-kvm\nqemu-system-x86_64 <args> <image> -enable-kvm"; - displayName = file.getName().substring( 0, file.getName().indexOf( "." ) ); - setOs( "anyOs" ); - hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, file.getAbsolutePath() ) ); - makeStartSequence(); } - // initiates the arguments map with a default working sequence that will later be used in the definition array - public void makeStartSequence() + /** + * Adds an existing and observed storage disk device to the HDD metadata. + * + * @param storageDiskDevice existing and observed storage disk that should be added to the + * metadata. + */ + private void addHddMetaData( DiskStorage storageDiskDevice ) { - arguments.put( "cpu", "host" ); - arguments.put( "smp", "2" ); - arguments.put( "m", "1024" ); - arguments.put( "vga", "std" ); + String hddChipsetModel = null; + DriveBusType hddChipsetBus = QemuMetaDataUtils.convertBusType( storageDiskDevice.getBusType() ); + String hddImagePath = storageDiskDevice.getStorageSource(); + + this.hdds.add( new HardDisk( hddChipsetModel, hddChipsetBus, hddImagePath ) ); } - private String configWithArgs() + @Override + public byte[] getFilteredDefinitionArray() { - String tempString = ""; - for ( String key : arguments.keySet() ) { - tempString += "-" + key + " " + arguments.get( key ) + " "; - } - return config.replaceAll( "<args>", tempString ); + // remove UUID in Libvirt domain XML configuration + this.vmConfig.removeUuid(); + + // removes all specified boot order entries + this.vmConfig.removeBootOrder(); + + // removes all referenced storage files of all specified CDROMs, Floppy drives and HDDs + this.vmConfig.removeDiskDevicesStorage(); + + // removes all source networks of all specified network interfaces + this.vmConfig.removeInterfaceDevicesSource(); + + // output filtered Libvirt domain XML configuration + String configuration = this.vmConfig.toString(); + return configuration.getBytes( StandardCharsets.UTF_8 ); } @Override - public byte[] getFilteredDefinitionArray() + public List<DiskImage.ImageFormat> getSupportedImageFormats() { - return configWithArgs().getBytes( StandardCharsets.UTF_8 ); + return QemuMetaData.SUPPORTED_IMAGE_FORMATS; } @Override public void applySettingsForLocalEdit() { + // NOT implemented yet } @Override public boolean addHddTemplate( File diskImage, String hddMode, String redoDir ) { - String tempS = config.replaceAll( "<image>", diskImage.getAbsolutePath() ); - config = tempS; - hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, diskImage.getAbsolutePath() ) ); - return true; + return this.addHddTemplate( diskImage.getAbsolutePath(), hddMode, redoDir ); } @Override public boolean addHddTemplate( String diskImagePath, String hddMode, String redoDir ) { - String tempS = config.replaceAll( "<image>", diskImagePath ); - config = tempS; - hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, diskImagePath ) ); - return true; + return this.addHddTemplate( this.vmDeviceIndexHddAdd++, diskImagePath, hddMode, redoDir ); + } + + /** + * Adds hard disk drive (HDD) to the QEMU virtual machine configuration. + * + * @param index current index of HDD to be added to the virtual machine configuration. + * @param diskImagePath path to the virtual disk image for the HDD. + * @param hddMode operation mode of the HDD. + * @param redoDir directory for the redo log if an independent non-persistent + * <code>hddMode</code> is set. + * @return result state of adding the HDD. + */ + public boolean addHddTemplate( int index, String diskImagePath, String hddMode, String redoDir ) + { + ArrayList<DiskStorage> storageDiskDevices = this.vmConfig.getDiskStorageDevices(); + DiskStorage storageDiskDevice = QemuMetaDataUtils.getArrayIndex( storageDiskDevices, index ); + + if ( storageDiskDevice == null ) { + // HDD does not exist, so create new storage (HDD) device + storageDiskDevice = this.vmConfig.addDiskStorageDevice(); + storageDiskDevice.setReadOnly( false ); + storageDiskDevice.setBusType( BusType.VIRTIO ); + String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "vd", index ); + storageDiskDevice.setTargetDevice( targetDevName ); + storageDiskDevice.setStorage( StorageType.FILE, diskImagePath ); + + // add new created HDD to the metadata of the QemuMetaData object, too + this.addHddMetaData( storageDiskDevice ); + } else { + // HDD exists, so update existing storage (HDD) device + storageDiskDevice.setStorage( StorageType.FILE, diskImagePath ); + } + + return false; } @Override public boolean addDefaultNat() { - return true; + return this.addEthernet( EtherType.NAT ); } @Override public void setOs( String vendorOsId ) { - setOs( TConst.VIRT_QEMU, vendorOsId ); + this.setOs( vendorOsId ); } @Override public boolean addDisplayName( String name ) { - // TODO Auto-generated method stub - return false; + this.vmConfig.setName( name ); + + final boolean statusName = this.vmConfig.getName().equals( name ); + + return statusName; } @Override public boolean addRam( int mem ) { - this.arguments.put( "m", Integer.toString( mem ) ); - return true; + BigInteger memory = BigInteger.valueOf( mem ); + + this.vmConfig.setMemory( memory ); + this.vmConfig.setCurrentMemory( memory ); + + final boolean isMemorySet = this.vmConfig.getMemory().toString().equals( memory.toString() ); + final boolean isCurrentMemorySet = this.vmConfig.getCurrentMemory().toString().equals( memory.toString() ); + + return isMemorySet && isCurrentMemorySet; } @Override public void addFloppy( int index, String image, boolean readOnly ) { - // TODO Auto-generated method stub - + ArrayList<DiskFloppy> floppyDiskDevices = this.vmConfig.getDiskFloppyDevices(); + DiskFloppy floppyDiskDevice = QemuMetaDataUtils.getArrayIndex( floppyDiskDevices, index ); + + if ( floppyDiskDevice == null ) { + // floppy device does not exist, so create new floppy device + floppyDiskDevice = this.vmConfig.addDiskFloppyDevice(); + floppyDiskDevice.setBusType( BusType.FDC ); + String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "fd", index ); + floppyDiskDevice.setTargetDevice( targetDevName ); + floppyDiskDevice.setReadOnly( readOnly ); + floppyDiskDevice.setStorage( StorageType.FILE, image ); + } else { + // floppy device exists, so update existing floppy device + floppyDiskDevice.setReadOnly( readOnly ); + floppyDiskDevice.setStorage( StorageType.FILE, image ); + } } @Override public boolean addCdrom( String image ) { - // TODO Auto-generated method stub + return this.addCdrom( this.vmDeviceIndexCdromAdd++, image ); + } + + /** + * Adds CDROM drive to the QEMU virtual machine configuration. + * + * @param index current index of CDROM drive to be added to the virtual machine configuration. + * @param image path to a virtual image that will be inserted as CDROM into the drive. + * @return result state of adding the CDROM drive. + */ + public boolean addCdrom( int index, String image ) + { + ArrayList<DiskCdrom> cdromDiskDevices = this.vmConfig.getDiskCdromDevices(); + DiskCdrom cdromDiskDevice = QemuMetaDataUtils.getArrayIndex( cdromDiskDevices, index ); + + if ( cdromDiskDevice == null ) { + // CDROM device does not exist, so create new CDROM device + cdromDiskDevice = this.vmConfig.addDiskCdromDevice(); + cdromDiskDevice.setBusType( BusType.SATA ); + String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "sd", index ); + cdromDiskDevice.setTargetDevice( targetDevName ); + cdromDiskDevice.setReadOnly( true ); + + if ( image == null ) { + cdromDiskDevice.setStorage( StorageType.BLOCK, CDROM_DEFAULT_PHYSICAL_DRIVE ); + } else { + cdromDiskDevice.setStorage( StorageType.FILE, image ); + } + } else { + // CDROM device exists, so update existing CDROM device + cdromDiskDevice.setReadOnly( true ); + + if ( image == null ) { + cdromDiskDevice.setStorage( StorageType.BLOCK, CDROM_DEFAULT_PHYSICAL_DRIVE ); + } else { + cdromDiskDevice.setStorage( StorageType.FILE, image ); + } + } + return false; } @Override public boolean addCpuCoreCount( int nrOfCores ) { - this.arguments.put( "smp", Integer.toString( nrOfCores ) ); - return true; + this.vmConfig.setVCpu( nrOfCores ); + + boolean isVCpuSet = this.vmConfig.getVCpu() == nrOfCores; + + return isVCpuSet; } @Override - public void setSoundCard( VmMetaData.SoundCardType type ) + public void setSoundCard( SoundCardType type ) { + QemuSoundCardMeta soundDeviceConfig = this.soundCards.get( type ); + ArrayList<Sound> soundDevices = this.vmConfig.getSoundDevices(); + Sound.Model soundDeviceModel = soundDeviceConfig.getModel(); + + if ( soundDevices.isEmpty() ) { + // create new sound device with 'soundDeviceModel' hardware + Sound soundDevice = this.vmConfig.addSoundDevice(); + soundDevice.setModel( soundDeviceModel ); + } else { + // update sound device model type of existing sound devices + for ( Sound soundDevice : soundDevices ) { + soundDevice.setModel( soundDeviceModel ); + } + } } @Override - public VmMetaData.SoundCardType getSoundCard() + public SoundCardType getSoundCard() { - return null; + ArrayList<Sound> soundDevices = this.vmConfig.getSoundDevices(); + SoundCardType soundDeviceType = SoundCardType.DEFAULT; + + if ( soundDevices.isEmpty() ) { + // the VM configuration does not contain a sound card device + soundDeviceType = SoundCardType.NONE; + } else { + // the VM configuration at least one sound card device, so return the type of the first one + Sound.Model soundDeviceModel = soundDevices.get( 0 ).getModel(); + soundDeviceType = QemuMetaDataUtils.convertSoundDeviceModel( soundDeviceModel ); + } + + return soundDeviceType; } @Override - public void setDDAcceleration( VmMetaData.DDAcceleration type ) + public void setDDAcceleration( DDAcceleration type ) { + QemuDDAccelMeta accelerationConfig = this.ddacc.get( type ); + ArrayList<Graphics> graphicDevices = this.vmConfig.getGraphicDevices(); + ArrayList<Video> videoDevices = this.vmConfig.getVideoDevices(); + final boolean accelerationEnabled = accelerationConfig.isEnabled(); + + boolean acceleratedGraphicsAvailable = false; + + if ( graphicDevices.isEmpty() ) { + // add new graphics device with enabled acceleration to VM configuration + GraphicsSpice graphicSpiceDevice = this.vmConfig.addGraphicsSpiceDevice(); + graphicSpiceDevice.setOpenGl( true ); + acceleratedGraphicsAvailable = true; + } else { + // enable graphic acceleration of existing graphics devices + for ( Graphics graphicDevice : graphicDevices ) { + // set hardware acceleration for SPICE based graphics output + // other graphic devices do not support hardware acceleration + if ( graphicDevice instanceof GraphicsSpice ) { + GraphicsSpice.class.cast( graphicDevice ).setOpenGl( true ); + acceleratedGraphicsAvailable = true; + } + } + } + + // only configure hardware acceleration of video card(s) if graphics with hardware acceleration is available + if ( acceleratedGraphicsAvailable ) { + if ( videoDevices.isEmpty() ) { + // add new video device with enabled acceleration to VM configuration + Video videoDevice = this.vmConfig.addVideoDevice(); + videoDevice.setModel( Video.Model.VIRTIO ); + videoDevice.set2DAcceleration( true ); + videoDevice.set3DAcceleration( true ); + } else { + // enable graphic acceleration of existing graphics and video devices + for ( Video videoDevice : videoDevices ) { + // set hardware acceleration for Virtio GPUs + // other GPUs do not support hardware acceleration + if ( videoDevice.getModel() == Video.Model.VIRTIO ) { + videoDevice.set2DAcceleration( accelerationEnabled ); + videoDevice.set3DAcceleration( accelerationEnabled ); + } + } + } + } } @Override - public VmMetaData.DDAcceleration getDDAcceleration() + public DDAcceleration getDDAcceleration() { - return null; + ArrayList<Graphics> graphicsDevices = this.vmConfig.getGraphicDevices(); + ArrayList<Video> videoDevices = this.vmConfig.getVideoDevices(); + DDAcceleration accelerationState = DDAcceleration.OFF; + + boolean acceleratedGraphicsAvailable = false; + boolean acceleratedVideoDevAvailable = false; + + // search for hardware accelerated graphics + for ( Graphics graphicDevice : graphicsDevices ) { + // only SPICE based graphic devices support hardware acceleration + if ( graphicDevice instanceof GraphicsSpice ) { + acceleratedGraphicsAvailable = true; + break; + } + } + + // search for hardware accelerated video devices + for ( Video videoDevice : videoDevices ) { + // only Virtio based video devices support hardware acceleration + if ( videoDevice.getModel() == Video.Model.VIRTIO ) { + acceleratedVideoDevAvailable = true; + break; + } + } + + // hardware acceleration is available if at least one accelerated graphics and video device is available + if ( acceleratedGraphicsAvailable && acceleratedVideoDevAvailable ) { + accelerationState = DDAcceleration.ON; + } else { + accelerationState = DDAcceleration.OFF; + } + + return accelerationState; } @Override - public void setHWVersion( VmMetaData.HWVersion type ) + public void setHWVersion( HWVersion type ) { + // NOT supported by the QEMU hypervisor } @Override - public VmMetaData.HWVersion getHWVersion() + public HWVersion getHWVersion() { + // NOT supported by the QEMU hypervisor return null; } @Override - public void setEthernetDevType( int cardIndex, VmMetaData.EthernetDevType type ) + public void setEthernetDevType( int cardIndex, EthernetDevType type ) { + QemuEthernetDevTypeMeta networkDeviceConfig = this.networkCards.get( type ); + ArrayList<Interface> networkDevices = this.vmConfig.getInterfaceDevices(); + Interface networkDevice = QemuMetaDataUtils.getArrayIndex( networkDevices, cardIndex ); + Interface.Model networkDeviceModel = networkDeviceConfig.getModel(); + + if ( networkDevice != null ) { + networkDevice.setModel( networkDeviceModel ); + } } @Override - public VmMetaData.EthernetDevType getEthernetDevType( int cardIndex ) + public EthernetDevType getEthernetDevType( int cardIndex ) { - return null; + ArrayList<Interface> networkDevices = this.vmConfig.getInterfaceDevices(); + Interface networkDevice = QemuMetaDataUtils.getArrayIndex( networkDevices, cardIndex ); + EthernetDevType networkDeviceType = EthernetDevType.NONE; + + if ( networkDevice == null ) { + // network interface device is not present + networkDeviceType = EthernetDevType.NONE; + } else { + // get model of existing network interface device + Interface.Model networkDeviceModel = networkDevice.getModel(); + networkDeviceType = QemuMetaDataUtils.convertNetworkDeviceModel( networkDeviceModel ); + } + + return networkDeviceType; } @Override - public byte[] getDefinitionArray() + public void setMaxUsbSpeed( UsbSpeed speed ) { - return configWithArgs().getBytes( StandardCharsets.UTF_8 ); + QemuUsbSpeedMeta usbControllerConfig = this.usbSpeeds.get( speed ); + ArrayList<ControllerUsb> usbControllerDevices = this.vmConfig.getUsbControllerDevices(); + ControllerUsb.Model usbControllerModel = usbControllerConfig.getModel(); + + if ( usbControllerDevices.isEmpty() ) { + // add new USB controller with specified speed 'usbControllerModel' + ControllerUsb usbControllerDevice = this.vmConfig.addControllerUsbDevice(); + usbControllerDevice.setModel( usbControllerModel ); + } else { + // update model of all USB controller devices to support the maximum speed + for ( ControllerUsb usbControllerDevice : usbControllerDevices ) { + usbControllerDevice.setModel( usbControllerModel ); + } + } } @Override - public boolean addEthernet( VmMetaData.EtherType type ) + public UsbSpeed getMaxUsbSpeed() { - return false; + ArrayList<ControllerUsb> usbControllerDevices = this.vmConfig.getUsbControllerDevices(); + UsbSpeed maxUsbSpeed = VmMetaData.UsbSpeed.NONE; + int maxUsbSpeedNumeric = 0; + + for ( ControllerUsb usbControllerDevice : usbControllerDevices ) { + ControllerUsb.Model usbControllerModel = usbControllerDevice.getModel(); + + for ( Entry<UsbSpeed, QemuUsbSpeedMeta> usbSpeedEntry : this.usbSpeeds.entrySet() ) { + QemuUsbSpeedMeta usbSpeed = usbSpeedEntry.getValue(); + if ( usbSpeed.getSpeed() > maxUsbSpeedNumeric && usbSpeed.getModel() == usbControllerModel ) { + maxUsbSpeed = usbSpeedEntry.getKey(); + maxUsbSpeedNumeric = usbSpeed.getSpeed(); + } + } + } + + return maxUsbSpeed; } @Override - public Virtualizer getVirtualizer() + public byte[] getDefinitionArray() { - return virtualizer; + String configuration = this.vmConfig.toString(); + + if ( configuration == null ) { + return null; + } else { + // append newline at the end of the XML content to match the structure of an original Libvirt XML file + configuration += System.lineSeparator(); + return configuration.getBytes( StandardCharsets.UTF_8 ); + } } @Override - public boolean tweakForNonPersistent() + public boolean addEthernet( EtherType type ) + { + return this.addEthernet( this.vmDeviceIndexEthernetAdd++, type ); + } + + /** + * Adds an ethernet card to the QEMU virtual machine configuration. + * + * @param index current index of the ethernet card to be added to the virtual machine + * configuration. + * @param type card model of the ethernet card. + * @return result state of adding the ethernet card. + */ + public boolean addEthernet( int index, EtherType type ) { + QemuEthernetDevTypeMeta defaultNetworkDeviceConfig = this.networkCards.get( EthernetDevType.AUTO ); + ArrayList<Interface> interfaceDevices = this.vmConfig.getInterfaceDevices(); + Interface interfaceDevice = QemuMetaDataUtils.getArrayIndex( interfaceDevices, index ); + + final Interface.Model defaultNetworkDeviceModel = defaultNetworkDeviceConfig.getModel(); + + if ( interfaceDevice == null ) { + // network interface device does not exist, so create new network interface device + switch ( type ) { + case BRIDGED: + // add network bridge interface device + interfaceDevice = this.vmConfig.addInterfaceBridgeDevice(); + interfaceDevice.setModel( defaultNetworkDeviceModel ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_BRIDGE ); + break; + case HOST_ONLY: + // add network interface device with link to the isolated host network + interfaceDevice = this.vmConfig.addInterfaceNetworkDevice(); + interfaceDevice.setModel( defaultNetworkDeviceModel ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_HOST_ONLY ); + break; + case NAT: + // add network interface device with link to the NAT network + interfaceDevice = this.vmConfig.addInterfaceNetworkDevice(); + interfaceDevice.setModel( defaultNetworkDeviceModel ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_NAT ); + break; + } + } else { + // network interface device exists, so update existing network interface device + switch ( type ) { + case BRIDGED: + interfaceDevice.setType( Interface.Type.BRIDGE ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_BRIDGE ); + break; + case HOST_ONLY: + interfaceDevice.setType( Interface.Type.NETWORK ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_HOST_ONLY ); + break; + case NAT: + interfaceDevice.setType( Interface.Type.NETWORK ); + interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_NAT ); + break; + } + } + return false; } @Override - public void registerVirtualHW() + public Virtualizer getVirtualizer() { + return QemuMetaData.VIRTUALIZER; } @Override - public void setMaxUsbSpeed( VmMetaData.UsbSpeed speed ) + public boolean tweakForNonPersistent() { - // TODO: Actual speed setting? - if ( speed == null || speed == VmMetaData.UsbSpeed.NONE ) { - arguments.remove( "usb" ); - } else { - arguments.put( "usb", "" ); - } + // NOT implemented yet + return false; } @Override - public VmMetaData.UsbSpeed getMaxUsbSpeed() + public void registerVirtualHW() { - if ( arguments.containsKey( "usb" ) ) - return VmMetaData.UsbSpeed.USB2_0; // TODO - return VmMetaData.UsbSpeed.NONE; + // @formatter:off + soundCards.put( VmMetaData.SoundCardType.NONE, new QemuSoundCardMeta( null ) ); + soundCards.put( VmMetaData.SoundCardType.DEFAULT, new QemuSoundCardMeta( Sound.Model.ICH9 ) ); + soundCards.put( VmMetaData.SoundCardType.SOUND_BLASTER, new QemuSoundCardMeta( Sound.Model.SB16 ) ); + soundCards.put( VmMetaData.SoundCardType.ES, new QemuSoundCardMeta( Sound.Model.ES1370 ) ); + soundCards.put( VmMetaData.SoundCardType.AC, new QemuSoundCardMeta( Sound.Model.AC97 ) ); + soundCards.put( VmMetaData.SoundCardType.HD_AUDIO, new QemuSoundCardMeta( Sound.Model.ICH9 ) ); + + ddacc.put( VmMetaData.DDAcceleration.OFF, new QemuDDAccelMeta( false ) ); + ddacc.put( VmMetaData.DDAcceleration.ON, new QemuDDAccelMeta( true ) ); + + hwversion.put( VmMetaData.HWVersion.DEFAULT, new QemuHWVersionMeta( 0 ) ); + + networkCards.put( VmMetaData.EthernetDevType.NONE, new QemuEthernetDevTypeMeta( null ) ); + networkCards.put( VmMetaData.EthernetDevType.AUTO, new QemuEthernetDevTypeMeta( Interface.Model.VIRTIO_NET_PCI ) ); + networkCards.put( VmMetaData.EthernetDevType.PCNETPCI2, new QemuEthernetDevTypeMeta( Interface.Model.PCNET ) ); + networkCards.put( VmMetaData.EthernetDevType.E1000, new QemuEthernetDevTypeMeta( Interface.Model.E1000 ) ); + networkCards.put( VmMetaData.EthernetDevType.E1000E, new QemuEthernetDevTypeMeta( Interface.Model.E1000E ) ); + networkCards.put( VmMetaData.EthernetDevType.VMXNET3, new QemuEthernetDevTypeMeta( Interface.Model.VMXNET3 ) ); + networkCards.put( VmMetaData.EthernetDevType.PARAVIRT, new QemuEthernetDevTypeMeta( Interface.Model.VIRTIO_NET_PCI ) ); + + usbSpeeds.put( VmMetaData.UsbSpeed.NONE, new QemuUsbSpeedMeta( 0, ControllerUsb.Model.NONE ) ); + usbSpeeds.put( VmMetaData.UsbSpeed.USB1_1, new QemuUsbSpeedMeta( 1, ControllerUsb.Model.ICH9_UHCI1 ) ); + usbSpeeds.put( VmMetaData.UsbSpeed.USB2_0, new QemuUsbSpeedMeta( 2, ControllerUsb.Model.ICH9_EHCI1 ) ); + usbSpeeds.put( VmMetaData.UsbSpeed.USB3_0, new QemuUsbSpeedMeta( 3, ControllerUsb.Model.QEMU_XHCI ) ); + // @formatter:on } - } |