diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 82e2f38a522..5c53430388d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1499,7 +1499,7 @@ public class ApiConstants { } public enum HostDetails { - all, capacity, events, stats, min; + all, capacity, core, events, stats, min; } public enum VMDetails { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java index f8e1af8d5b7..10bd62804fb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java @@ -201,6 +201,10 @@ public class HostResponse extends BaseResponseWithAnnotations { @Param(description = "the virtual machine id for host type ConsoleProxy and SecondaryStorageVM", since = "4.21.0") private String virtualMachineId; + @SerializedName("msid") + @Param(description = "(only for details=core) the msid of the host's management server") + private Long msId; + @SerializedName(ApiConstants.MANAGEMENT_SERVER_ID) @Param(description = "The management server ID of the host") private String managementServerId; @@ -492,6 +496,14 @@ public class HostResponse extends BaseResponseWithAnnotations { this.virtualMachineId = virtualMachineId; } + public Long getMsId() { + return msId; + } + + public void setMsId(Long msId) { + this.msId = msId; + } + public void setManagementServerId(String managementServerId) { this.managementServerId = managementServerId; } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java index a6c267bb189..beab7ce2cd5 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java @@ -51,6 +51,8 @@ public interface VlanDao extends GenericDao { List listVlansByNetworkId(long networkId); + List listVlansByNetworkIds(List networkIds); + List listVlansByNetworkIdIncludingRemoved(long networkId); List listVlansByPhysicalNetworkId(long physicalNetworkId); diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index d9fad3cad12..5687e858877 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -20,6 +20,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -27,6 +28,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import com.cloud.dc.VlanDetailsVO; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -134,7 +136,7 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao ZoneTypeSearch.done(); NetworkVlanSearch = createSearchBuilder(); - NetworkVlanSearch.and("networkId", NetworkVlanSearch.entity().getNetworkId(), SearchCriteria.Op.EQ); + NetworkVlanSearch.and("networkId", NetworkVlanSearch.entity().getNetworkId(), SearchCriteria.Op.IN); NetworkVlanSearch.done(); PhysicalNetworkVlanSearch = createSearchBuilder(); @@ -392,6 +394,16 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao return listBy(sc); } + @Override + public List listVlansByNetworkIds(List networkIds) { + if (CollectionUtils.isEmpty(networkIds)) { + return Collections.emptyList(); + } + SearchCriteria sc = NetworkVlanSearch.create(); + sc.setParameters("networkId", networkIds.toArray()); + return listBy(sc); + } + @Override public List listVlansByNetworkIdIncludingRemoved(long networkId) { SearchCriteria sc = NetworkVlanSearch.create(); sc.setParameters("networkId", networkId); diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java index 7767b7512b9..ad599053ff0 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java @@ -99,6 +99,8 @@ public interface NicDao extends GenericDao { NicVO findByMacAddress(String macAddress, long networkId); + List listByMacAddresses(List macAddresses); + NicVO findByNetworkIdAndMacAddressIncludingRemoved(long networkId, String mac); List findNicsByIpv6GatewayIpv6CidrAndReserver(String ipv6Gateway, String ipv6Cidr, String reserverName); diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java index 6202dabf730..e468b1b9a3b 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java @@ -18,12 +18,13 @@ package com.cloud.vm.dao; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; import com.cloud.utils.db.Filter; @@ -71,7 +72,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { AllFieldsSearch.and("strategy", AllFieldsSearch.entity().getReservationStrategy(), Op.EQ); AllFieldsSearch.and("strategyNEQ", AllFieldsSearch.entity().getReservationStrategy(), Op.NEQ); AllFieldsSearch.and("reserverName",AllFieldsSearch.entity().getReserver(),Op.EQ); - AllFieldsSearch.and("macAddress", AllFieldsSearch.entity().getMacAddress(), Op.EQ); + AllFieldsSearch.and("macAddress", AllFieldsSearch.entity().getMacAddress(), Op.IN); AllFieldsSearch.and("deviceid", AllFieldsSearch.entity().getDeviceId(), Op.EQ); AllFieldsSearch.and("ipv6Gateway", AllFieldsSearch.entity().getIPv6Gateway(), Op.EQ); AllFieldsSearch.and("ipv6Cidr", AllFieldsSearch.entity().getIPv6Cidr(), Op.EQ); @@ -434,6 +435,16 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { return findOneBy(sc); } + @Override + public List listByMacAddresses(List macAddresses) { + if (CollectionUtils.isEmpty(macAddresses)) { + return Collections.emptyList(); + } + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("macAddress", macAddresses.toArray()); + return listBy(sc); + } + @Override public List findNicsByIpv6GatewayIpv6CidrAndReserver(String ipv6Gateway, String ipv6Cidr, String reserverName) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index 7672b9dc6f9..9d71c6d07b4 100644 --- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -184,6 +184,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, private volatile long _executionRunNumber = 1; private final ScheduledExecutorService _heartbeatScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AsyncJobMgr-Heartbeat")); + private final ExecutorService _eventBusPublisher = Executors.newSingleThreadExecutor(new NamedThreadFactory("AsyncJobMgr-EventBus")); private ExecutorService _apiJobExecutor; private ExecutorService _workerJobExecutor; @@ -1378,6 +1379,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, @Override public boolean stop() { _heartbeatScheduler.shutdown(); + _eventBusPublisher.shutdown(); _apiJobExecutor.shutdown(); _workerJobExecutor.shutdown(); return true; @@ -1397,8 +1399,26 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, } private void publishOnEventBus(AsyncJob job, String jobEvent) { - _messageBus.publish(null, AsyncJob.Topics.JOB_EVENT_PUBLISH, PublishScope.LOCAL, - new Pair(job, jobEvent)); + try { + _eventBusPublisher.submit(new ManagedContextRunnable() { + @Override + protected void runInContext() { + publishJobEvent(job, jobEvent); + } + }); + } catch (RejectedExecutionException e) { + logger.warn("Failed to publish async job event, event bus publisher is shut down", e); + } + } + + private void publishJobEvent(AsyncJob job, String jobEvent) { + try { + _messageBus.publish(null, AsyncJob.Topics.JOB_EVENT_PUBLISH, PublishScope.LOCAL, + new Pair<>(job, jobEvent)); + } catch (Throwable t) { + logger.warn("Failed to publish async job event on message bus. jobId={}, jobEvent={}", + job != null ? job.getId() : null, jobEvent, t); + } } @Override diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckOnHostCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckOnHostCommandWrapper.java index f901fd97ca7..c069416cca5 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckOnHostCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtCheckOnHostCommandWrapper.java @@ -55,7 +55,7 @@ public final class LibvirtCheckOnHostCommandWrapper extends CommandWrapper poolTypesThatEnableCreateDiskFromTemplateBacking = new HashSet<>(Arrays.asList(StoragePoolType.NetworkFilesystem, - StoragePoolType.Filesystem)); + private static final Set QEMU_IMG_MANAGED_POOL_TYPES = Set.of(StoragePoolType.NetworkFilesystem, StoragePoolType.Filesystem, StoragePoolType.SharedMountPoint); public LibvirtStorageAdaptor(StorageLayer storage) { _storageLayer = storage; @@ -134,8 +132,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { String volumeDesc = String.format("volume [%s], with template backing [%s], in pool [%s] (%s), with size [%s] and encryption is %s", name, template.getName(), destPool.getUuid(), destPool.getType(), size, passphrase != null && passphrase.length > 0); - if (!poolTypesThatEnableCreateDiskFromTemplateBacking.contains(destPool.getType())) { - logger.info(String.format("Skipping creation of %s due to pool type is none of the following types %s.", volumeDesc, poolTypesThatEnableCreateDiskFromTemplateBacking.stream() + if (!QEMU_IMG_MANAGED_POOL_TYPES.contains(destPool.getType())) { + logger.info(String.format("Skipping creation of %s due to pool type is none of the following types %s.", volumeDesc, QEMU_IMG_MANAGED_POOL_TYPES.stream() .map(type -> type.toString()).collect(Collectors.joining(", ")))); return null; @@ -961,7 +959,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { * * *
  • - * {@link StoragePoolType#NetworkFilesystem} and {@link StoragePoolType#Filesystem} + * {@link StoragePoolType#NetworkFilesystem}, {@link StoragePoolType#Filesystem} and {@link StoragePoolType#SharedMountPoint} *
      *
    • * If the format is {@link PhysicalDiskFormat#QCOW2} or {@link PhysicalDiskFormat#RAW}, utilizes QemuImg to create the physical disk through the method @@ -992,7 +990,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { return (dataPool == null) ? createPhysicalDiskByLibVirt(name, pool, PhysicalDiskFormat.RAW, provisioningType, size) : createPhysicalDiskByQemuImg(name, pool, PhysicalDiskFormat.RAW, provisioningType, size, passphrase); - } else if (StoragePoolType.NetworkFilesystem.equals(poolType) || StoragePoolType.Filesystem.equals(poolType)) { + } else if (QEMU_IMG_MANAGED_POOL_TYPES.contains(poolType)) { switch (format) { case QCOW2: case RAW: @@ -1062,7 +1060,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { destFile.setFormat(format); destFile.setSize(size); Map options = new HashMap(); - if (List.of(StoragePoolType.NetworkFilesystem, StoragePoolType.Filesystem).contains(pool.getType())) { + if (QEMU_IMG_MANAGED_POOL_TYPES.contains(pool.getType())) { options.put(QemuImg.PREALLOCATION, QemuImg.PreallocationType.getPreallocationType(provisioningType).toString()); } diff --git a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/kvm/ha/KVMHostActivityChecker.java b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/kvm/ha/KVMHostActivityChecker.java index af7441c4fd2..96fd42d4d54 100644 --- a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/kvm/ha/KVMHostActivityChecker.java +++ b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/kvm/ha/KVMHostActivityChecker.java @@ -109,6 +109,7 @@ public class KVMHostActivityChecker extends AdapterBase implements ActivityCheck } Status hostStatusFromNeighbour = checkHostStatusWithNeighbourHosts(host); + logger.debug("{} status reported from itself: {} and neighbor: {}", host.toString(), hostStatusFromItself, hostStatusFromNeighbour); Status hostStatus = hostStatusFromItself; if (hostStatusFromNeighbour == Status.Up && (hostStatusFromItself == Status.Disconnected || hostStatusFromItself == Status.Down)) { hostStatus = Status.Disconnected; diff --git 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 index ce431d9bab2..0b72f2232ed 100644 --- 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 @@ -61,6 +61,7 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import com.cloud.agent.api.CheckOnHostAnswer; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -3139,7 +3140,9 @@ public class LibvirtComputingResourceTest { assertNotNull(wrapper); final Answer answer = wrapper.execute(command, libvirtComputingResourceMock); - assertFalse(answer.getResult()); + assertTrue(answer.getResult()); + assertTrue(answer instanceof CheckOnHostAnswer); + assertFalse(((CheckOnHostAnswer)answer).isAlive()); verify(libvirtComputingResourceMock, times(1)).getMonitor(); } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java index 511306854cf..f104eadd18b 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapperTest.java @@ -52,6 +52,12 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { " net4 2e:9b:60:dc:49:30 N/A N/A\n" + // " lxc5b7327203b6f 92:b2:77:0b:a9:20 N/A N/A\n"; + private static String VIRSH_DOMIF_OUTPUT_WINDOWS = " Name MAC address Protocol Address\n" + // + "-------------------------------------------------------------------------------\n" + // + " Ethernet Instance 0 02:0c:02:f9:00:80 ipv4 192.168.0.10/24\n" + // + " Loopback Pseudo-Interface 1 ipv6 ::1/128\n" + // + " - - ipv4 127.0.0.1/8\n"; + @Before public void setUp() { MockitoAnnotations.openMocks(this); @@ -118,7 +124,34 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24"); when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80"); when(getVmIpAddressCommand.isWindows()).thenReturn(true); - when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, "192.168.0.10")); + when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, VIRSH_DOMIF_OUTPUT_WINDOWS)); + + Answer answer = commandWrapper.execute(getVmIpAddressCommand, libvirtComputingResource); + + assertTrue(answer.getResult()); + assertEquals("192.168.0.10", answer.getDetails()); + } finally { + if (scriptMock != null) + scriptMock.close(); + } + } + + + @Test + public void testExecuteWithWindowsVm2() { + LibvirtComputingResource libvirtComputingResource = mock(LibvirtComputingResource.class); + GetVmIpAddressCommand getVmIpAddressCommand = mock(GetVmIpAddressCommand.class); + LibvirtGetVmIpAddressCommandWrapper commandWrapper = new LibvirtGetVmIpAddressCommandWrapper(); + MockedStatic