package org.ovirt.engine.core.vdsbroker.builder.vminfo; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.codec.CharEncoding; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.FeatureSupported; import org.ovirt.engine.core.common.businessentities.ArchitectureType; import org.ovirt.engine.core.common.businessentities.ChipsetType; import org.ovirt.engine.core.common.businessentities.DisplayType; import org.ovirt.engine.core.common.businessentities.GraphicsInfo; import org.ovirt.engine.core.common.businessentities.GraphicsType; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType; import org.ovirt.engine.core.common.businessentities.VmDeviceId; import org.ovirt.engine.core.common.businessentities.VmPayload; import org.ovirt.engine.core.common.businessentities.comparators.LexoNumericNameableComparator; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.network.NetworkCluster; import org.ovirt.engine.core.common.businessentities.network.NetworkFilter; import org.ovirt.engine.core.common.businessentities.network.NetworkQoS; import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType; import org.ovirt.engine.core.common.businessentities.network.VmNic; import org.ovirt.engine.core.common.businessentities.network.VmNicFilterParameter; import org.ovirt.engine.core.common.businessentities.network.VnicProfile; import org.ovirt.engine.core.common.businessentities.qos.StorageQos; import org.ovirt.engine.core.common.businessentities.storage.CinderConnectionInfo; import org.ovirt.engine.core.common.businessentities.storage.CinderDisk; import org.ovirt.engine.core.common.businessentities.storage.CinderVolumeDriver; import org.ovirt.engine.core.common.businessentities.storage.Disk; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.DiskInterface; import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement; import org.ovirt.engine.core.common.businessentities.storage.PropagateErrors; import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.osinfo.OsRepository; import org.ovirt.engine.core.common.utils.SimpleDependencyInjector; import org.ovirt.engine.core.common.utils.VmDeviceCommonUtils; import org.ovirt.engine.core.common.utils.VmDeviceType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.WindowsJavaTimezoneMapping; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl; import org.ovirt.engine.core.dao.VmDeviceDao; import org.ovirt.engine.core.dao.network.NetworkClusterDao; import org.ovirt.engine.core.dao.network.NetworkDao; import org.ovirt.engine.core.dao.network.NetworkFilterDao; import org.ovirt.engine.core.dao.network.NetworkQoSDao; import org.ovirt.engine.core.dao.network.VmNicFilterParameterDao; import org.ovirt.engine.core.dao.network.VnicProfileDao; import org.ovirt.engine.core.dao.qos.StorageQosDao; import org.ovirt.engine.core.utils.NetworkUtils; import org.ovirt.engine.core.utils.StringMapUtils; import org.ovirt.engine.core.utils.archstrategy.ArchStrategyFactory; import org.ovirt.engine.core.utils.collections.ComparatorUtils; import org.ovirt.engine.core.vdsbroker.architecture.GetControllerIndices; import org.ovirt.engine.core.vdsbroker.vdsbroker.IoTuneUtils; import org.ovirt.engine.core.vdsbroker.vdsbroker.NetworkQosMapper; import org.ovirt.engine.core.vdsbroker.vdsbroker.VdsProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class VmInfoBuildUtils { private static final Logger log = LoggerFactory.getLogger(VmInfoBuildUtils.class); private static final String FIRST_MASTER_MODEL = "ich9-ehci1"; private static final String CLOUD_INIT_VOL_ID = "config-2"; private static final Base64 BASE_64 = new Base64(0, null); private final NetworkClusterDao networkClusterDao; private final NetworkDao networkDao; private final NetworkFilterDao networkFilterDao; private final NetworkQoSDao networkQosDao; private final StorageQosDao storageQosDao; private final VmDeviceDao vmDeviceDao; private final VnicProfileDao vnicProfileDao; private final VmNicFilterParameterDao vmNicFilterParameterDao; private OsRepository osRepository = SimpleDependencyInjector.getInstance().get(OsRepository.class); @Inject VmInfoBuildUtils( NetworkDao networkDao, NetworkFilterDao networkFilterDao, NetworkQoSDao networkQosDao, StorageQosDao storageQosDao, VmDeviceDao vmDeviceDao, VnicProfileDao vnicProfileDao, VmNicFilterParameterDao vmNicFilterParameterDao, NetworkClusterDao networkClusterDao) { this.networkDao = Objects.requireNonNull(networkDao); this.networkFilterDao = Objects.requireNonNull(networkFilterDao); this.networkQosDao = Objects.requireNonNull(networkQosDao); this.storageQosDao = Objects.requireNonNull(storageQosDao); this.vmDeviceDao = Objects.requireNonNull(vmDeviceDao); this.vnicProfileDao = Objects.requireNonNull(vnicProfileDao); this.vmNicFilterParameterDao = Objects.requireNonNull(vmNicFilterParameterDao); this.networkClusterDao = Objects.requireNonNull(networkClusterDao); } OsRepository getOsRepository() { return SimpleDependencyInjector.getInstance().get(OsRepository.class); } @SuppressWarnings("unchecked") public void buildCinderDisk(CinderDisk cinderDisk, Map<String, Object> struct) { CinderConnectionInfo connectionInfo = cinderDisk.getCinderConnectionInfo(); CinderVolumeDriver cinderVolumeDriver = CinderVolumeDriver.forValue(connectionInfo.getDriverVolumeType()); if (cinderVolumeDriver == null) { log.error("Unsupported Cinder volume driver: '{}' (disk: '{}')", connectionInfo.getDriverVolumeType(), cinderDisk.getDiskAlias()); return; } switch (cinderVolumeDriver) { case RBD: Map<String, Object> connectionInfoData = cinderDisk.getCinderConnectionInfo().getData(); struct.put(VdsProperties.Path, connectionInfoData.get("name")); struct.put(VdsProperties.Format, VolumeFormat.RAW.toString().toLowerCase()); struct.put(VdsProperties.PropagateErrors, PropagateErrors.Off.toString().toLowerCase()); struct.put(VdsProperties.Protocol, cinderDisk.getCinderConnectionInfo().getDriverVolumeType()); struct.put(VdsProperties.DiskType, VdsProperties.NETWORK); List<String> hostAddresses = (ArrayList<String>) connectionInfoData.get("hosts"); List<String> hostPorts = (ArrayList<String>) connectionInfoData.get("ports"); List<Map<String, Object>> hosts = new ArrayList<>(); // Looping over hosts addresses to create 'hosts' element // (Cinder should ensure that the addresses and ports lists are synced in order). for (int i = 0; i < hostAddresses.size(); i++) { Map<String, Object> hostMap = new HashMap<>(); hostMap.put(VdsProperties.NetworkDiskName, hostAddresses.get(i)); hostMap.put(VdsProperties.NetworkDiskPort, hostPorts.get(i)); hostMap.put(VdsProperties.NetworkDiskTransport, VdsProperties.Tcp); hosts.add(hostMap); } struct.put(VdsProperties.NetworkDiskHosts, hosts); boolean authEnabled = (boolean) connectionInfoData.get(VdsProperties.CinderAuthEnabled); String secretType = (String) connectionInfoData.get(VdsProperties.CinderSecretType); String authUsername = (String) connectionInfoData.get(VdsProperties.CinderAuthUsername); String secretUuid = (String) connectionInfoData.get(VdsProperties.CinderSecretUuid); if (authEnabled) { Map<String, Object> authMap = new HashMap<>(); authMap.put(VdsProperties.NetworkDiskAuthSecretType, secretType); authMap.put(VdsProperties.NetworkDiskAuthUsername, authUsername); authMap.put(VdsProperties.NetworkDiskAuthSecretUuid, secretUuid); struct.put(VdsProperties.NetworkDiskAuth, authMap); } break; } } /** * Prepare the ioTune limits map and add it to the specParams if supported by the cluster * * @param vmDevice The disk device with QoS limits * @param storageQos StorageQos */ public void handleIoTune(VmDevice vmDevice, StorageQos storageQos) { if (storageQos != null) { if (vmDevice.getSpecParams() == null) { vmDevice.setSpecParams(new HashMap<>()); } vmDevice.getSpecParams().put(VdsProperties.Iotune, IoTuneUtils.ioTuneMapFrom(storageQos)); } } public StorageQos loadStorageQos(DiskImage diskImage) { if (diskImage.getDiskProfileId() == null) { return null; } return storageQosDao.getQosByDiskProfileId(diskImage.getDiskProfileId()); } public String evaluateInterfaceType(VmInterfaceType ifaceType, boolean vmHasAgent) { return ifaceType == VmInterfaceType.rtl8139_pv ? vmHasAgent ? VmInterfaceType.pv.name() : VmInterfaceType.rtl8139.name() : ifaceType.getInternalName(); } public void addNetworkVirtualFunctionProperties(Map<String, Object> struct, VmNic vmInterface, VmDevice vmDevice, String vfName, VM vm) { struct.put(VdsProperties.Type, vmDevice.getType().getValue()); struct.put(VdsProperties.Device, vmDevice.getDevice()); struct.put(VdsProperties.HostDev, vfName); addAddress(vmDevice, struct); struct.put(VdsProperties.MAC_ADDR, vmInterface.getMacAddress()); struct.put(VdsProperties.DeviceId, String.valueOf(vmDevice.getId().getDeviceId())); Map<String, Object> specParams = new HashMap<>(); VnicProfile vnicProfile = vnicProfileDao.get(vmInterface.getVnicProfileId()); Network network = networkDao.get(vnicProfile.getNetworkId()); if (NetworkUtils.isVlan(network)) { specParams.put(VdsProperties.VLAN_ID, network.getVlanId()); } struct.put(VdsProperties.SpecParams, specParams); addCustomPropertiesForDevice(struct, vm, vmDevice, getVnicCustomProperties(vnicProfile)); } public void addProfileDataToNic(Map<String, Object> struct, VM vm, VmDevice vmDevice, VmNic nic) { VnicProfile vnicProfile = null; Network network = null; String networkName = ""; List<VnicProfileProperties> unsupportedFeatures = new ArrayList<>(); if (nic.getVnicProfileId() != null) { vnicProfile = vnicProfileDao.get(nic.getVnicProfileId()); if (vnicProfile != null) { network = networkDao.get(vnicProfile.getNetworkId()); networkName = network.getName(); log.debug("VNIC '{}' is using profile '{}' on network '{}'", nic.getName(), vnicProfile, networkName); addQosForDevice(struct, vnicProfile); } } struct.put(VdsProperties.NETWORK, networkName); addPortMirroringToVmInterface(struct, vnicProfile, network); addCustomPropertiesForDevice(struct, vm, vmDevice, getVnicCustomProperties(vnicProfile)); reportUnsupportedVnicProfileFeatures(vm, nic, vnicProfile, unsupportedFeatures); } private void addPortMirroringToVmInterface(Map<String, Object> struct, VnicProfile vnicProfile, Network network) { if (vnicProfile != null && vnicProfile.isPortMirroring()) { struct.put( VdsProperties.PORT_MIRRORING, network == null ? Collections.<String> emptyList() : Collections.singletonList(network.getName())); } } private void addQosForDevice(Map<String, Object> struct, VnicProfile vnicProfile) { Guid qosId = vnicProfile.getNetworkQosId(); @SuppressWarnings("unchecked") Map<String, Object> specParams = (Map<String, Object>) struct.get(VdsProperties.SpecParams); if (specParams == null) { specParams = new HashMap<>(); struct.put(VdsProperties.SpecParams, specParams); } NetworkQoS networkQoS = (qosId == null) ? new NetworkQoS() : networkQosDao.get(qosId); NetworkQosMapper qosMapper = new NetworkQosMapper(specParams, VdsProperties.QOS_INBOUND, VdsProperties.QOS_OUTBOUND); qosMapper.serialize(networkQoS); } private Map<String, String> getVnicCustomProperties(VnicProfile vnicProfile) { Map<String, String> customProperties = null; if (vnicProfile != null) { customProperties = vnicProfile.getCustomProperties(); } return customProperties == null ? new HashMap<>() : customProperties; } private void addCustomPropertiesForDevice(Map<String, Object> struct, VM vm, VmDevice vmDevice, Map<String, String> customProperties) { if (customProperties == null) { customProperties = new HashMap<>(); } customProperties.putAll(vmDevice.getCustomProperties()); Map<String, String> runtimeCustomProperties = vm.getRuntimeDeviceCustomProperties().get(vmDevice.getId()); if (runtimeCustomProperties != null) { customProperties.putAll(runtimeCustomProperties); } if (!customProperties.isEmpty()) { struct.put(VdsProperties.Custom, customProperties); } } public void addNetworkFiltersToNic(Map<String, Object> struct, VmNic vmNic) { final NetworkFilter networkFilter = fetchVnicProfileNetworkFilter(vmNic); if (networkFilter != null) { final String networkFilterName = networkFilter.getName(); struct.put(VdsProperties.NW_FILTER, networkFilterName); final List<VmNicFilterParameter> vmNicFilterParameters = vmNicFilterParameterDao.getAllForVmNic(vmNic.getId()); struct.put(VdsProperties.NETWORK_FILTER_PARAMETERS, mapVmNicFilterParameter(vmNicFilterParameters)); } } private List<Map<String, Object>> mapVmNicFilterParameter(List<VmNicFilterParameter> vmNicFilterParameters) { return vmNicFilterParameters.stream().map(this::mapVmNicFilterParameter).collect(Collectors.toList()); } private Map<String, Object> mapVmNicFilterParameter(VmNicFilterParameter nicFilterParameter) { Map<String, Object> parameter = new HashMap<>(); parameter.put("name", nicFilterParameter.getName()); parameter.put("value", nicFilterParameter.getValue()); return parameter; } protected NetworkFilter fetchVnicProfileNetworkFilter(VmNic vmNic) { if (vmNic.getVnicProfileId() != null) { VnicProfile vnicProfile = vnicProfileDao.get(vmNic.getVnicProfileId()); if (vnicProfile != null) { final Guid networkFilterId = vnicProfile.getNetworkFilterId(); return networkFilterId == null ? null : networkFilterDao.getNetworkFilterById(networkFilterId); } } return null; } Map<String, Object> buildFloppyDetails(VmDevice vmDevice) { Map<String, Object> struct = new HashMap<>(); struct.put(VdsProperties.Type, vmDevice.getType().getValue()); struct.put(VdsProperties.Device, vmDevice.getDevice()); struct.put(VdsProperties.Index, "0"); // IDE slot 2 is reserved by VDSM to CDROM struct.put(VdsProperties.INTERFACE, VdsProperties.Fdc); struct.put(VdsProperties.ReadOnly, String.valueOf(vmDevice.getReadOnly())); struct.put(VdsProperties.Shareable, Boolean.FALSE.toString()); return struct; } Map<String, Object> buildCdDetails(VmDevice vmDevice, VM vm) { Map<String, Object> struct = new HashMap<>(); struct.put(VdsProperties.Type, vmDevice.getType().getValue()); struct.put(VdsProperties.Device, vmDevice.getDevice()); String cdInterface = getOsRepository().getCdInterface( vm.getOs(), vm.getCompatibilityVersion(), ChipsetType.fromMachineType(vm.getEmulatedMachine())); struct.put(VdsProperties.INTERFACE, cdInterface); int index = VmDeviceCommonUtils.getCdDeviceIndex(cdInterface); struct.put(VdsProperties.Index, Integer.toString(index)); if ("scsi".equals(cdInterface)) { struct.put(VdsProperties.Address, createAddressForScsiDisk(0, index)); } struct.put(VdsProperties.ReadOnly, Boolean.TRUE.toString()); struct.put(VdsProperties.Shareable, Boolean.FALSE.toString()); return struct; } void setVdsPropertiesFromSpecParams(Map<String, Object> specParams, Map<String, Object> struct) { Set<Entry<String, Object>> values = specParams.entrySet(); for (Entry<String, Object> currEntry : values) { if (currEntry.getValue() instanceof String) { struct.put(currEntry.getKey(), currEntry.getValue()); } else if (currEntry.getValue() instanceof Map) { struct.put(currEntry.getKey(), currEntry.getValue()); } } } /** * This method returns true if it is the first master model It is used due to the requirement to send this device * before the other controllers. There is an open bug on libvirt on that. Until then we make sure it is passed * first. */ boolean isFirstMasterController(String model) { return model.equalsIgnoreCase(FIRST_MASTER_MODEL); } /** * @return A map of VirtIO-SCSI index to a map of disk's index in that VirtIO-SCSI controller: * for example: * (0 -> (disk1 -> 0, disk2 -> 1)), * (1 -> (disk3 -> 0, disk4 -> 1)) * means that there are two controllers, 0 and 1. On the 0 there are 2 disks, first mapped to 0 and second to 1 * inside that particular controller. Similar for second controller. */ public Map<Integer, Map<VmDevice, Integer>> getVmDeviceUnitMapForVirtioScsiDisks(VM vm) { return getVmDeviceUnitMapForScsiDisks(vm, DiskInterface.VirtIO_SCSI, false); } /** * @return A map of sPAPR VSCSI index to a map of disk's index in that sPAPR VSCSI controller: * for example: * (0 -> (disk1 -> 0, disk2 -> 1)), * (1 -> (disk3 -> 0, disk4 -> 1)) * means that there are two controllers, 0 and 1. On the 0 there are 2 disks, first mapped to 0 and second to 1 * inside that particular controller. Similar for second controller. */ public Map<Integer, Map<VmDevice, Integer>> getVmDeviceUnitMapForSpaprScsiDisks(VM vm) { return getVmDeviceUnitMapForScsiDisks(vm, DiskInterface.SPAPR_VSCSI, true); } protected Map<Integer, Map<VmDevice, Integer>> getVmDeviceUnitMapForScsiDisks(VM vm, DiskInterface scsiInterface, boolean reserveFirstTwoLuns) { List<Disk> disks = getSortedDisks(vm); Map<Integer, Map<VmDevice, Integer>> vmDeviceUnitMap = new HashMap<>(); LinkedList<VmDevice> vmDeviceList = new LinkedList<>(); for (Disk disk : disks) { DiskVmElement dve = disk.getDiskVmElementForVm(vm.getId()); if (dve.getDiskInterface() == scsiInterface) { VmDevice vmDevice = getVmDeviceByDiskId(disk.getId(), vm.getId()); Map<String, String> address = StringMapUtils.string2Map(vmDevice.getAddress()); String unitStr = address.get(VdsProperties.Unit); String controllerStr = address.get(VdsProperties.Controller); // If unit property is available adding to 'vmDeviceUnitMap'; // Otherwise, adding to 'vmDeviceList' for setting the unit property later. if (StringUtils.isNotEmpty(unitStr) && StringUtils.isNotEmpty(controllerStr)) { Integer controllerInt = Integer.valueOf(controllerStr); boolean controllerOutOfRange = controllerInt >= vm.getNumOfIoThreads() + getDefaultVirtioScsiIndex(vm); boolean ioThreadsEnabled = vm.getNumOfIoThreads() > 0 && FeatureSupported.virtioScsiIoThread(vm.getCompatibilityVersion()); if ((ioThreadsEnabled && !controllerOutOfRange) || (controllerInt == getDefaultVirtioScsiIndex(vm))) { if (!vmDeviceUnitMap.containsKey(controllerInt)) { vmDeviceUnitMap.put(controllerInt, new HashMap<>()); } vmDeviceUnitMap.get(controllerInt).put(vmDevice, Integer.valueOf(unitStr)); } else { // controller id not correct, generate the address again later vmDevice.setAddress(null); vmDeviceList.add(vmDevice); } } else { vmDeviceList.add(vmDevice); } } } // Find available unit (disk's index in VirtIO-SCSI controller) for disks with empty address\ IntStream.range(0, vmDeviceList.size()).forEach(index -> { VmDevice vmDevice = vmDeviceList.get(index); int controller = getControllerForScsiDisk(vmDevice, vm, index); if (!vmDeviceUnitMap.containsKey(controller)) { vmDeviceUnitMap.put(controller, new HashMap<>()); } int unit = getAvailableUnitForScsiDisk(vmDeviceUnitMap.get(controller), reserveFirstTwoLuns); vmDeviceUnitMap.get(controller).put(vmDevice, unit); }); return vmDeviceUnitMap; } private int getDefaultVirtioScsiIndex(VM vm) { Map<DiskInterface, Integer> controllerIndexMap = ArchStrategyFactory.getStrategy(vm.getClusterArch()).run(new GetControllerIndices()).returnValue(); return controllerIndexMap.get(DiskInterface.VirtIO_SCSI); } /** * Generates the next controller id using round robin. * If the disk already has an controller id, returns it. * * @param disk the disk for which the controller id has to be generated * @param vm a VM to which this disk is attached * @param increment a number from 0..N to let the round robin cycle * @return a controller id */ public int getControllerForScsiDisk(VmDevice disk, VM vm, int increment) { Map<String, String> address = StringMapUtils.string2Map(disk.getAddress()); String controllerStr = address.get(VdsProperties.Controller); int defaultIndex = getDefaultVirtioScsiIndex(vm); boolean ioThreadsEnabled = FeatureSupported.virtioScsiIoThread(vm.getCompatibilityVersion()); if (!ioThreadsEnabled) { // no io threads, only 1 controller allowed and it is the default one return defaultIndex; } if (StringUtils.isNotEmpty(controllerStr)) { int controllerInt = Integer.parseInt(controllerStr); boolean controllerOutOfRange = controllerInt > vm.getNumOfIoThreads() + getDefaultVirtioScsiIndex(vm); if (!controllerOutOfRange) { // io threads enabled and the controller in range, use it return controllerInt; } } // Here it can end up either if the controller has not been set or it has been set but it is out of range. // Out of range it can be when: // The VM was started with, say, 2 io threads and this disk had the controller id set to 1 // Than the VM has been turned off, set the io threads to 1 and ran the VM again. In that case this disk will // be out of range. // In both cases the controller index needs to be generated again. if (vm.getNumOfIoThreads() > 0) { // the num of IO threads equals to num of controllers // the result of this will be a round robin over the controller indexes from the default index return increment % vm.getNumOfIoThreads() + defaultIndex; } return defaultIndex; } public List<Disk> getSortedDisks(VM vm) { // order first by drive numbers and then order by boot for the bootable // drive to be first (important for IDE to be index 0) ! List<Disk> disks = new ArrayList<>(vm.getDiskMap().values()); Collections.sort(disks, new LexoNumericNameableComparator<>()); Collections.sort(disks, Collections.reverseOrder(new DiskByBootAndSnapshotComparator(vm.getId()))); return disks; } public int getAvailableUnitForScsiDisk(Map<VmDevice, Integer> vmDeviceUnitMap, boolean reserveFirstTwoLuns) { int unit = reserveFirstTwoLuns ? 2 : 0; if (vmDeviceUnitMap == null) { return unit; } while (vmDeviceUnitMap.containsValue(unit)) { unit++; } return unit; } public Map<String, String> createAddressForScsiDisk(int controller, int unit) { Map<String, String> addressMap = new HashMap<>(); addressMap.put(VdsProperties.Type, "drive"); addressMap.put(VdsProperties.Controller, String.valueOf(controller)); addressMap.put(VdsProperties.Bus, "0"); addressMap.put(VdsProperties.target, "0"); addressMap.put(VdsProperties.Unit, String.valueOf(unit)); return addressMap; } void addAddress(VmDevice vmDevice, Map<String, Object> struct) { Map<String, String> addressMap = StringMapUtils.string2Map(vmDevice.getAddress()); if (!addressMap.isEmpty()) { struct.put(VdsProperties.Address, addressMap); } } VmDevice getVmDeviceByDiskId(Guid diskId, Guid vmId) { // get vm device for this disk from DB return vmDeviceDao.get(new VmDeviceId(diskId, vmId)); } private void reportUnsupportedVnicProfileFeatures(VM vm, VmNic nic, VnicProfile vnicProfile, List<VnicProfileProperties> unsupportedFeatures) { if (unsupportedFeatures.isEmpty()) { return; } AuditLogable event = new AuditLogableImpl(); event.setVmId(vm.getId()); event.setVmName(vm.getName()); event.setClusterId(vm.getClusterId()); event.setClusterName(vm.getClusterName()); event.setCustomId(nic.getId().toString()); event.setCompatibilityVersion(vm.getCompatibilityVersion().toString()); event.addCustomValue("NicName", nic.getName()); event.addCustomValue("VnicProfile", vnicProfile == null ? null : vnicProfile.getName()); String[] unsupportedFeatureNames = new String[unsupportedFeatures.size()]; for (int i = 0; i < unsupportedFeatures.size(); i++) { unsupportedFeatureNames[i] = unsupportedFeatures.get(i).getFeatureName(); } event.addCustomValue("UnsupportedFeatures", StringUtils.join(unsupportedFeatureNames, ", ")); new AuditLogDirector().log(event, AuditLogType.VNIC_PROFILE_UNSUPPORTED_FEATURES); } public Network getDisplayNetwork(VM vm) { List<NetworkCluster> all = networkClusterDao.getAllForCluster(vm.getClusterId()); NetworkCluster networkCluster = null; for (NetworkCluster tempNetworkCluster : all) { if (tempNetworkCluster.isDisplay()) { networkCluster = tempNetworkCluster; break; } } if (networkCluster != null) { List<Network> allNetworks = networkDao.getAll(); for (Network tempNetwork : allNetworks) { if (tempNetwork.getId().equals(networkCluster.getNetworkId())) { return tempNetwork; } } } return null; } private String getTimeZoneForVm(VM vm) { if (!StringUtils.isEmpty(vm.getTimeZone())) { return vm.getTimeZone(); } // else fallback to engine config default for given OS type if (osRepository.isWindows(vm.getOs())) { return Config.getValue(ConfigValues.DefaultWindowsTimeZone); } else { return "Etc/GMT"; } } public int getVmTimeZone(VM vm) { // get vm timezone String timeZone = getTimeZoneForVm(vm); final String javaZoneId; if (osRepository.isWindows(vm.getOs())) { // convert to java & calculate offset javaZoneId = WindowsJavaTimezoneMapping.get(timeZone); } else { javaZoneId = timeZone; } int offset = 0; if (javaZoneId != null) { offset = TimeZone.getTimeZone(javaZoneId).getOffset( new Date().getTime()) / 1000; } return offset; } public String getEmulatedMachineByClusterArch(ArchitectureType arch) { switch(arch) { case ppc64: case ppc64le: return "pseries"; case x86_64: default: return "pc"; } } public VmDevice createVideoDeviceByDisplayType(DisplayType displayType, Guid vmId) { VmDevice vmDevice = new VmDevice(); vmDevice.setId(new VmDeviceId(Guid.newGuid(), vmId)); vmDevice.setType(VmDeviceGeneralType.VIDEO); vmDevice.setDevice(displayType.getDefaultVmDeviceType().getName()); vmDevice.setPlugged(true); vmDevice.setAddress(""); return vmDevice; } public void addVmGraphicsOptions(Map<GraphicsType, GraphicsInfo> infos, Map<String, Object> params, VM vm) { if (infos != null && infos.containsKey(GraphicsType.SPICE)) { params.put(VdsProperties.spiceFileTransferEnable, Boolean.toString(vm.isSpiceFileTransferEnabled())); params.put(VdsProperties.spiceCopyPasteEnable, Boolean.toString(vm.isSpiceCopyPasteEnabled())); if (Config.getValue(ConfigValues.SSLEnabled)) { params.put(VdsProperties.SpiceSecureChannels, Config.getValue( ConfigValues.SpiceSecureChannels, vm.getCompatibilityVersion().toString())); } } if (infos != null && infos.containsKey(GraphicsType.VNC)) { String keyboardLayout = vm.getDynamicData().getVncKeyboardLayout(); if (keyboardLayout == null) { keyboardLayout = vm.getDefaultVncKeyboardLayout(); if (keyboardLayout == null) { keyboardLayout = Config.getValue(ConfigValues.VncKeyboardLayout); } } params.put(VdsProperties.KeyboardMap, keyboardLayout); } } public List<VmDevice> createGraphicsDevices( Map<GraphicsType, GraphicsInfo> graphicsInfos, Map<String, Object> extraSpecParams, Guid vmId) { final Comparator<GraphicsType> spiceLastComparator = ComparatorUtils.sortLast(GraphicsType.SPICE); final List<Entry<GraphicsType, GraphicsInfo>> sortedGraphicsInfos = graphicsInfos.entrySet().stream() .sorted(Comparator.comparing(Entry::getKey, spiceLastComparator)) .collect(Collectors.toList()); List<VmDevice> result = new ArrayList<>(); for (Entry<GraphicsType, GraphicsInfo> graphicsInfo : sortedGraphicsInfos) { VmDevice device = new VmDevice(); device.setId(new VmDeviceId(Guid.newGuid(), vmId)); device.setType(VmDeviceGeneralType.GRAPHICS); device.setDevice(graphicsInfo.getKey().name().toLowerCase()); device.setPlugged(true); device.setAddress(""); if (extraSpecParams != null) { device.setSpecParams(extraSpecParams); } result.add(device); } return result; } /** * See {@link VmInfoBuildUtilsTest#testMakeDiskName()} */ public String makeDiskName(String diskInterface, int index) { String devIndex = ""; while (index > 0) { devIndex = (char)('a' + (index % 26)) + devIndex; index /= 26; } return diskInterfaceToDevName(diskInterface) + (devIndex.isEmpty() ? 'a' : devIndex); } private String diskInterfaceToDevName(String iface) { switch(iface) { case "virtio": return "vd"; case "fdc": return "fd"; case "scsi": case "sata": return "sd"; case "ide": default: return "hd"; } } public VmDevice createSysprepPayloadDevice(String sysPrepContent, VM vm) { // We do not validate the size of the content being passed to the VM payload by VmPayload.isPayloadSizeLegal(). // The sysprep file size isn't being verified for 3.0 clusters and below, so we maintain the same behavior here. VmPayload vmPayload = new VmPayload(); vmPayload.setDeviceType(VmDeviceType.FLOPPY); vmPayload.getFiles().put( getOsRepository().getSysprepFileName(vm.getOs(), vm.getCompatibilityVersion()), new String(BASE_64.encode(sysPrepContent.getBytes()), Charset.forName(CharEncoding.UTF_8))); return new VmDevice(new VmDeviceId(Guid.newGuid(), vm.getId()), VmDeviceGeneralType.DISK, VmDeviceType.FLOPPY.getName(), "", vmPayload.getSpecParams(), true, true, true, "", null, null, null); } public VmDevice createCloudInitPayloadDevice(Map<String, byte[]> cloudInitContent, VM vm) { VmPayload vmPayload = new VmPayload(); vmPayload.setDeviceType(VmDeviceType.CDROM); vmPayload.setVolumeId(CLOUD_INIT_VOL_ID); for (Entry<String, byte[]> entry : cloudInitContent.entrySet()) { vmPayload.getFiles().put(entry.getKey(), new String(BASE_64.encode(entry.getValue()), Charset.forName(CharEncoding.UTF_8))); } return new VmDevice(new VmDeviceId(Guid.newGuid(), vm.getId()), VmDeviceGeneralType.DISK, VmDeviceType.CDROM.getName(), "", vmPayload.getSpecParams(), true, true, true, "", null, null, null); } public VmDevice createFloppyDevice(VM vm) { return new VmDevice(new VmDeviceId(Guid.newGuid(), vm.getId()), VmDeviceGeneralType.DISK, VmDeviceType.FLOPPY.getName(), "", null, true, true, true, "", null, null, null); } }