package org.openslx.virtualization.configuration; import java.util.ArrayList; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openslx.libvirt.domain.Domain; import org.openslx.libvirt.domain.device.Disk; import org.openslx.libvirt.domain.device.Disk.BusType; import org.openslx.virtualization.Version; import org.openslx.virtualization.configuration.VirtualizationConfiguration.DriveBusType; /** * Collection of utils to convert data types from bwLehrpool to Libvirt and vice versa. * * @author Manuel Bentele * @version 1.0 */ public class VirtualizationConfigurationQemuUtils { /** * Separator symbol between Libvirt/QEMU machine name and machine version. */ private static final String OS_MACHINE_NAME_VERSION_SEPARATOR = "-"; /** * Converts a Libvirt disk device bus type to a VM metadata driver bus type. * * @param busType Libvirt disk device bus type. * @return VM metadata bus type of the disk drive. */ public static DriveBusType convertBusType( Disk.BusType busType ) { DriveBusType type = null; if ( busType == null ) return null; switch ( busType ) { case IDE: type = DriveBusType.IDE; break; case SATA: type = DriveBusType.SATA; break; case SCSI: type = DriveBusType.SCSI; break; default: type = null; break; } return type; } /** * Converts a VM metadata driver bus type to a Libvirt disk device bus type. * * @param busType VM metadata bus type of the disk drive. * @return Libvirt disk device bus type. */ public static Disk.BusType convertBusType( DriveBusType busType ) { Disk.BusType type = null; switch ( busType ) { case IDE: type = BusType.IDE; break; case NVME: type = null; break; case SATA: type = BusType.SATA; break; case SCSI: type = BusType.SCSI; break; } return type; } /** * Returns an item from a given {@link ArrayList}. * * The item is selected by a given index. If the item is not available within the * {@link ArrayList}, null is returned. * * @param type of the {@link ArrayList}. * @param array {@link ArrayList} of type T. * @param index selects the item from the {@link ArrayList}. * @return selected item of the {@link ArrayList}. */ public static T getArrayIndex( ArrayList array, int index ) { T ret; try { ret = array.get( index ); } catch ( IndexOutOfBoundsException e ) { ret = null; } return ret; } /** * Creates an alphabetical device name constructed from a device prefix and a device number. * * @param devicePrefix prefix of the constructed device name. * @param deviceNumber number of the device. * @return alphabetical device name. */ private static String createAlphabeticalDeviceName( String devicePrefix, int deviceNumber ) { if ( deviceNumber < 0 || deviceNumber >= ( 'z' - 'a' ) ) { String errorMsg = "Device number is out of range to be able to create a valid device name."; throw new IllegalArgumentException( errorMsg ); } return devicePrefix + Character.valueOf( (char) ( 'a' + deviceNumber ) ).toString(); } /** * Creates an alphabetical device name for a disk device with a bus type that is unique in * a Libvirt domain XML configuration. * * @param config Libvirt domain XML configuration. * @param type device type for device name. * @return alphabetical device name. */ public static String createDeviceName( final Domain config, final BusType type ) throws IllegalArgumentException { final String devicePrefix; final int deviceNumber; switch ( type ) { case FDC: devicePrefix = "fd"; break; case IDE: devicePrefix = "hd"; break; case SATA: devicePrefix = "sd"; break; case VIRTIO: devicePrefix = "vd"; break; default: return null; } final Predicate bySpecifiedBusType = d -> d.getBusType() == type; deviceNumber = Long.valueOf( config.getDiskDevices().stream().filter( bySpecifiedBusType ).count() ).intValue(); return VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( devicePrefix, deviceNumber ); } /** * Data container to store a Libvirt/QEMU machine name with version information. * * @author Manuel Bentele * @version 1.0 */ static class OsMachineNameAndVersion { /** * Stores the machine name. */ final private String osMachineName; /** * Stores the machine version. */ final private Version osMachineVersion; /** * Creates a data container for a machine name with version information. * * @param osMachineName name of the machine. * @param osMachineVersion version of the machine. */ public OsMachineNameAndVersion( String osMachineName, Version osMachineVersion ) { this.osMachineName = osMachineName; this.osMachineVersion = osMachineVersion; } /** * Returns the machine name. * * @return machine name. */ public String getOsMachineName() { return this.osMachineName; } /** * Returns the version information. * * @return version information. */ public Version getOsMachineVersion() { return this.osMachineVersion; } } /** * Parses a machine name with version information from a Libvirt/QEMU machine description. * * @param osMachine Libvirt/QEMU machine description as {@link String}. * @return data container containing the parsed machine name with version information. */ private static OsMachineNameAndVersion parseOsMachineNameAndVersion( String osMachine ) { final String osMachineName; final Version osMachineVersion; if ( osMachine == null || osMachine.isEmpty() ) { // there is no machine description given, so we can not parse anything osMachineName = null; osMachineVersion = null; } else { // create regular expression based matcher to extract machine name and version number final Pattern osMachineNameAndVersionPattern = Pattern.compile( "^([a-z0-9\\-]+)" + VirtualizationConfigurationQemuUtils.OS_MACHINE_NAME_VERSION_SEPARATOR + "([0-9]+).([0-9]+)$" ); final Matcher osMachineNameAndVersionMatcher = osMachineNameAndVersionPattern.matcher( osMachine ); final boolean matches = osMachineNameAndVersionMatcher.find(); if ( matches ) { // get results of regular expression based matcher osMachineName = osMachineNameAndVersionMatcher.group( 1 ); final String osMachineMajorString = osMachineNameAndVersionMatcher.group( 2 ); final String osMachineMinorString = osMachineNameAndVersionMatcher.group( 3 ); // create version representation final short osMachineMajor = Short.valueOf( osMachineMajorString ); final short osMachineMinor = Short.valueOf( osMachineMinorString ); osMachineVersion = new Version( osMachineMajor, osMachineMinor ); } else { osMachineName = null; osMachineVersion = null; } } return new OsMachineNameAndVersion( osMachineName, osMachineVersion ); } /** * Parses a machine name from a Libvirt/QEMU machine description. * * @param osMachine Libvirt/QEMU machine description as {@link String}. * @return parsed machine name. */ public static String getOsMachineName( String osMachine ) { final OsMachineNameAndVersion machineNameAndVersion = VirtualizationConfigurationQemuUtils .parseOsMachineNameAndVersion( osMachine ); return machineNameAndVersion.getOsMachineName(); } /** * Parses a machine version from a Libvirt/QEMU machine description. * * @param osMachine Libvirt/QEMU machine description as {@link String}. * @return parsed machine version. */ public static Version getOsMachineVersion( String osMachine ) { final OsMachineNameAndVersion machineNameAndVersion = VirtualizationConfigurationQemuUtils .parseOsMachineNameAndVersion( osMachine ); return machineNameAndVersion.getOsMachineVersion(); } /** * Combines a machine name with a machine version and returns a Libvirt/QEMU machine description. * * @param osMachineName name of the machine. * @param osMachineVersion version of the machine. * @return Libvirt/QEMU machine description. */ public static String getOsMachine( String osMachineName, String osMachineVersion ) { return osMachineName + VirtualizationConfigurationQemuUtils.OS_MACHINE_NAME_VERSION_SEPARATOR + osMachineVersion; } /** * Converts a {@link Version} to a Libvirt/QEMU machine version. * * @param version Libvirt/QEMU machine version as {@link Version}. * @return Libvirt/QEMU machine version. */ public static String getOsMachineVersion( Version version ) { return String.format( "%d.%d", version.getMajor(), version.getMinor() ); } /** * Returns the size of a given architecture {@link String}. * * @param osArch Libvirt/QEMU machine architecture as {@link String}. * @return Size of the Libvirt/QEMU machine architecture. */ public static int getOsArchSize( String osArch ) { final int archSize; if ( osArch == null || osArch.isEmpty() ) { archSize = 0; } else { switch ( osArch ) { case "alpha": archSize = 64; break; case "armv6l": archSize = 32; break; case "armv7l": archSize = 32; break; case "aarch64": archSize = 64; break; case "cris": archSize = 32; break; case "i686": archSize = 32; break; case "m68k": archSize = 32; break; case "microblaze": archSize = 32; break; case "microblazeel": archSize = 32; break; case "mips": archSize = 32; break; case "mipsel": archSize = 32; break; case "mips64": archSize = 64; break; case "mips64el": archSize = 64; break; case "ppc": archSize = 32; break; case "ppc64": archSize = 64; break; case "ppc64le": archSize = 64; break; case "riscv32": archSize = 32; break; case "riscv64": archSize = 64; break; case "s390x": archSize = 64; break; case "sh4": archSize = 32; break; case "sh4eb": archSize = 64; break; case "sparc": archSize = 32; break; case "sparc64": archSize = 64; break; case "x86_64": archSize = 64; break; case "xtensa": archSize = 32; break; case "xtensaeb": archSize = 32; break; default: archSize = 0; } } return archSize; } }