From ae23e19bb83d3322ed734bb77a200cda4805fcd6 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 7 May 2026 14:23:23 +0200 Subject: [PATCH] create method runVirtualMachineCustomAction --- .../main/java/com/cloud/network/Networks.java | 9 +- .../manager/ExtensionsManagerImpl.java | 85 +++++++++---------- .../network/NetworkExtensionElement.java | 15 ++-- .../manager/ExtensionsManagerImplTest.java | 22 ++--- 4 files changed, 68 insertions(+), 63 deletions(-) diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java index 5f767686dc9..61a1c820723 100644 --- a/api/src/main/java/com/cloud/network/Networks.java +++ b/api/src/main/java/com/cloud/network/Networks.java @@ -81,7 +81,11 @@ public class Networks { return uri == null ? null : uri.getAuthority(); } }, - Vswitch("vs", String.class), LinkLocal(null, null), Vnet("vnet", Long.class), Storage("storage", Integer.class), Lswitch("lswitch", String.class) { + Vswitch("vs", String.class), + LinkLocal(null, null), + Vnet("vnet", Long.class), + Storage("storage", Integer.class), + Lswitch("lswitch", String.class) { @Override public URI toUri(T value) { try { @@ -99,7 +103,8 @@ public class Networks { return uri == null ? null : uri.getSchemeSpecificPart(); } }, - Mido("mido", String.class), Pvlan("pvlan", String.class), + Mido("mido", String.class), + Pvlan("pvlan", String.class), Vxlan("vxlan", Long.class) { @Override public URI toUri(T value) { diff --git a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java index cb63715047f..1f2f009abe4 100644 --- a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java +++ b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImpl.java @@ -123,7 +123,6 @@ import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; import com.cloud.host.Host; -import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; import com.cloud.hypervisor.ExternalProvisioner; @@ -433,16 +432,15 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana unregisterExtensionWithCluster(cluster, extensionId); } - protected Extension getExtensionFromResource(ExtensionCustomAction.ResourceType resourceType, String resourceUuid) { + protected Extension getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType resourceType, String resourceUuid) { Object object = entityManager.findByUuid(resourceType.getAssociatedClass(), resourceUuid); if (object == null) { return null; } - Long clusterId = null; - if (resourceType == ExtensionCustomAction.ResourceType.VirtualMachine) { + if (ExtensionCustomAction.ResourceType.VirtualMachine.equals(resourceType)) { VirtualMachine vm = (VirtualMachine) object; Pair clusterHostId = virtualMachineManager.findClusterAndHostIdForVm(vm, false); - clusterId = clusterHostId.first(); + Long clusterId = clusterHostId.first(); if (clusterId == null) { return null; } @@ -452,7 +450,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana return null; } return extensionDao.findById(mapVO.getExtensionId()); - } else if (resourceType == ExtensionCustomAction.ResourceType.Network) { + } else if (ExtensionCustomAction.ResourceType.Network.equals(resourceType)) { Network network = (Network) object; Long physicalNetworkId = network.getPhysicalNetworkId(); if (physicalNetworkId == null) { @@ -469,7 +467,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana } } return null; - } else if (resourceType == ExtensionCustomAction.ResourceType.Vpc) { + } else if (ExtensionCustomAction.ResourceType.Vpc.equals(resourceType)) { Vpc vpc = (Vpc) object; // Find extension via the VPC's CustomAction service provider String providerName = vpcServiceMapDao.getProviderForServiceInVpc(vpc.getId(), Service.CustomAction); @@ -808,12 +806,15 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana if (id != null) { sc.setParameters("id", id); } + if (name != null) { sc.setParameters("name", name); } + if (keyword != null) { sc.setParameters("keyword", "%" + keyword + "%"); } + if (typeStr != null) { Extension.Type type = EnumUtils.getEnum(Extension.Type.class, typeStr); if (type == null) { @@ -1635,7 +1636,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana } if (extensionId == null && resourceType != null && StringUtils.isNotBlank(resourceId)) { - Extension extension = getExtensionFromResource(resourceType, resourceId); + Extension extension = getExtensionWithCustomActionFromResource(resourceType, resourceId); if (extension == null) { logger.error("No extension found for the specified resource [type: {}, id: {}]", resourceTypeStr, resourceId); throw new InvalidParameterValueException("Internal error listing custom actions with specified resource"); @@ -1827,7 +1828,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana @Override public CustomActionResultResponse runCustomAction(RunCustomActionCmd cmd) { - final Long id = cmd.getCustomActionId(); + final Long id = cmd.getCustomActionId(); final String resourceTypeStr = cmd.getResourceType(); final String resourceUuid = cmd.getResourceId(); Map cmdParameters = cmd.getParameters(); @@ -1852,8 +1853,6 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana logger.error("Failed to run {} as it is not enabled", customActionVO); throw new InvalidParameterValueException(error); } - final String actionName = customActionVO.getName(); - RunCustomActionCommand runCustomActionCommand = new RunCustomActionCommand(actionName); final long extensionId = customActionVO.getExtensionId(); final ExtensionVO extensionVO = extensionDao.findById(extensionId); if (extensionVO == null) { @@ -1884,47 +1883,47 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana logger.error("Specified resource does not exist for running {}", customActionVO); throw new CloudRuntimeException(error); } - Long clusterId = null; - Long hostId = null; - if (entity instanceof Cluster) { - clusterId = ((Cluster)entity).getId(); - List hosts = hostDao.listByClusterAndHypervisorType(clusterId, Hypervisor.HypervisorType.External); - if (CollectionUtils.isEmpty(hosts)) { - logger.error("No hosts found for {} for running {}", entity, customActionVO); - throw new CloudRuntimeException(error); - } - hostId = hosts.get(0).getId(); - } else if (entity instanceof Host) { - Host host = (Host)entity; - if (!Hypervisor.HypervisorType.External.equals(host.getHypervisorType())) { - logger.error("Invalid {} specified as host resource for running {}", entity, customActionVO); - throw new InvalidParameterValueException(error); - } - hostId = host.getId(); - clusterId = host.getClusterId(); - } else if (entity instanceof VirtualMachine) { - VirtualMachine virtualMachine = (VirtualMachine)entity; + if (entity instanceof VirtualMachine) { + VirtualMachine virtualMachine = (VirtualMachine) entity; accountService.checkAccess(caller, null, true, virtualMachine); - if (!Hypervisor.HypervisorType.External.equals(virtualMachine.getHypervisorType())) { - logger.error("Invalid {} specified as VM resource for running {}", entity, customActionVO); - throw new InvalidParameterValueException(error); - } - VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(virtualMachine); - VirtualMachineTO virtualMachineTO = virtualMachineManager.toVmTO(vmProfile); - runCustomActionCommand.setVmTO(virtualMachineTO); - Pair clusterAndHostId = virtualMachineManager.findClusterAndHostIdForVm(virtualMachine, false); - clusterId = clusterAndHostId.first(); - hostId = clusterAndHostId.second(); + return runVirtualMachineCustomAction(virtualMachine, customActionVO, extensionVO, + actionResourceType, cmdParameters); } else if (entity instanceof Network) { // Network custom action: dispatched directly to NetworkCustomActionProvider (no agent) Network network = (Network) entity; + accountService.checkAccess(caller, null, true, network); return runNetworkCustomAction(network, customActionVO, extensionVO, actionResourceType, cmdParameters); } else if (entity instanceof Vpc) { // VPC custom action: find a tier network and dispatch to the same NetworkCustomActionProvider Vpc vpc = (Vpc) entity; + accountService.checkAccess(caller, null, true, vpc); return runVpcCustomAction(vpc, customActionVO, extensionVO, actionResourceType, cmdParameters); } + throw new CloudRuntimeException(String.format("Custom action for resource type %s is not supported", + actionResourceType.name())); + } + private CustomActionResultResponse runVirtualMachineCustomAction(VirtualMachine virtualMachine, + ExtensionCustomActionVO customActionVO, ExtensionVO extensionVO, + ExtensionCustomAction.ResourceType actionResourceType, + Map cmdParameters) { + + String error = "Internal error running action on virtual machine"; + + if (!Hypervisor.HypervisorType.External.equals(virtualMachine.getHypervisorType())) { + logger.error("Invalid {} specified as VM resource for running {}", virtualMachine, customActionVO); + throw new InvalidParameterValueException(error); + } + + final String actionName = customActionVO.getName(); + RunCustomActionCommand runCustomActionCommand = new RunCustomActionCommand(actionName); + VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(virtualMachine); + VirtualMachineTO virtualMachineTO = virtualMachineManager.toVmTO(vmProfile); + runCustomActionCommand.setVmTO(virtualMachineTO); + Pair clusterAndHostId = virtualMachineManager.findClusterAndHostIdForVm(virtualMachine, false); + + Long clusterId = clusterAndHostId.first();; + Long hostId = clusterAndHostId.second(); if (clusterId == null || hostId == null) { logger.error( "Unable to find cluster or host with the specified resource - cluster ID: {}, host ID: {}", @@ -1958,7 +1957,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana Map result = new HashMap<>(); response.setSuccess(false); result.put(ApiConstants.MESSAGE, getActionMessage(false, customActionVO, extensionVO, - actionResourceType, entity)); + actionResourceType, virtualMachine)); Map> externalDetails = getExternalAccessDetails(allDetails.first(), hostId, extensionResource); Map vmExternalDetails = null; @@ -1983,7 +1982,7 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana RunCustomActionAnswer customActionAnswer = (RunCustomActionAnswer) answer; response.setSuccess(answer.getResult()); result.put(ApiConstants.MESSAGE, getActionMessage(answer.getResult(), customActionVO, extensionVO, - actionResourceType, entity)); + actionResourceType, virtualMachine)); result.put(ApiConstants.DETAILS, customActionAnswer.getDetails()); } } catch (AgentUnavailableException e) { diff --git a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java index 7f286612566..19b713c834c 100644 --- a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java +++ b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java @@ -17,6 +17,10 @@ package org.apache.cloudstack.framework.extensions.network; import java.io.File; +import java.net.URI; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -24,9 +28,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.file.Files; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -513,7 +514,7 @@ public class NetworkExtensionElement extends AdapterBase implements try { NetworkVO networkVo = networkDao.findById(network.getId()); if (networkVo != null) { - java.net.URI ovnUri = java.net.URI.create("ovn://cs-net-" + network.getId()); + URI ovnUri = URI.create("ovn://cs-net-" + network.getId()); networkVo.setBroadcastDomainType(Networks.BroadcastDomainType.Lswitch); networkVo.setBroadcastUri(ovnUri); networkDao.update(networkVo.getId(), networkVo); @@ -582,9 +583,9 @@ public class NetworkExtensionElement extends AdapterBase implements // / DB queries report consistent OVN identifiers instead of // the stale VLAN URI the GuestNetworkGuru allocated at // design-time. - java.net.URI ovnUri = null; + URI ovnUri = null; try { - ovnUri = java.net.URI.create("ovn://cs-net-" + network.getId()); + ovnUri = URI.create("ovn://cs-net-" + network.getId()); } catch (Exception e) { logger.warn("Failed to build OVN URI for NIC {}: {}", nic.getId(), e.getMessage()); } @@ -593,7 +594,7 @@ public class NetworkExtensionElement extends AdapterBase implements nic.setBroadcastUri(ovnUri); nic.setIsolationUri(ovnUri); try { - com.cloud.vm.NicVO nicVo = nicDao.findById(nic.getId()); + NicVO nicVo = nicDao.findById(nic.getId()); if (nicVo != null) { nicVo.setBroadcastUri(ovnUri); nicVo.setIsolationUri(ovnUri); diff --git a/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java b/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java index 1df3eb0efea..726c8921f30 100644 --- a/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java +++ b/framework/extensions/src/test/java/org/apache/cloudstack/framework/extensions/manager/ExtensionsManagerImplTest.java @@ -318,7 +318,7 @@ public class ExtensionsManagerImplTest { @Test public void getExtensionFromResourceReturnsNullIfEntityNotFound() { when(entityManager.findByUuid(any(), anyString())).thenReturn(null); - assertNull(extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "uuid")); + assertNull(extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "uuid")); } @@ -408,7 +408,7 @@ public class ExtensionsManagerImplTest { ExtensionVO extension = mock(ExtensionVO.class); when(extensionDao.findById(100L)).thenReturn(extension); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); assertEquals(extension, result); } @@ -417,7 +417,7 @@ public class ExtensionsManagerImplTest { public void getExtensionFromResourceReturnsNullForInvalidResourceUuid() { when(entityManager.findByUuid(eq(VirtualMachine.class), eq("invalid-uuid"))).thenReturn(null); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "invalid-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "invalid-uuid"); assertNull(result); } @@ -428,7 +428,7 @@ public class ExtensionsManagerImplTest { when(entityManager.findByUuid(eq(VirtualMachine.class), eq("vm-uuid"))).thenReturn(vm); when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(null, null)); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); assertNull(result); } @@ -440,7 +440,7 @@ public class ExtensionsManagerImplTest { when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(1L, 1L)); when(extensionResourceMapDao.findByResourceIdAndType(1L, ExtensionResourceMap.ResourceType.Cluster)).thenReturn(null); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.VirtualMachine, "vm-uuid"); assertNull(result); } @@ -2662,7 +2662,7 @@ public class ExtensionsManagerImplTest { ExtensionVO ext = mock(ExtensionVO.class); doReturn(ext).when(extensionsManager).getExtensionForPhysicalNetworkAndProvider(5L, "my-ext-provider"); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); assertEquals(ext, result); } @@ -2680,7 +2680,7 @@ public class ExtensionsManagerImplTest { when(extensionResourceMapDao.listByResourceIdAndType(5L, ExtensionResourceMap.ResourceType.PhysicalNetwork)) .thenReturn(List.of(mapVO)); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); assertNull(result); } @@ -2691,7 +2691,7 @@ public class ExtensionsManagerImplTest { when(network.getPhysicalNetworkId()).thenReturn(null); when(entityManager.findByUuid(eq(Network.class), eq("net-uuid"))).thenReturn(network); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Network, "net-uuid"); assertNull(result); } @@ -2710,7 +2710,7 @@ public class ExtensionsManagerImplTest { ExtensionVO ext = mock(ExtensionVO.class); when(extensionDao.findByName("my-vpc-provider")).thenReturn(ext); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); assertEquals(ext, result); } @@ -2723,7 +2723,7 @@ public class ExtensionsManagerImplTest { when(vpcServiceMapDao.getProviderForServiceInVpc(20L, Network.Service.CustomAction)).thenReturn(null); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); assertNull(result); verify(extensionDao, never()).findByName(anyString()); @@ -2738,7 +2738,7 @@ public class ExtensionsManagerImplTest { when(vpcServiceMapDao.getProviderForServiceInVpc(20L, Network.Service.CustomAction)).thenReturn("missing-provider"); when(extensionDao.findByName("missing-provider")).thenReturn(null); - Extension result = extensionsManager.getExtensionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); + Extension result = extensionsManager.getExtensionWithCustomActionFromResource(ExtensionCustomAction.ResourceType.Vpc, "vpc-uuid"); assertNull(result); }