package org.ovirt.engine.core.vdsbroker.vdsbroker;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.network.cluster.ManagementNetworkUtil;
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.AutoNumaBalanceStatus;
import org.ovirt.engine.core.common.businessentities.CpuStatistics;
import org.ovirt.engine.core.common.businessentities.DisplayType;
import org.ovirt.engine.core.common.businessentities.Entities;
import org.ovirt.engine.core.common.businessentities.GraphicsInfo;
import org.ovirt.engine.core.common.businessentities.GraphicsType;
import org.ovirt.engine.core.common.businessentities.GuestContainer;
import org.ovirt.engine.core.common.businessentities.HostDevice;
import org.ovirt.engine.core.common.businessentities.KdumpStatus;
import org.ovirt.engine.core.common.businessentities.LeaseStatus;
import org.ovirt.engine.core.common.businessentities.NumaNodeStatistics;
import org.ovirt.engine.core.common.businessentities.SessionState;
import org.ovirt.engine.core.common.businessentities.StoragePool;
import org.ovirt.engine.core.common.businessentities.V2VJobInfo;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSDomainsData;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
import org.ovirt.engine.core.common.businessentities.VdsTransparentHugePagesState;
import org.ovirt.engine.core.common.businessentities.VmBalloonInfo;
import org.ovirt.engine.core.common.businessentities.VmBlockJob;
import org.ovirt.engine.core.common.businessentities.VmBlockJobType;
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.VmDynamic;
import org.ovirt.engine.core.common.businessentities.VmExitReason;
import org.ovirt.engine.core.common.businessentities.VmExitStatus;
import org.ovirt.engine.core.common.businessentities.VmGuestAgentInterface;
import org.ovirt.engine.core.common.businessentities.VmJob;
import org.ovirt.engine.core.common.businessentities.VmJobState;
import org.ovirt.engine.core.common.businessentities.VmJobType;
import org.ovirt.engine.core.common.businessentities.VmPauseStatus;
import org.ovirt.engine.core.common.businessentities.VmRngDevice;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.businessentities.VmStatistics;
import org.ovirt.engine.core.common.businessentities.network.Bond;
import org.ovirt.engine.core.common.businessentities.network.BondMode;
import org.ovirt.engine.core.common.businessentities.network.HostNetworkQos;
import org.ovirt.engine.core.common.businessentities.network.InterfaceStatus;
import org.ovirt.engine.core.common.businessentities.network.Ipv4BootProtocol;
import org.ovirt.engine.core.common.businessentities.network.Ipv6BootProtocol;
import org.ovirt.engine.core.common.businessentities.network.NetworkInterface;
import org.ovirt.engine.core.common.businessentities.network.NetworkStatistics;
import org.ovirt.engine.core.common.businessentities.network.Nic;
import org.ovirt.engine.core.common.businessentities.network.VdsInterfaceType;
import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface;
import org.ovirt.engine.core.common.businessentities.network.VdsNetworkStatistics;
import org.ovirt.engine.core.common.businessentities.network.Vlan;
import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType;
import org.ovirt.engine.core.common.businessentities.network.VmNetworkInterface;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskImageDynamic;
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.LUNs;
import org.ovirt.engine.core.common.businessentities.storage.StorageType;
import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat;
import org.ovirt.engine.core.common.businessentities.storage.VolumeType;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.network.SwitchType;
import org.ovirt.engine.core.common.utils.EnumUtils;
import org.ovirt.engine.core.common.utils.NetworkCommonUtils;
import org.ovirt.engine.core.common.utils.SizeConverter;
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.RpmVersion;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
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.di.Injector;
import org.ovirt.engine.core.utils.NetworkUtils;
import org.ovirt.engine.core.utils.NumaUtils;
import org.ovirt.engine.core.utils.SerializationFactory;
import org.ovirt.engine.core.utils.network.predicate.InterfaceByAddressPredicate;
import org.ovirt.engine.core.utils.network.predicate.IpAddressPredicate;
import org.ovirt.engine.core.vdsbroker.NetworkStatisticsBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class encapsulate the knowledge of how to create objects from the VDS RPC protocol response.
* This class has methods that receive struct and construct the following Classes: VmDynamic VdsDynamic VdsStatic.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public class VdsBrokerObjectsBuilder {
private static final Logger log = LoggerFactory.getLogger(VdsBrokerObjectsBuilder.class);
private static final int VNC_START_PORT = 5900;
private static final double NANO_SECONDS = 1000000000;
private static final AuditLogDirector auditLogDirector = new AuditLogDirector();
private static final Comparator<VdsNumaNode> numaNodeComparator = Comparator.comparing(VdsNumaNode::getIndex);
private static final Pattern IPV6_ADDRESS_CAPTURE_PREFIX_PATTERN = Pattern.compile("^.*?/(\\d+)?$");
private static final Pattern IPV6_ADDRESS_CAPTURE_PATTERN = Pattern.compile("^([^/]+)(:?/\\d{1,3})?$");
public static VM buildVmsDataFromExternalProvider(Map<String, Object> struct) {
VmStatic vmStatic = buildVmStaticDataFromExternalProvider(struct);
if (vmStatic == null) {
return null;
}
VmDynamic vmDynamic = buildVMDynamicDataFromList(struct);
VM vm = new VM(vmStatic, vmDynamic, new VmStatistics());
for (DiskImage image : vm.getImages()) {
vm.getDiskMap().put(Guid.newGuid(), image);
}
try {
vm.setClusterArch(parseArchitecture(struct));
} catch (IllegalArgumentException ex) {
log.warn("Illegal architecture type: {}, replacing with x86_64", struct.get(VdsProperties.vm_arch));
vm.setClusterArch(ArchitectureType.x86_64);
} catch (NullPointerException ex) {
log.warn("null architecture type, replacing with x86_64, {}", vm);
vm.setClusterArch(ArchitectureType.x86_64);
}
return vm;
}
/**
* Convert the devices map and make a list of {@linkplain DiskImage}
* Mainly used to import the Hosted Engine Vm disks.
*
* @return A List of Disk Images {@linkplain DiskImage}
*/
public static ArrayList<DiskImage> buildDiskImagesFromDevices(Map<String, Object> vmStruct, Guid vmId) {
ArrayList<DiskImage> diskImages = new ArrayList<>();
Object[] devices = (Object[]) vmStruct.get("devices");
if (devices != null) {
for (Object device : devices) {
Map <String, Object> deviceMap = (Map<String, Object>) device;
if (VdsProperties.Disk.equals(deviceMap.get(VdsProperties.Device))) {
DiskImage image = new DiskImage();
image.setDiskAlias((String) deviceMap.get(VdsProperties.Alias));
image.setSize(Long.parseLong((String) deviceMap.get("apparentsize")));
image.setActualSize(Long.parseLong((String) deviceMap.get("truesize")));
image.setId(Guid.newGuid());
image.setVolumeFormat(VolumeFormat.valueOf(((String) deviceMap.get(VdsProperties.Format)).toUpperCase()));
image.setShareable(false);
image.setId(Guid.createGuidFromString((String) deviceMap.get(VdsProperties.DeviceId)));
image.setImageId(Guid.createGuidFromString((String) deviceMap.get(VdsProperties.VolumeId)));
Guid domainId = Guid.createGuidFromString((String) deviceMap.get(VdsProperties.DomainId));
List<Guid> domainIds = Collections.singletonList(domainId);
image.setStorageIds(new ArrayList<>(domainIds));
// TODO not sure how to extract that info
image.setVolumeType(VolumeType.Preallocated);
DiskVmElement dve = new DiskVmElement(image.getId(), vmId);
image.setDiskVmElements(Collections.singletonList(dve));
switch ((String) deviceMap.get("iface")) {
case "virtio":
dve.setDiskInterface(DiskInterface.VirtIO);
break;
case "iscsi":
dve.setDiskInterface(DiskInterface.VirtIO_SCSI);
break;
case "ide":
dve.setDiskInterface(DiskInterface.IDE);
break;
}
diskImages.add(image);
}
}
}
return diskImages;
}
/**
* Convert the devices map and make a list of {@linkplain VmNetworkInterface}
* Mainly used to import the Hosted Engine Vm disks.
*
* @return A List of VM network interfaces {@linkplain VmNetworkInterface}
*/
public static ArrayList<VmNetworkInterface> buildVmNetworkInterfacesFromDevices(Map<String, Object> vmStruct) {
ArrayList<VmNetworkInterface> nics = new ArrayList<>();
Object[] devices = (Object[]) vmStruct.get(VdsProperties.Devices);
if (devices != null) {
for (Object device : devices) {
Map<String, Object> deviceMap = (Map<String, Object>) device;
if (VdsProperties.VM_INTERFACE_DEVICE_TYPE.equals(deviceMap.get(VdsProperties.Type))) {
VmNetworkInterface nic = new VmNetworkInterface();
nic.setId(Guid.createGuidFromString((String)deviceMap.get(VdsProperties.DeviceId)));
nic.setMacAddress((String) deviceMap.get(VdsProperties.MAC_ADDR));
nic.setName((String) deviceMap.get(VdsProperties.Name));
// FIXME we can't deduce the network profile by the network name. its many to many.
nic.setNetworkName((String) deviceMap.get(VdsProperties.NETWORK));
nic.setType(VmInterfaceType.valueOf((String) deviceMap.get(VdsProperties.NIC_TYPE)).getValue());
if (deviceMap.containsKey(VdsProperties.Model)) {
String model = (String) deviceMap.get(VdsProperties.Model);
for (VmInterfaceType type : VmInterfaceType.values()) {
if (model.equals(type.getInternalName())) {
nic.setType(type.getValue());
break;
}
}
}
nics.add(nic);
}
}
}
return nics;
}
public static VmDevice buildConsoleDevice(Map<String, Object> vmStruct, Guid vmId){
Object[] devices = (Object[]) vmStruct.get(VdsProperties.Devices);
if (devices != null) {
for (Object device : devices) {
Map<String, Object> vdsmDevice = (Map<String, Object>) device;
String deviceName = (String) vdsmDevice.get(VdsProperties.Device);
if (VmDeviceType.CONSOLE.getName().equals(deviceName)) {
String typeName = (String) vdsmDevice.get(VdsProperties.Type);
String alias = StringUtils.defaultString((String) vdsmDevice.get(VdsProperties.Alias));
Guid newDeviceId = Guid.createGuidFromString((String) vdsmDevice.get(VdsProperties.DeviceId));
VmDeviceId id = new VmDeviceId(newDeviceId, vmId);
VmDevice consoleDevice = new VmDevice(id,
VmDeviceGeneralType.forValue(typeName),
deviceName,
"",
new HashMap<>(),
false,
true,
false,
alias,
null,
null,
null);
return consoleDevice;
}
}
}
return null;
}
private static VmStatic buildVmStaticDataFromExternalProvider(Map<String, Object> struct) {
if (!struct.containsKey(VdsProperties.vm_guid) || !struct.containsKey(VdsProperties.vm_name)
|| !struct.containsKey(VdsProperties.mem_size_mb)
|| !struct.containsKey(VdsProperties.num_of_cpus)) {
return null;
}
VmStatic vmStatic = new VmStatic();
vmStatic.setId(Guid.createGuidFromString((String) struct.get(VdsProperties.vm_guid)));
vmStatic.setName((String) struct.get(VdsProperties.vm_name));
vmStatic.setMemSizeMb(parseIntVdsProperty(struct.get(VdsProperties.mem_size_mb)));
vmStatic.setNumOfSockets(parseIntVdsProperty(struct.get(VdsProperties.num_of_cpus)));
vmStatic.setCustomCpuName((String) struct.get(VdsProperties.cpu_model));
vmStatic.setCustomEmulatedMachine((String) struct.get(VdsProperties.emulatedMachine));
addGraphicsDeviceFromExternalProvider(vmStatic, struct);
if (struct.containsKey(VdsProperties.vm_disks)) {
for (Object disk : (Object[]) struct.get(VdsProperties.vm_disks)) {
Map<String, Object> diskMap = (Map<String, Object>) disk;
if (VdsProperties.Disk.equals(diskMap.get(VdsProperties.type))) {
DiskImage image = buildDiskImageFromExternalProvider(diskMap);
vmStatic.getImages().add(image);
}
}
}
if (struct.containsKey(VdsProperties.NETWORKS)) {
int idx = 0;
for (Object networkMap : (Object[]) struct.get(VdsProperties.NETWORKS)) {
VmNetworkInterface nic = buildNetworkInterfaceFromExternalProvider((Map<String, Object>) networkMap);
nic.setName(String.format("nic%d", ++idx));
nic.setVmName(vmStatic.getName());
nic.setVmId(vmStatic.getId());
vmStatic.getInterfaces().add(nic);
}
}
return vmStatic;
}
/**
* libvirt video: "vga", "cirrus", "vmvga", "xen", "vbox", "qxl"
* ovirt video: "vga", "cirrus", "qxl"
* libvirt grahics: sdl, vnc, spice, rdp or desktop
* ovirt graphics: cirrus, spice, vnc
* try to add the displaytype and graphics if ovirt support the channels
*/
private static void addGraphicsDeviceFromExternalProvider(VmStatic vmStatic, Map<String, Object> struct) {
Object graphicsName = struct.get(VdsProperties.GRAPHICS_DEVICE);
Object videoName = struct.get(VdsProperties.VIDEO_DEVICE);
if (graphicsName == null || videoName == null) {
return;
}
try {
vmStatic.setDefaultDisplayType(DisplayType.valueOf(videoName.toString()));
} catch (IllegalArgumentException ex) {
log.error("Illegal video name '{}'.", videoName.toString());
return;
}
GraphicsType graphicsType = GraphicsType.fromString(graphicsName.toString());
if (graphicsType == null) {
log.error("Illegal graphics name '{}'.", graphicsName.toString());
return;
}
VmDeviceCommonUtils.addGraphicsDevice(vmStatic, graphicsType.getCorrespondingDeviceType());
VmDeviceCommonUtils.addVideoDevice(vmStatic);
}
private static DiskImage buildDiskImageFromExternalProvider(Map<String, Object> map) {
DiskImage image = new DiskImage();
image.setDiskAlias((String) map.get(VdsProperties.Alias));
image.setSize(Long.parseLong((String) map.get(VdsProperties.DISK_VIRTUAL_SIZE)));
image.setActualSizeInBytes(Long.parseLong((String) map.get(VdsProperties.DISK_ALLOCATION)));
image.setId(Guid.newGuid());
if (map.containsKey(VdsProperties.Format)) {
image.setVolumeFormat(VolumeFormat.valueOf(((String) map.get(VdsProperties.Format)).toUpperCase()));
}
return image;
}
private static VmNetworkInterface buildNetworkInterfaceFromExternalProvider(Map<String, Object> map) {
VmNetworkInterface nic = new VmNetworkInterface();
nic.setMacAddress((String) map.get(VdsProperties.MAC_ADDR));
nic.setRemoteNetworkName((String) map.get(VdsProperties.BRIDGE));
nic.setType(VmInterfaceType.pv.getValue());
if (map.containsKey(VdsProperties.Model)) {
String model = (String) map.get(VdsProperties.Model);
for (VmInterfaceType type : VmInterfaceType.values()) {
if (model.equals(type.getInternalName())) {
nic.setType(type.getValue());
break;
}
}
}
return nic;
}
public static VmDynamic buildVMDynamicDataFromList(Map<String, Object> struct) {
VmDynamic vmdynamic = new VmDynamic();
if (struct.containsKey(VdsProperties.vm_guid)) {
vmdynamic.setId(new Guid((String) struct.get(VdsProperties.vm_guid)));
}
if (struct.containsKey(VdsProperties.status)) {
vmdynamic.setStatus(convertToVmStatus((String) struct.get(VdsProperties.status)));
}
return vmdynamic;
}
public static Double getVdsmCallTimestamp(Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.statusTime)) {
return assignDoubleValue(struct, VdsProperties.statusTime);
}
return -1d;
}
public static String getVmDevicesHash(Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.hash)) {
return (String) struct.get(VdsProperties.hash);
}
return null;
}
public static VmDynamic buildVMDynamicData(Map<String, Object> struct, VDS host) {
VmDynamic vmdynamic = new VmDynamic();
updateVMDynamicData(vmdynamic, struct, host);
return vmdynamic;
}
public static StoragePool buildStoragePool(Map<String, Object> struct) {
StoragePool sPool = new StoragePool();
if (struct.containsKey("type")) {
sPool.setIsLocal(StorageType.valueOf(struct.get("type").toString()).isLocal());
}
sPool.setName(assignStringValue(struct, "name"));
Integer masterVersion = assignIntValue(struct, "master_ver");
if (masterVersion != null) {
sPool.setMasterDomainVersion(masterVersion);
}
return sPool;
}
public static VmStatistics buildVMStatisticsData(Map<String, Object> struct) {
VmStatistics vmStatistics = new VmStatistics();
updateVMStatisticsData(vmStatistics, struct);
return vmStatistics;
}
public static Map<String, LUNs> buildVmLunDisksData(Map<String, Object> struct) {
Map<String, Object> disks = (Map<String, Object>) struct.get(VdsProperties.vm_disks);
Map<String, LUNs> lunsMap = new HashMap<>();
if (disks != null) {
for (Object diskAsObj : disks.values()) {
Map<String, Object> disk = (Map<String, Object>) diskAsObj;
String lunGuidString = assignStringValue(disk, VdsProperties.lun_guid);
if (!StringUtils.isEmpty(lunGuidString)) {
LUNs lun = new LUNs();
lun.setLUNId(lunGuidString);
if (disk.containsKey(VdsProperties.disk_true_size)) {
long sizeInBytes = assignLongValue(disk, VdsProperties.disk_true_size);
int sizeInGB = SizeConverter.convert(
sizeInBytes, SizeConverter.SizeUnit.BYTES, SizeConverter.SizeUnit.GiB).intValue();
lun.setDeviceSize(sizeInGB);
}
lunsMap.put(lunGuidString, lun);
}
}
}
return lunsMap;
}
public static void updateVMDynamicData(VmDynamic vm, Map<String, Object> struct, VDS host) {
if (struct.containsKey(VdsProperties.vm_guid)) {
vm.setId(new Guid((String) struct.get(VdsProperties.vm_guid)));
}
if (struct.containsKey(VdsProperties.session)) {
String session = (String) struct.get(VdsProperties.session);
try {
vm.setSession(SessionState.valueOf(session));
} catch (Exception e) {
log.error("Illegal vm session '{}'.", session);
}
}
if (struct.containsKey(VdsProperties.acpiEnable)) {
vm.setAcpiEnable(Boolean.parseBoolean((String) struct.get(VdsProperties.acpiEnable)));
}
if (struct.containsKey(VdsProperties.status)) {
vm.setStatus(convertToVmStatus((String) struct.get(VdsProperties.status)));
}
boolean hasGraphicsInfo = updateGraphicsInfo(vm, struct);
if (!hasGraphicsInfo) {
updateGraphicsInfoFromConf(vm, struct);
}
adjustDisplayIp(vm.getGraphicsInfos(), host);
if (struct.containsKey(VdsProperties.utc_diff)) {
String utc_diff = struct.get(VdsProperties.utc_diff).toString();
if (utc_diff.startsWith("+")) {
utc_diff = utc_diff.substring(1);
}
try {
vm.setUtcDiff(Integer.parseInt(utc_diff));
} catch (NumberFormatException e) {
log.error("Illegal vm offset (utc_diff) '{}'.", utc_diff);
}
}
// ------------- vm internal agent data
if (struct.containsKey(VdsProperties.vm_host)) {
vm.setVmHost(assignStringValue(struct, VdsProperties.vm_host));
}
if (struct.containsKey(VdsProperties.guest_cur_user_name)) {
vm.setGuestCurrentUserName(assignStringValue(struct, VdsProperties.guest_cur_user_name));
}
initAppsList(struct, vm);
initGuestContainers(struct, vm);
if (struct.containsKey(VdsProperties.guest_os)) {
vm.setGuestOs(assignStringValue(struct, VdsProperties.guest_os));
}
if (struct.containsKey(VdsProperties.VM_FQDN)) {
vm.setFqdn(assignStringValue(struct, VdsProperties.VM_FQDN));
String fqdn = vm.getFqdn().trim();
if ("localhost".equalsIgnoreCase(fqdn) || "localhost.localdomain".equalsIgnoreCase(fqdn)) {
vm.setFqdn(null);
}
else {
vm.setFqdn(fqdn);
}
}
if (struct.containsKey(VdsProperties.VM_IP)) {
vm.setIp(assignStringValue(struct, VdsProperties.VM_IP));
}
if (vm.getIp() != null) {
if (vm.getIp().startsWith("127.0.")) {
vm.setIp(null);
} else {
vm.setIp(vm.getIp().trim());
}
}
if (struct.containsKey(VdsProperties.exit_code)) {
String exitCodeStr = struct.get(VdsProperties.exit_code).toString();
vm.setExitStatus(VmExitStatus.forValue(Integer.parseInt(exitCodeStr)));
}
if (struct.containsKey(VdsProperties.exit_message)) {
String exitMsg = (String) struct.get(VdsProperties.exit_message);
vm.setExitMessage(exitMsg);
}
if (struct.containsKey(VdsProperties.exit_reason)) {
String exitReasonStr = struct.get(VdsProperties.exit_reason).toString();
VmExitReason exitReason = VmExitReason.forValue(Integer.parseInt(exitReasonStr));
if (exitReason == null) {
log.warn("Illegal exit reason: {}, replacing with Unknown", exitReasonStr);
exitReason = VmExitReason.Unknown;
}
vm.setExitReason(exitReason);
}
// if monitorResponse returns negative it means its erroneous
if (struct.containsKey(VdsProperties.monitorResponse)) {
int response = Integer.parseInt(struct.get(VdsProperties.monitorResponse).toString());
if (response < 0) {
vm.setStatus(VMStatus.NotResponding);
}
}
if (struct.containsKey(VdsProperties.clientIp)) {
vm.setClientIp(struct.get(VdsProperties.clientIp).toString());
}
if (struct.containsKey(VdsProperties.pauseCode)) {
String pauseCodeStr = (String) struct.get(VdsProperties.pauseCode);
try {
vm.setPauseStatus(VmPauseStatus.valueOf(pauseCodeStr));
} catch (IllegalArgumentException ex) {
log.error("Error in parsing vm pause status. Setting value to NONE");
}
}
if (struct.containsKey(VdsProperties.watchdogEvent)) {
Map<String, Object> watchdogStruct = (Map<String, Object>) struct.get(VdsProperties.watchdogEvent);
double time = Double.parseDouble(watchdogStruct.get(VdsProperties.time).toString());
// vdsm may not send the action http://gerrit.ovirt.org/14134
String action =
watchdogStruct.containsKey(VdsProperties.action) ? watchdogStruct.get(VdsProperties.action)
.toString() : null;
vm.setLastWatchdogEvent((long) time);
vm.setLastWatchdogAction(action);
}
if (struct.containsKey(VdsProperties.CDRom)) {
Path fileName = Paths.get((String) struct.get(VdsProperties.CDRom)).getFileName();
if (fileName != null) {
String isoName = fileName.toString();
vm.setCurrentCd(isoName);
}
}
if (struct.containsKey(VdsProperties.GUEST_CPU_COUNT)) {
vm.setGuestCpuCount(assignIntValue(struct, VdsProperties.GUEST_CPU_COUNT));
}
// Guest OS Info
if (struct.containsKey(VdsProperties.GUEST_OS_INFO)) {
updateGuestOsInfo(vm, struct);
}
// Guest Timezone
if (struct.containsKey(VdsProperties.GUEST_TIMEZONE)) {
Map<String, Object> guestTimeZoneStruct =
(Map<String, Object>) struct.get(VdsProperties.GUEST_TIMEZONE);
vm.setGuestOsTimezoneName(assignStringValue(guestTimeZoneStruct, VdsProperties.GUEST_TIMEZONE_ZONE));
vm.setGuestOsTimezoneOffset(assignIntValue(guestTimeZoneStruct, VdsProperties.GUEST_TIMEZONE_OFFSET));
}
}
/**
* Adjusts displayIp for graphicsInfos:
* - if displayIp is overriden on cluster level then overriden address is used,
* or
* - if current displayIp starts with "0" then host's hostname is used.
*
* @param graphicsInfos - graphicsInfo to adjust
*/
private static void adjustDisplayIp(Map<GraphicsType, GraphicsInfo> graphicsInfos, VDS host) {
if (graphicsInfos == null) {
return;
}
for (GraphicsInfo graphicsInfo : graphicsInfos.values()) {
if (graphicsInfo == null) {
continue;
}
if (host.getConsoleAddress() != null) {
graphicsInfo.setIp(host.getConsoleAddress());
} else if (graphicsInfo.getIp() != null && graphicsInfo.getIp().startsWith("0")) {
graphicsInfo.setIp(host.getHostName());
}
}
}
private static void updateGuestOsInfo(VmDynamic vm, Map<String, Object> struct) {
Map<String, Object> guestOsInfoStruct = (Map<String, Object>) struct.get(VdsProperties.GUEST_OS_INFO);
if(guestOsInfoStruct.containsKey(VdsProperties.GUEST_OS_INFO_ARCH)) {
String arch = assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_ARCH);
try {
vm.setGuestOsArch(arch);
} catch(IllegalArgumentException e) {
log.warn("Invalid or unknown guest architecture type '{}' received from guest agent", arch);
}
}
vm.setGuestOsCodename(assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_CODENAME));
vm.setGuestOsDistribution(assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_DISTRIBUTION));
vm.setGuestOsKernelVersion(assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_KERNEL));
if(guestOsInfoStruct.containsKey(VdsProperties.GUEST_OS_INFO_TYPE)) {
String osType = assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_TYPE);
try {
vm.setGuestOsType(osType);
} catch(IllegalArgumentException e) {
log.warn("Invalid or unknown guest os type '{}' received from guest agent", osType);
}
} else {
log.warn("Guest OS type not reported by guest agent but expected.");
}
vm.setGuestOsVersion(assignStringValue(guestOsInfoStruct, VdsProperties.GUEST_OS_INFO_VERSION));
}
/**
* Updates graphics runtime information according displayInfo VDSM structure if it exists.
*
* @param vm - VmDynamic to update
* @param struct - data from VDSM
* @return true if displayInfo exists, false otherwise
*/
private static boolean updateGraphicsInfo(VmDynamic vm, Map<String, Object> struct) {
Object displayInfo = struct.get(VdsProperties.displayInfo);
if (displayInfo == null) {
return false;
}
for (Object info : (Object[]) displayInfo) {
Map<String, String> infoMap = (Map<String, String>) info;
GraphicsType graphicsType = GraphicsType.fromString(infoMap.get(VdsProperties.type));
GraphicsInfo graphicsInfo = new GraphicsInfo();
graphicsInfo.setIp(infoMap.get(VdsProperties.ipAddress))
.setPort(parseIntegerOrNull(infoMap.get(VdsProperties.port)))
.setTlsPort(parseIntegerOrNull(infoMap.get(VdsProperties.tlsPort)));
if (graphicsInfo.getPort() != null || graphicsInfo.getTlsPort() != null) {
vm.getGraphicsInfos().put(graphicsType, graphicsInfo);
}
}
return true;
}
/**
* Updates graphics runtime information according to vm.conf vdsm structure. It's used with legacy VDSMs that have
* no notion about graphics device.
* @param vm - VmDynamic to update
* @param struct - data from VDSM
*/
private static void updateGraphicsInfoFromConf(VmDynamic vm, Map<String, Object> struct) {
GraphicsType vmGraphicsType = parseGraphicsType(struct);
if (vmGraphicsType == null) {
log.debug("graphics data missing in XML.");
return;
}
GraphicsInfo graphicsInfo = new GraphicsInfo();
if (struct.containsKey(VdsProperties.display_port)) {
try {
graphicsInfo.setPort(Integer.parseInt(struct.get(VdsProperties.display_port).toString()));
} catch (NumberFormatException e) {
log.error("vm display_port value illegal : {0}", struct.get(VdsProperties.display_port));
}
} else if (struct.containsKey(VdsProperties.display)) {
try {
graphicsInfo
.setPort(VNC_START_PORT + Integer.parseInt(struct.get(VdsProperties.display).toString()));
} catch (NumberFormatException e) {
log.error("vm display value illegal : {0}", struct.get(VdsProperties.display));
}
}
if (struct.containsKey(VdsProperties.display_secure_port)) {
try {
graphicsInfo
.setTlsPort(Integer.parseInt(struct.get(VdsProperties.display_secure_port).toString()));
} catch (NumberFormatException e) {
log.error("vm display_secure_port value illegal : {0}",
struct.get(VdsProperties.display_secure_port));
}
}
if (struct.containsKey(VdsProperties.displayIp)) {
graphicsInfo.setIp((String) struct.get(VdsProperties.displayIp));
}
vm.getGraphicsInfos().put(vmGraphicsType, graphicsInfo);
}
/**
* Retrieves graphics type from xml.
* @return
* - graphics type derived from xml on success
* - null on error
*/
private static GraphicsType parseGraphicsType(Map<String, Object> struct) {
GraphicsType result = null;
try {
String displayTypeStr = struct.get(VdsProperties.displayType).toString();
switch (displayTypeStr) {
case VdsProperties.VNC:
result = GraphicsType.VNC;
break;
case VdsProperties.QXL:
result = GraphicsType.SPICE;
break;
}
} catch (Exception ignore) {
}
return result;
}
private static Integer parseIntegerOrNull(String s) {
try {
return Integer.parseInt(s);
} catch (Exception e) {
return null;
}
}
/**
* Some properties were changed recently from String to Integer
* This method checks what type is the property, and returns int
*/
public static int parseIntVdsProperty(Object vdsProperty) {
if (vdsProperty instanceof Integer) {
return (Integer) vdsProperty;
} else {
return Integer.parseInt((String) vdsProperty);
}
}
protected static ArchitectureType parseArchitecture(Map<String, Object> struct) {
return ArchitectureType.valueOf((String) struct.get(VdsProperties.vm_arch));
}
public static List<VmNetworkInterface> buildInterfaceStatisticsData(Map<String, Object> struct) {
// ------------- vm network statistics -----------------------
if (!struct.containsKey(VdsProperties.VM_NETWORK)) {
return null;
}
Map networkStruct = (Map) struct.get(VdsProperties.VM_NETWORK);
List<VmNetworkInterface> interfaceStatistics = new ArrayList<>();
for (Object tempNic : networkStruct.values()) {
Map nic = (Map) tempNic;
VmNetworkInterface stats = new VmNetworkInterface();
if (nic.containsKey(VdsProperties.VM_INTERFACE_NAME)) {
stats.setName((String) ((nic.get(VdsProperties.VM_INTERFACE_NAME) instanceof String) ? nic
.get(VdsProperties.VM_INTERFACE_NAME) : null));
}
extractInterfaceStatistics(nic, stats);
stats.setMacAddress((String) ((nic.get(VdsProperties.MAC_ADDR) instanceof String) ? nic
.get(VdsProperties.MAC_ADDR) : null));
interfaceStatistics.add(stats);
}
return interfaceStatistics;
}
public static void updateVMStatisticsData(VmStatistics vm, Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.vm_guid)) {
vm.setId(new Guid((String) struct.get(VdsProperties.vm_guid)));
}
vm.setElapsedTime(assignDoubleValue(struct, VdsProperties.elapsed_time));
if (struct.containsKey(VdsProperties.VM_DISKS_USAGE)) {
initDisksUsage(struct, vm);
}
// ------------- vm cpu statistics -----------------------
vm.setCpuSys(assignDoubleValue(struct, VdsProperties.cpu_sys));
vm.setCpuUser(assignDoubleValue(struct, VdsProperties.cpu_user));
// ------------- vm memory statistics -----------------------
vm.setUsageMemPercent(assignIntValue(struct, VdsProperties.vm_usage_mem_percent));
if (struct.containsKey(VdsProperties.vm_guest_mem_stats)) {
Map<String, Object> sub = (Map<String, Object>)struct.get(VdsProperties.vm_guest_mem_stats);
if (sub.containsKey(VdsProperties.vm_guest_mem_buffered)) {
vm.setGuestMemoryBuffered(Long.parseLong(sub.get(VdsProperties.vm_guest_mem_buffered).toString()));
}
if (sub.containsKey(VdsProperties.vm_guest_mem_cached)) {
vm.setGuestMemoryCached(Long.parseLong(sub.get(VdsProperties.vm_guest_mem_cached).toString()));
}
if (sub.containsKey(VdsProperties.vm_guest_mem_free)) {
vm.setGuestMemoryFree(Long.parseLong(sub.get(VdsProperties.vm_guest_mem_free).toString()));
}
}
// ------------- vm migration statistics -----------------------
Integer migrationProgress = assignIntValue(struct, VdsProperties.vm_migration_progress_percent);
vm.setMigrationProgressPercent(migrationProgress != null ? migrationProgress : 0);
}
public static VmBalloonInfo buildVmBalloonInfo(Map<String, Object> struct) {
VmBalloonInfo vmBalloonInfo = new VmBalloonInfo();
Map<String, Object> balloonInfo = (Map<String, Object>) struct.get(VdsProperties.vm_balloonInfo);
if (balloonInfo != null && !balloonInfo.isEmpty()) {
vmBalloonInfo.setCurrentMemory(assignLongValue(balloonInfo, VdsProperties.vm_balloon_cur));
vmBalloonInfo.setBalloonMaxMemory(assignLongValue(balloonInfo, VdsProperties.vm_balloon_max));
vmBalloonInfo.setBalloonTargetMemory(assignLongValue(balloonInfo, VdsProperties.vm_balloon_target));
vmBalloonInfo.setBalloonMinMemory(assignLongValue(balloonInfo, VdsProperties.vm_balloon_min));
// only if all 4 properties are found the balloon is considered enabled (available from 3.3)
vmBalloonInfo.setBalloonDeviceEnabled(balloonInfo.size() >= 4);
}
return vmBalloonInfo;
}
public static List<VmJob> buildVmJobsData(Map<String, Object> struct) {
if (!struct.containsKey(VdsProperties.vmJobs)) {
return null;
}
Guid vmId = new Guid((String) struct.get(VdsProperties.vm_guid));
return ((Map<String, Object>) struct.get(VdsProperties.vmJobs)).values().stream()
.map(jobMap -> buildVmJobData(vmId, (Map<String, Object>) jobMap))
.collect(Collectors.toList());
}
private static VmJob buildVmJobData(Guid vmId, Map<String, Object> struct) {
VmJob ret;
VmJobType jobType = VmJobType.getByName(assignStringValue(struct, VdsProperties.vmJobType));
if (jobType == null) {
jobType = VmJobType.UNKNOWN;
}
switch (jobType) {
case BLOCK:
VmBlockJob blockJob = new VmBlockJob();
blockJob.setBlockJobType(VmBlockJobType.getByName(assignStringValue(struct, VdsProperties.vmBlockJobType)));
blockJob.setCursorCur(assignLongValue(struct, VdsProperties.vmJobCursorCur));
blockJob.setCursorEnd(assignLongValue(struct, VdsProperties.vmJobCursorEnd));
blockJob.setBandwidth(assignLongValue(struct, VdsProperties.vmJobBandwidth));
blockJob.setImageGroupId(new Guid(assignStringValue(struct, VdsProperties.vmJobImageUUID)));
ret = blockJob;
break;
default:
ret = new VmJob();
break;
}
ret.setVmId(vmId);
ret.setId(new Guid(assignStringValue(struct, VdsProperties.vmJobId)));
ret.setJobState(VmJobState.NORMAL);
ret.setJobType(jobType);
return ret;
}
public static void updateVDSDynamicData(VDS vds, Map<String, Object> struct) {
vds.setSupportedClusterLevels(assignStringValueFromArray(struct, VdsProperties.supported_cluster_levels));
updateNetworkData(vds, struct);
updateNumaNodesData(vds, struct);
vds.setCpuThreads(assignIntValue(struct, VdsProperties.cpuThreads));
vds.setCpuCores(assignIntValue(struct, VdsProperties.cpu_cores));
vds.setCpuSockets(assignIntValue(struct, VdsProperties.cpu_sockets));
vds.setCpuModel(assignStringValue(struct, VdsProperties.cpu_model));
vds.setOnlineCpus(assignStringValue(struct, VdsProperties.online_cpus));
vds.setCpuSpeedMh(assignDoubleValue(struct, VdsProperties.cpu_speed_mh));
vds.setPhysicalMemMb(assignIntValue(struct, VdsProperties.physical_mem_mb));
vds.setKernelArgs(assignStringValue(struct, VdsProperties.kernel_args));
vds.setKvmEnabled(assignBoolValue(struct, VdsProperties.kvm_enabled));
vds.setReservedMem(assignIntValue(struct, VdsProperties.reservedMem));
Integer guestOverhead = assignIntValue(struct, VdsProperties.guestOverhead);
vds.setGuestOverhead(guestOverhead != null ? guestOverhead : 0);
vds.setCpuFlags(assignStringValue(struct, VdsProperties.cpu_flags));
updatePackagesVersions(vds, struct);
vds.setSupportedEngines(assignStringValueFromArray(struct, VdsProperties.supported_engines));
vds.setIScsiInitiatorName(assignStringValue(struct, VdsProperties.iSCSIInitiatorName));
vds.setSupportedEmulatedMachines(assignStringValueFromArray(struct, VdsProperties.emulatedMachines));
setRngSupportedSourcesToVds(vds, struct);
String hooksStr = ""; // default value if hooks is not in the xml rpc struct
if (struct.containsKey(VdsProperties.hooks)) {
hooksStr = struct.get(VdsProperties.hooks).toString();
}
vds.setHooksStr(hooksStr);
// parse out the HBAs available in this host
Map<String, List<Map<String, String>>> hbas = new HashMap<>();
for (Map.Entry<String, Object[]> el: ((Map<String, Object[]>)struct.get(VdsProperties.HBAInventory)).entrySet()) {
List<Map<String, String>> devicesList = new ArrayList<>();
for (Object device: el.getValue()) {
devicesList.add((Map<String, String>)device);
}
hbas.put(el.getKey(), devicesList);
}
vds.setHBAs(hbas);
vds.setBootTime(assignLongValue(struct, VdsProperties.bootTime));
vds.setKdumpStatus(KdumpStatus.valueOfNumber(assignIntValue(struct, VdsProperties.KDUMP_STATUS)));
vds.setHostDevicePassthroughEnabled(assignBoolValue(struct, VdsProperties.HOST_DEVICE_PASSTHROUGH));
Map<String, Object> selinux = (Map<String, Object>) struct.get(VdsProperties.selinux);
if (selinux != null) {
vds.setSELinuxEnforceMode(assignIntValue(selinux, VdsProperties.selinux_mode));
} else {
vds.setSELinuxEnforceMode(null);
}
vds.setHostedEngineConfigured(assignBoolValue(struct, VdsProperties.hosted_engine_configured));
updateAdditionalFeatures(vds, struct);
}
private static void updateAdditionalFeatures(VDS vds, Map<String, Object> struct) {
String[] addtionalFeaturesSupportedByHost =
assignStringArrayValue(struct, VdsProperties.ADDITIONAL_FEATURES);
if (addtionalFeaturesSupportedByHost != null) {
for (String feature : addtionalFeaturesSupportedByHost) {
vds.getAdditionalFeatures().add(feature);
}
}
}
private static void setRngSupportedSourcesToVds(VDS vds, Map<String, Object> struct) {
vds.getSupportedRngSources().clear();
String rngSourcesFromStruct = assignStringValueFromArray(struct, VdsProperties.rngSources);
if (rngSourcesFromStruct != null) {
vds.getSupportedRngSources().addAll(VmRngDevice.csvToSourcesSet(rngSourcesFromStruct.toUpperCase()));
}
}
public static void checkTimeDrift(VDS vds, Map<String, Object> struct) {
Boolean isHostTimeDriftEnabled = Config.getValue(ConfigValues.EnableHostTimeDrift);
if (isHostTimeDriftEnabled) {
Integer maxTimeDriftAllowed = Config.getValue(ConfigValues.HostTimeDriftInSec);
Date hostDate = assignDatetimeValue(struct, VdsProperties.hostDatetime);
if (hostDate != null) {
Long timeDrift =
TimeUnit.MILLISECONDS.toSeconds(Math.abs(hostDate.getTime() - System.currentTimeMillis()));
if (timeDrift > maxTimeDriftAllowed) {
AuditLogable logable = createAuditLogableForHost(vds);
logable.addCustomValue("Actual", timeDrift.toString());
logable.addCustomValue("Max", maxTimeDriftAllowed.toString());
auditLogDirector.log(logable, AuditLogType.VDS_TIME_DRIFT_ALERT);
}
} else {
log.error("Time Drift validation: failed to get Host or Engine time.");
}
}
}
private static void initDisksUsage(Map<String, Object> vmStruct, VmStatistics vm) {
Object[] vmDisksUsage = (Object[]) vmStruct.get(VdsProperties.VM_DISKS_USAGE);
if (vmDisksUsage != null) {
ArrayList<Object> disksUsageList = new ArrayList<>(Arrays.asList(vmDisksUsage));
vm.setDisksUsage(SerializationFactory.getSerializer().serializeUnformattedJson(disksUsageList));
}
}
private static void updatePackagesVersions(VDS vds, Map<String, Object> struct) {
vds.setVersionName(assignStringValue(struct, VdsProperties.version_name));
vds.setSoftwareVersion(assignStringValue(struct, VdsProperties.software_version));
vds.setBuildName(assignStringValue(struct, VdsProperties.build_name));
if (struct.containsKey(VdsProperties.host_os)) {
Map<String, Object> hostOsMap = (Map<String, Object>) struct.get(VdsProperties.host_os);
vds.setHostOs(getPackageVersionFormated(hostOsMap, true));
if (hostOsMap.containsKey(VdsProperties.pretty_name)) {
vds.setPrettyName(assignStringValue(hostOsMap, VdsProperties.pretty_name));
}
}
if (struct.containsKey(VdsProperties.packages)) {
// packages is an array of struct (that each is a name, ver,
// release.. of a package)
for (Object hostPackageMap : (Object[]) struct.get(VdsProperties.packages)) {
Map<String, Object> hostPackage = (Map<String, Object>) hostPackageMap;
String packageName = assignStringValue(hostPackage, VdsProperties.package_name);
if (VdsProperties.kvmPackageName.equals(packageName)) {
vds.setKvmVersion(getPackageVersionFormated(hostPackage, false));
} else if (VdsProperties.spicePackageName.equals(packageName)) {
vds.setSpiceVersion(getPackageVersionFormated(hostPackage, false));
} else if (VdsProperties.kernelPackageName.equals(packageName)) {
vds.setKernelVersion(getPackageVersionFormated(hostPackage, false));
}
}
} else if (struct.containsKey(VdsProperties.packages2)) {
Map<String, Object> packages = (Map<String, Object>) struct.get(VdsProperties.packages2);
if (packages.containsKey(VdsProperties.vdsmPackageName)) {
Map<String, Object> vdsm = (Map<String, Object>) packages.get(VdsProperties.vdsmPackageName);
vds.setVersion(getPackageRpmVersion("vdsm", vdsm));
}
if (packages.containsKey(VdsProperties.qemuKvmPackageName)) {
Map<String, Object> kvm = (Map<String, Object>) packages.get(VdsProperties.qemuKvmPackageName);
vds.setKvmVersion(getPackageVersionFormated2(kvm));
}
if (packages.containsKey(VdsProperties.libvirtPackageName)) {
Map<String, Object> libvirt = (Map<String, Object>) packages.get(VdsProperties.libvirtPackageName);
vds.setLibvirtVersion(getPackageRpmVersion("libvirt", libvirt));
}
if (packages.containsKey(VdsProperties.librbdPackageName)) {
Map<String, Object> librbd1 = (Map<String, Object>) packages.get(VdsProperties.librbdPackageName);
vds.setLibrbdVersion(getPackageRpmVersion(VdsProperties.librbdPackageName, librbd1));
}
if (packages.containsKey(VdsProperties.glusterfsCliPackageName)) {
Map<String, Object> glusterfsCli = (Map<String, Object>) packages.get(VdsProperties.glusterfsCliPackageName);
vds.setGlusterfsCliVersion(getPackageRpmVersion(VdsProperties.glusterfsCliPackageName, glusterfsCli));
}
if (packages.containsKey(VdsProperties.spiceServerPackageName)) {
Map<String, Object> spice = (Map<String, Object>) packages.get(VdsProperties.spiceServerPackageName);
vds.setSpiceVersion(getPackageVersionFormated2(spice));
}
if (packages.containsKey(VdsProperties.kernelPackageName)) {
Map<String, Object> kernel = (Map<String, Object>) packages.get(VdsProperties.kernelPackageName);
vds.setKernelVersion(getPackageVersionFormated2(kernel));
}
if (packages.containsKey(VdsProperties.GLUSTER_PACKAGE_NAME)) {
Map<String, Object> gluster = (Map<String, Object>) packages.get(VdsProperties.GLUSTER_PACKAGE_NAME);
vds.setGlusterVersion(getPackageRpmVersion("glusterfs", gluster));
}
}
}
// Version 2 of GetPackageVersionFormated2:
// from 2.3 we get dictionary and not a flat list.
// from now the packages names (of spice, kernel, qemu and libvirt) are the same as far as VDSM and ENGINE.
// (VDSM use to report packages name of rpm so in RHEL6 when it change it broke our interface)
private static String getPackageVersionFormated2(Map<String, Object> hostPackage) {
String packageVersion = (hostPackage.get(VdsProperties.package_version) != null) ? (String) hostPackage
.get(VdsProperties.package_version) : null;
String packageRelease = (hostPackage.get(VdsProperties.package_release) != null) ? (String) hostPackage
.get(VdsProperties.package_release) : null;
StringBuilder sb = new StringBuilder();
if (!StringUtils.isEmpty(packageVersion)) {
sb.append(packageVersion);
}
if (!StringUtils.isEmpty(packageRelease)) {
if (sb.length() > 0) {
sb.append(String.format(" - %1$s", packageRelease));
} else {
sb.append(packageRelease);
}
}
return sb.toString();
}
private static RpmVersion getPackageRpmVersion(String packageName, Map<String, Object> hostPackage) {
String packageVersion = (hostPackage.get(VdsProperties.package_version) != null) ? (String) hostPackage
.get(VdsProperties.package_version) : null;
String packageRelease = (hostPackage.get(VdsProperties.package_release) != null) ? (String) hostPackage
.get(VdsProperties.package_release) : null;
StringBuilder sb = new StringBuilder();
if (!StringUtils.isEmpty(packageName)) {
sb.append(packageName);
}
boolean hasPackageVersion = StringUtils.isEmpty(packageVersion);
boolean hasPackageRelease = StringUtils.isEmpty(packageRelease);
if (!hasPackageVersion || !hasPackageRelease) {
sb.append("-");
}
if (!hasPackageVersion) {
sb.append(packageVersion);
}
if (!hasPackageRelease) {
if (sb.length() > 0) {
sb.append(String.format("-%1$s", packageRelease));
} else {
sb.append(packageRelease);
}
}
return new RpmVersion(sb.toString());
}
public static void updateHardwareSystemInformation(Map<String, Object> hwInfo, VDS vds){
vds.setHardwareManufacturer(assignStringValue(hwInfo, VdsProperties.hwManufacturer));
vds.setHardwareProductName(assignStringValue(hwInfo, VdsProperties.hwProductName));
vds.setHardwareVersion(assignStringValue(hwInfo, VdsProperties.hwVersion));
vds.setHardwareSerialNumber(assignStringValue(hwInfo, VdsProperties.hwSerialNumber));
vds.setHardwareUUID(assignStringValue(hwInfo, VdsProperties.hwUUID));
vds.setHardwareFamily(assignStringValue(hwInfo, VdsProperties.hwFamily));
}
private static String getPackageVersionFormated(Map<String, Object> hostPackage, boolean getName) {
String packageName = assignStringValue(hostPackage, VdsProperties.package_name);
String packageVersion = assignStringValue(hostPackage, VdsProperties.package_version);
String packageRelease = assignStringValue(hostPackage, VdsProperties.package_release);
StringBuilder sb = new StringBuilder();
if (!StringUtils.isEmpty(packageName) && getName) {
sb.append(packageName);
}
if (!StringUtils.isEmpty(packageVersion)) {
if (sb.length() > 0) {
sb.append(String.format(" - %1$s", packageVersion));
} else {
sb.append(packageVersion);
}
}
if (!StringUtils.isEmpty(packageRelease)) {
if (sb.length() > 0) {
sb.append(String.format(" - %1$s", packageRelease));
} else {
sb.append(packageRelease);
}
}
return sb.toString();
}
public static void updateVDSStatisticsData(VDS vds, Map<String, Object> struct) {
// ------------- vds memory usage ---------------------------
vds.setUsageMemPercent(assignIntValue(struct, VdsProperties.mem_usage));
// ------------- vds network statistics ---------------------
Map<String, Object> interfaces = (Map<String, Object>) struct.get(VdsProperties.NETWORK);
if (interfaces != null) {
int networkUsage = 0;
Map<String, VdsNetworkInterface> nicsByName = Entities.entitiesByName(vds.getInterfaces());
NetworkStatisticsBuilder statsBuilder = new NetworkStatisticsBuilder();
for (Entry<String, Object> entry : interfaces.entrySet()) {
if (nicsByName.containsKey(entry.getKey())) {
VdsNetworkInterface existingIface = nicsByName.get(entry.getKey());
existingIface.setVdsId(vds.getId());
Map<String, Object> dict = (Map<String, Object>) entry.getValue();
VdsNetworkInterface reportedIface = new VdsNetworkInterface();
extractInterfaceStatistics(dict, reportedIface);
statsBuilder.updateExistingInterfaceStatistics(existingIface, reportedIface);
existingIface.getStatistics()
.setStatus(assignInterfaceStatusValue(dict, VdsProperties.iface_status));
if (!NetworkCommonUtils.isVlan(existingIface) && !existingIface.isPartOfBond()) {
Double ifaceUsage = computeInterfaceUsage(existingIface);
if (ifaceUsage != null) {
networkUsage = (int) Math.max(networkUsage, ifaceUsage);
}
}
}
}
vds.setUsageNetworkPercent(networkUsage);
}
// ----------- vds cpu statistics info ---------------------
vds.setCpuSys(assignDoubleValue(struct, VdsProperties.cpu_sys));
vds.setCpuUser(assignDoubleValue(struct, VdsProperties.cpu_user));
if (vds.getCpuSys() != null && vds.getCpuUser() != null) {
vds.setUsageCpuPercent((int) (vds.getCpuSys() + vds.getCpuUser()));
}
// CPU load reported by VDSM is in uptime-style format, i.e. normalized
// to unity, so that say an 8% load is reported as 0.08
Double d = assignDoubleValue(struct, VdsProperties.cpu_load);
d = (d != null) ? d : 0;
vds.setCpuLoad(d.doubleValue() * 100.0);
vds.setCpuIdle(assignDoubleValue(struct, VdsProperties.cpu_idle));
vds.setMemAvailable(assignLongValue(struct, VdsProperties.mem_available));
vds.setMemFree(assignLongValue(struct, VdsProperties.memFree));
vds.setMemShared(assignLongValue(struct, VdsProperties.mem_shared));
vds.setSwapFree(assignLongValue(struct, VdsProperties.swap_free));
vds.setSwapTotal(assignLongValue(struct, VdsProperties.swap_total));
vds.setKsmCpuPercent(assignIntValue(struct, VdsProperties.ksm_cpu_percent));
vds.setKsmPages(assignLongValue(struct, VdsProperties.ksm_pages));
vds.setKsmState(assignBoolValue(struct, VdsProperties.ksm_state));
// dynamic data got from GetVdsStats
if (struct.containsKey(VdsProperties.transparent_huge_pages_state)) {
vds.setTransparentHugePagesState(EnumUtils.valueOf(VdsTransparentHugePagesState.class, struct
.get(VdsProperties.transparent_huge_pages_state).toString(), true));
}
if (struct.containsKey(VdsProperties.anonymous_transparent_huge_pages)) {
vds.setAnonymousHugePages(assignIntValue(struct, VdsProperties.anonymous_transparent_huge_pages));
}
vds.setNetConfigDirty(assignBoolValue(struct, VdsProperties.netConfigDirty));
vds.setImagesLastCheck(assignDoubleValue(struct, VdsProperties.images_last_check));
vds.setImagesLastDelay(assignDoubleValue(struct, VdsProperties.images_last_delay));
Integer vm_count = assignIntValue(struct, VdsProperties.vm_count);
vds.setVmCount(vm_count == null ? 0 : vm_count);
vds.setVmActive(assignIntValue(struct, VdsProperties.vm_active));
vds.setVmMigrating(assignIntValue(struct, VdsProperties.vm_migrating));
Integer inOutMigrations;
inOutMigrations = assignIntValue(struct, VdsProperties.INCOMING_VM_MIGRATIONS);
if (inOutMigrations != null) {
vds.setIncomingMigrations(inOutMigrations);
} else {
// TODO remove in 4.x when all hosts will send in/out migrations separately
vds.setIncomingMigrations(-1);
}
inOutMigrations = assignIntValue(struct, VdsProperties.OUTGOING_VM_MIGRATIONS);
if (inOutMigrations != null) {
vds.setOutgoingMigrations(inOutMigrations);
} else {
// TODO remove in 4.x when all hosts will send in/out migrations separately
vds.setOutgoingMigrations(-1);
}
updateVDSDomainData(vds, struct);
updateLocalDisksUsage(vds, struct);
// hosted engine
Integer haScore = null;
Boolean haIsConfigured = null;
Boolean haIsActive = null;
Boolean haGlobalMaint = null;
Boolean haLocalMaint = null;
if (struct.containsKey(VdsProperties.ha_stats)) {
Map<String, Object> haStats = (Map<String, Object>) struct.get(VdsProperties.ha_stats);
if (haStats != null) {
haScore = assignIntValue(haStats, VdsProperties.ha_stats_score);
haIsConfigured = assignBoolValue(haStats, VdsProperties.ha_stats_is_configured);
haIsActive = assignBoolValue(haStats, VdsProperties.ha_stats_is_active);
haGlobalMaint = assignBoolValue(haStats, VdsProperties.ha_stats_global_maintenance);
haLocalMaint = assignBoolValue(haStats, VdsProperties.ha_stats_local_maintenance);
}
} else {
haScore = assignIntValue(struct, VdsProperties.ha_score);
// prior to 3.4, haScore was returned if ha was installed; assume active if > 0
if (haScore != null) {
haIsConfigured = true;
haIsActive = haScore > 0;
}
}
vds.setHighlyAvailableScore(haScore != null ? haScore : 0);
vds.setHighlyAvailableIsConfigured(haIsConfigured != null ? haIsConfigured : false);
vds.setHighlyAvailableIsActive(haIsActive != null ? haIsActive : false);
vds.setHighlyAvailableGlobalMaintenance(haGlobalMaint != null ? haGlobalMaint : false);
vds.setHighlyAvailableLocalMaintenance(haLocalMaint != null ? haLocalMaint : false);
vds.setBootTime(assignLongValue(struct, VdsProperties.bootTime));
updateNumaStatisticsData(vds, struct);
updateV2VJobs(vds, struct);
}
private static void extractInterfaceStatistics(Map<String, Object> dict, NetworkInterface<?> iface) {
NetworkStatistics stats = iface.getStatistics();
stats.setReceiveDropRate(assignDoubleValueWithNullProtection(dict, VdsProperties.rx_dropped));
stats.setReceivedBytes(assignLongValue(dict, VdsProperties.rx_total));
stats.setTransmitDropRate(assignDoubleValueWithNullProtection(dict, VdsProperties.tx_dropped));
stats.setTransmittedBytes(assignLongValue(dict, VdsProperties.tx_total));
stats.setSampleTime(assignDoubleValue(dict, VdsProperties.sample_time));
iface.setSpeed(assignIntValue(dict, VdsProperties.INTERFACE_SPEED));
}
private static Double computeInterfaceUsage(VdsNetworkInterface iface) {
Double receiveRate = iface.getStatistics().getReceiveRate();
Double transmitRate = iface.getStatistics().getTransmitRate();
if (receiveRate == null) {
return transmitRate;
} else if (transmitRate == null) {
return receiveRate;
} else {
return Math.max(receiveRate, transmitRate);
}
}
public static void updateNumaStatisticsData(VDS vds, Map<String, Object> struct) {
List<VdsNumaNode> vdsNumaNodes = new ArrayList<>();
if (vds.getNumaNodeList() != null && !vds.getNumaNodeList().isEmpty()) {
vdsNumaNodes.addAll(vds.getNumaNodeList());
}
List<CpuStatistics> cpuStatsData = new ArrayList<>();
if (struct.containsKey(VdsProperties.CPU_STATS)) {
Map<String, Map<String, Object>> cpuStats = (Map<String, Map<String, Object>>)
struct.get(VdsProperties.CPU_STATS);
Map<Integer, List<CpuStatistics>> numaNodeCpuStats = new HashMap<>();
for (Map.Entry<String, Map<String, Object>> item : cpuStats.entrySet()) {
CpuStatistics data = buildVdsCpuStatistics(item);
cpuStatsData.add(data);
int numaNodeIndex = assignIntValue(item.getValue(), VdsProperties.NUMA_NODE_INDEX);
if (!numaNodeCpuStats.containsKey(numaNodeIndex)) {
numaNodeCpuStats.put(numaNodeIndex, new ArrayList<>());
}
numaNodeCpuStats.get(numaNodeIndex).add(data);
}
DecimalFormat percentageFormatter = new DecimalFormat("#.##");
for (Map.Entry<Integer, List<CpuStatistics>> item : numaNodeCpuStats.entrySet()) {
VdsNumaNode nodeWithStatistics = buildVdsNumaNodeStatistics(percentageFormatter, item);
if (vdsNumaNodes.isEmpty()) {
vdsNumaNodes.add(nodeWithStatistics);
} else {
boolean foundNumaNode = false;
// append the statistics to the correct numaNode (search by its Index.)
for (VdsNumaNode currNumaNode : vdsNumaNodes) {
if (currNumaNode.getIndex() == nodeWithStatistics.getIndex()) {
currNumaNode.setNumaNodeStatistics(nodeWithStatistics.getNumaNodeStatistics());
foundNumaNode = true;
break;
}
}
// append new numaNode (contains only statistics) if not found existing
if (!foundNumaNode) {
vdsNumaNodes.add(nodeWithStatistics);
}
}
}
}
if (struct.containsKey(VdsProperties.NUMA_NODE_FREE_MEM_STAT)) {
Map<String, Map<String, Object>> memStats = (Map<String, Map<String, Object>>)
struct.get(VdsProperties.NUMA_NODE_FREE_MEM_STAT);
for (Map.Entry<String, Map<String, Object>> item : memStats.entrySet()) {
VdsNumaNode node = NumaUtils.getVdsNumaNodeByIndex(vdsNumaNodes, Integer.parseInt(item.getKey()));
if (node != null && node.getNumaNodeStatistics() != null) {
node.getNumaNodeStatistics().setMemFree(assignLongValue(item.getValue(),
VdsProperties.NUMA_NODE_FREE_MEM));
node.getNumaNodeStatistics().setMemUsagePercent(assignIntValue(item.getValue(),
VdsProperties.NUMA_NODE_MEM_PERCENT));
}
}
}
vds.getNumaNodeList().clear();
vds.getNumaNodeList().addAll(vdsNumaNodes);
vds.getStatisticsData().getCpuCoreStatistics().clear();
vds.getStatisticsData().getCpuCoreStatistics().addAll(cpuStatsData);
}
private static VdsNumaNode buildVdsNumaNodeStatistics(DecimalFormat percentageFormatter,
Map.Entry<Integer, List<CpuStatistics>> item) {
VdsNumaNode node = new VdsNumaNode();
NumaNodeStatistics nodeStat = new NumaNodeStatistics();
double nodeCpuUser = 0.0;
double nodeCpuSys = 0.0;
double nodeCpuIdle = 0.0;
for (CpuStatistics cpuStat : item.getValue()) {
nodeCpuUser += cpuStat.getCpuUser();
nodeCpuSys += cpuStat.getCpuSys();
nodeCpuIdle += cpuStat.getCpuIdle();
}
nodeStat.setCpuUser(Double.parseDouble(percentageFormatter.format(nodeCpuUser / item.getValue().size())));
nodeStat.setCpuSys(Double.parseDouble(percentageFormatter.format(nodeCpuSys / item.getValue().size())));
nodeStat.setCpuIdle(Double.parseDouble(percentageFormatter.format(nodeCpuIdle / item.getValue().size())));
nodeStat.setCpuUsagePercent((int) (nodeStat.getCpuSys() + nodeStat.getCpuUser()));
node.setIndex(item.getKey());
node.setNumaNodeStatistics(nodeStat);
return node;
}
private static CpuStatistics buildVdsCpuStatistics(Map.Entry<String, Map<String, Object>> item) {
CpuStatistics data = new CpuStatistics();
data.setCpuId(Integer.parseInt(item.getKey()));
data.setCpuUser(assignDoubleValue(item.getValue(), VdsProperties.NUMA_CPU_USER));
data.setCpuSys(assignDoubleValue(item.getValue(), VdsProperties.NUMA_CPU_SYS));
data.setCpuIdle(assignDoubleValue(item.getValue(), VdsProperties.NUMA_CPU_IDLE));
data.setCpuUsagePercent((int) (data.getCpuSys() + data.getCpuUser()));
return data;
}
/**
* Update {@link VDS#setLocalDisksUsage(Map)} with map of paths usage extracted from the returned returned value. The
* usage is reported in MB.
*
* @param vds
* The VDS object to update.
* @param struct
* The struct to extract the usage from.
*/
protected static void updateLocalDisksUsage(VDS vds, Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.DISK_STATS)) {
Map<String, Object> diskStatsStruct = (Map<String, Object>) struct.get(VdsProperties.DISK_STATS);
Map<String, Long> diskStats = new HashMap<>();
// collect(Collectors.toMap(...)) will not work here as it uses merge() internally and
// will fail on null values
diskStatsStruct.entrySet()
.forEach(e -> diskStats.put(e.getKey(),
assignLongValue((Map<String, Object>) e.getValue(), VdsProperties.DISK_STATS_FREE)));
vds.setLocalDisksUsage(diskStats);
}
}
private static void updateVDSDomainData(VDS vds, Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.domains)) {
Map<String, Object> domains = (Map<String, Object>)
struct.get(VdsProperties.domains);
ArrayList<VDSDomainsData> domainsData = new ArrayList<>();
for (Map.Entry<String, ?> value : domains.entrySet()) {
try {
VDSDomainsData data = new VDSDomainsData();
data.setDomainId(new Guid(value.getKey().toString()));
Map<String, Object> internalValue = (Map<String, Object>) value.getValue();
double lastCheck = 0;
data.setCode((Integer) internalValue.get(VdsProperties.code));
if (internalValue.containsKey(VdsProperties.lastCheck)) {
lastCheck = Double.parseDouble((String) internalValue.get(VdsProperties.lastCheck));
}
data.setLastCheck(lastCheck);
double delay = 0;
if (internalValue.containsKey(VdsProperties.delay)) {
delay = Double.parseDouble((String) internalValue.get(VdsProperties.delay));
}
data.setDelay(delay);
Boolean actual = Boolean.TRUE;
if (internalValue.containsKey(VdsProperties.actual)) {
actual = (Boolean)internalValue.get(VdsProperties.actual);
}
data.setActual(actual);
domainsData.add(data);
} catch (Exception e) {
log.error("failed building domains: {}", e.getMessage());
log.debug("Exception", e);
}
}
vds.setDomains(domainsData);
}
}
private static InterfaceStatus assignInterfaceStatusValue(Map<String, Object> input, String name) {
InterfaceStatus ifaceStatus = InterfaceStatus.NONE;
if (input.containsKey(name)) {
String stringValue = (String) ((input.get(name) instanceof String) ? input.get(name) : null);
if (!StringUtils.isEmpty(stringValue)) {
if (stringValue.toLowerCase().trim().equals("up")) {
ifaceStatus = InterfaceStatus.UP;
} else {
ifaceStatus = InterfaceStatus.DOWN;
}
}
}
return ifaceStatus;
}
private static Double assignDoubleValue(Map<String, Object> input, String name) {
Object value = input.get(name);
if (value instanceof Double) {
return (Double) value;
} else if (value instanceof String) {
return Double.parseDouble((String) value);
}
return null;
}
/**
* Do the same logic as assignDoubleValue does, but instead, in case of null we return 0.
* @param input - the Input xml
* @param name - The name of the field we want to cast it to double.
* @return - the double value.
*/
private static Double assignDoubleValueWithNullProtection(Map<String, Object> input, String name) {
Double doubleValue = assignDoubleValue(input, name);
return doubleValue == null ? Double.valueOf(0.0) : doubleValue;
}
private static Integer assignIntValue(Map input, String name) {
if (input.containsKey(name)) {
if (input.get(name) instanceof Integer) {
return (Integer) input.get(name);
}
String stringValue = (String) input.get(name);
if (StringUtils.isNotEmpty(stringValue)) { // in case the input
// is decimal and we
// need int.
stringValue = stringValue.split("[.]", -1)[0];
try {
return Integer.parseInt(stringValue);
} catch (NumberFormatException nfe) {
log.error("Failed to parse '{}' value '{}' to integer: {}", name, stringValue, nfe.getMessage());
}
}
}
return null;
}
private static Long assignLongValue(Map<String, Object> input, String name) {
if (input.containsKey(name)) {
if (input.get(name) instanceof Long || input.get(name) instanceof Integer) {
return Long.parseLong(input.get(name).toString());
}
String stringValue = (String) ((input.get(name) instanceof String) ? input.get(name) : null);
if (!StringUtils.isEmpty(stringValue)) { // in case the input
// is decimal and we
// need int.
stringValue = stringValue.split("[.]", -1)[0];
try {
return Long.parseLong(stringValue);
} catch (NumberFormatException e) {
log.error("Failed to parse '{}' value '{}' to long: {}", name, stringValue, e.getMessage());
}
}
}
return null;
}
private static String assignStringValue(Map<String, Object> input, String name) {
if (input.containsKey(name)) {
return (String) ((input.get(name) instanceof String) ? input.get(name) : null);
}
return null;
}
private static String[] assignStringArrayValue(Map<String, Object> input, String name) {
String[] array = null;
if (input.containsKey(name)) {
array = (String[]) ((input.get(name) instanceof String[]) ? input.get(name) : null);
if (array == null) {
Object[] arr2 = (Object[]) ((input.get(name) instanceof Object[]) ? input.get(name) : null);
if (arr2 != null) {
array = new String[arr2.length];
for (int i = 0; i < arr2.length; i++) {
array[i] = arr2[i].toString();
}
}
}
}
return array;
}
private static String assignStringValueFromArray(Map<String, Object> input, String name) {
String[] arr = assignStringArrayValue(input, name);
if (arr != null) {
return StringUtils.join(arr, ',');
}
return null;
}
private static Date assignDatetimeValue(Map<String, Object> input, String name) {
if (input.containsKey(name)) {
if (input.get(name) instanceof Date) {
return (Date) input.get(name);
}
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
String dateStr = input.get(name).toString().replaceFirst("T", " ").trim();
try {
return formatter.parse(dateStr);
} catch (ParseException e) {
log.error("Failed parsing {}", dateStr, e);
}
}
return null;
}
private static Boolean assignBoolValue(Map<String, Object> input, String name) {
if (input.containsKey(name)) {
if (input.get(name) instanceof Boolean) {
return (Boolean) input.get(name);
}
return Boolean.parseBoolean(input.get(name).toString());
}
return Boolean.FALSE;
}
public static List<DiskImageDynamic> buildVmDiskStatistics(Map<String, Object> vmStruct) {
Map<String, Object> disks = (Map<String, Object>) vmStruct.get(VdsProperties.vm_disks);
if (disks == null) {
return Collections.emptyList();
}
List<DiskImageDynamic> disksData = new ArrayList<>();
for (Object diskAsObj : disks.values()) {
Map<String, Object> disk = (Map<String, Object>) diskAsObj;
DiskImageDynamic diskData = new DiskImageDynamic();
String imageGroupIdString = assignStringValue(disk, VdsProperties.image_group_id);
if (!StringUtils.isEmpty(imageGroupIdString)) {
Guid imageGroupIdGuid = new Guid(imageGroupIdString);
diskData.setId(imageGroupIdGuid);
diskData.setReadRate(assignIntValue(disk, VdsProperties.vm_disk_read_rate));
diskData.setWriteRate(assignIntValue(disk, VdsProperties.vm_disk_write_rate));
if (disk.containsKey(VdsProperties.disk_actual_size)) {
Long size = assignLongValue(disk, VdsProperties.disk_actual_size);
diskData.setActualSize(size != null ? size * 512 : 0);
} else if (disk.containsKey(VdsProperties.disk_true_size)) {
Long size = assignLongValue(disk, VdsProperties.disk_true_size);
diskData.setActualSize(size != null ? size : 0);
}
if (disk.containsKey(VdsProperties.vm_disk_read_latency)) {
diskData.setReadLatency(assignDoubleValueWithNullProtection(disk,
VdsProperties.vm_disk_read_latency) / NANO_SECONDS);
}
if (disk.containsKey(VdsProperties.vm_disk_write_latency)) {
diskData.setWriteLatency(assignDoubleValueWithNullProtection(disk,
VdsProperties.vm_disk_write_latency) / NANO_SECONDS);
}
if (disk.containsKey(VdsProperties.vm_disk_flush_latency)) {
diskData.setFlushLatency(assignDoubleValueWithNullProtection(disk,
VdsProperties.vm_disk_flush_latency) / NANO_SECONDS);
}
disksData.add(diskData);
}
}
return disksData;
}
private static void initAppsList(Map<String, Object> vmStruct, VmDynamic vm) {
if (vmStruct.containsKey(VdsProperties.app_list)) {
Object tempAppsList = vmStruct.get(VdsProperties.app_list);
if (tempAppsList instanceof Object[]) {
Object[] apps = (Object[]) tempAppsList;
StringBuilder builder = new StringBuilder();
boolean firstTime = true;
for (Object app : apps) {
String appString = (String) ((app instanceof String) ? app : null);
if (app == null) {
log.warn("Failed to convert app: [null] to string");
continue; // Don't process this
}
if(appString == null) {
// Note: app cannot be null here anymore
log.warn("Failed to convert app: [" + app.getClass().getName() + "] is not a string");
continue; // Don't process this
}
if (!firstTime) {
builder.append(",");
} else {
firstTime = false;
}
builder.append(appString);
}
vm.setAppList(builder.toString());
} else {
vm.setAppList("");
}
}
}
private static void initGuestContainers(Map<String, Object> vmStruct, VmDynamic vm) {
if (vmStruct.containsKey(VdsProperties.guest_containers)) {
vm.setGuestContainers(new ArrayList<>());
Object obj = vmStruct.get(VdsProperties.guest_containers);
if (obj instanceof Object[]) {
Object[] containers = (Object[])obj;
for (Object containerObj : containers) {
Map<String, Object> container = (Map<String, Object>) containerObj;
ArrayList<String> names = new ArrayList<>();
for(Object o : (Object[]) container.get(VdsProperties.guest_container_names)) {
names.add((String)o);
}
vm.getGuestContainers().add(new GuestContainer(
(String)container.get(VdsProperties.guest_container_id),
names,
(String)container.get(VdsProperties.guest_container_image),
(String)container.get(VdsProperties.guest_container_command),
(String)container.get(VdsProperties.guest_container_status)
));
}
}
} else {
vm.setGuestContainers(Collections.emptyList());
}
}
public static VMStatus convertToVmStatus(String status) {
switch(status) {
case VdsProperties.MIGRATION_SOURCE:
return VMStatus.MigratingFrom;
case VdsProperties.MIGRATION_DESTINATION:
return VMStatus.MigratingTo;
default:
status = status.replace(" ", "");
try {
return EnumUtils.valueOf(VMStatus.class, status, true);
} catch (Exception e) {
log.error("Illegal VM status: '{}'.", status);
return VMStatus.Unassigned;
}
}
}
/**
* Updates the host network data with the network data reported by the host
*
* @param vds
* The host to update
* @param struct
* A nested map contains network interfaces data
*/
public static void updateNetworkData(VDS vds, Map<String, Object> struct) {
List<VdsNetworkInterface> oldInterfaces =
DbFacade.getInstance().getInterfaceDao().getAllInterfacesForVds(vds.getId());
vds.getInterfaces().clear();
addHostNetworkInterfaces(vds, struct);
addHostVlanDevices(vds, struct);
addHostBondDevices(vds, struct);
addHostNetworksAndUpdateInterfaces(vds, struct);
// set bonding options
setBondingOptions(vds, oldInterfaces);
// This information was added in 3.1, so don't use it if it's not there.
if (struct.containsKey(VdsProperties.netConfigDirty)) {
vds.setNetConfigDirty(assignBoolValue(struct, VdsProperties.netConfigDirty));
}
}
/***
* resolve the the host's interface that is being used to communicate with engine.
*
* @return host's interface that being used to communicate with engine, null otherwise
*/
private static VdsNetworkInterface resolveActiveNic(VDS host, String hostIp) {
if (hostIp == null) {
return null;
}
VdsNetworkInterface activeIface = host.getInterfaces().stream()
.filter(new InterfaceByAddressPredicate(hostIp)).findFirst().orElse(null);
return activeIface;
}
private static void addHostNetworksAndUpdateInterfaces(VDS host, Map<String, Object> struct) {
Map<String, Map<String, Object>> bridges =
(Map<String, Map<String, Object>>) struct.get(VdsProperties.NETWORK_BRIDGES);
final String hostActiveNicName = findActiveNicName(host, bridges);
host.setActiveNic(hostActiveNicName);
// Networks collection (name point to list of nics or bonds)
Map<String, Map<String, Object>> networks =
(Map<String, Map<String, Object>>) struct.get(VdsProperties.NETWORKS);
Map<String, VdsNetworkInterface> vdsInterfaces = Entities.entitiesByName(host.getInterfaces());
if (networks != null) {
host.getNetworkNames().clear();
for (Entry<String, Map<String, Object>> entry : networks.entrySet()) {
Map<String, Object> networkProperties = entry.getValue();
String networkName = entry.getKey();
if (networkProperties != null) {
String interfaceName = (String) networkProperties.get(VdsProperties.INTERFACE);
Map<String, Object> bridgeProperties = (bridges == null) ? null : bridges.get(interfaceName);
boolean bridgedNetwork = isBridgedNetwork(networkProperties);
SwitchType switchType = getSwitchType(
host.getSupportedClusterVersionsSet().stream().sorted().reduce((first, second) -> second).get(),
networkProperties
);
HostNetworkQos qos = new HostNetworkQosMapper(networkProperties).deserialize();
/**
* TODO: remove overly-defensive code in 4.0 - IP address, subnet, gateway and boot protocol should
* only be extracted for bridged networks and from bridge entries (not network entries)
**/
Map<String, Object> effectiveProperties =
(bridgedNetwork && bridgeProperties != null) ?
bridgeProperties : networkProperties;
String v4addr = extractAddress(effectiveProperties);
String v4Subnet = extractSubnet(effectiveProperties);
String v4gateway = (String) effectiveProperties.get(VdsProperties.GLOBAL_GATEWAY);
final String rawIpv6Address = getIpv6Address(effectiveProperties);
String v6Addr = extractIpv6Address(rawIpv6Address);
Integer v6Prefix = extractIpv6Prefix(rawIpv6Address);
String v6gateway = (String) effectiveProperties.get(VdsProperties.IPV6_GLOBAL_GATEWAY);
List<VdsNetworkInterface> interfaces = findNetworkInterfaces(vdsInterfaces, interfaceName, bridgeProperties);
for (VdsNetworkInterface iface : interfaces) {
iface.setNetworkName(networkName);
iface.setIpv4Address(v4addr);
iface.setIpv4Subnet(v4Subnet);
iface.setIpv6Address(v6Addr);
iface.setIpv6Prefix(v6Prefix);
iface.setBridged(bridgedNetwork);
iface.setReportedSwitchType(switchType);
iface.setQos(qos);
// set the management ip
if (getManagementNetworkUtil().isManagementNetwork(iface.getNetworkName(), host.getClusterId())) {
iface.setType(iface.getType() | VdsInterfaceType.MANAGEMENT.getValue());
}
iface.setIpv4Gateway(v4gateway);
iface.setIpv6Gateway(v6gateway);
if (bridgedNetwork) {
addBootProtocol(effectiveProperties, iface);
}
}
host.getNetworkNames().add(networkName);
reportInvalidInterfacesForNetwork(interfaces, networkName, host);
}
}
}
}
private static String findActiveNicName(VDS vds, Map<String, Map<String, Object>> bridges) {
final String hostIp = NetworkUtils.getHostIp(vds);
final String activeBridge = findActiveBridge(hostIp, bridges);
if (activeBridge != null) {
return activeBridge;
}
// by now, if the host is communicating with engine over a valid interface,
// the interface will have the host's engine IP
final VdsNetworkInterface activeIface = resolveActiveNic(vds, hostIp);
String hostActiveNic = (activeIface == null) ? null : activeIface.getName();
return hostActiveNic;
}
/***
* @return the name of the bridge obtaining ipAddress, null in case no such exist
*/
private static String findActiveBridge(String ipAddress, Map<String, Map<String, Object>> bridges) {
if (bridges != null) {
final Predicate<String> ipAddressPredicate = new IpAddressPredicate(ipAddress);
for (Entry<String, Map<String, Object>> entry : bridges.entrySet()) {
Map<String, Object> bridgeProperties = entry.getValue();
String bridgeName = entry.getKey();
if (bridgeProperties != null) {
String bridgeIpv4Address = (String) bridgeProperties.get("addr");
String bridgeIpv6Address = extractIpv6Address(getIpv6Address(bridgeProperties));
// in case host is communicating with engine over a bridge
if (ipAddressPredicate.test(bridgeIpv4Address) || ipAddressPredicate.test(bridgeIpv6Address)) {
return bridgeName;
}
}
}
}
return null;
}
/**
* Reports a warning to the audit log if a bridge is connected to more than one interface which is considered bad
* configuration.
*
* @param interfaces
* The network's interfaces
* @param networkName
* The network to report for
* @param vds
* The host in which the network is defined
*/
private static void reportInvalidInterfacesForNetwork(List<VdsNetworkInterface> interfaces, String networkName, VDS vds) {
if (interfaces.isEmpty()) {
auditLogDirector.log(createHostNetworkAuditLog(networkName, vds), AuditLogType.NETWORK_WITHOUT_INTERFACES);
} else if (interfaces.size() > 1) {
AuditLogable logable = createHostNetworkAuditLog(networkName, vds);
logable.addCustomValue("Interfaces",
interfaces.stream().map(VdsNetworkInterface::getName).collect(Collectors.joining(",")));
auditLogDirector.log(logable, AuditLogType.BRIDGED_NETWORK_OVER_MULTIPLE_INTERFACES);
}
}
protected static AuditLogable createHostNetworkAuditLog(String networkName, VDS vds) {
AuditLogable logable = createAuditLogableForHost(vds);
logable.addCustomValue("NetworkName", networkName);
return logable;
}
private static AuditLogable createAuditLogableForHost(VDS vds) {
AuditLogable logable = new AuditLogableImpl();
logable.setVdsId(vds.getId());
logable.setVdsName(vds.getName());
return logable;
}
private static List<VdsNetworkInterface> findNetworkInterfaces(Map<String, VdsNetworkInterface> vdsInterfaces,
String interfaceName,
Map<String, Object> bridgeProperties) {
List<VdsNetworkInterface> interfaces = new ArrayList<>();
VdsNetworkInterface iface = vdsInterfaces.get(interfaceName);
if (iface == null) {
if (bridgeProperties != null) {
interfaces.addAll(findBridgedNetworkInterfaces(bridgeProperties, vdsInterfaces));
}
} else {
interfaces.add(iface);
}
return interfaces;
}
private static List<VdsNetworkInterface> findBridgedNetworkInterfaces(Map<String, Object> bridge,
Map<String, VdsNetworkInterface> vdsInterfaces) {
Object[] ports = (Object[]) bridge.get("ports");
if (ports != null) {
return Arrays.stream(ports).filter(port -> vdsInterfaces.containsKey(port.toString()))
.map(port -> vdsInterfaces.get(port.toString())).collect(Collectors.toList());
}
return new ArrayList<>();
}
private static void addHostBondDevices(VDS vds, Map<String, Object> struct) {
Map<String, Map<String, Object>> bonds =
(Map<String, Map<String, Object>>) struct.get(VdsProperties.NETWORK_BONDINGS);
if (bonds != null) {
for (Entry<String, Map<String, Object>> entry : bonds.entrySet()) {
Bond bond = new Bond();
updateCommonInterfaceData(bond, vds, entry);
bond.setBonded(true);
Map<String, Object> bondProperties = entry.getValue();
if (bondProperties != null) {
bond.setMacAddress((String) bondProperties.get("hwaddr"));
if (bondProperties.get("slaves") != null) {
addBondDeviceToHost(vds, bond, (Object[]) bondProperties.get("slaves"));
}
bond.setBondOptions(parseBondOptions((Map<String, Object>) bondProperties.get("opts")));
bond.setAdPartnerMac((String) bondProperties.get("ad_partner_mac"));
bond.setActiveSlave((String) bondProperties.get("active_slave"));
}
}
}
}
/**
* Retrieves bonding options string from the structure that describes the bond options as reported by VDSM
* @param struct
* a map contains pairs of option name and value
* @return
* - null is returned for null valued `struct`
* - else bonding options string
*/
private static String parseBondOptions(Map<String, Object> struct) {
if (struct == null) {
return null;
}
Set<String> reservedPositionKeys = new LinkedHashSet<>();
reservedPositionKeys.add("mode");
reservedPositionKeys.add("miimon");
reservedPositionKeys.add(VdsProperties.BOND_XMIT_POLICY);
List<String> bondOptions = new ArrayList<>();
for(String key : reservedPositionKeys) {
String value = (String) struct.get(key);
if (value != null) {
bondOptions.add(
String.format("%s=%s", key, value));
}
}
for (Entry<String, Object> entry : struct.entrySet()) {
if (!reservedPositionKeys.contains(entry.getKey())) {
bondOptions.add(
String.format("%s=%s", entry.getKey(), entry.getValue()));
}
}
return normalizeBondOptions(StringUtils.join(bondOptions, ' '));
}
private static String normalizeBondOptions(String bondOptions){
Matcher matcher = Pattern.compile("mode=([\\w-\\.]+)").matcher(bondOptions);
if (!matcher.find()) {
return bondOptions;
}
BondMode bondMode = BondMode.getBondMode(matcher.group(1));
if (bondMode != null) {
return matcher.replaceAll("mode=" + bondMode.getValue());
}
return bondOptions;
}
/**
* Updates the host interfaces list with vlan devices
*
* @param vds
* The host to update
* @param struct
* a map contains pairs of vlan device name and vlan data
*/
private static void addHostVlanDevices(VDS vds, Map<String, Object> struct) {
// vlans
Map<String, Map<String, Object>> vlans = (Map<String, Map<String, Object>>) struct.get(VdsProperties.NETWORK_VLANS);
if (vlans != null) {
for (Entry<String, Map<String, Object>> entry : vlans.entrySet()) {
VdsNetworkInterface vlan = new Vlan();
updateCommonInterfaceData(vlan, vds, entry);
String vlanDeviceName = entry.getKey();
Map<String, Object> vlanProperties = entry.getValue();
if (vlanProperties.get(VdsProperties.VLAN_ID) != null && vlanProperties.get(VdsProperties.BASE_INTERFACE) != null) {
vlan.setVlanId((Integer) vlanProperties.get(VdsProperties.VLAN_ID));
vlan.setBaseInterface((String) vlanProperties.get(VdsProperties.BASE_INTERFACE));
} else if (vlanDeviceName.contains(".")) {
String[] names = vlanDeviceName.split("[.]", -1);
String vlanId = names[1];
vlan.setVlanId(Integer.parseInt(vlanId));
vlan.setBaseInterface(names[0]);
}
vds.getInterfaces().add(vlan);
}
}
}
/**
* Updates the host network interfaces with the collected data from the host
*
* @param vds
* The host to update its interfaces
* @param struct
* A nested map contains network interfaces data
*/
private static void addHostNetworkInterfaces(VDS vds, Map<String, Object> struct) {
Map<String, Map<String, Object>> nics =
(Map<String, Map<String, Object>>) struct.get(VdsProperties.NETWORK_NICS);
if (nics != null) {
for (Entry<String, Map<String, Object>> entry : nics.entrySet()) {
VdsNetworkInterface nic = new Nic();
updateCommonInterfaceData(nic, vds, entry);
Map<String, Object> nicProperties = entry.getValue();
if (nicProperties != null) {
if (nicProperties.get("speed") != null) {
Object speed = nicProperties.get("speed");
nic.setSpeed((Integer) speed);
}
nic.setMacAddress((String) nicProperties.get("hwaddr"));
// if we get "permhwaddr", we are a part of a bond and we use that as the mac address
String mac = (String) nicProperties.get("permhwaddr");
if (mac != null) {
//TODO remove when the minimal supported vdsm version is >=3.6
// in older VDSM version, slave's Mac is in upper case
nic.setMacAddress(mac.toLowerCase());
}
}
vds.getInterfaces().add(nic);
}
}
}
/**
* Updates a given interface (be it physical, bond or VLAN) by data as collected from the host.
*
* @param iface
* The interface to update
* @param host
* The host to which the interface belongs.
* @param ifaceEntry
* A pair whose key is the interface's name, and whose value it a map of the interface properties.
*/
private static void updateCommonInterfaceData(VdsNetworkInterface iface,
VDS host,
Entry<String, Map<String, Object>> ifaceEntry) {
iface.setName(ifaceEntry.getKey());
iface.setId(Guid.newGuid());
iface.setVdsId(host.getId());
VdsNetworkStatistics iStats = new VdsNetworkStatistics();
iStats.setId(iface.getId());
iStats.setVdsId(host.getId());
iface.setStatistics(iStats);
Map<String, Object> nicProperties = ifaceEntry.getValue();
if (nicProperties != null) {
iface.setIpv4Address(extractAddress(nicProperties));
iface.setIpv4Subnet(extractSubnet(nicProperties));
final String ipv6Address = getIpv6Address(nicProperties);
iface.setIpv6Address(extractIpv6Address(ipv6Address));
iface.setIpv6Prefix(extractIpv6Prefix(ipv6Address));
final Integer mtu = assignIntValue(nicProperties, VdsProperties.MTU);
if (mtu != null) {
iface.setMtu(mtu);
}
addBootProtocol(nicProperties, iface);
addAdAggregatorId(nicProperties, iface);
}
}
private static void addAdAggregatorId(Map<String, Object> nicProperties,
VdsNetworkInterface iface) {
Object adAggregatorId = nicProperties.get("ad_aggregator_id");
if (adAggregatorId != null) {
iface.setAdAggregatorId(Integer.parseInt((String) adAggregatorId));
}
}
static Integer extractIpv6Prefix(String ipv6Address) {
if (ipv6Address == null) {
return null;
}
final Matcher matcher = IPV6_ADDRESS_CAPTURE_PREFIX_PATTERN.matcher(ipv6Address);
if (matcher.matches()) {
final String prefixString = matcher.group(1);
return Integer.valueOf(prefixString);
}
return null;
}
private static String extractAddress(Map<String, Object> properties) {
return (String) properties.get("addr");
}
private static String extractSubnet(Map<String, Object> properties) {
return (String) properties.get("netmask");
}
private static String getIpv6Address(Map<String, Object> properties) {
final Object[] ipv6Addresses = (Object[]) properties.get("ipv6addrs");
if (ipv6Addresses == null || ipv6Addresses.length == 0) {
return null;
}
return (String) ipv6Addresses[0];
}
static String extractIpv6Address(String address) {
if (StringUtils.isEmpty(address)) {
return null;
}
final Matcher matcher = IPV6_ADDRESS_CAPTURE_PATTERN.matcher(address);
return matcher.matches() ? matcher.group(1) : address;
}
/**
* Returns true if vdsm doesn't report the 'bridged' attribute or if reported - its actual value.<br>
* The assumption is bridge-less network isn't supported if the 'bridged' attribute wasn't reported.<br>
* Bridge-less networks must report 'false' for this property.
*
* @param network
* The network to evaluate its bridge attribute
* @return true is no attribute is reported or its actual value
*/
private static boolean isBridgedNetwork(Map<String, Object> network) {
return network.get("bridged") == null || Boolean.parseBoolean(network.get("bridged").toString());
}
/**
* @return {@link SwitchType} obtained from reported network properties.
* @throws IllegalStateException when switch type is not reported.
*/
private static SwitchType getSwitchType(Version clusterVersion, Map<String, Object> networkProperties) {
Object switchType = networkProperties.get(VdsProperties.SWITCH_KEY);
boolean switchTypeShouldBeReportedByVdsm = FeatureSupported.ovsSupported(clusterVersion);
if (switchTypeShouldBeReportedByVdsm && switchType == null) {
throw new IllegalStateException("Required SwitchType is not reported.");
}
return SwitchType.parse(Objects.toString(switchType, SwitchType.LEGACY.getOptionValue()));
}
// we check for old bonding options,
// if we had value for the bonding options, i.e. the user set it by the UI
// and we have host that is not returning it's bonding options(host below 2.2.4) we override
// the "new" bonding options with the old one only if we have the new one as null and the old one is not
private static void setBondingOptions(VDS vds, List<VdsNetworkInterface> oldInterfaces) {
oldInterfaces.stream().
filter(iface -> iface.getBondOptions() != null).
forEach(iface -> vds.getInterfaces()
.stream()
.filter(newIface -> iface.getName().equals(newIface.getName()))
.filter(newIface -> newIface.getBondOptions() == null)
.findFirst()
.ifPresent(newIface -> newIface.setBondOptions(iface.getBondOptions())));
}
private static Ipv4BootProtocolResolver getIpv4BootProtocolResolver() {
return Injector.get(Ipv4BootProtocolResolver.class);
}
private static Ipv6BootProtocolResolver getIpv6BootProtocolResolver() {
return Injector.get(Ipv6BootProtocolResolver.class);
}
private static void addBootProtocol(Map<String, Object> nicProperties, VdsNetworkInterface iface) {
if (nicProperties == null) {
return;
}
setBootProtocolAndGateway(
getIpv4BootProtocolResolver(),
new NoCfgIpv4InfoFetcher(nicProperties, iface.getIpv4Address()),
bootProtocol -> Ipv4BootProtocol.STATIC_IP == bootProtocol,
iface::setIpv4BootProtocol,
iface::setIpv4Gateway);
setBootProtocolAndGateway(
getIpv6BootProtocolResolver(),
new NoCfgIpv6InfoFetcher(nicProperties, iface.getIpv6Address()),
bootProtocol -> Ipv6BootProtocol.STATIC_IP == bootProtocol,
iface::setIpv6BootProtocol,
iface::setIpv6Gateway);
}
private static <T, F extends IpInfoFetcher> void setBootProtocolAndGateway(
BootProtocolResolver<T, F> bootProtocolResolver,
F infoFetcher,
Predicate<T> bootProtocolStaticIpPredicate,
Consumer<T> bootProtocolSetter,
Consumer<String> gatewaySetter) {
final T bootProtocol = bootProtocolResolver.resolve(infoFetcher);
bootProtocolSetter.accept(bootProtocol);
if (bootProtocolStaticIpPredicate.test(bootProtocol)) {
String gateway = infoFetcher.fetchGateway();
if (StringUtils.isNotEmpty(gateway)) {
gatewaySetter.accept(gateway);
}
}
}
private static void addBondDeviceToHost(VDS vds, VdsNetworkInterface iface, Object[] interfaces) {
vds.getInterfaces().add(iface);
if (interfaces != null) {
Arrays.stream(interfaces).
forEach(name -> vds.getInterfaces()
.stream()
.filter(tempInterface -> tempInterface.getName().equals(name.toString()))
.findFirst()
.ifPresent(tempInterface -> tempInterface.setBondName(iface.getName())));
}
}
private static ManagementNetworkUtil getManagementNetworkUtil() {
final ManagementNetworkUtil managementNetworkUtil = Injector.get(ManagementNetworkUtil.class);
return managementNetworkUtil;
}
/**
* Creates a list of {@link VmGuestAgentInterface} from the {@link VdsProperties.GuestNetworkInterfaces}
*
* @param vmId
* the Vm's ID which contains the interfaces
*
* @param struct
* the structure that describes the VM as reported by VDSM
* @return a list of {@link VmGuestAgentInterface} or null if no guest vNics were reported
*/
public static List<VmGuestAgentInterface> buildVmGuestAgentInterfacesData(Guid vmId, Map<String, Object> struct) {
if (!struct.containsKey(VdsProperties.VM_NETWORK_INTERFACES)) {
return null;
}
List<VmGuestAgentInterface> interfaces = new ArrayList<>();
for (Object ifaceStruct : (Object[]) struct.get(VdsProperties.VM_NETWORK_INTERFACES)) {
VmGuestAgentInterface nic = new VmGuestAgentInterface();
Map ifaceMap = (Map) ifaceStruct;
nic.setInterfaceName(assignStringValue(ifaceMap, VdsProperties.VM_INTERFACE_NAME));
nic.setMacAddress(getMacAddress(ifaceMap));
nic.setIpv4Addresses(extractList(ifaceMap, VdsProperties.VM_IPV4_ADDRESSES, true));
nic.setIpv6Addresses(extractList(ifaceMap, VdsProperties.VM_IPV6_ADDRESSES, true));
nic.setVmId(vmId);
interfaces.add(nic);
}
return interfaces;
}
private static String getMacAddress(Map<String, Object> ifaceMap) {
String macAddress = assignStringValue(ifaceMap, VdsProperties.VM_INTERFACE_MAC_ADDRESS);
return macAddress != null ? macAddress.replace('-', ':') : null;
}
/**
* Build through the received NUMA nodes information
*/
private static void updateNumaNodesData(VDS vds, Map<String, Object> struct) {
if (struct.containsKey(VdsProperties.AUTO_NUMA)) {
vds.getDynamicData().setAutoNumaBalancing(AutoNumaBalanceStatus.forValue(
assignIntValue(struct, VdsProperties.AUTO_NUMA)));
}
if (struct.containsKey(VdsProperties.NUMA_NODES)) {
Map<String, Map<String, Object>> numaNodeMap =
(Map<String, Map<String, Object>>) struct.get(VdsProperties.NUMA_NODES);
Map<String, Object> numaNodeDistanceMap =
(Map<String, Object>) struct.get(VdsProperties.NUMA_NODE_DISTANCE);
List<VdsNumaNode> newNumaNodeList = new ArrayList<>(numaNodeMap.size());
for (Map.Entry<String, Map<String, Object>> item : numaNodeMap.entrySet()) {
int index = Integer.parseInt(item.getKey());
Map<String, Object> itemMap = item.getValue();
List<Integer> cpuIds = extractList(itemMap, VdsProperties.NUMA_NODE_CPU_LIST, false);
long memTotal = assignLongValue(itemMap, VdsProperties.NUMA_NODE_TOTAL_MEM);
VdsNumaNode numaNode = new VdsNumaNode();
numaNode.setIndex(index);
if (cpuIds != null) {
numaNode.setCpuIds(cpuIds);
}
numaNode.setMemTotal(memTotal);
newNumaNodeList.add(numaNode);
}
Collections.sort(newNumaNodeList, numaNodeComparator);
for (VdsNumaNode vdsNumaNode : newNumaNodeList) {
int index = vdsNumaNode.getIndex();
Map<Integer, Integer> distanceMap = new HashMap<>();
List<Integer> distances = Collections.emptyList();
if (numaNodeDistanceMap != null) {
// Save the received NUMA node distances
distances = extractList(numaNodeDistanceMap, String.valueOf(index), false);
for (int i = 0; i < distances.size(); i++) {
distanceMap.put(newNumaNodeList.get(i).getIndex(), distances.get(i));
}
}
if (distances.isEmpty()) {
// Save faked distances
for (VdsNumaNode otherNumaNode : newNumaNodeList) {
// There is no distance if the node is the same one
if (otherNumaNode.getIndex() == vdsNumaNode.getIndex()) {
continue;
}
distanceMap.put(otherNumaNode.getIndex(), 0);
}
}
VdsNumaNode newNumaNode = NumaUtils.getVdsNumaNodeByIndex(newNumaNodeList, index);
if (newNumaNode != null) {
newNumaNode.setNumaNodeDistances(distanceMap);
}
}
vds.getDynamicData().setNumaNodeList(newNumaNodeList);
vds.setNumaSupport(newNumaNodeList.size() > 1);
}
}
private static <T> List<T> extractList(Map<String, Object> struct, String propertyName, boolean returnNullOnEmpty) {
if (struct.containsKey(propertyName)){
Object[] items = (Object[]) struct.get(propertyName);
if (items.length > 0) {
return Arrays.stream(items).map(item -> (T) item).collect(Collectors.toList());
}
}
return returnNullOnEmpty ? null : Collections.emptyList();
}
/**
* Parse Host Device Information in the form of
*
* {
* 'computer': {
* 'params': {'capability': 'system', 'product': 'ProLiant DL160 G6 '}
* },
* 'pci_0000_00_1d_2': {
* 'params': {
* 'capability': 'pci',
* 'iommu_group': '9',
* 'parent': 'computer',
* 'product': '82801JI (ICH10 Family) USB UHCI Controller #3',
* 'product_id': '0x3a36',
* 'vendor': 'Intel Corporation',
* 'vendor_id': '0x8086'
* }
* },
* 'pci_0000_00_1d_1': {
* ...
* }
* }
*/
public static List<HostDevice> buildHostDevices(Map<String, Map<String, Map<String, Object>>> deviceList) {
List<HostDevice> devices = new ArrayList<>();
for (Entry<String, Map<String, Map<String, Object>>> entry : deviceList.entrySet()) {
Map<String, Object> params = entry.getValue().get(VdsProperties.PARAMS);
String deviceName = entry.getKey();
HostDevice device = new HostDevice();
device.setDeviceName(entry.getKey());
device.setCapability(params.get(VdsProperties.CAPABILITY).toString());
// special case for root device "computer"
if (VdsProperties.ROOT_HOST_DEVICE.equals(deviceName)) {
device.setParentDeviceName(VdsProperties.ROOT_HOST_DEVICE); // set parent to self, for DB integrity
} else {
device.setParentDeviceName(params.get(VdsProperties.PARENT_NAME).toString());
}
if (params.containsKey(VdsProperties.IOMMU_GROUP)) {
device.setIommuGroup(Integer.parseInt(params.get(VdsProperties.IOMMU_GROUP).toString()));
}
if (params.containsKey(VdsProperties.PRODUCT_ID)) {
device.setProductId(params.get(VdsProperties.PRODUCT_ID).toString());
}
if (params.containsKey(VdsProperties.PRODUCT_NAME)) {
device.setProductName(params.get(VdsProperties.PRODUCT_NAME).toString());
}
if (params.containsKey(VdsProperties.VENDOR_NAME)) {
device.setVendorName(params.get(VdsProperties.VENDOR_NAME).toString());
}
if (params.containsKey(VdsProperties.VENDOR_ID)) {
device.setVendorId(params.get(VdsProperties.VENDOR_ID).toString());
}
if (params.containsKey(VdsProperties.PHYSICAL_FUNCTION)) {
device.setParentPhysicalFunction(params.get(VdsProperties.PHYSICAL_FUNCTION).toString());
}
if (params.containsKey(VdsProperties.TOTAL_VFS)) {
device.setTotalVirtualFunctions(Integer.parseInt(params.get(VdsProperties.TOTAL_VFS).toString()));
}
if (params.containsKey(VdsProperties.NET_INTERFACE_NAME)) {
device.setNetworkInterfaceName(params.get(VdsProperties.NET_INTERFACE_NAME).toString());
}
if (params.containsKey(VdsProperties.DRIVER)) {
device.setDriver(params.get(VdsProperties.DRIVER).toString());
}
if (params.containsKey(VdsProperties.IS_ASSIGNABLE)) {
device.setAssignable(assignBoolValue(params, VdsProperties.IS_ASSIGNABLE));
} else {
device.setAssignable(true);
}
devices.add(device);
}
return devices;
}
private static void updateV2VJobs(VDS vds, Map<String, Object> struct) {
if (!struct.containsKey(VdsProperties.v2vJobs)) {
return;
}
List<V2VJobInfo> v2vJobs = ((Map<String, Object>) struct.get(VdsProperties.v2vJobs)).entrySet()
.stream()
.map(job -> buildV2VJobData(job.getKey(), (Map<String, Object>) job.getValue())).collect(Collectors.toList());
vds.getStatisticsData().setV2VJobs(v2vJobs);
}
private static V2VJobInfo buildV2VJobData(String jobId, Map<String, Object> struct) {
V2VJobInfo job = new V2VJobInfo();
job.setId(Guid.createGuidFromString(jobId));
job.setStatus(getV2VJobStatusValue(struct));
job.setDescription(assignStringValue(struct, VdsProperties.v2vDescription));
job.setProgress(assignIntValue(struct, VdsProperties.v2vProgress));
return job;
}
private static V2VJobInfo.JobStatus getV2VJobStatusValue(Map<String, Object> input) {
String status = (String) input.get(VdsProperties.v2vJobStatus);
try {
return V2VJobInfo.JobStatus.valueOf(status.toUpperCase());
} catch (Exception e) {
log.warn("Got invalid status for virt-v2v job: {}", status);
return V2VJobInfo.JobStatus.UNKNOWN;
}
}
public static Double removeNotifyTimeFromVmStatusEvent(Map<String, Object> struct) {
Object notifyTime = struct.remove(VdsProperties.notify_time);
if (Long.class.isInstance(notifyTime)) {
return ((Long) notifyTime).doubleValue();
}
return null;
}
public static LeaseStatus buildLeaseStatus(Map<String, Object> struct) {
return new LeaseStatus(extractList(struct, "owners", true));
}
}