diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index bd371ceacecf..1a65f81a6633 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -5093,82 +5093,91 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li String mergeCommand = String.format("virsh qemu-agent-command %s '{\"execute\":\"guest-info\"}'", vmName); String result = Script.runSimpleBashScript(mergeCommand); - if (result != null) { - qemuAgentVersion = new JsonParser().parse(result).getAsJsonObject().get("return").getAsJsonObject().get("version").getAsString(); - metrics.setQemuAgentVersion(qemuAgentVersion); - - result = dm.qemuAgentCommand(QemuCommand.buildQemuCommand(QemuCommand.AGENT_NETWORK_GET_INTERFACES, null), 2, 0); - if (result != null && !(result.startsWith("error"))) { - LOGGER.debug(dm.getName() +" >> " + result); - JsonArray arrData = (JsonArray) new JsonParser().parse(result).getAsJsonObject().get("return"); - for (JsonElement je : arrData) { - JsonElement nicName = je.getAsJsonObject().get("name") == null ? null : je.getAsJsonObject().get("name"); - JsonElement nicAddrs = je.getAsJsonObject().get("ip-addresses") == null ? null : je.getAsJsonObject().get("ip-addresses"); - if(nicName == null || "lo".equals(nicName.getAsString())) { - continue; - } else { - if (nicAddrs == null){ + if (StringUtils.isNotBlank(result) && !(result.startsWith("error"))) { + try { + qemuAgentVersion = new JsonParser().parse(result).getAsJsonObject().get("return").getAsJsonObject().get("version").getAsString(); + metrics.setQemuAgentVersion(qemuAgentVersion); + } catch (Exception e) { + LOGGER.warn("Failed to parse qemu guest-info result for VM [{}], keeping default qemu agent version.", vmName, e); + } + + try { + result = dm.qemuAgentCommand(QemuCommand.buildQemuCommand(QemuCommand.AGENT_NETWORK_GET_INTERFACES, null), 2, 0); + if (StringUtils.isNotBlank(result) && !(result.startsWith("error"))) { + LOGGER.debug(dm.getName() + " >> " + result); + JsonArray arrData = (JsonArray) new JsonParser().parse(result).getAsJsonObject().get("return"); + for (JsonElement je : arrData) { + JsonElement nicName = je.getAsJsonObject().get("name") == null ? null : je.getAsJsonObject().get("name"); + JsonElement nicAddrs = je.getAsJsonObject().get("ip-addresses") == null ? null : je.getAsJsonObject().get("ip-addresses"); + if (nicName == null || "lo".equals(nicName.getAsString())) { continue; } else { - JsonElement nicMac = je.getAsJsonObject().get("hardware-address") == null ? null : je.getAsJsonObject().get("hardware-address"); - if (nicMac == null) { + if (nicAddrs == null) { continue; } else { - JsonArray arrData2 = (JsonArray) je.getAsJsonObject().get("ip-addresses"); - for (JsonElement je2 : arrData2) { - JsonElement nicAddrIp = je2.getAsJsonObject().get("ip-address") == null ? null : je2.getAsJsonObject().get("ip-address"); - JsonElement nicAddrIpType = je2.getAsJsonObject().get("ip-address-type") == null ? null : je2.getAsJsonObject().get("ip-address-type"); - if(nicAddrIp == null || nicAddrIpType== null || !"ipv4".equals(nicAddrIpType.getAsString())) { - continue; - } else { - nicAddrMap.put(nicMac.getAsString(), nicAddrIp.getAsString()); + JsonElement nicMac = je.getAsJsonObject().get("hardware-address") == null ? null : je.getAsJsonObject().get("hardware-address"); + if (nicMac == null) { + continue; + } else { + JsonArray arrData2 = (JsonArray) je.getAsJsonObject().get("ip-addresses"); + for (JsonElement je2 : arrData2) { + JsonElement nicAddrIp = je2.getAsJsonObject().get("ip-address") == null ? null : je2.getAsJsonObject().get("ip-address"); + JsonElement nicAddrIpType = je2.getAsJsonObject().get("ip-address-type") == null ? null : je2.getAsJsonObject().get("ip-address-type"); + if (nicAddrIp == null || nicAddrIpType == null || !"ipv4".equals(nicAddrIpType.getAsString())) { + continue; + } else { + nicAddrMap.put(nicMac.getAsString(), nicAddrIp.getAsString()); + } } } } } } + metrics.setNicAddrMap(nicAddrMap); } - metrics.setNicAddrMap(nicAddrMap); + } catch (Exception e) { + LOGGER.warn("Failed to fetch guest network interfaces for VM [{}], continuing without NIC address stats.", vmName, e); } - result = dm.qemuAgentCommand(QemuCommand.buildQemuCommand(QemuCommand.AGENT_GET_FSINFO, null), 2, 0); - if (result != null && !(result.startsWith("error"))) { - // logger.debug(dm.getName() + " >> " + result); - - JsonArray arrData = (JsonArray) new JsonParser().parse(result).getAsJsonObject().get("return"); - - for (JsonElement je : arrData) { - JsonObject jsonObj = je.getAsJsonObject(); - JsonElement diskInfo = jsonObj.get("disk"); - - if (diskInfo != null && diskInfo.isJsonArray()) { - for (JsonElement diskElement : diskInfo.getAsJsonArray()) { - // Capacity used by disk file system - JsonObject diskObj = diskElement.getAsJsonObject(); - - JsonElement serialElement = diskObj.get("serial"); - JsonElement usedFsBytesElement = jsonObj.get("used-bytes"); - if (serialElement == null || serialElement.isJsonNull() || usedFsBytesElement == null || usedFsBytesElement.isJsonNull()) { - continue; - } + try { + result = dm.qemuAgentCommand(QemuCommand.buildQemuCommand(QemuCommand.AGENT_GET_FSINFO, null), 2, 0); + if (StringUtils.isNotBlank(result) && !(result.startsWith("error"))) { + JsonArray arrData = (JsonArray) new JsonParser().parse(result).getAsJsonObject().get("return"); + + for (JsonElement je : arrData) { + JsonObject jsonObj = je.getAsJsonObject(); + JsonElement diskInfo = jsonObj.get("disk"); + + if (diskInfo != null && diskInfo.isJsonArray()) { + for (JsonElement diskElement : diskInfo.getAsJsonArray()) { + // Capacity used by disk file system + JsonObject diskObj = diskElement.getAsJsonObject(); + + JsonElement serialElement = diskObj.get("serial"); + JsonElement usedFsBytesElement = jsonObj.get("used-bytes"); + if (serialElement == null || serialElement.isJsonNull() || usedFsBytesElement == null || usedFsBytesElement.isJsonNull()) { + continue; + } - String serial = diskObj.get("serial").getAsString(); - long usedFsBytes = usedFsBytesElement.getAsLong(); - if (serial.length() >= 20) { - //serial to half path uuid - String serial_val = serial.substring(serial.length() - 20); - String serial_uuid = serial_val.substring(0, 8) + "-" - + serial_val.substring(8, 12) + "-" - + serial_val.substring(12, 16) + "-" - + serial_val.substring(16, 20); - serial = serial_uuid; - System.out.println(serial); + String serial = diskObj.get("serial").getAsString(); + long usedFsBytes = usedFsBytesElement.getAsLong(); + if (serial.length() >= 20) { + // serial to half path uuid + String serialVal = serial.substring(serial.length() - 20); + String serialUuid = serialVal.substring(0, 8) + "-" + + serialVal.substring(8, 12) + "-" + + serialVal.substring(12, 16) + "-" + + serialVal.substring(16, 20); + serial = serialUuid; + } + fsUsageMap.put(serial, fsUsageMap.getOrDefault(serial, 0L) + usedFsBytes); } - fsUsageMap.put(serial, fsUsageMap.getOrDefault(serial, 0L) + usedFsBytes); } } + metrics.setFsUsageMap(fsUsageMap); } - metrics.setFsUsageMap(fsUsageMap); + } catch (Exception e) { + LOGGER.warn("Failed to fetch guest filesystem info for VM [{}], continuing without filesystem usage stats.", vmName, e); } } @@ -6451,4 +6460,3 @@ public void createRBDSecretKeyFileIfNoExist(String uuid, String localPath, Strin } catch (IOException e) {} } } - diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index 3ffeabafc67e..8bb49007e20c 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -304,9 +304,12 @@ export default { message: 'message.action.delete.volume', dataView: true, show: (record, store) => { + const isDetached = !record.virtualmachineid + const isDetachedAllocatedRoot = record.state === 'Allocated' && record.type === 'ROOT' && isDetached return ['Expunging', 'Expunged', 'UploadError'].includes(record.state) || - ['Allocated', 'Uploaded'].includes(record.state) && record.type !== 'ROOT' && !record.virtualmachineid || - (record.state === 'Ready' && record.type !== 'ROOT' && !record.virtualmachineid) || + ['Allocated', 'Uploaded'].includes(record.state) && record.type !== 'ROOT' && isDetached || + (record.state === 'Ready' && record.type !== 'ROOT' && isDetached) || + isDetachedAllocatedRoot || ((['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) || store.features.allowuserexpungerecovervolume) && record.state === 'Destroy') }, groupAction: true,