Fixes for KVM unmanaged instances import on advanced network and VNC password (#8492)

This PR fixes a regression caused by #8465 on advanced zones, import fails with:

2024-01-10 12:13:33,234 DEBUG [o.a.c.e.o.NetworkOrchestrator] (API-Job-Executor-3:ctx-991bbe9f job-128 ctx-f49517d4) (logid:d7b8e716) Allocating nic for vm 142272e8-9e2e-407b-9d7e-e9a03b81653c in network Network {"id": 204, "name": "Isolated", "uuid": "9679fac5-e3ac-4694-a57b-beb635340f39", "networkofferingid": 10} during import
2024-01-10 12:13:33,239 ERROR [o.a.c.v.UnmanagedVMsManagerImpl] (API-Job-Executor-3:ctx-991bbe9f job-128 ctx-f49517d4) (logid:d7b8e716) Failed to import NICs while importing vm: i-2-31-VM
com.cloud.exception.InsufficientVirtualNetworkCapacityException: Unable to acquire Guest IP  address for network Network {"id": 204, "name": "Isolated", "uuid": "9679fac5-e3ac-4694-a57b-beb635340f39", "networkofferingid": 10}Scope=interface com.cloud.dc.DataCenter; id=1
	at org.apache.cloudstack.engine.orchestration.NetworkOrchestrator.importNic(NetworkOrchestrator.java:4582)
	at org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.importNic(UnmanagedVMsManagerImpl.java:859)
	at org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.importVirtualMachineInternal(UnmanagedVMsManagerImpl.java:1198)
	at org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.importUnmanagedInstanceFromHypervisor(UnmanagedVMsManagerImpl.java:1511)
	at org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.baseImportInstance(UnmanagedVMsManagerImpl.java:1342)
	at org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.importUnmanagedInstance(UnmanagedVMsManagerImpl.java:1282)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

Also, addresses the VNC password field set instead of a fixed string
This commit is contained in:
Nicolas Vazquez 2024-01-12 05:44:01 -03:00 committed by GitHub
parent 59e78cbc45
commit a3a4833c3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 40 deletions

View File

@ -4567,23 +4567,18 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
public Pair<NicProfile, Integer> importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses, final DataCenter dataCenter, final boolean forced)
throws ConcurrentOperationException, InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
s_logger.debug("Allocating nic for vm " + vm.getUuid() + " in network " + network + " during import");
String guestIp = null;
IPAddressVO freeIpAddress = null;
String selectedIp = null;
if (ipAddresses != null && StringUtils.isNotEmpty(ipAddresses.getIp4Address())) {
if (ipAddresses.getIp4Address().equals("auto")) {
ipAddresses.setIp4Address(null);
}
freeIpAddress = getGuestIpForNicImport(network, dataCenter, ipAddresses);
if (freeIpAddress != null && freeIpAddress.getAddress() != null) {
guestIp = freeIpAddress.getAddress().addr();
}
if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
selectedIp = getSelectedIpForNicImport(network, dataCenter, ipAddresses);
if (selectedIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) {
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP address for network " + network, DataCenter.class,
network.getDataCenterId());
}
}
final String finalGuestIp = guestIp;
final IPAddressVO freeIp = freeIpAddress;
final String finalSelectedIp = selectedIp;
final NicVO vo = Transaction.execute(new TransactionCallback<NicVO>() {
@Override
public NicVO doInTransaction(TransactionStatus status) {
@ -4595,11 +4590,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());
vo.setMacAddress(macAddressToPersist);
vo.setAddressFormat(Networks.AddressFormat.Ip4);
Pair<String, String> pair = getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, freeIp);
Pair<String, String> pair = getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, finalSelectedIp);
String gateway = pair.first();
String netmask = pair.second();
if (NetUtils.isValidIp4(finalGuestIp) && StringUtils.isNotEmpty(gateway)) {
vo.setIPv4Address(finalGuestIp);
if (NetUtils.isValidIp4(finalSelectedIp) && StringUtils.isNotEmpty(gateway)) {
vo.setIPv4Address(finalSelectedIp);
vo.setIPv4Gateway(gateway);
vo.setIPv4Netmask(netmask);
}
@ -4638,27 +4633,42 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
return new Pair<NicProfile, Integer>(vmNic, Integer.valueOf(deviceId));
}
protected IPAddressVO getGuestIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
protected String getSelectedIpForNicImport(Network network, DataCenter dataCenter, Network.IpAddresses ipAddresses) {
if (network.getGuestType() == GuestType.L2) {
return null;
}
if (dataCenter.getNetworkType() == NetworkType.Advanced) {
String guestIpAddress = _ipAddrMgr.acquireGuestIpAddress(network, ipAddresses.getIp4Address());
return _ipAddressDao.findByIp(guestIpAddress);
return dataCenter.getNetworkType() == NetworkType.Basic ?
getSelectedIpForNicImportOnBasicZone(ipAddresses.getIp4Address(), network, dataCenter):
_ipAddrMgr.acquireGuestIpAddress(network, ipAddresses.getIp4Address());
}
protected String getSelectedIpForNicImportOnBasicZone(String requestedIp, Network network, DataCenter dataCenter) {
IPAddressVO ipAddressVO = StringUtils.isBlank(requestedIp) ?
_ipAddressDao.findBySourceNetworkIdAndDatacenterIdAndState(network.getId(), dataCenter.getId(), IpAddress.State.Free):
_ipAddressDao.findByIp(requestedIp);
if (ipAddressVO == null || ipAddressVO.getState() != IpAddress.State.Free) {
String msg = String.format("Cannot find a free IP to assign to VM NIC on network %s", network.getName());
s_logger.error(msg);
throw new CloudRuntimeException(msg);
}
return _ipAddressDao.findBySourceNetworkIdAndDatacenterIdAndState(network.getId(), dataCenter.getId(), IpAddress.State.Free);
return ipAddressVO.getAddress() != null ? ipAddressVO.getAddress().addr() : null;
}
/**
* Obtain the gateway and netmask for a VM NIC to import
* If the VM to import is on a Basic Zone, then obtain the information from the vlan table instead of the network
*/
protected Pair<String, String> getNetworkGatewayAndNetmaskForNicImport(Network network, DataCenter dataCenter, IPAddressVO freeIp) {
VlanVO vlan = dataCenter.getNetworkType() == NetworkType.Basic && freeIp != null ?
_vlanDao.findById(freeIp.getVlanId()) : null;
String gateway = vlan != null ? vlan.getVlanGateway() : network.getGateway();
String netmask = vlan != null ? vlan.getVlanNetmask() :
(StringUtils.isNotEmpty(network.getCidr()) ? NetUtils.cidr2Netmask(network.getCidr()) : null);
protected Pair<String, String> getNetworkGatewayAndNetmaskForNicImport(Network network, DataCenter dataCenter, String selectedIp) {
String gateway = network.getGateway();
String netmask = StringUtils.isNotEmpty(network.getCidr()) ? NetUtils.cidr2Netmask(network.getCidr()) : null;
if (dataCenter.getNetworkType() == NetworkType.Basic) {
IPAddressVO freeIp = _ipAddressDao.findByIp(selectedIp);
if (freeIp != null) {
VlanVO vlan = _vlanDao.findById(freeIp.getVlanId());
gateway = vlan != null ? vlan.getVlanGateway() : null;
netmask = vlan != null ? vlan.getVlanNetmask() : null;
}
}
return new Pair<>(gateway, netmask);
}

View File

@ -717,7 +717,7 @@ public class NetworkOrchestratorTest extends TestCase {
public void testGetNetworkGatewayAndNetmaskForNicImportAdvancedZone() {
Network network = Mockito.mock(Network.class);
DataCenter dataCenter = Mockito.mock(DataCenter.class);
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
String ipAddress = "10.1.1.10";
String networkGateway = "10.1.1.1";
String networkNetmask = "255.255.255.0";
@ -725,7 +725,7 @@ public class NetworkOrchestratorTest extends TestCase {
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
Mockito.when(network.getGateway()).thenReturn(networkGateway);
Mockito.when(network.getCidr()).thenReturn(networkCidr);
Pair<String, String> pair = testOrchastrator.getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, ipAddressVO);
Pair<String, String> pair = testOrchastrator.getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, ipAddress);
Assert.assertNotNull(pair);
Assert.assertEquals(networkGateway, pair.first());
Assert.assertEquals(networkNetmask, pair.second());
@ -736,8 +736,9 @@ public class NetworkOrchestratorTest extends TestCase {
Network network = Mockito.mock(Network.class);
DataCenter dataCenter = Mockito.mock(DataCenter.class);
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
String ipAddress = "172.1.1.10";
String defaultNetworkGateway = "10.1.1.1";
String defaultNetworkGateway = "172.1.1.1";
String defaultNetworkNetmask = "255.255.255.0";
VlanVO vlan = Mockito.mock(VlanVO.class);
Mockito.when(vlan.getVlanGateway()).thenReturn(defaultNetworkGateway);
@ -745,7 +746,8 @@ public class NetworkOrchestratorTest extends TestCase {
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
Mockito.when(ipAddressVO.getVlanId()).thenReturn(1L);
Mockito.when(testOrchastrator._vlanDao.findById(1L)).thenReturn(vlan);
Pair<String, String> pair = testOrchastrator.getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, ipAddressVO);
Mockito.when(testOrchastrator._ipAddressDao.findByIp(ipAddress)).thenReturn(ipAddressVO);
Pair<String, String> pair = testOrchastrator.getNetworkGatewayAndNetmaskForNicImport(network, dataCenter, ipAddress);
Assert.assertNotNull(pair);
Assert.assertEquals(defaultNetworkGateway, pair.first());
Assert.assertEquals(defaultNetworkNetmask, pair.second());
@ -757,7 +759,7 @@ public class NetworkOrchestratorTest extends TestCase {
DataCenter dataCenter = Mockito.mock(DataCenter.class);
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
Mockito.when(network.getGuestType()).thenReturn(GuestType.L2);
Assert.assertNull(testOrchastrator.getGuestIpForNicImport(network, dataCenter, ipAddresses));
Assert.assertNull(testOrchastrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses));
}
@Test
@ -768,32 +770,76 @@ public class NetworkOrchestratorTest extends TestCase {
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
String ipAddress = "10.1.10.10";
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
Mockito.when(ipAddresses.getIp4Address()).thenReturn(ipAddress);
Mockito.when(testOrchastrator._ipAddrMgr.acquireGuestIpAddress(network, ipAddress)).thenReturn(ipAddress);
Ip ip = mock(Ip.class);
Mockito.when(ipAddressVO.getAddress()).thenReturn(ip);
Mockito.when(testOrchastrator._ipAddressDao.findByIp(ipAddress)).thenReturn(ipAddressVO);
IPAddressVO guestIp = testOrchastrator.getGuestIpForNicImport(network, dataCenter, ipAddresses);
Assert.assertEquals(ip, guestIp.getAddress());
String guestIp = testOrchastrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
Assert.assertEquals(ipAddress, guestIp);
}
@Test
public void testGetGuestIpForNicImportBasicZone() {
public void testGetGuestIpForNicImportBasicZoneAutomaticIP() {
Network network = Mockito.mock(Network.class);
DataCenter dataCenter = Mockito.mock(DataCenter.class);
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
Mockito.when(network.getGuestType()).thenReturn(GuestType.Isolated);
Mockito.when(network.getGuestType()).thenReturn(GuestType.Shared);
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
long networkId = 1L;
long dataCenterId = 1L;
String freeIp = "172.10.10.10";
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
Ip ip = mock(Ip.class);
Mockito.when(ip.addr()).thenReturn(freeIp);
Mockito.when(ipAddressVO.getAddress()).thenReturn(ip);
Mockito.when(ipAddressVO.getState()).thenReturn(State.Free);
Mockito.when(network.getId()).thenReturn(networkId);
Mockito.when(dataCenter.getId()).thenReturn(dataCenterId);
Mockito.when(testOrchastrator._ipAddressDao.findBySourceNetworkIdAndDatacenterIdAndState(networkId, dataCenterId, State.Free)).thenReturn(ipAddressVO);
IPAddressVO guestIp = testOrchastrator.getGuestIpForNicImport(network, dataCenter, ipAddresses);
Assert.assertEquals(ip, guestIp.getAddress());
String ipAddress = testOrchastrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
Assert.assertEquals(freeIp, ipAddress);
}
@Test
public void testGetGuestIpForNicImportBasicZoneManualIP() {
Network network = Mockito.mock(Network.class);
DataCenter dataCenter = Mockito.mock(DataCenter.class);
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
Mockito.when(network.getGuestType()).thenReturn(GuestType.Shared);
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
long networkId = 1L;
long dataCenterId = 1L;
String requestedIp = "172.10.10.10";
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
Ip ip = mock(Ip.class);
Mockito.when(ip.addr()).thenReturn(requestedIp);
Mockito.when(ipAddressVO.getAddress()).thenReturn(ip);
Mockito.when(ipAddressVO.getState()).thenReturn(State.Free);
Mockito.when(network.getId()).thenReturn(networkId);
Mockito.when(dataCenter.getId()).thenReturn(dataCenterId);
Mockito.when(ipAddresses.getIp4Address()).thenReturn(requestedIp);
Mockito.when(testOrchastrator._ipAddressDao.findByIp(requestedIp)).thenReturn(ipAddressVO);
String ipAddress = testOrchastrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
Assert.assertEquals(requestedIp, ipAddress);
}
@Test(expected = CloudRuntimeException.class)
public void testGetGuestIpForNicImportBasicUsedIP() {
Network network = Mockito.mock(Network.class);
DataCenter dataCenter = Mockito.mock(DataCenter.class);
Network.IpAddresses ipAddresses = Mockito.mock(Network.IpAddresses.class);
Mockito.when(network.getGuestType()).thenReturn(GuestType.Shared);
Mockito.when(dataCenter.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
long networkId = 1L;
long dataCenterId = 1L;
String requestedIp = "172.10.10.10";
IPAddressVO ipAddressVO = Mockito.mock(IPAddressVO.class);
Ip ip = mock(Ip.class);
Mockito.when(ip.addr()).thenReturn(requestedIp);
Mockito.when(ipAddressVO.getAddress()).thenReturn(ip);
Mockito.when(ipAddressVO.getState()).thenReturn(State.Allocated);
Mockito.when(network.getId()).thenReturn(networkId);
Mockito.when(dataCenter.getId()).thenReturn(dataCenterId);
Mockito.when(ipAddresses.getIp4Address()).thenReturn(requestedIp);
Mockito.when(testOrchastrator._ipAddressDao.findByIp(requestedIp)).thenReturn(ipAddressVO);
testOrchastrator.getSelectedIpForNicImport(network, dataCenter, ipAddresses);
}
}

View File

@ -28,6 +28,7 @@ import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.libvirt.Connect;
@ -43,6 +44,8 @@ import java.util.List;
public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWrapper<GetUnmanagedInstancesCommand, GetUnmanagedInstancesAnswer, LibvirtComputingResource> {
private static final Logger LOGGER = Logger.getLogger(LibvirtGetUnmanagedInstancesCommandWrapper.class);
private static final int requiredVncPasswordLength = 22;
@Override
public GetUnmanagedInstancesAnswer execute(GetUnmanagedInstancesCommand command, LibvirtComputingResource libvirtComputingResource) {
LOGGER.info("Fetching unmanaged instance on host");
@ -130,7 +133,7 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
instance.setMemory((int) LibvirtComputingResource.getDomainMemory(domain) / 1024);
instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces()));
instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, conn, domain.getName()));
instance.setVncPassword(parser.getVncPasswd() + "aaaaaaaaaaaaaa"); // Suffix back extra characters for DB compatibility
instance.setVncPassword(getFormattedVncPassword(parser.getVncPasswd()));
return instance;
} catch (Exception e) {
@ -139,6 +142,14 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
}
}
protected String getFormattedVncPassword(String vncPasswd) {
if (StringUtils.isBlank(vncPasswd)) {
return null;
}
String randomChars = RandomStringUtils.random(requiredVncPasswordLength - vncPasswd.length(), true, false);
return String.format("%s%s", vncPasswd, randomChars);
}
private UnmanagedInstanceTO.PowerState getPowerState(VirtualMachine.PowerState vmPowerState) {
switch (vmPowerState) {
case PowerOn:

View File

@ -4581,7 +4581,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Host host, Host lastHost, VirtualMachine.PowerState powerState) {
if (isImport) {
vm.setDataCenterId(zone.getId());
if (List.of(HypervisorType.VMware, HypervisorType.KVM).contains(hypervisorType)) {
if (List.of(HypervisorType.VMware, HypervisorType.KVM).contains(hypervisorType) && host != null) {
vm.setHostId(host.getId());
}
if (lastHost != null) {