Skip to content

Commit f7b7339

Browse files
committed
Merge branch '4.19'
2 parents 8af08dd + 5b7c86a commit f7b7339

File tree

9 files changed

+98
-26
lines changed

9 files changed

+98
-26
lines changed

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -2078,8 +2078,8 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
20782078
migrateDiskInfo = configureMigrateDiskInfo(srcVolumeInfo, destPath, backingPath);
20792079
migrateDiskInfo.setSourceDiskOnStorageFileSystem(isStoragePoolTypeOfFile(sourceStoragePool));
20802080
migrateDiskInfoList.add(migrateDiskInfo);
2081-
prepareDiskWithSecretConsumerDetail(vmTO, srcVolumeInfo, destVolumeInfo.getPath());
20822081
}
2082+
prepareDiskWithSecretConsumerDetail(vmTO, srcVolumeInfo, destVolumeInfo.getPath());
20832083

20842084
migrateStorage.put(srcVolumeInfo.getPath(), migrateDiskInfo);
20852085

@@ -2479,7 +2479,8 @@ protected void verifyLiveMigrationForKVM(Map<VolumeInfo, DataStore> volumeDataSt
24792479
throw new CloudRuntimeException("Destination storage pool with ID " + dataStore.getId() + " was not located.");
24802480
}
24812481

2482-
if (srcStoragePoolVO.isManaged() && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
2482+
boolean isSrcAndDestPoolPowerFlexStorage = srcStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex) && destStoragePoolVO.getPoolType().equals(Storage.StoragePoolType.PowerFlex);
2483+
if (srcStoragePoolVO.isManaged() && !isSrcAndDestPoolPowerFlexStorage && srcStoragePoolVO.getId() != destStoragePoolVO.getId()) {
24832484
throw new CloudRuntimeException("Migrating a volume online with KVM from managed storage is not currently supported.");
24842485
}
24852486

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtOvsFetchInterfaceCommandWrapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public Ternary<String, String, String> getInterfaceDetails(String interfaceName)
8989

9090
@Override
9191
public Answer execute(final OvsFetchInterfaceCommand command, final LibvirtComputingResource libvirtComputingResource) {
92-
final String label = "'" + command.getLabel() + "'";
92+
final String label = command.getLabel();
9393

9494
logger.debug("Will look for network with name-label:" + label);
9595
try {

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java

+62-15
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.cloud.hypervisor.kvm.storage;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.Collections;
2122
import java.util.HashMap;
2223
import java.util.List;
@@ -48,6 +49,7 @@
4849
import com.linbit.linstor.api.model.Resource;
4950
import com.linbit.linstor.api.model.ResourceConnectionModify;
5051
import com.linbit.linstor.api.model.ResourceDefinition;
52+
import com.linbit.linstor.api.model.ResourceDefinitionModify;
5153
import com.linbit.linstor.api.model.ResourceGroupSpawn;
5254
import com.linbit.linstor.api.model.ResourceMakeAvailable;
5355
import com.linbit.linstor.api.model.ResourceWithVolumes;
@@ -235,6 +237,34 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
235237
}
236238
}
237239

240+
private void setAllowTwoPrimariesOnRD(DevelopersApi api, String rscName) throws ApiException {
241+
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
242+
Properties props = new Properties();
243+
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
244+
props.put("DrbdOptions/Net/protocol", "C");
245+
rdm.setOverrideProps(props);
246+
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
247+
if (answers.hasError()) {
248+
logger.error(String.format("Unable to set protocol C and 'allow-two-primaries' on %s", rscName));
249+
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
250+
}
251+
}
252+
253+
private void setAllowTwoPrimariesOnRc(DevelopersApi api, String rscName, String inUseNode) throws ApiException {
254+
ResourceConnectionModify rcm = new ResourceConnectionModify();
255+
Properties props = new Properties();
256+
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
257+
props.put("DrbdOptions/Net/protocol", "C");
258+
rcm.setOverrideProps(props);
259+
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
260+
if (answers.hasError()) {
261+
logger.error(String.format(
262+
"Unable to set protocol C and 'allow-two-primaries' on %s/%s/%s",
263+
inUseNode, localNodeName, rscName));
264+
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
265+
}
266+
}
267+
238268
/**
239269
* Checks if the given resource is in use by drbd on any host and
240270
* if so set the drbd option allow-two-primaries
@@ -246,16 +276,13 @@ private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws Ap
246276
String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
247277
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
248278
// allow 2 primaries for live migration, should be removed by disconnect on the other end
249-
ResourceConnectionModify rcm = new ResourceConnectionModify();
250-
Properties props = new Properties();
251-
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
252-
props.put("DrbdOptions/Net/protocol", "C");
253-
rcm.setOverrideProps(props);
254-
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
255-
if (answers.hasError()) {
256-
logger.error("Unable to set protocol C and 'allow-two-primaries' on {}/{}/{}",
257-
inUseNode, localNodeName, rscName);
258-
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
279+
280+
// if non hyperconverged setup, we have to set allow-two-primaries on the resource-definition
281+
// as there is no resource connection between diskless nodes.
282+
if (LinstorUtil.areResourcesDiskless(api, rscName, Arrays.asList(inUseNode, localNodeName))) {
283+
setAllowTwoPrimariesOnRD(api, rscName);
284+
} else {
285+
setAllowTwoPrimariesOnRc(api, rscName, inUseNode);
259286
}
260287
}
261288
}
@@ -294,11 +321,22 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
294321
return true;
295322
}
296323

297-
private void removeTwoPrimariesRcProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
324+
private void removeTwoPrimariesRDProps(DevelopersApi api, String rscName, List<String> deleteProps)
325+
throws ApiException {
326+
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
327+
rdm.deleteProps(deleteProps);
328+
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
329+
if (answers.hasError()) {
330+
logger.error(
331+
String.format("Failed to remove 'protocol' and 'allow-two-primaries' on %s: %s",
332+
rscName, LinstorUtil.getBestErrorMessage(answers)));
333+
// do not fail here as removing allow-two-primaries property isn't fatal
334+
}
335+
}
336+
337+
private void removeTwoPrimariesRcProps(DevelopersApi api, String rscName, String inUseNode, List<String> deleteProps)
338+
throws ApiException {
298339
ResourceConnectionModify rcm = new ResourceConnectionModify();
299-
List<String> deleteProps = new ArrayList<>();
300-
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
301-
deleteProps.add("DrbdOptions/Net/protocol");
302340
rcm.deleteProps(deleteProps);
303341
ApiCallRcList answers = api.resourceConnectionModify(rscName, localNodeName, inUseNode, rcm);
304342
if (answers.hasError()) {
@@ -310,6 +348,15 @@ private void removeTwoPrimariesRcProps(DevelopersApi api, String inUseNode, Stri
310348
}
311349
}
312350

351+
private void removeTwoPrimariesProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
352+
List<String> deleteProps = new ArrayList<>();
353+
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
354+
deleteProps.add("DrbdOptions/Net/protocol");
355+
356+
removeTwoPrimariesRDProps(api, rscName, deleteProps);
357+
removeTwoPrimariesRcProps(api, rscName, inUseNode, deleteProps);
358+
}
359+
313360
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
314361
{
315362
if (volumePath == null) {
@@ -343,7 +390,7 @@ private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
343390
try {
344391
String inUseNode = LinstorUtil.isResourceInUse(api, rsc.getName());
345392
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
346-
removeTwoPrimariesRcProps(api, inUseNode, rsc.getName());
393+
removeTwoPrimariesProps(api, inUseNode, rsc.getName());
347394
}
348395
} catch (ApiException apiEx) {
349396
logger.error(apiEx.getBestMessage());

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java

+24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.cloudstack.storage.datastore.util;
1818

1919
import com.linbit.linstor.api.ApiClient;
20+
import com.linbit.linstor.api.ApiConsts;
2021
import com.linbit.linstor.api.ApiException;
2122
import com.linbit.linstor.api.DevelopersApi;
2223
import com.linbit.linstor.api.model.ApiCallRc;
@@ -33,6 +34,7 @@
3334

3435
import javax.annotation.Nonnull;
3536

37+
import java.util.Collection;
3638
import java.util.Collections;
3739
import java.util.List;
3840
import java.util.stream.Collectors;
@@ -210,6 +212,28 @@ public static String isResourceInUse(DevelopersApi api, String rscName) throws A
210212
return null;
211213
}
212214

215+
/**
216+
* Check if the given resources are diskless.
217+
*
218+
* @param api developer api object to use
219+
* @param rscName resource name to check in use state.
220+
* @return NodeName where the resource is inUse, if not in use `null`
221+
* @throws ApiException forwards api errors
222+
*/
223+
public static boolean areResourcesDiskless(DevelopersApi api, String rscName, Collection<String> nodeNames)
224+
throws ApiException {
225+
List<Resource> rscs = api.resourceList(rscName, null, null);
226+
if (rscs != null) {
227+
Collection<String> disklessNodes = rscs.stream()
228+
.filter(rsc -> rsc.getFlags() != null && (rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS) ||
229+
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS)))
230+
.map(rsc -> rsc.getNodeName().toLowerCase())
231+
.collect(Collectors.toList());
232+
return disklessNodes.containsAll(nodeNames.stream().map(String::toLowerCase).collect(Collectors.toList()));
233+
}
234+
return false;
235+
}
236+
213237
/**
214238
* Try to get the device path for the given resource name.
215239
* This could be made a bit more direct after java-linstor api is fixed for layer data subtypes.

systemvm/debian/opt/cloud/bin/cs/CsFile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,6 @@ def deleteLine(self, search):
174174
self.new_config = list(temp_config)
175175

176176
def compare(self, o):
177-
result = (isinstance(o, self.__class__) and set(self.config) == set(o.config))
177+
result = (isinstance(o, self.__class__) and self.config == o.config)
178178
logging.debug("Comparison of CsFiles content is ==> %s" % result)
179179
return result

ui/src/config/section/compute.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ export default {
542542
if (store.listAllProjects) {
543543
fields.push('project')
544544
}
545-
if (store.apis.scaleKubernetesCluster.params.filter(x => x.name === 'autoscalingenabled').length > 0) {
545+
if (store.apis.scaleKubernetesCluster?.params?.filter(x => x.name === 'autoscalingenabled').length > 0) {
546546
fields.splice(2, 0, 'autoscalingenabled')
547547
}
548548
fields.push('zonename')

ui/src/views/compute/KubernetesServiceTab.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ export default {
284284
}
285285
},
286286
mounted () {
287-
if (this.$store.getters.apis.scaleKubernetesCluster.params.filter(x => x.name === 'nodeids').length > 0 && this.resource.clustertype === 'CloudManaged') {
287+
if (this.$store.getters.apis.scaleKubernetesCluster?.params?.filter(x => x.name === 'nodeids').length > 0 && this.resource.clustertype === 'CloudManaged') {
288288
this.vmColumns.push({
289289
key: 'actions',
290290
title: this.$t('label.actions'),

utils/src/main/java/com/cloud/utils/HttpUtils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ public static boolean validateSessionKey(final HttpSession session, final Map<St
117117
return false;
118118
}
119119
final String jsessionidFromCookie = HttpUtils.findCookie(cookies, "JSESSIONID");
120-
if (jsessionidFromCookie == null
121-
|| !(jsessionidFromCookie.startsWith(session.getId() + '.'))) {
120+
if (jsessionidFromCookie != null
121+
&& !(jsessionidFromCookie.equals(session.getId()) || jsessionidFromCookie.startsWith(session.getId() + '.'))) {
122122
LOGGER.error("JSESSIONID from cookie is invalid.");
123123
return false;
124124
}

utils/src/test/java/com/cloud/utils/HttpUtilsTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public void validateSessionKeyTest() {
7474
params = null;
7575
cookies = new Cookie[]{new Cookie(sessionKeyString, sessionKeyValue)};
7676
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, "randomString", HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
77-
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
77+
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
7878

7979
// param null, cookies not null test (JSESSIONID is not null and matches)
8080
cookies = new Cookie[2];
@@ -95,7 +95,7 @@ public void validateSessionKeyTest() {
9595
cookies = null;
9696
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
9797
params.put(sessionKeyString, new String[]{sessionKeyValue});
98-
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
98+
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
9999

100100
// both param and cookies not null test (JSESSIONID is null)
101101
params = new HashMap<String, Object[]>();
@@ -104,7 +104,7 @@ public void validateSessionKeyTest() {
104104
params.put(sessionKeyString, new String[]{"incorrectValue"});
105105
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
106106
params.put(sessionKeyString, new String[]{sessionKeyValue});
107-
assertFalse(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
107+
assertTrue(HttpUtils.validateSessionKey(session, params, cookies, sessionKeyString, HttpUtils.ApiSessionKeyCheckOption.CookieOrParameter));
108108

109109
// both param and cookies not null test (JSESSIONID is not null but mismatches)
110110
params = new HashMap<String, Object[]>();

0 commit comments

Comments
 (0)