From ea32a1a71aa60bc8de3d06ea9af43007399da2b6 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 9 May 2025 10:19:30 +0200 Subject: [PATCH] server: fetch IP of VMs on L2 networks (#10431) --- .../agent/api/GetVmIpAddressCommand.java | 8 ++- .../LibvirtGetVmIpAddressCommandWrapper.java | 57 ++++++++++++++----- ...bvirtGetVmIpAddressCommandWrapperTest.java | 3 + .../xenbase/CitrixRequestWrapperTest.java | 2 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 15 +++-- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/com/cloud/agent/api/GetVmIpAddressCommand.java b/core/src/main/java/com/cloud/agent/api/GetVmIpAddressCommand.java index a9c7413b9f0..4efc0781f91 100644 --- a/core/src/main/java/com/cloud/agent/api/GetVmIpAddressCommand.java +++ b/core/src/main/java/com/cloud/agent/api/GetVmIpAddressCommand.java @@ -24,11 +24,13 @@ public class GetVmIpAddressCommand extends Command { String vmName; String vmNetworkCidr; boolean windows = false; + String macAddress; - public GetVmIpAddressCommand(String vmName, String vmNetworkCidr, boolean windows) { + public GetVmIpAddressCommand(String vmName, String vmNetworkCidr, boolean windows, String macAddress) { this.vmName = vmName; this.windows = windows; this.vmNetworkCidr = vmNetworkCidr; + this.macAddress = macAddress; } @Override @@ -47,4 +49,8 @@ public class GetVmIpAddressCommand extends Command { public String getVmNetworkCidr() { return vmNetworkCidr; } + + public String getMacAddress() { + return macAddress; + } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java index 0dd52ddfb10..51a125a504f 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java @@ -69,10 +69,13 @@ public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper commands = new ArrayList<>(); commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, "--source", "agent"}); Pair response = executePipedCommands(commands, 0); if (response != null) { String output = response.second(); - String[] lines = output.split("\n"); - for (String line : lines) { - if (line.contains("ipv4")) { - String[] parts = line.split(" "); - String[] ipParts = parts[parts.length-1].split("/"); - if (ipParts.length > 1) { - if (NetUtils.isIpWithInCidrRange(ipParts[0], networkCidr)) { - ip = ipParts[0]; - break; - } - } - } + Pair ipAddresses = getIpAddresses(output, macAddress); + String ipv4 = ipAddresses.first(); + if (networkCidr == null || NetUtils.isIpWithInCidrRange(ipv4, networkCidr)) { + ip = ipv4; } } else { s_logger.error("ipFromDomIf: Command execution failed for VM: " + sanitizedVmName); @@ -116,6 +111,38 @@ public final class LibvirtGetVmIpAddressCommandWrapper extends CommandWrapper getIpAddresses(String output, String macAddress) { + String ipv4 = null; + String ipv6 = null; + boolean found = false; + String[] lines = output.split("\n"); + for (String line : lines) { + String[] parts = line.replaceAll(" +", " ").trim().split(" "); + if (parts.length < 4) { + continue; + } + String device = parts[0]; + String mac = parts[1]; + if (found) { + if (!device.equals("-") || !mac.equals("-")) { + break; + } + } else if (!mac.equals(macAddress)) { + continue; + } + found = true; + String ipFamily = parts[2]; + String ipPart = parts[3].split("/")[0]; + if (ipFamily.equals("ipv4")) { + ipv4 = ipPart; + } else if (ipFamily.equals("ipv6")) { + ipv6 = ipPart; + } + } + s_logger.debug(String.format("Found ipv4: %s and ipv6: %s with mac address %s", ipv4, ipv6, macAddress)); + return new Pair<>(ipv4, ipv6); + } + private String ipFromDhcpLeaseFile(String sanitizedVmName, String networkCidr) { String ip = null; List commands = new ArrayList<>(); 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 bd09fe03d49..511306854cf 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 @@ -66,6 +66,7 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { when(getVmIpAddressCommand.getVmName()).thenReturn("validVmName"); when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24"); + when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80"); when(getVmIpAddressCommand.isWindows()).thenReturn(false); when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, VIRSH_DOMIF_OUTPUT)); @@ -88,6 +89,7 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { when(getVmIpAddressCommand.getVmName()).thenReturn("invalidVmName!"); when(getVmIpAddressCommand.getVmNetworkCidr()).thenReturn("192.168.0.0/24"); + when(getVmIpAddressCommand.getMacAddress()).thenReturn("02:0c:02:f9:00:80"); when(getVmIpAddressCommand.isWindows()).thenReturn(false); when(Script.executePipedCommands(anyList(), anyLong())).thenReturn(new Pair<>(0, VIRSH_DOMIF_OUTPUT)); @@ -114,6 +116,7 @@ public class LibvirtGetVmIpAddressCommandWrapperTest { when(getVmIpAddressCommand.getVmName()).thenReturn("validVmName"); 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")); diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java index 9ecb14d841f..d464a266493 100755 --- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java +++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java @@ -1934,7 +1934,7 @@ public class CitrixRequestWrapperTest { vmIpsMap.put("Test", "127.0.0.1"); rec.networks = vmIpsMap; - final GetVmIpAddressCommand getVmIpAddrCmd = new GetVmIpAddressCommand("Test", "127.0.0.1/24", false); + final GetVmIpAddressCommand getVmIpAddrCmd = new GetVmIpAddressCommand("Test", "127.0.0.1/24", false, null); final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance(); assertNotNull(wrapper); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 173cec83d71..64684d5e8d1 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -757,19 +757,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir boolean isWindows; Long hostId; String networkCidr; + String macAddress; - public VmIpAddrFetchThread(long vmId, long nicId, String instanceName, boolean windows, Long hostId, String networkCidr) { + public VmIpAddrFetchThread(long vmId, long nicId, String instanceName, boolean windows, Long hostId, String networkCidr, String macAddress) { this.vmId = vmId; this.nicId = nicId; this.vmName = instanceName; this.isWindows = windows; this.hostId = hostId; this.networkCidr = networkCidr; + this.macAddress = macAddress; } @Override protected void runInContext() { - GetVmIpAddressCommand cmd = new GetVmIpAddressCommand(vmName, networkCidr, isWindows); + GetVmIpAddressCommand cmd = new GetVmIpAddressCommand(vmName, networkCidr, isWindows, macAddress); boolean decrementCount = true; try { @@ -2397,9 +2399,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private void loadVmDetailsInMapForExternalDhcpIp() { List networks = _networkDao.listByGuestType(Network.GuestType.Shared); + networks.addAll(_networkDao.listByGuestType(Network.GuestType.L2)); for (NetworkVO network: networks) { - if(_networkModel.isSharedNetworkWithoutServices(network.getId())) { + if (GuestType.L2.equals(network.getGuestType()) || _networkModel.isSharedNetworkWithoutServices(network.getId())) { List nics = _nicDao.listByNetworkId(network.getId()); for (NicVO nic : nics) { @@ -2642,7 +2645,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows"); _vmIpFetchThreadExecutor.execute(new VmIpAddrFetchThread(vmId, nicId, vmInstance.getInstanceName(), - isWindows, vm.getHostId(), network.getCidr())); + isWindows, vm.getHostId(), network.getCidr(), nicVo.getMacAddress())); } } catch (Exception e) { @@ -3279,7 +3282,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir final List nics = _nicDao.listByVmId(vmId); for (NicVO nic : nics) { Network network = _networkModel.getNetwork(nic.getNetworkId()); - if (_networkModel.isSharedNetworkWithoutServices(network.getId())) { + if (GuestType.L2.equals(network.getGuestType()) || _networkModel.isSharedNetworkWithoutServices(network.getId())) { s_logger.debug("Adding vm " +vmId +" nic id "+ nic.getId() +" into vmIdCountMap as part of vm " + "reboot for vm ip fetch "); vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value())); @@ -5202,7 +5205,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir final List nics = _nicDao.listByVmId(vm.getId()); for (NicVO nic : nics) { Network network = _networkModel.getNetwork(nic.getNetworkId()); - if (_networkModel.isSharedNetworkWithoutServices(network.getId())) { + if (GuestType.L2.equals(network.getGuestType()) || _networkModel.isSharedNetworkWithoutServices(network.getId())) { vmIdCountMap.put(nic.getId(), new VmAndCountDetails(nic.getInstanceId(), VmIpFetchTrialMax.value())); } }