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