Skip to content

Commit 1ba9f76

Browse files
committed
Linstor fix host picking (apache#12047)
1 parent 5fedf32 commit 1ba9f76

1 file changed

Lines changed: 55 additions & 46 deletions

File tree

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
@@ -62,6 +62,8 @@
6262
import com.cloud.api.storage.LinstorRevertBackupSnapshotCommand;
6363
import com.cloud.configuration.Config;
6464
import com.cloud.host.Host;
65+
import com.cloud.host.HostVO;
66+
import com.cloud.host.Status;
6567
import com.cloud.host.dao.HostDao;
6668
import com.cloud.resource.ResourceState;
6769
import com.cloud.storage.DataStoreRole;
@@ -918,9 +920,10 @@ private String revertSnapshotFromImageStore(
918920
_backupsnapshotwait,
919921
VirtualMachineManager.ExecuteInSequence.value());
920922

921-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, rscName);
923+
final StoragePool pool = (StoragePool) volumeInfo.getDataStore();
924+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, pool, rscName);
922925
if (optEP.isEmpty()) {
923-
optEP = getLinstorEP(linstorApi, rscName);
926+
optEP = getLinstorEP(linstorApi, pool, rscName);
924927
}
925928

926929
if (optEP.isPresent()) {
@@ -1060,13 +1063,29 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10601063
Answer answer = copyVolume(srcData, dstData);
10611064
res = new CopyCommandResult(null, answer);
10621065
} else {
1063-
Answer answer = new Answer(null, false, "noimpl");
1064-
res = new CopyCommandResult(null, answer);
1065-
res.setResult("Not implemented yet");
1066+
throw new CloudRuntimeException("Not implemented for Linstor primary storage.");
10661067
}
10671068
callback.complete(res);
10681069
}
10691070

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

1100-
if (host == null)
1101-
{
1102-
s_logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1103-
return Optional.empty();
1104-
}
1105-
else
1106-
{
1107-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1108-
}
1114+
s_logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1115+
return Optional.empty();
11091116
}
11101117

1111-
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rscName) throws ApiException {
1118+
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, StoragePool storagePool, String rscName)
1119+
throws ApiException {
11121120
List<com.linbit.linstor.api.model.StoragePool> linSPs = LinstorUtil.getDiskfulStoragePools(api, rscName);
11131121
if (linSPs != null) {
1114-
for (com.linbit.linstor.api.model.StoragePool sp : linSPs) {
1115-
Host host = _hostDao.findByName(sp.getNodeName());
1116-
if (host != null && host.getResourceState() == ResourceState.Enabled) {
1117-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1118-
}
1122+
List<String> linstorNodeNames = linSPs.stream()
1123+
.map(com.linbit.linstor.api.model.StoragePool::getNodeName)
1124+
.collect(Collectors.toList());
1125+
Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
1126+
if (host != null) {
1127+
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
11191128
}
11201129
}
11211130
s_logger.error("Linstor: No diskfull host found.");
@@ -1196,12 +1205,12 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
11961205
VirtualMachineManager.ExecuteInSequence.value());
11971206

11981207
try {
1199-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1208+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12001209
if (optEP.isPresent()) {
12011210
answer = optEP.get().sendMessage(cmd);
12021211
} else {
1203-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
12041212
deleteResourceDefinition(pool, rscName);
1213+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12051214
}
12061215
} catch (ApiException exc) {
12071216
s_logger.error("copy template failed: ", exc);
@@ -1238,12 +1247,12 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
12381247
Answer answer;
12391248

12401249
try {
1241-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1250+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12421251
if (optEP.isPresent()) {
12431252
answer = optEP.get().sendMessage(cmd);
12441253
}
12451254
else {
1246-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
1255+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12471256
}
12481257
} catch (ApiException exc) {
12491258
s_logger.error("copy volume failed: ", exc);
@@ -1276,14 +1285,14 @@ private Answer copyFromTemporaryResource(
12761285
try {
12771286
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
12781287

1279-
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
1288+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, restoreName);
12801289
if (optEPAny.isPresent()) {
12811290
// patch the src device path to the temporary linstor resource
12821291
snapshotObject.setPath(devName);
12831292
origCmd.setSrcTO(snapshotObject.getTO());
12841293
answer = optEPAny.get().sendMessage(origCmd);
1285-
} else{
1286-
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
1294+
} else {
1295+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12871296
}
12881297
} finally {
12891298
// delete the temporary resource, noop if already gone
@@ -1345,7 +1354,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
13451354
VirtualMachineManager.ExecuteInSequence.value());
13461355
cmd.setOptions(options);
13471356

1348-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
1357+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, rscName);
13491358
Answer answer;
13501359
if (optEP.isPresent()) {
13511360
answer = optEP.get().sendMessage(cmd);

0 commit comments

Comments
 (0)