This is an automated email from the ASF dual-hosted git repository. joao pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 8af08ddafbc3bb4d0737b731ce54ca6dd25eaf60 Merge: be247334a7f a6cef7a78dd Author: João Jandre <48719461+joaojan...@users.noreply.github.com> AuthorDate: Mon Nov 4 08:58:48 2024 -0300 Merge branch '4.19' .../kvm/resource/LibvirtComputingResource.java | 15 ++- .../kvm/storage/KVMStorageProcessor.java | 2 +- .../kvm/resource/LibvirtComputingResourceTest.java | 113 +++++++++++++++++++++ plugins/storage/volume/linstor/CHANGELOG.md | 7 ++ ui/src/views/infra/UpdatePrimaryStorage.vue | 10 +- 5 files changed, 142 insertions(+), 5 deletions(-) diff --cc plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 30d0b2ab163,17bff8325ce..15c2b46e077 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@@ -6224,195 -6299,113 +6227,305 @@@ public class LibvirtComputingResourceTe } } + @Test + public void testGetHostTags() throws ConfigurationException { + try (MockedStatic<AgentPropertiesFileHandler> ignored = Mockito.mockStatic(AgentPropertiesFileHandler.class)) { + Mockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.HOST_TAGS))) + .thenReturn("aa,bb,cc,dd"); + + List<String> hostTagsList = libvirtComputingResourceSpy.getHostTags(); + Assert.assertEquals(4, hostTagsList.size()); + Assert.assertEquals("aa,bb,cc,dd", StringUtils.join(hostTagsList, ",")); + } + } + + @Test + public void testGetHostTagsWithSpace() throws ConfigurationException { + try (MockedStatic<AgentPropertiesFileHandler> ignored = Mockito.mockStatic(AgentPropertiesFileHandler.class)) { + Mockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.HOST_TAGS))) + .thenReturn(" aa, bb , cc , dd "); + + List<String> hostTagsList = libvirtComputingResourceSpy.getHostTags(); + Assert.assertEquals(4, hostTagsList.size()); + Assert.assertEquals("aa,bb,cc,dd", StringUtils.join(hostTagsList, ",")); + } + } + + @Test + public void testGetHostTagsWithEmptyPropertyValue() throws ConfigurationException { + try (MockedStatic<AgentPropertiesFileHandler> ignored = Mockito.mockStatic(AgentPropertiesFileHandler.class)) { + Mockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.eq(AgentProperties.HOST_TAGS))) + .thenReturn(" "); + + List<String> hostTagsList = libvirtComputingResourceSpy.getHostTags(); + Assert.assertEquals(0, hostTagsList.size()); + Assert.assertEquals("", StringUtils.join(hostTagsList, ",")); + } + } + + @Test + public void getVmStatTestVmIsNullReturnsNull() throws LibvirtException { + doReturn(null).when(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME); + + VmStatsEntry stat = libvirtComputingResourceSpy.getVmStat(connMock, VM_NAME); + + verify(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME); + verify(libvirtComputingResourceSpy, never()).getVmCurrentStats(domainMock); + verify(libvirtComputingResourceSpy, never()).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any()); + Assert.assertNull(stat); + } + + @Test + public void getVmStatTestVmIsNotNullReturnsMetrics() throws LibvirtException { + doReturn(domainMock).when(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME); + doReturn(Mockito.mock(LibvirtExtendedVmStatsEntry.class)).when(libvirtComputingResourceSpy).getVmCurrentStats(domainMock); + doReturn(Mockito.mock(VmStatsEntry.class)).when(libvirtComputingResourceSpy).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any()); + + VmStatsEntry stat = libvirtComputingResourceSpy.getVmStat(connMock, VM_NAME); + + verify(libvirtComputingResourceSpy).getDomain(connMock, VM_NAME); + verify(libvirtComputingResourceSpy).getVmCurrentStats(domainMock); + verify(libvirtComputingResourceSpy).calculateVmMetrics(Mockito.any(), Mockito.any(), Mockito.any()); + Assert.assertNotNull(stat); + } + + private void prepareVmInfoForGetVmCurrentStats() throws LibvirtException { + final NodeInfo nodeInfo = new NodeInfo(); + nodeInfo.cpus = 8; + nodeInfo.memory = 8 * 1024 * 1024; + nodeInfo.sockets = 2; + nodeInfo.threads = 2; + nodeInfo.model = "Foo processor"; + + Mockito.when(domainMock.getName()).thenReturn(VM_NAME); + Mockito.when(domainMock.getConnect()).thenReturn(connMock); + domainInfoMock.cpuTime = 500L; + domainInfoMock.nrVirtCpu = 4; + domainInfoMock.memory = 2048; + domainInfoMock.maxMem = 4096; + Mockito.when(domainMock.getInfo()).thenReturn(domainInfoMock); + final MemoryStatistic[] domainMem = new MemoryStatistic[2]; + domainMem[0] = Mockito.mock(MemoryStatistic.class); + doReturn(1024L).when(libvirtComputingResourceSpy).getMemoryFreeInKBs(domainMock); + + domainInterfaceStatsMock.rx_bytes = 1000L; + domainInterfaceStatsMock.tx_bytes = 2000L; + doReturn(domainInterfaceStatsMock).when(domainMock).interfaceStats(Mockito.any()); + doReturn(List.of(new InterfaceDef())).when(libvirtComputingResourceSpy).getInterfaces(connMock, VM_NAME); + + domainBlockStatsMock.rd_req = 3000L; + domainBlockStatsMock.rd_bytes = 4000L; + domainBlockStatsMock.wr_req = 5000L; + domainBlockStatsMock.wr_bytes = 6000L; + doReturn(domainBlockStatsMock).when(domainMock).blockStats(Mockito.any()); + doReturn(List.of(new DiskDef())).when(libvirtComputingResourceSpy).getDisks(connMock, VM_NAME); + } + + @Test + public void getVmCurrentStatsTestIfStatsAreAsExpected() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + + LibvirtExtendedVmStatsEntry vmStatsEntry = libvirtComputingResourceSpy.getVmCurrentStats(domainMock); + + Assert.assertEquals(domainInfoMock.cpuTime, vmStatsEntry.getCpuTime()); + Assert.assertEquals((double) domainInterfaceStatsMock.rx_bytes / 1024, vmStatsEntry.getNetworkReadKBs(), 0); + Assert.assertEquals((double) domainInterfaceStatsMock.tx_bytes / 1024, vmStatsEntry.getNetworkWriteKBs(), 0); + Assert.assertEquals(domainBlockStatsMock.rd_req, vmStatsEntry.getDiskReadIOs(), 0); + Assert.assertEquals((double) domainBlockStatsMock.rd_bytes / 1024, vmStatsEntry.getDiskReadKBs(), 0); + Assert.assertEquals(domainBlockStatsMock.wr_req, vmStatsEntry.getDiskWriteIOs(), 0); + Assert.assertEquals((double) domainBlockStatsMock.wr_bytes / 1024, vmStatsEntry.getDiskWriteKBs(), 0); + Assert.assertNotNull(vmStatsEntry.getTimestamp()); + } + + @Test + public void getVmCurrentCpuStatsTestIfStatsAreAsExpected() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + + LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry(); + libvirtComputingResourceSpy.getVmCurrentCpuStats(domainMock, vmStatsEntry); + + Assert.assertEquals(domainInfoMock.cpuTime, vmStatsEntry.getCpuTime()); + } + + @Test + public void getVmCurrentNetworkStatsTestIfStatsAreAsExpected() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + + LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry(); + libvirtComputingResourceSpy.getVmCurrentNetworkStats(domainMock, vmStatsEntry); + + Assert.assertEquals((double) domainInterfaceStatsMock.rx_bytes / 1024, vmStatsEntry.getNetworkReadKBs(), 0); + Assert.assertEquals((double) domainInterfaceStatsMock.tx_bytes / 1024, vmStatsEntry.getNetworkWriteKBs(), 0); + } + + @Test + public void getVmCurrentDiskStatsTestIfStatsAreAsExpected() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + + LibvirtExtendedVmStatsEntry vmStatsEntry = new LibvirtExtendedVmStatsEntry(); + libvirtComputingResourceSpy.getVmCurrentDiskStats(domainMock, vmStatsEntry); + + Assert.assertEquals(domainBlockStatsMock.rd_req, vmStatsEntry.getDiskReadIOs(), 0); + Assert.assertEquals((double) domainBlockStatsMock.rd_bytes / 1024, vmStatsEntry.getDiskReadKBs(), 0); + Assert.assertEquals(domainBlockStatsMock.wr_req, vmStatsEntry.getDiskWriteIOs(), 0); + Assert.assertEquals((double) domainBlockStatsMock.wr_bytes / 1024, vmStatsEntry.getDiskWriteKBs(), 0); + } + + @Test + public void calculateVmMetricsTestOldStatsIsNullDoesNotCalculateUtilization() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + + LibvirtExtendedVmStatsEntry vmStatsEntry = libvirtComputingResourceSpy.getVmCurrentStats(domainMock); + VmStatsEntry metrics = libvirtComputingResourceSpy.calculateVmMetrics(domainMock, null, vmStatsEntry); + + Assert.assertEquals(domainInfoMock.nrVirtCpu, metrics.getNumCPUs()); + Assert.assertEquals(domainInfoMock.maxMem, (long) metrics.getMemoryKBs()); + Assert.assertEquals(libvirtComputingResourceSpy.getMemoryFreeInKBs(domainMock), (long) metrics.getIntFreeMemoryKBs()); + Assert.assertEquals(domainInfoMock.memory, (long) metrics.getTargetMemoryKBs()); + Assert.assertEquals(0, metrics.getCPUUtilization(), 0); + Assert.assertEquals(0, metrics.getNetworkReadKBs(), 0); + Assert.assertEquals(0, metrics.getNetworkWriteKBs(), 0); + Assert.assertEquals(0, metrics.getDiskReadKBs(), 0); + Assert.assertEquals(0, metrics.getDiskReadIOs(), 0); + Assert.assertEquals(0, metrics.getDiskWriteKBs(), 0); + Assert.assertEquals(0, metrics.getDiskWriteIOs(), 0); + } + + @Test + public void calculateVmMetricsTestOldStatsIsNotNullCalculatesUtilization() throws LibvirtException { + prepareVmInfoForGetVmCurrentStats(); + LibvirtExtendedVmStatsEntry oldStats = libvirtComputingResourceSpy.getVmCurrentStats(domainMock); + domainInfoMock.cpuTime *= 3; + domainInterfaceStatsMock.rx_bytes *= 3; + domainInterfaceStatsMock.tx_bytes *= 3; + domainBlockStatsMock.rd_req *= 3; + domainBlockStatsMock.rd_bytes *= 3; + domainBlockStatsMock.wr_req *= 3; + domainBlockStatsMock.wr_bytes *= 3; + LibvirtExtendedVmStatsEntry newStats = libvirtComputingResourceSpy.getVmCurrentStats(domainMock); + + VmStatsEntry metrics = libvirtComputingResourceSpy.calculateVmMetrics(domainMock, oldStats, newStats); + + Assert.assertEquals(domainInfoMock.nrVirtCpu, metrics.getNumCPUs()); + Assert.assertEquals(domainInfoMock.maxMem, (long) metrics.getMemoryKBs()); + Assert.assertEquals(libvirtComputingResourceSpy.getMemoryFreeInKBs(domainMock), (long) metrics.getIntFreeMemoryKBs()); + Assert.assertEquals(domainInfoMock.memory, (long) metrics.getTargetMemoryKBs()); + Assert.assertTrue(metrics.getCPUUtilization() > 0); + Assert.assertEquals(newStats.getNetworkReadKBs() - oldStats.getNetworkReadKBs(), metrics.getNetworkReadKBs(), 0); + Assert.assertEquals(newStats.getNetworkWriteKBs() - oldStats.getNetworkWriteKBs(), metrics.getNetworkWriteKBs(), 0); + Assert.assertEquals(newStats.getDiskReadIOs() - oldStats.getDiskReadIOs(), metrics.getDiskReadIOs(), 0); + Assert.assertEquals(newStats.getDiskWriteIOs() - oldStats.getDiskWriteIOs(), metrics.getDiskWriteIOs(), 0); + Assert.assertEquals(newStats.getDiskReadKBs() - oldStats.getDiskReadKBs(), metrics.getDiskReadKBs(), 0); + Assert.assertEquals(newStats.getDiskWriteKBs() - oldStats.getDiskWriteKBs(), metrics.getDiskWriteKBs(), 0); + } ++ + @Test + public void createLinstorVdb() throws LibvirtException, InternalErrorException, URISyntaxException { + final Connect connect = Mockito.mock(Connect.class); + + final int id = random.nextInt(65534); + final String name = "test-instance-1"; + + final int cpus = 2; + final int speed = 1024; + final int minRam = 256 * 1024; + final int maxRam = 512 * 1024; + final String os = "Ubuntu"; + final String vncPassword = "mySuperSecretPassword"; + + final VirtualMachineTO to = new VirtualMachineTO(id, name, VirtualMachine.Type.User, cpus, speed, minRam, + maxRam, BootloaderType.HVM, os, false, false, vncPassword); + to.setVncAddr(""); + to.setArch("x86_64"); + to.setUuid("b0f0a72d-7efb-3cad-a8ff-70ebf30b3af9"); + to.setVcpuMaxLimit(cpus + 1); + final HashMap<String, String> vmToDetails = new HashMap<>(); + to.setDetails(vmToDetails); + + String diskLinPath = "9ebe53c1-3d35-46e5-b7aa-6fc223ba0fcf"; + final DiskTO diskTO = new DiskTO(); + diskTO.setDiskSeq(1L); + diskTO.setType(Volume.Type.ROOT); + diskTO.setDetails(new HashMap<>()); + diskTO.setPath(diskLinPath); + + final PrimaryDataStoreTO primaryDataStoreTO = Mockito.mock(PrimaryDataStoreTO.class); + String pDSTOUUID = "9ebe53c1-3d35-46e5-b7aa-6fc223ac4fcf"; + when(primaryDataStoreTO.getPoolType()).thenReturn(StoragePoolType.Linstor); + when(primaryDataStoreTO.getUuid()).thenReturn(pDSTOUUID); + + VolumeObjectTO dataTO = new VolumeObjectTO(); + + dataTO.setUuid("12be53c1-3d35-46e5-b7aa-6fc223ba0f34"); + dataTO.setPath(diskTO.getPath()); + dataTO.setDataStore(primaryDataStoreTO); + diskTO.setData(dataTO); + to.setDisks(new DiskTO[]{diskTO}); + + String path = "/dev/drbd1020"; + final KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class); + final KVMStoragePool storagePool = Mockito.mock(KVMStoragePool.class); + final KVMPhysicalDisk vol = Mockito.mock(KVMPhysicalDisk.class); + + when(libvirtComputingResourceSpy.getStoragePoolMgr()).thenReturn(storagePoolMgr); + when(storagePool.getType()).thenReturn(StoragePoolType.Linstor); + when(storagePoolMgr.getPhysicalDisk(StoragePoolType.Linstor, pDSTOUUID, diskLinPath)).thenReturn(vol); + when(vol.getPath()).thenReturn(path); + when(vol.getPool()).thenReturn(storagePool); + when(vol.getFormat()).thenReturn(PhysicalDiskFormat.RAW); + + // 1. test Bus: IDE and broken qemu version -> NO discard + when(libvirtComputingResourceSpy.getHypervisorQemuVersion()).thenReturn(6000000L); + vmToDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, DiskDef.DiskBus.IDE.name()); + { + LibvirtVMDef vm = new LibvirtVMDef(); + vm.addComp(new DevicesDef()); + libvirtComputingResourceSpy.createVbd(connect, to, name, vm); + + DiskDef rootDisk = vm.getDevices().getDisks().get(0); + assertEquals(DiskDef.DiskType.BLOCK, rootDisk.getDiskType()); + assertEquals(DiskDef.DiskBus.IDE, rootDisk.getBusType()); + assertEquals(DiskDef.DiscardType.IGNORE, rootDisk.getDiscard()); + } + + // 2. test Bus: VIRTIO and broken qemu version -> discard unmap + vmToDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, DiskDef.DiskBus.VIRTIO.name()); + { + LibvirtVMDef vm = new LibvirtVMDef(); + vm.addComp(new DevicesDef()); + libvirtComputingResourceSpy.createVbd(connect, to, name, vm); + + DiskDef rootDisk = vm.getDevices().getDisks().get(0); + assertEquals(DiskDef.DiskType.BLOCK, rootDisk.getDiskType()); + assertEquals(DiskDef.DiskBus.VIRTIO, rootDisk.getBusType()); + assertEquals(DiskDef.DiscardType.UNMAP, rootDisk.getDiscard()); + } + + // 3. test Bus; IDE and "good" qemu version -> discard unmap + vmToDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, DiskDef.DiskBus.IDE.name()); + when(libvirtComputingResourceSpy.getHypervisorQemuVersion()).thenReturn(7000000L); + { + LibvirtVMDef vm = new LibvirtVMDef(); + vm.addComp(new DevicesDef()); + libvirtComputingResourceSpy.createVbd(connect, to, name, vm); + + DiskDef rootDisk = vm.getDevices().getDisks().get(0); + assertEquals(DiskDef.DiskType.BLOCK, rootDisk.getDiskType()); + assertEquals(DiskDef.DiskBus.IDE, rootDisk.getBusType()); + assertEquals(DiskDef.DiscardType.UNMAP, rootDisk.getDiscard()); + } + + // 4. test Bus: VIRTIO and "good" qemu version -> discard unmap + vmToDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, DiskDef.DiskBus.VIRTIO.name()); + { + LibvirtVMDef vm = new LibvirtVMDef(); + vm.addComp(new DevicesDef()); + libvirtComputingResourceSpy.createVbd(connect, to, name, vm); + + DiskDef rootDisk = vm.getDevices().getDisks().get(0); + assertEquals(DiskDef.DiskType.BLOCK, rootDisk.getDiskType()); + assertEquals(DiskDef.DiskBus.VIRTIO, rootDisk.getBusType()); + assertEquals(DiskDef.DiscardType.UNMAP, rootDisk.getDiscard()); + } + } }