diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java index 559a369b4d9..f892e253b35 100644 --- a/api/src/main/java/com/cloud/network/Networks.java +++ b/api/src/main/java/com/cloud/network/Networks.java @@ -20,6 +20,7 @@ import java.net.URI; import java.net.URISyntaxException; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.commons.lang3.StringUtils; /** * Network includes all of the enums used within networking. @@ -253,20 +254,42 @@ public class Networks { Long.parseLong(candidate); return Vlan.toUri(candidate); } catch (NumberFormatException nfe) { - if (com.cloud.dc.Vlan.UNTAGGED.equalsIgnoreCase(candidate)) { - return Native.toUri(candidate); - } - try { - URI uri = new URI(candidate); - BroadcastDomainType tiep = getSchemeValue(uri); - if (tiep.scheme != null && tiep.scheme.equals(uri.getScheme())) { - return uri; - } else { - throw new CloudRuntimeException("string '" + candidate + "' has an unknown BroadcastDomainType."); - } - } catch (URISyntaxException e) { - throw new CloudRuntimeException("string is not a broadcast URI: " + candidate); + return getVlanUriWhenNumberFormatException(candidate); + } + } + + /** + * This method is called in case of NumberFormatException is thrown when parsing the String into long + */ + private static URI getVlanUriWhenNumberFormatException(String candidate) { + if(StringUtils.isBlank(candidate)) { + throw new CloudRuntimeException("Expected VLAN or VXLAN but got a null isolation method"); + } + if (com.cloud.dc.Vlan.UNTAGGED.equalsIgnoreCase(candidate)) { + return Native.toUri(candidate); + } + try { + URI uri = new URI(candidate); + BroadcastDomainType tiep = getSchemeValue(uri); + if (tiep.scheme != null && tiep.scheme.equals(uri.getScheme())) { + return uri; + } else { + throw new CloudRuntimeException("string '" + candidate + "' has an unknown BroadcastDomainType."); } + } catch (URISyntaxException e) { + throw new CloudRuntimeException("string is not a broadcast URI: " + candidate); + } + } + + /** + * Encodes a string into a BroadcastUri, according to the given BroadcastDomainType + */ + public static URI encodeStringIntoBroadcastUri(String candidate, BroadcastDomainType isolationMethod) { + try{ + Long.parseLong(candidate); + return isolationMethod.toUri(candidate); + } catch (NumberFormatException nfe) { + return getVlanUriWhenNumberFormatException(candidate); } } }; diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java index 3f1b50691b2..f69f54c2f0d 100644 --- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java @@ -1082,10 +1082,15 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl ReadyCommand ready = null; try { final List agentMSHostList = new ArrayList<>(); + String lbAlgorithm = null; if (startup != null && startup.length > 0) { final String agentMSHosts = startup[0].getMsHostList(); if (!Strings.isNullOrEmpty(agentMSHosts)) { - agentMSHostList.addAll(Arrays.asList(agentMSHosts.split(","))); + String[] msHosts = agentMSHosts.split("@"); + if (msHosts.length > 1) { + lbAlgorithm = msHosts[1]; + } + agentMSHostList.addAll(Arrays.asList(msHosts[0].split(","))); } } @@ -1093,7 +1098,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl if (host != null) { ready = new ReadyCommand(host.getDataCenterId(), host.getId(), NumbersUtil.enableHumanReadableSizes); - if (!indirectAgentLB.compareManagementServerList(host.getId(), host.getDataCenterId(), agentMSHostList)) { + if (!indirectAgentLB.compareManagementServerList(host.getId(), host.getDataCenterId(), agentMSHostList, lbAlgorithm)) { final List newMSList = indirectAgentLB.getManagementServerList(host.getId(), host.getDataCenterId(), null); ready.setMsHostList(newMSList); ready.setLbAlgorithm(indirectAgentLB.getLBAlgorithmName()); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 892f7711908..e12dca04e31 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2359,7 +2359,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } if (vlanSpecified) { - URI uri = BroadcastDomainType.fromString(vlanId); + URI uri = encodeVlanIdIntoBroadcastUri(vlanId, pNtwk); // Aux: generate secondary URI for secondary VLAN ID (if provided) for performing checks URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null; //don't allow to specify vlan tag used by physical network for dynamic vlan allocation @@ -2513,7 +2513,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra //Logical router's UUID provided as VLAN_ID userNetwork.setVlanIdAsUUID(vlanIdFinal); //Set transient field } else { - uri = BroadcastDomainType.fromString(vlanIdFinal); + uri = encodeVlanIdIntoBroadcastUri(vlanIdFinal, pNtwk); } if (_networksDao.listByPhysicalNetworkPvlan(physicalNetworkId, uri.toString()).size() > 0) { @@ -2577,6 +2577,25 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return network; } + /** + * Encodes VLAN/VXLAN ID into a Broadcast URI according to the isolation method from the Physical Network. + * @return Broadcast URI, e.g. 'vlan://vlan_ID' or 'vxlan://vlxan_ID' + */ + protected URI encodeVlanIdIntoBroadcastUri(String vlanId, PhysicalNetwork pNtwk) { + if (pNtwk == null) { + throw new InvalidParameterValueException(String.format("Failed to encode VLAN/VXLAN %s into a Broadcast URI. Physical Network cannot be null.", vlanId)); + } + + if(StringUtils.isNotBlank(pNtwk.getIsolationMethods().get(0))) { + String isolationMethod = pNtwk.getIsolationMethods().get(0).toLowerCase(); + String vxlan = BroadcastDomainType.Vxlan.toString().toLowerCase(); + if(isolationMethod.equals(vxlan)) { + return BroadcastDomainType.encodeStringIntoBroadcastUri(vlanId, BroadcastDomainType.Vxlan); + } + } + return BroadcastDomainType.fromString(vlanId); + } + /** * Checks bypass VLAN id/range overlap check during network creation for guest networks * @param bypassVlanOverlapCheck bypass VLAN id/range overlap check diff --git a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java index e68ac5cde42..ff0a6faae2d 100644 --- a/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java +++ b/engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java @@ -22,12 +22,15 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Before; @@ -483,4 +486,74 @@ public class NetworkOrchestratorTest extends TestCase { verify(testOrchastrator._nicDao, never()).remove(nicId); } + public void encodeVlanIdIntoBroadcastUriTestVxlan() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("123", "VXLAN", "vxlan", "vxlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestVlan() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("123", "VLAN", "vlan", "vlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestEmpty() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("123", "", "vlan", "vlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestNull() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("123", null, "vlan", "vlan://123"); + } + + @Test(expected = CloudRuntimeException.class) + public void encodeVlanIdIntoBroadcastUriTestEmptyVlanId() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("", "vxlan", "vlan", "vlan://123"); + } + + @Test(expected = CloudRuntimeException.class) + public void encodeVlanIdIntoBroadcastUriTestNullVlanId() { + encodeVlanIdIntoBroadcastUriPrepareAndTest(null, "vlan", "vlan", "vlan://123"); + } + + @Test(expected = CloudRuntimeException.class) + public void encodeVlanIdIntoBroadcastUriTestBlankVlanId() { + encodeVlanIdIntoBroadcastUriPrepareAndTest(" ", "vlan", "vlan", "vlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestNullVlanIdWithSchema() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("vlan://123", "vlan", "vlan", "vlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestNullVlanIdWithSchemaIsolationVxlan() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("vlan://123", "vxlan", "vlan", "vlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestNullVxlanIdWithSchema() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("vxlan://123", "vxlan", "vxlan", "vxlan://123"); + } + + @Test + public void encodeVlanIdIntoBroadcastUriTestNullVxlanIdWithSchemaIsolationVlan() { + encodeVlanIdIntoBroadcastUriPrepareAndTest("vxlan://123", "vlan", "vxlan", "vxlan://123"); + } + + @Test(expected = InvalidParameterValueException.class) + public void encodeVlanIdIntoBroadcastUriTestNullNetwork() { + URI resultUri = testOrchastrator.encodeVlanIdIntoBroadcastUri("vxlan://123", null); + } + + private void encodeVlanIdIntoBroadcastUriPrepareAndTest(String vlanId, String isolationMethod, String expectedIsolation, String expectedUri) { + PhysicalNetworkVO physicalNetwork = new PhysicalNetworkVO(); + List isolationMethods = new ArrayList<>(); + isolationMethods.add(isolationMethod); + physicalNetwork.setIsolationMethods(isolationMethods); + + URI resultUri = testOrchastrator.encodeVlanIdIntoBroadcastUri(vlanId, physicalNetwork); + + Assert.assertEquals(expectedIsolation, resultUri.getScheme()); + Assert.assertEquals(expectedUri, resultUri.toString()); + } } diff --git a/framework/agent-lb/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLB.java b/framework/agent-lb/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLB.java index 464c489af84..9dfb9e1654e 100644 --- a/framework/agent-lb/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLB.java +++ b/framework/agent-lb/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLB.java @@ -37,7 +37,7 @@ public interface IndirectAgentLB { * @param receivedMSHosts received management server list * @return true if mgmtHosts is up to date, false if not */ - boolean compareManagementServerList(Long hostId, Long dcId, List receivedMSHosts); + boolean compareManagementServerList(Long hostId, Long dcId, List receivedMSHosts, String lbAlgorithm); /** * Returns the configure LB algorithm diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 86e06b6e832..740e122c9c4 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -318,8 +318,8 @@ import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo; import com.vmware.vim25.VirtualIDEController; -import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineBootOptions; +import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineFileLayoutEx; import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo; @@ -7135,7 +7135,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa VmwareHypervisorHost hyperHost = getHyperHost(context); String vmName = cmd.getInstanceName(); - List vmMos = hyperHost.listVmsOnHyperHost(vmName); + List vmMos = hyperHost.listVmsOnHyperHostWithHypervisorName(vmName); for (VirtualMachineMO vmMo : vmMos) { if (vmMo == null) { diff --git a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java index 8742e2dfe6f..a25575cd175 100644 --- a/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java +++ b/server/src/main/java/org/apache/cloudstack/agent/lb/IndirectAgentLBServiceImpl.java @@ -98,10 +98,13 @@ public class IndirectAgentLBServiceImpl extends ComponentLifecycleBase implement } @Override - public boolean compareManagementServerList(final Long hostId, final Long dcId, final List receivedMSHosts) { + public boolean compareManagementServerList(final Long hostId, final Long dcId, final List receivedMSHosts, final String lbAlgorithm) { if (receivedMSHosts == null || receivedMSHosts.size() < 1) { return false; } + if (getLBAlgorithmName() != lbAlgorithm) { + return false; + } final List expectedMSList = getManagementServerList(hostId, dcId, null); final org.apache.cloudstack.agent.lb.IndirectAgentLBAlgorithm algorithm = getAgentMSLBAlgorithm(); return algorithm.compare(expectedMSList, receivedMSHosts); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java index b8afdc84cfd..92b05f24521 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -217,13 +218,13 @@ public class ClusterMO extends BaseMO implements VmwareHypervisorHost { } @Override - public synchronized List listVmsOnHyperHost(String vmName) throws Exception { + public synchronized List listVmsOnHyperHostWithHypervisorName(String vmName) throws Exception { List vms = new ArrayList<>(); List hosts = _context.getVimClient().getDynamicProperty(_mor, "host"); - if (hosts != null && hosts.size() > 0) { + if (CollectionUtils.isNotEmpty(hosts)) { for (ManagedObjectReference morHost : hosts) { HostMO hostMo = new HostMO(_context, morHost); - vms.addAll(hostMo.listVmsOnHyperHost(vmName)); + vms.addAll(hostMo.listVmsOnHyperHostWithHypervisorName(vmName)); } } return vms; diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index 7877db980f4..c248f7a63f1 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -18,11 +18,14 @@ package com.cloud.hypervisor.vmware.mo; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.google.gson.Gson; @@ -497,10 +500,10 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { } @Override - public synchronized List listVmsOnHyperHost(String vmName) throws Exception { + public synchronized List listVmsOnHyperHostWithHypervisorName(String vmName) throws Exception { List vms = new ArrayList<>(); - if (vmName != null && !vmName.isEmpty()) { - vms.add(findVmOnHyperHost(vmName)); + if (StringUtils.isNotEmpty(vmName)) { + vms.add(findVmOnHyperHostWithHypervisorName(vmName)); } else { loadVmCache(); vms.addAll(_vmCache.values()); @@ -1209,4 +1212,36 @@ public class HostMO extends BaseMO implements VmwareHypervisorHost { return false; } + private synchronized VirtualMachineMO findVmOnHyperHostWithHypervisorName(String vmName) throws Exception { + if (s_logger.isDebugEnabled()) + s_logger.debug("find VM hypervisor name: " + vmName + " on host"); + + VirtualMachineMO vmMo = getVmWithHypervisorName(_vmCache.values(), vmName); + if (vmMo != null) { + if (s_logger.isDebugEnabled()) + s_logger.debug("VM hypervisor name: " + vmName + " found in host cache"); + return vmMo; + } + + s_logger.info("VM hypervisor name: " + vmName + " not found in host cache"); + loadVmCache(); + + return getVmWithHypervisorName(_vmCache.values(), vmName); + } + + private VirtualMachineMO getVmWithHypervisorName(Collection vmList, String vmName) { + if (CollectionUtils.isNotEmpty(vmList)) { + for (VirtualMachineMO vm : vmList) { + try { + if (StringUtils.isNotEmpty(vm.getVmName()) && vm.getVmName().equals(vmName)) { + return vm; + } + } catch (Exception e) { + s_logger.debug("Failed to get VM name, ignoring exception", e); + } + } + } + return null; + } + } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java index a9ceb5d806e..f99384a75e1 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java @@ -53,7 +53,7 @@ public interface VmwareHypervisorHost { String getHyperHostDefaultGateway() throws Exception; - List listVmsOnHyperHost(String name) throws Exception; + List listVmsOnHyperHostWithHypervisorName(String name) throws Exception; VirtualMachineMO findVmOnHyperHost(String name) throws Exception;