Skip to content

Commit 8dcfc7c

Browse files
authored
Linstor fix host picking (#12047)
1 parent 2b373a4 commit 8dcfc7c

File tree

1 file changed

+55
-46
lines changed

1 file changed

+55
-46
lines changed

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java

Lines changed: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
import com.cloud.api.storage.LinstorRevertBackupSnapshotCommand;
6464
import com.cloud.configuration.Config;
6565
import com.cloud.host.Host;
66+
import com.cloud.host.HostVO;
67+
import com.cloud.host.Status;
6668
import com.cloud.host.dao.HostDao;
6769
import com.cloud.resource.ResourceState;
6870
import com.cloud.storage.DataStoreRole;
@@ -921,9 +923,10 @@ private String revertSnapshotFromImageStore(
921923
_backupsnapshotwait,
922924
VirtualMachineManager.ExecuteInSequence.value());
923925

924-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, rscName);
926+
final StoragePool pool = (StoragePool) volumeInfo.getDataStore();
927+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, pool, rscName);
925928
if (optEP.isEmpty()) {
926-
optEP = getLinstorEP(linstorApi, rscName);
929+
optEP = getLinstorEP(linstorApi, pool, rscName);
927930
}
928931

929932
if (optEP.isPresent()) {
@@ -1063,13 +1066,29 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10631066
Answer answer = copyVolume(srcData, dstData);
10641067
res = new CopyCommandResult(null, answer);
10651068
} else {
1066-
Answer answer = new Answer(null, false, "noimpl");
1067-
res = new CopyCommandResult(null, answer);
1068-
res.setResult("Not implemented yet");
1069+
throw new CloudRuntimeException("Not implemented for Linstor primary storage.");
10691070
}
10701071
callback.complete(res);
10711072
}
10721073

1074+
private Host getEnabledClusterHost(StoragePool storagePool, List<String> linstorNodeNames) {
1075+
List<HostVO> csHosts;
1076+
if (storagePool.getClusterId() != null) {
1077+
csHosts = _hostDao.findByClusterId(storagePool.getClusterId());
1078+
} else {
1079+
csHosts = _hostDao.findByDataCenterId(storagePool.getDataCenterId());
1080+
}
1081+
Collections.shuffle(csHosts); // so we do not always pick the same host for operations
1082+
for (HostVO host : csHosts) {
1083+
if (host.getResourceState() == ResourceState.Enabled &&
1084+
host.getStatus() == Status.Up &&
1085+
linstorNodeNames.contains(host.getName())) {
1086+
return host;
1087+
}
1088+
}
1089+
return null;
1090+
}
1091+
10731092
/**
10741093
* Tries to get a Linstor cloudstack end point, that is at least diskless.
10751094
*
@@ -1078,47 +1097,37 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10781097
* @return Optional RemoteHostEndPoint if one could get found.
10791098
* @throws ApiException
10801099
*/
1081-
private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, String rscName) throws ApiException {
1100+
private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, StoragePool storagePool, String rscName)
1101+
throws ApiException {
10821102
List<String> linstorNodeNames = LinstorUtil.getLinstorNodeNames(api);
1083-
Collections.shuffle(linstorNodeNames); // do not always pick the first linstor node
1084-
1085-
Host host = null;
1086-
for (String nodeName : linstorNodeNames) {
1087-
host = _hostDao.findByName(nodeName);
1088-
if (host != null && host.getResourceState() == ResourceState.Enabled) {
1089-
logger.info(String.format("Linstor: Make resource %s available on node %s ...", rscName, nodeName));
1090-
ApiCallRcList answers = api.resourceMakeAvailableOnNode(rscName, nodeName, new ResourceMakeAvailable());
1091-
if (!answers.hasError()) {
1092-
break; // found working host
1093-
} else {
1094-
logger.error(
1095-
String.format("Linstor: Unable to make resource %s on node %s available: %s",
1096-
rscName,
1097-
nodeName,
1098-
LinstorUtil.getBestErrorMessage(answers)));
1099-
}
1103+
Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
1104+
if (host != null) {
1105+
logger.info("Linstor: Make resource {} available on node {} ...", rscName, host.getName());
1106+
ApiCallRcList answers = api.resourceMakeAvailableOnNode(
1107+
rscName, host.getName(), new ResourceMakeAvailable());
1108+
if (answers.hasError()) {
1109+
logger.error("Linstor: Unable to make resource {} on node {} available: {}",
1110+
rscName, host.getName(), LinstorUtil.getBestErrorMessage(answers));
1111+
return Optional.empty();
1112+
} else {
1113+
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
11001114
}
11011115
}
11021116

1103-
if (host == null)
1104-
{
1105-
logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1106-
return Optional.empty();
1107-
}
1108-
else
1109-
{
1110-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1111-
}
1117+
logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1118+
return Optional.empty();
11121119
}
11131120

1114-
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rscName) throws ApiException {
1121+
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, StoragePool storagePool, String rscName)
1122+
throws ApiException {
11151123
List<com.linbit.linstor.api.model.StoragePool> linSPs = LinstorUtil.getDiskfulStoragePools(api, rscName);
11161124
if (linSPs != null) {
1117-
for (com.linbit.linstor.api.model.StoragePool sp : linSPs) {
1118-
Host host = _hostDao.findByName(sp.getNodeName());
1119-
if (host != null && host.getResourceState() == ResourceState.Enabled) {
1120-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1121-
}
1125+
List<String> linstorNodeNames = linSPs.stream()
1126+
.map(com.linbit.linstor.api.model.StoragePool::getNodeName)
1127+
.collect(Collectors.toList());
1128+
Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
1129+
if (host != null) {
1130+
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
11221131
}
11231132
}
11241133
logger.error("Linstor: No diskfull host found.");
@@ -1199,12 +1208,12 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
11991208
VirtualMachineManager.ExecuteInSequence.value());
12001209

12011210
try {
1202-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1211+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12031212
if (optEP.isPresent()) {
12041213
answer = optEP.get().sendMessage(cmd);
12051214
} else {
1206-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
12071215
deleteResourceDefinition(pool, rscName);
1216+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12081217
}
12091218
} catch (ApiException exc) {
12101219
logger.error("copy template failed: ", exc);
@@ -1241,12 +1250,12 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
12411250
Answer answer;
12421251

12431252
try {
1244-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1253+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12451254
if (optEP.isPresent()) {
12461255
answer = optEP.get().sendMessage(cmd);
12471256
}
12481257
else {
1249-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
1258+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12501259
}
12511260
} catch (ApiException exc) {
12521261
logger.error("copy volume failed: ", exc);
@@ -1279,14 +1288,14 @@ private Answer copyFromTemporaryResource(
12791288
try {
12801289
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
12811290

1282-
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
1291+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, restoreName);
12831292
if (optEPAny.isPresent()) {
12841293
// patch the src device path to the temporary linstor resource
12851294
snapshotObject.setPath(devName);
12861295
origCmd.setSrcTO(snapshotObject.getTO());
12871296
answer = optEPAny.get().sendMessage(origCmd);
1288-
} else{
1289-
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
1297+
} else {
1298+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12901299
}
12911300
} finally {
12921301
// delete the temporary resource, noop if already gone
@@ -1348,7 +1357,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
13481357
VirtualMachineManager.ExecuteInSequence.value());
13491358
cmd.setOptions(options);
13501359

1351-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
1360+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, rscName);
13521361
Answer answer;
13531362
if (optEP.isPresent()) {
13541363
answer = optEP.get().sendMessage(cmd);

0 commit comments

Comments
 (0)