Merge release branch 4.15 to master

* 4.15:
  server: select root disk based on user input during vm import (#4591)
  kvm: Use Q35 chipset for UEFI x86_64 (#4576)
  server: fix wrong error message when create isolated network without SourceNat (#4624)
  server: add possibility to scale vm to current customer offerings (#4622)
  server: keep networks order and ips while move a vm with multiple networks (#4602)
  server: throw exception when update vm nic on L2 network (#4625)
  doc: fix typo in install notes (#4633)
This commit is contained in:
Daan Hoogland 2021-02-01 09:58:52 +00:00
commit ff376d8187
8 changed files with 113 additions and 51 deletions

View File

@ -136,7 +136,7 @@ To create rpms, install the following extra packages:
# yum -y install rpm-build
# yum -y install ws-commons-util
# yum -y instal gcc
# yum -y install gcc
# yum -y install glibc-devel
# yum -y install MySQL-python

View File

@ -129,7 +129,7 @@ public interface NetworkOrchestrationService {
void cleanupNics(VirtualMachineProfile vm);
void expungeNics(VirtualMachineProfile vm);
void removeNics(VirtualMachineProfile vm);
List<NicProfile> getNicProfiles(VirtualMachine vm);

View File

@ -2301,10 +2301,10 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
@Override
public void expungeNics(final VirtualMachineProfile vm) {
final List<NicVO> nics = _nicDao.listByVmIdIncludingRemoved(vm.getId());
public void removeNics(final VirtualMachineProfile vm) {
final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
for (final NicVO nic : nics) {
_nicDao.expunge(nic.getId());
_nicDao.remove(nic.getId());
}
}
@ -2545,8 +2545,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
&& (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated
&& !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat)));
if (cidr == null && ip6Cidr == null && cidrRequired) {
throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared
+ " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled");
if (ntwkOff.getGuestType() == GuestType.Shared) {
throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared);
} else {
throw new InvalidParameterValueException("gateway/netmask are required when create network of" + " type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled");
}
}
checkL2OfferingServices(ntwkOff);

View File

@ -2247,8 +2247,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
if (MapUtils.isNotEmpty(customParams) && customParams.containsKey(GuestDef.BootType.UEFI.toString())) {
guest.setBootType(GuestDef.BootType.UEFI);
guest.setBootMode(GuestDef.BootMode.LEGACY);
guest.setMachineType("q35");
if (StringUtils.isNotBlank(customParams.get(GuestDef.BootType.UEFI.toString())) && "secure".equalsIgnoreCase(customParams.get(GuestDef.BootType.UEFI.toString()))) {
guest.setMachineType("q35");
guest.setBootMode(GuestDef.BootMode.SECURE); // setting to secure mode
}
}

View File

@ -2955,7 +2955,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
_accountMgr.checkAccess(caller, null, true, vmInstance);
currentVmOffering = _srvOfferingDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId());
sc.addAnd("id", SearchCriteria.Op.NEQ, currentVmOffering.getId());
if (! currentVmOffering.isDynamic()) {
sc.addAnd("id", SearchCriteria.Op.NEQ, currentVmOffering.getId());
}
// 1. Only return offerings with the same storage type
sc.addAnd("useLocalStorage", SearchCriteria.Op.EQ, currentVmOffering.isUseLocalStorage());

View File

@ -24,8 +24,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -1736,8 +1736,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return null;
}
} else {
s_logger.error("UpdateVmNicIpCmd is not supported in this network...");
return null;
throw new InvalidParameterValueException("UpdateVmNicIpCmd is not supported in L2 network");
}
s_logger.debug("Updating IPv4 address of NIC " + nicVO + " to " + ipaddr + "/" + nicVO.getIPv4Netmask() + " with gateway " + nicVO.getIPv4Gateway());
@ -6454,7 +6453,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
_securityGroupMgr.removeInstanceFromGroups(cmd.getVmId());
// cleanup the network for the oldOwner
_networkMgr.cleanupNics(vmOldProfile);
_networkMgr.expungeNics(vmOldProfile);
_networkMgr.removeNics(vmOldProfile);
// security groups will be recreated for the new account, when the
// VM is started
List<NetworkVO> networkList = new ArrayList<NetworkVO>();
@ -6516,34 +6515,25 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
s_logger.debug("AssignVM: Basic zone, adding security groups no " + securityGroupIdList.size() + " to " + vm.getInstanceName());
} else {
Set<NetworkVO> applicableNetworks = new LinkedHashSet<>();
Map<Long, String> requestedIPv4ForNics = new HashMap<>();
Map<Long, String> requestedIPv6ForNics = new HashMap<>();
if (zone.isSecurityGroupEnabled()) { // advanced zone with security groups
// cleanup the old security groups
_securityGroupMgr.removeInstanceFromGroups(cmd.getVmId());
Set<NetworkVO> applicableNetworks = new HashSet<NetworkVO>();
String requestedIPv4ForDefaultNic = null;
String requestedIPv6ForDefaultNic = null;
// if networkIdList is null and the first network of vm is shared network, then keep it if possible
if (networkIdList == null || networkIdList.isEmpty()) {
NicVO defaultNicOld = _nicDao.findDefaultNicForVM(vm.getId());
if (defaultNicOld != null) {
NetworkVO defaultNetworkOld = _networkDao.findById(defaultNicOld.getNetworkId());
if (defaultNetworkOld != null && defaultNetworkOld.getGuestType() == Network.GuestType.Shared && defaultNetworkOld.getAclType() == ACLType.Domain) {
try {
_networkModel.checkNetworkPermissions(newAccount, defaultNetworkOld);
applicableNetworks.add(defaultNetworkOld);
requestedIPv4ForDefaultNic = defaultNicOld.getIPv4Address();
requestedIPv6ForDefaultNic = defaultNicOld.getIPv6Address();
s_logger.debug("AssignVM: use old shared network " + defaultNetworkOld.getName() + " with old ip " + requestedIPv4ForDefaultNic + " on default nic of vm:" + vm.getInstanceName());
} catch (PermissionDeniedException e) {
s_logger.debug("AssignVM: the shared network on old default nic can not be applied to new account");
}
if (canAccountUseNetwork(newAccount, defaultNetworkOld)) {
applicableNetworks.add(defaultNetworkOld);
requestedIPv4ForNics.put(defaultNetworkOld.getId(), defaultNicOld.getIPv4Address());
requestedIPv6ForNics.put(defaultNetworkOld.getId(), defaultNicOld.getIPv6Address());
s_logger.debug("AssignVM: use old shared network " + defaultNetworkOld.getName() + " with old ip " + defaultNicOld.getIPv4Address() + " on default nic of vm:" + vm.getInstanceName());
}
}
}
// cleanup the network for the oldOwner
_networkMgr.cleanupNics(vmOldProfile);
_networkMgr.expungeNics(vmOldProfile);
if (networkIdList != null && !networkIdList.isEmpty()) {
// add any additional networks
@ -6566,10 +6556,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
ex.addProxyObject(network.getUuid(), "networkId");
throw ex;
}
if (network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Domain) {
NicVO nicOld = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId());
if (nicOld != null) {
requestedIPv4ForNics.put(network.getId(), nicOld.getIPv4Address());
requestedIPv6ForNics.put(network.getId(), nicOld.getIPv6Address());
s_logger.debug("AssignVM: use old shared network " + network.getName() + " with old ip " + nicOld.getIPv4Address() + " on nic of vm:" + vm.getInstanceName());
}
}
s_logger.debug("AssignVM: Added network " + network.getName() + " to vm " + vm.getId());
applicableNetworks.add(network);
}
}
// cleanup the network for the oldOwner
_networkMgr.cleanupNics(vmOldProfile);
_networkMgr.removeNics(vmOldProfile);
// add the new nics
LinkedHashMap<Network, List<? extends NicProfile>> networks = new LinkedHashMap<Network, List<? extends NicProfile>>();
int toggle = 0;
@ -6578,11 +6582,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
NicProfile defaultNic = new NicProfile();
if (toggle == 0) {
defaultNic.setDefaultNic(true);
defaultNic.setRequestedIPv4(requestedIPv4ForDefaultNic);
defaultNic.setRequestedIPv6(requestedIPv6ForDefaultNic);
defaultNetwork = appNet;
toggle++;
}
defaultNic.setRequestedIPv4(requestedIPv4ForNics.get(appNet.getId()));
defaultNic.setRequestedIPv6(requestedIPv6ForNics.get(appNet.getId()));
networks.put(appNet, new ArrayList<NicProfile>(Arrays.asList(defaultNic)));
}
@ -6645,27 +6650,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (securityGroupIdList != null && !securityGroupIdList.isEmpty()) {
throw new InvalidParameterValueException("Can't move vm with security groups; security group feature is not enabled in this zone");
}
Set<NetworkVO> applicableNetworks = new HashSet<NetworkVO>();
// if networkIdList is null and the first network of vm is shared network, then keep it if possible
if (networkIdList == null || networkIdList.isEmpty()) {
NicVO defaultNicOld = _nicDao.findDefaultNicForVM(vm.getId());
if (defaultNicOld != null) {
NetworkVO defaultNetworkOld = _networkDao.findById(defaultNicOld.getNetworkId());
if (defaultNetworkOld != null && defaultNetworkOld.getGuestType() == Network.GuestType.Shared && defaultNetworkOld.getAclType() == ACLType.Domain) {
try {
_networkModel.checkNetworkPermissions(newAccount, defaultNetworkOld);
applicableNetworks.add(defaultNetworkOld);
} catch (PermissionDeniedException e) {
s_logger.debug("AssignVM: the shared network on old default nic can not be applied to new account");
}
if (canAccountUseNetwork(newAccount, defaultNetworkOld)) {
applicableNetworks.add(defaultNetworkOld);
requestedIPv4ForNics.put(defaultNetworkOld.getId(), defaultNicOld.getIPv4Address());
requestedIPv6ForNics.put(defaultNetworkOld.getId(), defaultNicOld.getIPv6Address());
s_logger.debug("AssignVM: use old shared network " + defaultNetworkOld.getName() + " with old ip " + defaultNicOld.getIPv4Address() + " on default nic of vm:" + vm.getInstanceName());
}
}
}
// cleanup the network for the oldOwner
_networkMgr.cleanupNics(vmOldProfile);
_networkMgr.expungeNics(vmOldProfile);
if (networkIdList != null && !networkIdList.isEmpty()) {
// add any additional networks
for (Long networkId : networkIdList) {
@ -6685,6 +6683,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
ex.addProxyObject(network.getUuid(), "networkId");
throw ex;
}
if (network.getGuestType() == Network.GuestType.Shared && network.getAclType() == ACLType.Domain) {
NicVO nicOld = _nicDao.findByNtwkIdAndInstanceId(network.getId(), vm.getId());
if (nicOld != null) {
requestedIPv4ForNics.put(network.getId(), nicOld.getIPv4Address());
requestedIPv6ForNics.put(network.getId(), nicOld.getIPv6Address());
s_logger.debug("AssignVM: use old shared network " + network.getName() + " with old ip " + nicOld.getIPv4Address() + " on nic of vm:" + vm.getInstanceName());
}
}
s_logger.debug("AssignVM: Added network " + network.getName() + " to vm " + vm.getId());
applicableNetworks.add(network);
}
} else if (applicableNetworks.isEmpty()) {
@ -6748,6 +6756,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
applicableNetworks.add(defaultNetwork);
}
// cleanup the network for the oldOwner
_networkMgr.cleanupNics(vmOldProfile);
_networkMgr.removeNics(vmOldProfile);
// add the new nics
LinkedHashMap<Network, List<? extends NicProfile>> networks = new LinkedHashMap<Network, List<? extends NicProfile>>();
int toggle = 0;
@ -6757,6 +6769,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
defaultNic.setDefaultNic(true);
toggle++;
}
defaultNic.setRequestedIPv4(requestedIPv4ForNics.get(appNet.getId()));
defaultNic.setRequestedIPv6(requestedIPv6ForNics.get(appNet.getId()));
networks.put(appNet, new ArrayList<NicProfile>(Arrays.asList(defaultNic)));
}
VirtualMachine vmi = _itMgr.findById(vm.getId());
@ -6769,6 +6783,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return vm;
}
private boolean canAccountUseNetwork(Account newAccount, Network network) {
if (network != null && network.getAclType() == ACLType.Domain
&& (network.getGuestType() == Network.GuestType.Shared
|| network.getGuestType() == Network.GuestType.L2)) {
try {
_networkModel.checkNetworkPermissions(newAccount, network);
return true;
} catch (PermissionDeniedException e) {
s_logger.debug(String.format("AssignVM: %s network %s can not be used by new account %s", network.getGuestType(), network.getName(), newAccount.getAccountName()));
return false;
}
}
return false;
}
@Override
public UserVm restoreVM(RestoreVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException {
// Input validation

View File

@ -517,6 +517,35 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
return storagePool;
}
private Pair<UnmanagedInstanceTO.Disk, List<UnmanagedInstanceTO.Disk>> getRootAndDataDisks(List<UnmanagedInstanceTO.Disk> disks, final Map<String, Long> dataDiskOfferingMap) {
UnmanagedInstanceTO.Disk rootDisk = null;
List<UnmanagedInstanceTO.Disk> dataDisks = new ArrayList<>();
if (disks.size() == 1) {
rootDisk = disks.get(0);
return new Pair<>(rootDisk, dataDisks);
}
Set<String> callerDiskIds = dataDiskOfferingMap.keySet();
if (callerDiskIds.size() != disks.size() - 1) {
String msg = String.format("VM has total %d disks for which %d disk offering mappings provided. %d disks need a disk offering for import", disks.size(), callerDiskIds.size(), disks.size()-1);
LOGGER.error(String.format("%s. %s parameter can be used to provide disk offerings for the disks", msg, ApiConstants.DATADISK_OFFERING_LIST));
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, msg);
}
List<String> diskIdsWithoutOffering = new ArrayList<>();
for (UnmanagedInstanceTO.Disk disk : disks) {
String diskId = disk.getDiskId();
if (!callerDiskIds.contains(diskId)) {
diskIdsWithoutOffering.add(diskId);
rootDisk = disk;
} else {
dataDisks.add(disk);
}
}
if (diskIdsWithoutOffering.size() > 1) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM has total %d disks, disk offering mapping not provided for %d disks. Disk IDs that may need a disk offering - %s", disks.size(), diskIdsWithoutOffering.size()-1, String.join(", ", diskIdsWithoutOffering)));
}
return new Pair<>(rootDisk, dataDisks);
}
private void checkUnmanagedDiskAndOfferingForImport(UnmanagedInstanceTO.Disk disk, DiskOffering diskOffering, ServiceOffering serviceOffering, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed)
throws ServerApiException, PermissionDeniedException, ResourceAllocationException {
if (serviceOffering == null && diskOffering == null) {
@ -942,17 +971,16 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
if (CollectionUtils.isEmpty(unmanagedInstanceDisks)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("No attached disks found for the unmanaged VM: %s", instanceName));
}
final UnmanagedInstanceTO.Disk rootDisk = unmanagedInstance.getDisks().get(0);
Pair<UnmanagedInstanceTO.Disk, List<UnmanagedInstanceTO.Disk>> rootAndDataDisksPair = getRootAndDataDisks(unmanagedInstanceDisks, dataDiskOfferingMap);
final UnmanagedInstanceTO.Disk rootDisk = rootAndDataDisksPair.first();
final List<UnmanagedInstanceTO.Disk> dataDisks = rootAndDataDisksPair.second();
if (rootDisk == null || Strings.isNullOrEmpty(rootDisk.getController())) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed. Unable to retrieve root disk details for VM: %s ", instanceName));
}
allDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, rootDisk.getController());
List<UnmanagedInstanceTO.Disk> dataDisks = new ArrayList<>();
try {
checkUnmanagedDiskAndOfferingForImport(rootDisk, null, validatedServiceOffering, owner, zone, cluster, migrateAllowed);
if (unmanagedInstanceDisks.size() > 1) { // Data disk(s) present
dataDisks.addAll(unmanagedInstanceDisks);
dataDisks.remove(0);
if (CollectionUtils.isNotEmpty(dataDisks)) { // Data disk(s) present
checkUnmanagedDiskAndOfferingForImport(dataDisks, dataDiskOfferingMap, owner, zone, cluster, migrateAllowed);
allDetails.put(VmDetailConstants.DATA_DISK_CONTROLLER, dataDisks.get(0).getController());
}

View File

@ -580,10 +580,10 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
}
/* (non-Javadoc)
* @see com.cloud.network.NetworkManager#expungeNics(com.cloud.vm.VirtualMachineProfile)
* @see com.cloud.network.NetworkManager#removeNics(com.cloud.vm.VirtualMachineProfile)
*/
@Override
public void expungeNics(VirtualMachineProfile vm) {
public void removeNics(VirtualMachineProfile vm) {
// TODO Auto-generated method stub
}