mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge branch '4.19'
This commit is contained in:
commit
f7b7339bcf
@ -2078,8 +2078,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
|||||||
migrateDiskInfo = configureMigrateDiskInfo(srcVolumeInfo, destPath, backingPath);
|
migrateDiskInfo = configureMigrateDiskInfo(srcVolumeInfo, destPath, backingPath);
|
||||||
migrateDiskInfo.setSourceDiskOnStorageFileSystem(isStoragePoolTypeOfFile(sourceStoragePool));
|
migrateDiskInfo.setSourceDiskOnStorageFileSystem(isStoragePoolTypeOfFile(sourceStoragePool));
|
||||||
migrateDiskInfoList.add(migrateDiskInfo);
|
migrateDiskInfoList.add(migrateDiskInfo);
|
||||||
prepareDiskWithSecretConsumerDetail(vmTO, srcVolumeInfo, destVolumeInfo.getPath());
|
|
||||||
}
|
}
|
||||||
|
prepareDiskWithSecretConsumerDetail(vmTO, srcVolumeInfo, destVolumeInfo.getPath());
|
||||||
|
|
||||||
migrateStorage.put(srcVolumeInfo.getPath(), migrateDiskInfo);
|
migrateStorage.put(srcVolumeInfo.getPath(), migrateDiskInfo);
|
||||||
|
|
||||||
@ -2479,7 +2479,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
|||||||
throw new CloudRuntimeException("Destination storage pool with ID " + dataStore.getId() + " was not located.");
|
throw new CloudRuntimeException("Destination storage pool with ID " + dataStore.getId() + " was not located.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcStoragePoolVO.isManaged() && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
|
boolean isSrcAndDestPoolPowerFlexStorage = srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex) && destStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex);
|
||||||
|
if (srcStoragePoolVO.isManaged() && !isSrcAndDestPoolPowerFlexStorage && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
|
||||||
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage is not currently supported.");
|
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage is not currently supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,7 @@ public final class LibvirtOvsFetchInterfaceCommandWrapper extends CommandWrapper
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Answer execute(final OvsFetchInterfaceCommand command, final LibvirtComputingResource libvirtComputingResource) {
|
public Answer execute(final OvsFetchInterfaceCommand command, final LibvirtComputingResource libvirtComputingResource) {
|
||||||
final String label = "'" + command.getLabel() + "'";
|
final String label = command.getLabel();
|
||||||
|
|
||||||
logger.debug("Will look for network with name-label:" + label);
|
logger.debug("Will look for network with name-label:" + label);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.hypervisor.kvm.storage;
|
package com.cloud.hypervisor.kvm.storage;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -48,6 +49,7 @@ import com.linbit.linstor.api.model.ProviderKind;
|
|||||||
import com.linbit.linstor.api.model.Resource;
|
import com.linbit.linstor.api.model.Resource;
|
||||||
import com.linbit.linstor.api.model.ResourceConnectionModify;
|
import com.linbit.linstor.api.model.ResourceConnectionModify;
|
||||||
import com.linbit.linstor.api.model.ResourceDefinition;
|
import com.linbit.linstor.api.model.ResourceDefinition;
|
||||||
|
import com.linbit.linstor.api.model.ResourceDefinitionModify;
|
||||||
import com.linbit.linstor.api.model.ResourceGroupSpawn;
|
import com.linbit.linstor.api.model.ResourceGroupSpawn;
|
||||||
import com.linbit.linstor.api.model.ResourceMakeAvailable;
|
import com.linbit.linstor.api.model.ResourceMakeAvailable;
|
||||||
import com.linbit.linstor.api.model.ResourceWithVolumes;
|
import com.linbit.linstor.api.model.ResourceWithVolumes;
|
||||||
@ -235,6 +237,34 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setAllowTwoPrimariesOnRD(DevelopersApi api, String rscName) throws ApiException {
|
||||||
|
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
|
||||||
|
props.put("DrbdOptions/Net/protocol", "C");
|
||||||
|
rdm.setOverrideProps(props);
|
||||||
|
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
|
||||||
|
if (answers.hasError()) {
|
||||||
|
logger.error(String.format("Unable to set protocol C and 'allow-two-primaries' on %s", rscName));
|
||||||
|
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAllowTwoPrimariesOnRc(DevelopersApi api, String rscName, String inUseNode) throws ApiException {
|
||||||
|
ResourceConnectionModify rcm = new ResourceConnectionModify();
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
|
||||||
|
props.put("DrbdOptions/Net/protocol", "C");
|
||||||
|
rcm.setOverrideProps(props);
|
||||||
|
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
|
||||||
|
if (answers.hasError()) {
|
||||||
|
logger.error(String.format(
|
||||||
|
"Unable to set protocol C and 'allow-two-primaries' on %s/%s/%s",
|
||||||
|
inUseNode, localNodeName, rscName));
|
||||||
|
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given resource is in use by drbd on any host and
|
* Checks if the given resource is in use by drbd on any host and
|
||||||
* if so set the drbd option allow-two-primaries
|
* if so set the drbd option allow-two-primaries
|
||||||
@ -246,16 +276,13 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
|
String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
|
||||||
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
|
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
|
||||||
// allow 2 primaries for live migration, should be removed by disconnect on the other end
|
// allow 2 primaries for live migration, should be removed by disconnect on the other end
|
||||||
ResourceConnectionModify rcm = new ResourceConnectionModify();
|
|
||||||
Properties props = new Properties();
|
// if non hyperconverged setup, we have to set allow-two-primaries on the resource-definition
|
||||||
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
|
// as there is no resource connection between diskless nodes.
|
||||||
props.put("DrbdOptions/Net/protocol", "C");
|
if (LinstorUtil.areResourcesDiskless(api, rscName, Arrays.asList(inUseNode, localNodeName))) {
|
||||||
rcm.setOverrideProps(props);
|
setAllowTwoPrimariesOnRD(api, rscName);
|
||||||
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
|
} else {
|
||||||
if (answers.hasError()) {
|
setAllowTwoPrimariesOnRc(api, rscName, inUseNode);
|
||||||
logger.error("Unable to set protocol C and 'allow-two-primaries' on {}/{}/{}",
|
|
||||||
inUseNode, localNodeName, rscName);
|
|
||||||
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,11 +321,22 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeTwoPrimariesRcProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
|
private void removeTwoPrimariesRDProps(DevelopersApi api, String rscName, List<String> deleteProps)
|
||||||
|
throws ApiException {
|
||||||
|
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
|
||||||
|
rdm.deleteProps(deleteProps);
|
||||||
|
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
|
||||||
|
if (answers.hasError()) {
|
||||||
|
logger.error(
|
||||||
|
String.format("Failed to remove 'protocol' and 'allow-two-primaries' on %s: %s",
|
||||||
|
rscName, LinstorUtil.getBestErrorMessage(answers)));
|
||||||
|
// do not fail here as removing allow-two-primaries property isn't fatal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeTwoPrimariesRcProps(DevelopersApi api, String rscName, String inUseNode, List<String> deleteProps)
|
||||||
|
throws ApiException {
|
||||||
ResourceConnectionModify rcm = new ResourceConnectionModify();
|
ResourceConnectionModify rcm = new ResourceConnectionModify();
|
||||||
List<String> deleteProps = new ArrayList<>();
|
|
||||||
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
|
|
||||||
deleteProps.add("DrbdOptions/Net/protocol");
|
|
||||||
rcm.deleteProps(deleteProps);
|
rcm.deleteProps(deleteProps);
|
||||||
ApiCallRcList answers = api.resourceConnectionModify(rscName, localNodeName, inUseNode, rcm);
|
ApiCallRcList answers = api.resourceConnectionModify(rscName, localNodeName, inUseNode, rcm);
|
||||||
if (answers.hasError()) {
|
if (answers.hasError()) {
|
||||||
@ -310,6 +348,15 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeTwoPrimariesProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
|
||||||
|
List<String> deleteProps = new ArrayList<>();
|
||||||
|
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
|
||||||
|
deleteProps.add("DrbdOptions/Net/protocol");
|
||||||
|
|
||||||
|
removeTwoPrimariesRDProps(api, rscName, deleteProps);
|
||||||
|
removeTwoPrimariesRcProps(api, rscName, inUseNode, deleteProps);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
|
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
|
||||||
{
|
{
|
||||||
if (volumePath == null) {
|
if (volumePath == null) {
|
||||||
@ -343,7 +390,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
|||||||
try {
|
try {
|
||||||
String inUseNode = LinstorUtil.isResourceInUse(api, rsc.getName());
|
String inUseNode = LinstorUtil.isResourceInUse(api, rsc.getName());
|
||||||
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
|
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
|
||||||
removeTwoPrimariesRcProps(api, inUseNode, rsc.getName());
|
removeTwoPrimariesProps(api, inUseNode, rsc.getName());
|
||||||
}
|
}
|
||||||
} catch (ApiException apiEx) {
|
} catch (ApiException apiEx) {
|
||||||
logger.error(apiEx.getBestMessage());
|
logger.error(apiEx.getBestMessage());
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package org.apache.cloudstack.storage.datastore.util;
|
package org.apache.cloudstack.storage.datastore.util;
|
||||||
|
|
||||||
import com.linbit.linstor.api.ApiClient;
|
import com.linbit.linstor.api.ApiClient;
|
||||||
|
import com.linbit.linstor.api.ApiConsts;
|
||||||
import com.linbit.linstor.api.ApiException;
|
import com.linbit.linstor.api.ApiException;
|
||||||
import com.linbit.linstor.api.DevelopersApi;
|
import com.linbit.linstor.api.DevelopersApi;
|
||||||
import com.linbit.linstor.api.model.ApiCallRc;
|
import com.linbit.linstor.api.model.ApiCallRc;
|
||||||
@ -33,6 +34,7 @@ import com.linbit.linstor.api.model.Volume;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -210,6 +212,28 @@ public class LinstorUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given resources are diskless.
|
||||||
|
*
|
||||||
|
* @param api developer api object to use
|
||||||
|
* @param rscName resource name to check in use state.
|
||||||
|
* @return NodeName where the resource is inUse, if not in use `null`
|
||||||
|
* @throws ApiException forwards api errors
|
||||||
|
*/
|
||||||
|
public static boolean areResourcesDiskless(DevelopersApi api, String rscName, Collection<String> nodeNames)
|
||||||
|
throws ApiException {
|
||||||
|
List<Resource> rscs = api.resourceList(rscName, null, null);
|
||||||
|
if (rscs != null) {
|
||||||
|
Collection<String> disklessNodes = rscs.stream()
|
||||||
|
.filter(rsc -> rsc.getFlags() != null && (rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS) ||
|
||||||
|
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS)))
|
||||||
|
.map(rsc -> rsc.getNodeName().toLowerCase())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return disklessNodes.containsAll(nodeNames.stream().map(String::toLowerCase).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get the device path for the given resource name.
|
* Try to get the device path for the given resource name.
|
||||||
* This could be made a bit more direct after java-linstor api is fixed for layer data subtypes.
|
* This could be made a bit more direct after java-linstor api is fixed for layer data subtypes.
|
||||||
|
|||||||
@ -174,6 +174,6 @@ class CsFile:
|
|||||||
self.new_config = list(temp_config)
|
self.new_config = list(temp_config)
|
||||||
|
|
||||||
def compare(self, o):
|
def compare(self, o):
|
||||||
result = (isinstance(o, self.__class__) and set(self.config) == set(o.config))
|
result = (isinstance(o, self.__class__) and self.config == o.config)
|
||||||
logging.debug("Comparison of CsFiles content is ==> %s" % result)
|
logging.debug("Comparison of CsFiles content is ==> %s" % result)
|
||||||
return result
|
return result
|
||||||
|
|||||||
@ -542,7 +542,7 @@ export default {
|
|||||||
if (store.listAllProjects) {
|
if (store.listAllProjects) {
|
||||||
fields.push('project')
|
fields.push('project')
|
||||||
}
|
}
|
||||||
if (store.apis.scaleKubernetesCluster.params.filter(x => x.name === 'autoscalingenabled').length > 0) {
|
if (store.apis.scaleKubernetesCluster?.params?.filter(x => x.name === 'autoscalingenabled').length > 0) {
|
||||||
fields.splice(2, 0, 'autoscalingenabled')
|
fields.splice(2, 0, 'autoscalingenabled')
|
||||||
}
|
}
|
||||||
fields.push('zonename')
|
fields.push('zonename')
|
||||||
|
|||||||
@ -284,7 +284,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
if (this.$store.getters.apis.scaleKubernetesCluster.params.filter(x => x.name === 'nodeids').length > 0 && this.resource.clustertype === 'CloudManaged') {
|
if (this.$store.getters.apis.scaleKubernetesCluster?.params?.filter(x => x.name === 'nodeids').length > 0 && this.resource.clustertype === 'CloudManaged') {
|
||||||
this.vmColumns.push({
|
this.vmColumns.push({
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
title: this.$t('label.actions'),
|
title: this.$t('label.actions'),
|
||||||
|
|||||||
@ -117,8 +117,8 @@ public class HttpUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final String jsessionidFromCookie = HttpUtils.findCookie(cookies, "JSESSIONID");
|
final String jsessionidFromCookie = HttpUtils.findCookie(cookies, "JSESSIONID");
|
||||||
if (jsessionidFromCookie == null
|
if (jsessionidFromCookie != null
|
||||||
|| !(jsessionidFromCookie.startsWith(session.getId() + '.'))) {
|
&& !(jsessionidFromCookie.equals(session.getId()) || jsessionidFromCookie.startsWith(session.getId() + '.'))) {
|
||||||
LOGGER.error("JSESSIONID from cookie is invalid.");
|
LOGGER.error("JSESSIONID from cookie is invalid.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,7 @@ public class HttpUtilsTest {
|
|||||||
params = null;
|
params = null;
|
||||||
cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)};
|
cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)};
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
|
|
||||||
// param null, cookies not null test (JSESSIONID is not null and matches)
|
// param null, cookies not null test (JSESSIONID is not null and matches)
|
||||||
cookies = new Cookie[2];
|
cookies = new Cookie[2];
|
||||||
@ -95,7 +95,7 @@ public class HttpUtilsTest {
|
|||||||
cookies = null;
|
cookies = null;
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
params.put(sessionKeyString, new String[]{sessionKeyValue});
|
params.put(sessionKeyString, new String[]{sessionKeyValue});
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
|
|
||||||
// both param and cookies not null test (JSESSIONID is null)
|
// both param and cookies not null test (JSESSIONID is null)
|
||||||
params = new HashMap<String, Object[]>();
|
params = new HashMap<String, Object[]>();
|
||||||
@ -104,7 +104,7 @@ public class HttpUtilsTest {
|
|||||||
params.put(sessionKeyString, new String[]{"incorrectValue"});
|
params.put(sessionKeyString, new String[]{"incorrectValue"});
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
params.put(sessionKeyString, new String[]{sessionKeyValue});
|
params.put(sessionKeyString, new String[]{sessionKeyValue});
|
||||||
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
|
||||||
|
|
||||||
// both param and cookies not null test (JSESSIONID is not null but mismatches)
|
// both param and cookies not null test (JSESSIONID is not null but mismatches)
|
||||||
params = new HashMap<String, Object[]>();
|
params = new HashMap<String, Object[]>();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user