diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 1165556d5f4..869b66bd3d0 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -222,9 +222,7 @@ public class LibvirtVMDef { guestDef.append("\n"); } } - if (_arch == null || !_arch.equals("aarch64")) { - guestDef.append("\n"); - } + guestDef.append("\n"); guestDef.append("\n"); if (iothreads) { guestDef.append(String.format("%s", NUMBER_OF_IOTHREADS)); diff --git a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java index dd50c8d2214..d560c4ee806 100644 --- a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java +++ b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java @@ -235,6 +235,28 @@ public class LinstorStorageAdaptor implements StorageAdaptor { } } + /** + * Checks if the given resource is in use by drbd on any host and + * if so set the drbd option allow-two-primaries + * @param api linstor api object + * @param rscName resource name to set allow-two-primaries if in use + * @throws ApiException if any problem connecting to the Linstor controller + */ + private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws ApiException { + if (LinstorUtil.isResourceInUse(api, rscName)) { + // allow 2 primaries for live migration, should be removed by disconnect on the other end + ResourceDefinitionModify rdm = new ResourceDefinitionModify(); + Properties props = new Properties(); + props.put("DrbdOptions/Net/allow-two-primaries", "yes"); + rdm.setOverrideProps(props); + ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm); + if (answers.hasError()) { + s_logger.error("Unable to set 'allow-two-primaries' on " + rscName); + // do not fail here as adding allow-two-primaries property is only a problem while live migrating + } + } + } + @Override public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details) { @@ -261,16 +283,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor { try { - // allow 2 primaries for live migration, should be removed by disconnect on the other end - ResourceDefinitionModify rdm = new ResourceDefinitionModify(); - Properties props = new Properties(); - props.put("DrbdOptions/Net/allow-two-primaries", "yes"); - rdm.setOverrideProps(props); - ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm); - if (answers.hasError()) { - s_logger.error("Unable to set 'allow-two-primaries' on " + rscName); - // do not fail here as adding allow-two-primaries property is only a problem while live migrating - } + allow2PrimariesIfInUse(api, rscName); } catch (ApiException apiEx) { s_logger.error(apiEx); // do not fail here as adding allow-two-primaries property is only a problem while live migrating diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java index 33cbea0996d..8c42bdc2a96 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java @@ -24,6 +24,7 @@ import com.linbit.linstor.api.model.ApiCallRc; import com.linbit.linstor.api.model.ApiCallRcList; import com.linbit.linstor.api.model.Node; import com.linbit.linstor.api.model.ProviderKind; +import com.linbit.linstor.api.model.Resource; import com.linbit.linstor.api.model.ResourceGroup; import com.linbit.linstor.api.model.ResourceWithVolumes; import com.linbit.linstor.api.model.StoragePool; @@ -183,4 +184,22 @@ public class LinstorUtil { throw new CloudRuntimeException(apiEx); } } + + /** + * Check if any resource of the given name is InUse on any host. + * + * @param api developer api object to use + * @param rscName resource name to check in use state. + * @return True if a resource found that is in use(primary) state, else false. + * @throws ApiException forwards api errors + */ + public static boolean isResourceInUse(DevelopersApi api, String rscName) throws ApiException { + List rscs = api.resourceList(rscName, null, null); + if (rscs != null) { + return rscs.stream() + .anyMatch(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse())); + } + s_logger.error("isResourceInUse: null returned from resourceList"); + return false; + } } diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index b5908935350..0178236a21a 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -353,6 +353,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage if (possibleAddr.getState() != State.Free) { continue; } + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("trying ip address %s", possibleAddr.getAddress())); + } possibleAddr.setSourceNat(sourceNat); possibleAddr.setAllocatedTime(new Date()); possibleAddr.setAllocatedInDomainId(owner.getDomainId()); @@ -367,15 +370,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage possibleAddr.setAssociatedWithNetworkId(guestNetworkId); possibleAddr.setVpcId(vpcId); } - if (_ipAddressDao.lockRow(possibleAddr.getId(), true) != null) { - final IPAddressVO userIp = _ipAddressDao.findById(possibleAddr.getId()); - if (userIp.getState() == State.Free) { - possibleAddr.setState(State.Allocating); - if (_ipAddressDao.update(possibleAddr.getId(), possibleAddr)) { - finalAddress = possibleAddr; - break; - } - } + finalAddress = assignIpAddressWithLock(possibleAddr); + if (finalAddress != null) { + break; } } @@ -397,6 +394,29 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage }); } + private IPAddressVO assignIpAddressWithLock(IPAddressVO possibleAddr) { + IPAddressVO finalAddress = null; + IPAddressVO userIp = _ipAddressDao.acquireInLockTable(possibleAddr.getId()); + if (userIp != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("locked row for ip address %s (id: %s)", possibleAddr.getAddress(), possibleAddr.getUuid())); + } + if (userIp.getState() == State.Free) { + possibleAddr.setState(State.Allocating); + if (_ipAddressDao.update(possibleAddr.getId(), possibleAddr)) { + s_logger.info(String.format("successfully allocated ip address %s", possibleAddr.getAddress())); + finalAddress = possibleAddr; + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug(String.format("locked ip address %s is not free (%s)", possibleAddr.getAddress(), userIp.getState())); + } + } + _ipAddressDao.releaseFromLockTable(possibleAddr.getId()); + } + return finalAddress; + } + @Override public boolean configure(String name, Map params) { // populate providers